]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/js/tinymce/tiny_mce_popup.js
WordPress 4.0.1-scripts
[autoinstalls/wordpress.git] / wp-includes / js / tinymce / tiny_mce_popup.js
1 /**
2  * Popup.js
3  *
4  * Copyright, Moxiecode Systems AB
5  * Released under LGPL License.
6  *
7  * License: http://www.tinymce.com/license
8  * Contributing: http://www.tinymce.com/contributing
9  */
10
11 var tinymce, tinyMCE;
12
13 /**
14  * TinyMCE popup/dialog helper class. This gives you easy access to the
15  * parent editor instance and a bunch of other things. It's higly recommended
16  * that you load this script into your dialogs.
17  *
18  * @static
19  * @class tinyMCEPopup
20  */
21 var tinyMCEPopup = {
22         /**
23          * Initializes the popup this will be called automatically.
24          *
25          * @method init
26          */
27         init: function() {
28                 var self = this, parentWin, settings, uiWindow;
29
30                 // Find window & API
31                 parentWin = self.getWin();
32                 tinymce = tinyMCE = parentWin.tinymce;
33                 self.editor = tinymce.EditorManager.activeEditor;
34                 self.params = self.editor.windowManager.getParams();
35
36                 uiWindow = self.editor.windowManager.windows[self.editor.windowManager.windows.length - 1];
37                 self.features = uiWindow.features;
38                 self.uiWindow = uiWindow;
39
40                 settings = self.editor.settings;
41
42                 // Setup popup CSS path(s)
43                 if (settings.popup_css !== false) {
44                         if (settings.popup_css) {
45                                 settings.popup_css = self.editor.documentBaseURI.toAbsolute(settings.popup_css);
46                         } else {
47                                 settings.popup_css = self.editor.baseURI.toAbsolute("plugins/compat3x/css/dialog.css");
48                         }
49                 }
50
51                 if (settings.popup_css_add) {
52                         settings.popup_css += ',' + self.editor.documentBaseURI.toAbsolute(settings.popup_css_add);
53                 }
54
55                 // Setup local DOM
56                 self.dom = self.editor.windowManager.createInstance('tinymce.dom.DOMUtils', document, {
57                         ownEvents: true,
58                         proxy: tinyMCEPopup._eventProxy
59                 });
60
61                 self.dom.bind(window, 'ready', self._onDOMLoaded, self);
62
63                 // Enables you to skip loading the default css
64                 if (self.features.popup_css !== false) {
65                         self.dom.loadCSS(self.features.popup_css || self.editor.settings.popup_css);
66                 }
67
68                 // Setup on init listeners
69                 self.listeners = [];
70
71                 /**
72                  * Fires when the popup is initialized.
73                  *
74                  * @event onInit
75                  * @param {tinymce.Editor} editor Editor instance.
76                  * @example
77                  * // Alerts the selected contents when the dialog is loaded
78                  * tinyMCEPopup.onInit.add(function(ed) {
79                  *     alert(ed.selection.getContent());
80                  * });
81                  * 
82                  * // Executes the init method on page load in some object using the SomeObject scope
83                  * tinyMCEPopup.onInit.add(SomeObject.init, SomeObject);
84                  */
85                 self.onInit = {
86                         add: function(func, scope) {
87                                 self.listeners.push({func : func, scope : scope});
88                         }
89                 };
90
91                 self.isWindow = !self.getWindowArg('mce_inline');
92                 self.id = self.getWindowArg('mce_window_id');
93         },
94
95         /**
96          * Returns the reference to the parent window that opened the dialog.
97          *
98          * @method getWin
99          * @return {Window} Reference to the parent window that opened the dialog.
100          */
101         getWin: function() {
102                 // Added frameElement check to fix bug: #2817583
103                 return (!window.frameElement && window.dialogArguments) || opener || parent || top;
104         },
105
106         /**
107          * Returns a window argument/parameter by name.
108          *
109          * @method getWindowArg
110          * @param {String} name Name of the window argument to retrive.
111          * @param {String} defaultValue Optional default value to return.
112          * @return {String} Argument value or default value if it wasn't found.
113          */
114         getWindowArg : function(name, defaultValue) {
115                 var value = this.params[name];
116
117                 return tinymce.is(value) ? value : defaultValue;
118         },
119
120         /**
121          * Returns a editor parameter/config option value.
122          *
123          * @method getParam
124          * @param {String} name Name of the editor config option to retrive.
125          * @param {String} defaultValue Optional default value to return.
126          * @return {String} Parameter value or default value if it wasn't found.
127          */
128         getParam : function(name, defaultValue) {
129                 return this.editor.getParam(name, defaultValue);
130         },
131
132         /**
133          * Returns a language item by key.
134          *
135          * @method getLang
136          * @param {String} name Language item like mydialog.something.
137          * @param {String} defaultValue Optional default value to return.
138          * @return {String} Language value for the item like "my string" or the default value if it wasn't found.
139          */
140         getLang : function(name, defaultValue) {
141                 return this.editor.getLang(name, defaultValue);
142         },
143
144         /**
145          * Executed a command on editor that opened the dialog/popup.
146          *
147          * @method execCommand
148          * @param {String} cmd Command to execute.
149          * @param {Boolean} ui Optional boolean value if the UI for the command should be presented or not.
150          * @param {Object} val Optional value to pass with the comman like an URL.
151          * @param {Object} a Optional arguments object.
152          */
153         execCommand : function(cmd, ui, val, args) {
154                 args = args || {};
155                 args.skip_focus = 1;
156
157                 this.restoreSelection();
158                 return this.editor.execCommand(cmd, ui, val, args);
159         },
160
161         /**
162          * Resizes the dialog to the inner size of the window. This is needed since various browsers
163          * have different border sizes on windows.
164          *
165          * @method resizeToInnerSize
166          */
167         resizeToInnerSize : function() {
168                 /*var self = this;
169
170                 // Detach it to workaround a Chrome specific bug
171                 // https://sourceforge.net/tracker/?func=detail&atid=635682&aid=2926339&group_id=103281
172                 setTimeout(function() {
173                         var vp = self.dom.getViewPort(window);
174
175                         self.editor.windowManager.resizeBy(
176                                 self.getWindowArg('mce_width') - vp.w,
177                                 self.getWindowArg('mce_height') - vp.h,
178                                 self.id || window
179                         );
180                 }, 10);*/
181         },
182
183         /**
184          * Will executed the specified string when the page has been loaded. This function
185          * was added for compatibility with the 2.x branch.
186          *
187          * @method executeOnLoad
188          * @param {String} evil String to evalutate on init.
189          */
190         executeOnLoad : function(evil) {
191                 this.onInit.add(function() {
192                         eval(evil);
193                 });
194         },
195
196         /**
197          * Stores the current editor selection for later restoration. This can be useful since some browsers
198          * looses it's selection if a control element is selected/focused inside the dialogs.
199          *
200          * @method storeSelection
201          */
202         storeSelection : function() {
203                 this.editor.windowManager.bookmark = tinyMCEPopup.editor.selection.getBookmark(1);
204         },
205
206         /**
207          * Restores any stored selection. This can be useful since some browsers
208          * looses it's selection if a control element is selected/focused inside the dialogs.
209          *
210          * @method restoreSelection
211          */
212         restoreSelection : function() {
213                 var self = tinyMCEPopup;
214
215                 if (!self.isWindow && tinymce.isIE) {
216                         self.editor.selection.moveToBookmark(self.editor.windowManager.bookmark);
217                 }
218         },
219
220         /**
221          * Loads a specific dialog language pack. If you pass in plugin_url as a argument
222          * when you open the window it will load the <plugin url>/langs/<code>_dlg.js lang pack file.
223          *
224          * @method requireLangPack
225          */
226         requireLangPack : function() {
227                 var self = this, url = self.getWindowArg('plugin_url') || self.getWindowArg('theme_url'), settings = self.editor.settings, lang;
228
229                 if (settings.language !== false) {
230                         lang = settings.language || "en";
231                 }
232
233                 if (url && lang && self.features.translate_i18n !== false && settings.language_load !== false) {
234                         url += '/langs/' + lang + '_dlg.js';
235
236                         if (!tinymce.ScriptLoader.isDone(url)) {
237                                 document.write('<script type="text/javascript" src="' + url + '"></script>');
238                                 tinymce.ScriptLoader.markDone(url);
239                         }
240                 }
241         },
242
243         /**
244          * Executes a color picker on the specified element id. When the user
245          * then selects a color it will be set as the value of the specified element.
246          *
247          * @method pickColor
248          * @param {DOMEvent} e DOM event object.
249          * @param {string} element_id Element id to be filled with the color value from the picker.
250          */
251         pickColor : function(e, element_id) {
252                 this.execCommand('mceColorPicker', true, {
253                         color : document.getElementById(element_id).value,
254                         func : function(c) {
255                                 document.getElementById(element_id).value = c;
256
257                                 try {
258                                         document.getElementById(element_id).onchange();
259                                 } catch (ex) {
260                                         // Try fire event, ignore errors
261                                 }
262                         }
263                 });
264         },
265
266         /**
267          * Opens a filebrowser/imagebrowser this will set the output value from
268          * the browser as a value on the specified element.
269          *
270          * @method openBrowser
271          * @param {string} element_id Id of the element to set value in.
272          * @param {string} type Type of browser to open image/file/flash.
273          * @param {string} option Option name to get the file_broswer_callback function name from.
274          */
275         openBrowser : function(element_id, type) {
276                 tinyMCEPopup.restoreSelection();
277                 this.editor.execCallback('file_browser_callback', element_id, document.getElementById(element_id).value, type, window);
278         },
279
280         /**
281          * Creates a confirm dialog. Please don't use the blocking behavior of this
282          * native version use the callback method instead then it can be extended.
283          *
284          * @method confirm
285          * @param {String} t Title for the new confirm dialog.
286          * @param {function} cb Callback function to be executed after the user has selected ok or cancel.
287          * @param {Object} s Optional scope to execute the callback in.
288          */
289         confirm : function(t, cb, s) {
290                 this.editor.windowManager.confirm(t, cb, s, window);
291         },
292
293         /**
294          * Creates a alert dialog. Please don't use the blocking behavior of this
295          * native version use the callback method instead then it can be extended.
296          *
297          * @method alert
298          * @param {String} tx Title for the new alert dialog.
299          * @param {function} cb Callback function to be executed after the user has selected ok.
300          * @param {Object} s Optional scope to execute the callback in.
301          */
302         alert : function(tx, cb, s) {
303                 this.editor.windowManager.alert(tx, cb, s, window);
304         },
305
306         /**
307          * Closes the current window.
308          *
309          * @method close
310          */
311         close : function() {
312                 var t = this;
313
314                 // To avoid domain relaxing issue in Opera
315                 function close() {
316                         t.editor.windowManager.close(window);
317                         tinymce = tinyMCE = t.editor = t.params = t.dom = t.dom.doc = null; // Cleanup
318                 }
319
320                 if (tinymce.isOpera) {
321                         t.getWin().setTimeout(close, 0);
322                 } else {
323                         close();
324                 }
325         },
326
327         // Internal functions   
328
329         _restoreSelection : function() {
330                 var e = window.event.srcElement;
331
332                 if (e.nodeName == 'INPUT' && (e.type == 'submit' || e.type == 'button')) {
333                         tinyMCEPopup.restoreSelection();
334                 }
335         },
336
337 /*      _restoreSelection : function() {
338                 var e = window.event.srcElement;
339
340                 // If user focus a non text input or textarea
341                 if ((e.nodeName != 'INPUT' && e.nodeName != 'TEXTAREA') || e.type != 'text')
342                         tinyMCEPopup.restoreSelection();
343         },*/
344
345         _onDOMLoaded : function() {
346                 var t = tinyMCEPopup, ti = document.title, h, nv;
347
348                 // Translate page
349                 if (t.features.translate_i18n !== false) {
350                         var map = {
351                                 "update": "Ok",
352                                 "insert": "Ok",
353                                 "cancel": "Cancel",
354                                 "not_set": "--",
355                                 "class_name": "Class name",
356                                 "browse": "Browse"
357                         };
358
359                         var langCode = tinymce.settings.language || 'en';
360                         for (var key in map) {
361                                 tinymce.i18n.data[langCode + "." + key] = tinymce.i18n.translate(map[key]);
362                         }
363
364                         h = document.body.innerHTML;
365
366                         // Replace a=x with a="x" in IE
367                         if (tinymce.isIE) {
368                                 h = h.replace(/ (value|title|alt)=([^"][^\s>]+)/gi, ' $1="$2"');
369                         }
370
371                         document.dir = t.editor.getParam('directionality','');
372
373                         if ((nv = t.editor.translate(h)) && nv != h) {
374                                 document.body.innerHTML = nv;
375                         }
376
377                         if ((nv = t.editor.translate(ti)) && nv != ti) {
378                                 document.title = ti = nv;
379                         }
380                 }
381
382                 if (!t.editor.getParam('browser_preferred_colors', false) || !t.isWindow) {
383                         t.dom.addClass(document.body, 'forceColors');
384                 }
385
386                 document.body.style.display = '';
387
388                 // Restore selection in IE when focus is placed on a non textarea or input element of the type text
389                 if (tinymce.Env.ie) {
390                         if (tinymce.Env.ie < 11) {
391                                 document.attachEvent('onmouseup', tinyMCEPopup._restoreSelection);
392
393                                 // Add base target element for it since it would fail with modal dialogs
394                                 t.dom.add(t.dom.select('head')[0], 'base', {target: '_self'});
395                         } else {
396                                 document.addEventListener('mouseup', tinyMCEPopup._restoreSelection, false);
397                         }
398                 }
399
400                 t.restoreSelection();
401                 t.resizeToInnerSize();
402
403                 // Set inline title
404                 if (!t.isWindow) {
405                         t.editor.windowManager.setTitle(window, ti);
406                 } else {
407                         window.focus();
408                 }
409
410                 if (!tinymce.isIE && !t.isWindow) {
411                         t.dom.bind(document, 'focus', function() {
412                                 t.editor.windowManager.focus(t.id);
413                         });
414                 }
415
416                 // Patch for accessibility
417                 tinymce.each(t.dom.select('select'), function(e) {
418                         e.onkeydown = tinyMCEPopup._accessHandler;
419                 });
420
421                 // Call onInit
422                 // Init must be called before focus so the selection won't get lost by the focus call
423                 tinymce.each(t.listeners, function(o) {
424                         o.func.call(o.scope, t.editor);
425                 });
426
427                 // Move focus to window
428                 if (t.getWindowArg('mce_auto_focus', true)) {
429                         window.focus();
430
431                         // Focus element with mceFocus class
432                         tinymce.each(document.forms, function(f) {
433                                 tinymce.each(f.elements, function(e) {
434                                         if (t.dom.hasClass(e, 'mceFocus') && !e.disabled) {
435                                                 e.focus();
436                                                 return false; // Break loop
437                                         }
438                                 });
439                         });
440                 }
441
442                 document.onkeyup = tinyMCEPopup._closeWinKeyHandler;
443
444                 if ('textContent' in document) {
445                         t.uiWindow.getEl('head').firstChild.textContent = document.title;
446                 } else {
447                         t.uiWindow.getEl('head').firstChild.innerText = document.title;
448                 }
449         },
450
451         _accessHandler : function(e) {
452                 e = e || window.event;
453
454                 if (e.keyCode == 13 || e.keyCode == 32) {
455                         var elm = e.target || e.srcElement;
456
457                         if (elm.onchange) {
458                                 elm.onchange();
459                         }
460
461                         return tinymce.dom.Event.cancel(e);
462                 }
463         },
464
465         _closeWinKeyHandler : function(e) {
466                 e = e || window.event;
467
468                 if (e.keyCode == 27) {
469                         tinyMCEPopup.close();
470                 }
471         },
472
473         _eventProxy: function(id) {
474                 return function(evt) {
475                         tinyMCEPopup.dom.events.callNativeHandler(id, evt);
476                 };
477         }
478 };
479
480 tinyMCEPopup.init();
481
482 tinymce.util.Dispatcher = function(scope) {
483         this.scope = scope || this;
484         this.listeners = [];
485
486         this.add = function(callback, scope) {
487                 this.listeners.push({cb : callback, scope : scope || this.scope});
488
489                 return callback;
490         };
491
492         this.addToTop = function(callback, scope) {
493                 var self = this, listener = {cb : callback, scope : scope || self.scope};
494
495                 // Create new listeners if addToTop is executed in a dispatch loop
496                 if (self.inDispatch) {
497                         self.listeners = [listener].concat(self.listeners);
498                 } else {
499                         self.listeners.unshift(listener);
500                 }
501
502                 return callback;
503         };
504
505         this.remove = function(callback) {
506                 var listeners = this.listeners, output = null;
507
508                 tinymce.each(listeners, function(listener, i) {
509                         if (callback == listener.cb) {
510                                 output = listener;
511                                 listeners.splice(i, 1);
512                                 return false;
513                         }
514                 });
515
516                 return output;
517         };
518
519         this.dispatch = function() {
520                 var self = this, returnValue, args = arguments, i, listeners = self.listeners, listener;
521
522                 self.inDispatch = true;
523                 
524                 // Needs to be a real loop since the listener count might change while looping
525                 // And this is also more efficient
526                 for (i = 0; i < listeners.length; i++) {
527                         listener = listeners[i];
528                         returnValue = listener.cb.apply(listener.scope, args.length > 0 ? args : [listener.scope]);
529
530                         if (returnValue === false) {
531                                 break;
532                         }
533                 }
534
535                 self.inDispatch = false;
536
537                 return returnValue;
538         };
539 };