]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/js/tinymce/tiny_mce_popup.js
Wordpress 4.5.3
[autoinstalls/wordpress.git] / wp-includes / js / tinymce / tiny_mce_popup.js
1 /**
2  * tinymce_mce_popup.js
3  *
4  * Released under LGPL License.
5  * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
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 retrieve.
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 retrieve.
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                 var el = document.getElementById(element_id), colorPickerCallback = this.editor.settings.color_picker_callback;
253                 if (colorPickerCallback) {
254                         colorPickerCallback.call(
255                                 this.editor,
256                                 function (value) {
257                                         el.value = value;
258                                         try {
259                                                 el.onchange();
260                                         } catch (ex) {
261                                                 // Try fire event, ignore errors
262                                         }
263                                 },
264                                 el.value
265                         );
266                 }
267         },
268
269         /**
270          * Opens a filebrowser/imagebrowser this will set the output value from
271          * the browser as a value on the specified element.
272          *
273          * @method openBrowser
274          * @param {string} element_id Id of the element to set value in.
275          * @param {string} type Type of browser to open image/file/flash.
276          * @param {string} option Option name to get the file_broswer_callback function name from.
277          */
278         openBrowser : function(element_id, type) {
279                 tinyMCEPopup.restoreSelection();
280                 this.editor.execCallback('file_browser_callback', element_id, document.getElementById(element_id).value, type, window);
281         },
282
283         /**
284          * Creates a confirm dialog. Please don't use the blocking behavior of this
285          * native version use the callback method instead then it can be extended.
286          *
287          * @method confirm
288          * @param {String} t Title for the new confirm dialog.
289          * @param {function} cb Callback function to be executed after the user has selected ok or cancel.
290          * @param {Object} s Optional scope to execute the callback in.
291          */
292         confirm : function(t, cb, s) {
293                 this.editor.windowManager.confirm(t, cb, s, window);
294         },
295
296         /**
297          * Creates a alert dialog. Please don't use the blocking behavior of this
298          * native version use the callback method instead then it can be extended.
299          *
300          * @method alert
301          * @param {String} tx Title for the new alert dialog.
302          * @param {function} cb Callback function to be executed after the user has selected ok.
303          * @param {Object} s Optional scope to execute the callback in.
304          */
305         alert : function(tx, cb, s) {
306                 this.editor.windowManager.alert(tx, cb, s, window);
307         },
308
309         /**
310          * Closes the current window.
311          *
312          * @method close
313          */
314         close : function() {
315                 var t = this;
316
317                 // To avoid domain relaxing issue in Opera
318                 function close() {
319                         t.editor.windowManager.close(window);
320                         tinymce = tinyMCE = t.editor = t.params = t.dom = t.dom.doc = null; // Cleanup
321                 }
322
323                 if (tinymce.isOpera) {
324                         t.getWin().setTimeout(close, 0);
325                 } else {
326                         close();
327                 }
328         },
329
330         // Internal functions
331
332         _restoreSelection : function() {
333                 var e = window.event.srcElement;
334
335                 if (e.nodeName == 'INPUT' && (e.type == 'submit' || e.type == 'button')) {
336                         tinyMCEPopup.restoreSelection();
337                 }
338         },
339
340 /*      _restoreSelection : function() {
341                 var e = window.event.srcElement;
342
343                 // If user focus a non text input or textarea
344                 if ((e.nodeName != 'INPUT' && e.nodeName != 'TEXTAREA') || e.type != 'text')
345                         tinyMCEPopup.restoreSelection();
346         },*/
347
348         _onDOMLoaded : function() {
349                 var t = tinyMCEPopup, ti = document.title, h, nv;
350
351                 // Translate page
352                 if (t.features.translate_i18n !== false) {
353                         var map = {
354                                 "update": "Ok",
355                                 "insert": "Ok",
356                                 "cancel": "Cancel",
357                                 "not_set": "--",
358                                 "class_name": "Class name",
359                                 "browse": "Browse"
360                         };
361
362                         var langCode = (tinymce.settings ? tinymce.settings : t.editor.settings).language || 'en';
363                         for (var key in map) {
364                                 tinymce.i18n.data[langCode + "." + key] = tinymce.i18n.translate(map[key]);
365                         }
366
367                         h = document.body.innerHTML;
368
369                         // Replace a=x with a="x" in IE
370                         if (tinymce.isIE) {
371                                 h = h.replace(/ (value|title|alt)=([^"][^\s>]+)/gi, ' $1="$2"');
372                         }
373
374                         document.dir = t.editor.getParam('directionality','');
375
376                         if ((nv = t.editor.translate(h)) && nv != h) {
377                                 document.body.innerHTML = nv;
378                         }
379
380                         if ((nv = t.editor.translate(ti)) && nv != ti) {
381                                 document.title = ti = nv;
382                         }
383                 }
384
385                 if (!t.editor.getParam('browser_preferred_colors', false) || !t.isWindow) {
386                         t.dom.addClass(document.body, 'forceColors');
387                 }
388
389                 document.body.style.display = '';
390
391                 // Restore selection in IE when focus is placed on a non textarea or input element of the type text
392                 if (tinymce.Env.ie) {
393                         if (tinymce.Env.ie < 11) {
394                                 document.attachEvent('onmouseup', tinyMCEPopup._restoreSelection);
395
396                                 // Add base target element for it since it would fail with modal dialogs
397                                 t.dom.add(t.dom.select('head')[0], 'base', {target: '_self'});
398                         } else {
399                                 document.addEventListener('mouseup', tinyMCEPopup._restoreSelection, false);
400                         }
401                 }
402
403                 t.restoreSelection();
404                 t.resizeToInnerSize();
405
406                 // Set inline title
407                 if (!t.isWindow) {
408                         t.editor.windowManager.setTitle(window, ti);
409                 } else {
410                         window.focus();
411                 }
412
413                 if (!tinymce.isIE && !t.isWindow) {
414                         t.dom.bind(document, 'focus', function() {
415                                 t.editor.windowManager.focus(t.id);
416                         });
417                 }
418
419                 // Patch for accessibility
420                 tinymce.each(t.dom.select('select'), function(e) {
421                         e.onkeydown = tinyMCEPopup._accessHandler;
422                 });
423
424                 // Call onInit
425                 // Init must be called before focus so the selection won't get lost by the focus call
426                 tinymce.each(t.listeners, function(o) {
427                         o.func.call(o.scope, t.editor);
428                 });
429
430                 // Move focus to window
431                 if (t.getWindowArg('mce_auto_focus', true)) {
432                         window.focus();
433
434                         // Focus element with mceFocus class
435                         tinymce.each(document.forms, function(f) {
436                                 tinymce.each(f.elements, function(e) {
437                                         if (t.dom.hasClass(e, 'mceFocus') && !e.disabled) {
438                                                 e.focus();
439                                                 return false; // Break loop
440                                         }
441                                 });
442                         });
443                 }
444
445                 document.onkeyup = tinyMCEPopup._closeWinKeyHandler;
446
447                 if ('textContent' in document) {
448                         t.uiWindow.getEl('head').firstChild.textContent = document.title;
449                 } else {
450                         t.uiWindow.getEl('head').firstChild.innerText = document.title;
451                 }
452         },
453
454         _accessHandler : function(e) {
455                 e = e || window.event;
456
457                 if (e.keyCode == 13 || e.keyCode == 32) {
458                         var elm = e.target || e.srcElement;
459
460                         if (elm.onchange) {
461                                 elm.onchange();
462                         }
463
464                         return tinymce.dom.Event.cancel(e);
465                 }
466         },
467
468         _closeWinKeyHandler : function(e) {
469                 e = e || window.event;
470
471                 if (e.keyCode == 27) {
472                         tinyMCEPopup.close();
473                 }
474         },
475
476         _eventProxy: function(id) {
477                 return function(evt) {
478                         tinyMCEPopup.dom.events.callNativeHandler(id, evt);
479                 };
480         }
481 };
482
483 tinyMCEPopup.init();
484
485 tinymce.util.Dispatcher = function(scope) {
486         this.scope = scope || this;
487         this.listeners = [];
488
489         this.add = function(callback, scope) {
490                 this.listeners.push({cb : callback, scope : scope || this.scope});
491
492                 return callback;
493         };
494
495         this.addToTop = function(callback, scope) {
496                 var self = this, listener = {cb : callback, scope : scope || self.scope};
497
498                 // Create new listeners if addToTop is executed in a dispatch loop
499                 if (self.inDispatch) {
500                         self.listeners = [listener].concat(self.listeners);
501                 } else {
502                         self.listeners.unshift(listener);
503                 }
504
505                 return callback;
506         };
507
508         this.remove = function(callback) {
509                 var listeners = this.listeners, output = null;
510
511                 tinymce.each(listeners, function(listener, i) {
512                         if (callback == listener.cb) {
513                                 output = listener;
514                                 listeners.splice(i, 1);
515                                 return false;
516                         }
517                 });
518
519                 return output;
520         };
521
522         this.dispatch = function() {
523                 var self = this, returnValue, args = arguments, i, listeners = self.listeners, listener;
524
525                 self.inDispatch = true;
526
527                 // Needs to be a real loop since the listener count might change while looping
528                 // And this is also more efficient
529                 for (i = 0; i < listeners.length; i++) {
530                         listener = listeners[i];
531                         returnValue = listener.cb.apply(listener.scope, args.length > 0 ? args : [listener.scope]);
532
533                         if (returnValue === false) {
534                                 break;
535                         }
536                 }
537
538                 self.inDispatch = false;
539
540                 return returnValue;
541         };
542 };