angelovcom.net

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

tiny_mce_popup.js (15988B)


      1 /**
      2  * tinymce_mce_popup.js
      3  *
      4  * Released under LGPL License.
      5  * Copyright (c) 1999-2017 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 };