This repository has been archived by the owner on Dec 27, 2023. It is now read-only.
/
PopupWindow.js
364 lines (314 loc) · 11.1 KB
/
PopupWindow.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
/*
* Tine 2.0
*
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
* @author Cornelius Weiss <c.weiss@metaways.de>
* @copyright Copyright (c) 2007-2008 Metaways Infosystems GmbH (http://www.metaways.de)
*
*/
Ext.ns('Ext.ux');
/**
* Class for handling of native browser popup window.
* <p>This class is intended to make the usage of a native popup window as easy as dealing with a modal window.<p>
* <p>Example usage:</p>
* <pre><code>
var win = new Ext.ux.PopupWindow({
name: 'TasksEditWindow',
width: 700,
height: 300,
url:index.php?method=Tasks.editTask&taskId=5
});
* </code></pre>
*
* @namespace Ext.ux
* @class Ext.ux.PopupWindow
* @extends Ext.Component
*/
Ext.ux.PopupWindow = function(config) {
Ext.apply(this, config);
this.contentPanelConstructorConfig = this.contentPanelConstructorConfig || {};
this.addEvents({
/**
* @event beforecolse
* @desc Fires before the Window is closed. A handler can return false to cancel the close.
* @param {Ext.ux.PopupWindow}
*/
"beforeclose" : true,
/**
* @event render
* @desc Fires after the viewport in the popup window is rendered
* @param {Ext.ux.PopupWindow}
*/
"render" : true,
/**
* @event close
* @desc Fired, when the window got closed
*/
"close" : true
});
Ext.ux.PopupWindow.superclass.constructor.call(this);
};
Ext.extend(Ext.ux.PopupWindow, Ext.Component, {
/**
* @cfg {String}
* @param {String} url
* @desc url to open
*/
url: null,
/**
* @cfg {String} internal name of new window
*/
name: 'new window',
/**
* @cfg {Int} width of new window
*/
width: 600,
/**
* @cfg {Int} height of new window
*/
height: 500,
/**
* @cfg {Bolean}
*/
modal: false,
/**
* @cfg {Boolean} cut relation to opener
* needed e.g. when opening a new mainWindow
*/
noParent: false,
/**
* @cfg {String}
*/
layout: 'fit',
/**
* @cfg {String}
*/
title: null,
/**
* @cfg {String} Name of a constructor to create item property
*/
contentPanelConstructor: null,
/**
* @cfg {Object} Config object to pass to itemContructor
*/
contentPanelConstructorConfig: null,
/**
* @property {Browser Window}
*/
popup: null,
/**
* @property {Ext.ux.PopupWindowMgr}
*/
windowManager: null,
renderTo: 'useRenderFn',
/**
* @private
*/
initComponent: function(){
if (! this.title) {
this.title = Tine.title;
}
this.manager = this.windowManager = Ext.ux.PopupWindowMgr;
this.stateful = true;
this.stateId = 'ux.popupwindow-' + this.contentPanelConstructor;
Ext.ux.PopupWindow.superclass.initComponent.call(this);
},
render: function() {
// open popup window first to save time
if (! this.popup) {
try {
// NOTE: FF scales windows itself -> no need for adoption
if (!Ext.isGecko) {
const zoomRatiosAvailable = [ 0.25, 1/3, 0.5, 2/3, 0.75, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2, 2.5, 3, 4, 5 ];
const widthCorrection = 16;
const cssPixelRatio = (window.outerWidth-widthCorrection) / window.innerWidth;
const diffs = zoomRatiosAvailable.map((r) => {return Math.abs(r-cssPixelRatio)});
const zoomRatio = zoomRatiosAvailable[diffs.indexOf(Math.min.apply(Math, diffs))];
this.width = Math.round(this.width * zoomRatio);
this.height = Math.round(this.height * zoomRatio);
}
// safari counts window decoration to window height oo
this.height += Ext.isSafari ? 28 : 0;
//limit the window size
this.width = Math.min(screen.availWidth, this.width);
this.height = Math.min(screen.availHeight, this.height);
this.popup = this.openWindow(this.name, this.url, this.width, this.height);
if (this.noParent) {
this.popup.opener = null;
}
} catch (e) {
this.popup = null;
}
}
if (! this.popup) {
return Ext.MessageBox.alert(
i18n._('Cannot open new window'),
String.format(i18n._('An attempt to open a new window failed. When clicking OK, the opening procedure will be tried again. To avoid this message, please deactivate your browsers popup blocker for {0}'), Tine.title),
function () {
this.render();
}.bind(this)
);
}
//. register window ( in fact register complete PopupWindow )
this.windowManager.register(this);
// closing properly or prevent close otherwise
this.popup.addEventListener('beforeunload', _.bind((e) => {
if(!this.forceClose && this.fireEvent("beforeclose", this) === false){
e.preventDefault();
e.returnValue = '';
}
}, this));
this.popup.addEventListener('resize', _.debounce(_.bind(this.saveState, this), 150));
// NOTE: 'beforeunload' in Chrome does not help
this.popup.setInterval(() => {
if (this.popup.screenX !== this.screenX || this.popup.screenY !== this.screenY) {
this.screenX = this.popup.screenX;
this.screenY = this.popup.screenY;
this.saveState();
}
}, 1000)
},
/**
* Open browsers native popup
*
* @param {string} windowName
* @param {string} url
* @param width
* @param height
*/
openWindow: function (windowName, url, width, height) {
windowName = Ext.isString(windowName) ? windowName.replace(/[^a-zA-Z0-9_]/g, '') : windowName;
// thanks to http://www.nigraphic.com/blog/java-script/how-open-new-window-popup-center-screen
// Determine offsets in case of dualscreen
const dualScreenLeft = window.screenLeft != undefined ? window.screenLeft : screen.left;
const dualScreenTop = window.screenTop != undefined ? window.screenTop : screen.top;
// Window should be opened on mid of tine window
const w = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
const h = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height;
// Determine correct left and top values including dual screen setup
this.screenX = _.isNumber(this.screenX) ? this.screenX : ((w / 2) - (width / 2)) + dualScreenLeft;
this.screenY = _.isNumber(this.screenY) ? this.screenY : ((h / 2) - (height / 2)) + dualScreenTop;
const popup = window.open(url, windowName,
'width=' + width + ',height=' + height + ',screenY=' + this.screenY + ',screenX=' + this.screenX +
',directories=no,toolbar=no,location=no,menubar=no,scrollbars=no,status=no,resizable=yes,dependent=no');
// NOTE: FF 105 on linux always opens new windows in fullscreen
// NOTE: in Chrome we don't have innerHeight that early
if (Ext.isGecko && Ext.isLinux) {
const heightOffset = popup.outerHeight - popup.innerHeight;
popup.resizeTo(width, heightOffset+height);
}
return popup;
},
getState : function() {
// NOTE: innerWidth/Height is the original dimension without scaling
// NOTE: FF does auto scaling!
const state = {
width: this.popup.innerWidth,
height: this.popup.innerHeight,
screenX: this.popup.screenX,
screenY: this.popup.screenY
};
return state;
},
// state might have tiny window (e.g. because of small beamer attached)
// -> only apply bigger states
applyState : function(state){
if(state){
state.width = Math.max(state.width, this.width);
state.height = Math.max(state.height, this.height);
}
Ext.ux.PopupWindow.superclass.applyState.call(this, state);
},
/**
* rename window name
*
* @param {String} new name
*/
rename: function(newName) {
this.windowManager.unregister(this);
this.name = this.popup.name = newName;
this.windowManager.register(this);
},
/**
* Sets the title text for the panel and optionally the icon class.
*
* @param {String} title The title text to set
* @param {String} iconCls (optional) iconCls A user-defined CSS class that provides the icon image for this panel
*/
setTitle: function(title, iconCls) {
if (this.popup && this.popup.document) {
this.popup.document.title = Ext.util.Format.stripTags(title);
}
},
/**
* Closes the window, removes it from the DOM and destroys the window object.
* The beforeclose event is fired before the close happens and will cancel
* the close action if it returns false.
*/
close: function(force) {
if(force || this.fireEvent("beforeclose", this) !== false){
this.forceClose = true;
this.fireEvent('close', this);
var popup = this.popup;
this.destroy();
if (this.navigateBackOnClose) {
popup.history.back();
} else {
Ext.ux.PopupWindow.close(popup);
}
return true;
} else {
this.confirmLeavSite(this);
}
},
/**
* @private
*
* called after this.popups native onLoad
* note: 'this' references the popup, whereas window references the parent
*/
onLoad: function() {
this.Ext.onReady(function() {
this.navigateBackOnClose = this.popup.history.length > 1;
}, this);
},
/**
* @private
*
* note: 'this' references the popup, whereas window references the parent
*/
onClose: function() {
},
/**
* @private
*/
destroy: function() {
Ext.ux.PopupWindow.superclass.destroy.call(this);
this.purgeListeners();
this.windowManager.unregister(this);
this.popup = null;
}
});
/**
* close window and show close message
*
* @static
* @param win
*/
Ext.ux.PopupWindow.close = function(win) {
win = win || window;
// defer messagebox as it should not be displayed too early
win.setTimeout(function(){
if (! win) {
return;
}
win.Ext.MessageBox.alert(
i18n._('Window can be closed'),
String.format(i18n._('This Window can be closed now. To avoid this message please deactivate your browsers popup blocker for {0}'), Tine.title),
function() {
win.close();
}
);
}, 2000);
win.close();
};