home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-includes / js / tinymce / tiny_mce_popup.js < prev    next >
Encoding:
JavaScript  |  2017-09-26  |  15.6 KB  |  543 lines

  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. };
  543.