diff -r fd8fb93e1b6a -r a361355b55c7 src/pyams_skin/resources/js/ext/tinymce/dev/classes/EditorManager.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_skin/resources/js/ext/tinymce/dev/classes/EditorManager.js Wed Jun 17 10:00:10 2015 +0200 @@ -0,0 +1,654 @@ +/** + * EditorManager.js + * + * Copyright, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://www.tinymce.com/license + * Contributing: http://www.tinymce.com/contributing + */ + +/** + * This class used as a factory for manager for tinymce.Editor instances. + * + * @example + * tinymce.EditorManager.init({}); + * + * @class tinymce.EditorManager + * @mixes tinymce.util.Observable + * @static + */ +define("tinymce/EditorManager", [ + "tinymce/Editor", + "tinymce/dom/DomQuery", + "tinymce/dom/DOMUtils", + "tinymce/util/URI", + "tinymce/Env", + "tinymce/util/Tools", + "tinymce/util/Observable", + "tinymce/util/I18n", + "tinymce/FocusManager" +], function(Editor, DomQuery, DOMUtils, URI, Env, Tools, Observable, I18n, FocusManager) { + var DOM = DOMUtils.DOM; + var explode = Tools.explode, each = Tools.each, extend = Tools.extend; + var instanceCounter = 0, beforeUnloadDelegate, EditorManager; + + function removeEditorFromList(editor) { + var editors = EditorManager.editors, removedFromList; + + delete editors[editor.id]; + + for (var i = 0; i < editors.length; i++) { + if (editors[i] == editor) { + editors.splice(i, 1); + removedFromList = true; + break; + } + } + + // Select another editor since the active one was removed + if (EditorManager.activeEditor == editor) { + EditorManager.activeEditor = editors[0]; + } + + // Clear focusedEditor if necessary, so that we don't try to blur the destroyed editor + if (EditorManager.focusedEditor == editor) { + EditorManager.focusedEditor = null; + } + + return removedFromList; + } + + function purgeDestroyedEditor(editor) { + // User has manually destroyed the editor lets clean up the mess + if (editor && !(editor.getContainer() || editor.getBody()).parentNode) { + removeEditorFromList(editor); + editor.unbindAllNativeEvents(); + editor.destroy(true); + editor = null; + } + + return editor; + } + + EditorManager = { + /** + * Dom query instance. + * + * @property $ + * @type tinymce.dom.DomQuery + */ + $: DomQuery, + + /** + * Major version of TinyMCE build. + * + * @property majorVersion + * @type String + */ + majorVersion: '@@majorVersion@@', + + /** + * Minor version of TinyMCE build. + * + * @property minorVersion + * @type String + */ + minorVersion: '@@minorVersion@@', + + /** + * Release date of TinyMCE build. + * + * @property releaseDate + * @type String + */ + releaseDate: '@@releaseDate@@', + + /** + * Collection of editor instances. + * + * @property editors + * @type Object + * @example + * for (edId in tinymce.editors) + * tinymce.editors[edId].save(); + */ + editors: [], + + /** + * Collection of language pack data. + * + * @property i18n + * @type Object + */ + i18n: I18n, + + /** + * Currently active editor instance. + * + * @property activeEditor + * @type tinymce.Editor + * @example + * tinyMCE.activeEditor.selection.getContent(); + * tinymce.EditorManager.activeEditor.selection.getContent(); + */ + activeEditor: null, + + setup: function() { + var self = this, baseURL, documentBaseURL, suffix = "", preInit, src; + + // Get base URL for the current document + documentBaseURL = document.location.href; + + // Check if the URL is a document based format like: http://site/dir/file and file:/// + // leave other formats like applewebdata://... intact + if (/^[^:]+:\/\/\/?[^\/]+\//.test(documentBaseURL)) { + documentBaseURL = documentBaseURL.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, ''); + + if (!/[\/\\]$/.test(documentBaseURL)) { + documentBaseURL += '/'; + } + } + + // If tinymce is defined and has a base use that or use the old tinyMCEPreInit + preInit = window.tinymce || window.tinyMCEPreInit; + if (preInit) { + baseURL = preInit.base || preInit.baseURL; + suffix = preInit.suffix; + } else { + // Get base where the tinymce script is located + var scripts = document.getElementsByTagName('script'); + for (var i = 0; i < scripts.length; i++) { + src = scripts[i].src; + + // Script types supported: + // tinymce.js tinymce.min.js tinymce.dev.js + // tinymce.jquery.js tinymce.jquery.min.js tinymce.jquery.dev.js + // tinymce.full.js tinymce.full.min.js tinymce.full.dev.js + if (/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(src)) { + if (src.indexOf('.min') != -1) { + suffix = '.min'; + } + + baseURL = src.substring(0, src.lastIndexOf('/')); + break; + } + } + + // We didn't find any baseURL by looking at the script elements + // Try to use the document.currentScript as a fallback + if (!baseURL && document.currentScript) { + src = document.currentScript.src; + + if (src.indexOf('.min') != -1) { + suffix = '.min'; + } + + baseURL = src.substring(0, src.lastIndexOf('/')); + } + } + + /** + * Base URL where the root directory if TinyMCE is located. + * + * @property baseURL + * @type String + */ + self.baseURL = new URI(documentBaseURL).toAbsolute(baseURL); + + /** + * Document base URL where the current document is located. + * + * @property documentBaseURL + * @type String + */ + self.documentBaseURL = documentBaseURL; + + /** + * Absolute baseURI for the installation path of TinyMCE. + * + * @property baseURI + * @type tinymce.util.URI + */ + self.baseURI = new URI(self.baseURL); + + /** + * Current suffix to add to each plugin/theme that gets loaded for example ".min". + * + * @property suffix + * @type String + */ + self.suffix = suffix; + + self.focusManager = new FocusManager(self); + }, + + /** + * Initializes a set of editors. This method will create editors based on various settings. + * + * @method init + * @param {Object} settings Settings object to be passed to each editor instance. + * @example + * // Initializes a editor using the longer method + * tinymce.EditorManager.init({ + * some_settings : 'some value' + * }); + * + * // Initializes a editor instance using the shorter version + * tinyMCE.init({ + * some_settings : 'some value' + * }); + */ + init: function(settings) { + var self = this, editors = []; + + function createId(elm) { + var id = elm.id; + + // Use element id, or unique name or generate a unique id + if (!id) { + id = elm.name; + + if (id && !DOM.get(id)) { + id = elm.name; + } else { + // Generate unique name + id = DOM.uniqueId(); + } + + elm.setAttribute('id', id); + } + + return id; + } + + function createEditor(id, settings, targetElm) { + if (!purgeDestroyedEditor(self.get(id))) { + var editor = new Editor(id, settings, self); + + editor.targetElm = editor.targetElm || targetElm; + editors.push(editor); + editor.render(); + } + } + + function execCallback(name) { + var callback = settings[name]; + + if (!callback) { + return; + } + + return callback.apply(self, Array.prototype.slice.call(arguments, 2)); + } + + function hasClass(elm, className) { + return className.constructor === RegExp ? className.test(elm.className) : DOM.hasClass(elm, className); + } + + function readyHandler() { + var l, co; + + DOM.unbind(window, 'ready', readyHandler); + + execCallback('onpageload'); + + if (settings.types) { + // Process type specific selector + each(settings.types, function(type) { + each(DOM.select(type.selector), function(elm) { + createEditor(createId(elm), extend({}, settings, type), elm); + }); + }); + + return; + } else if (settings.selector) { + // Process global selector + each(DOM.select(settings.selector), function(elm) { + createEditor(createId(elm), settings, elm); + }); + + return; + } else if (settings.target) { + createEditor(createId(settings.target), settings); + } + + // Fallback to old setting + switch (settings.mode) { + case "exact": + l = settings.elements || ''; + + if (l.length > 0) { + each(explode(l), function(id) { + var elm; + + if ((elm = DOM.get(id))) { + createEditor(id, settings, elm); + } else { + each(document.forms, function(f) { + each(f.elements, function(e) { + if (e.name === id) { + id = 'mce_editor_' + instanceCounter++; + DOM.setAttrib(e, 'id', id); + createEditor(id, settings, e); + } + }); + }); + } + }); + } + break; + + case "textareas": + case "specific_textareas": + each(DOM.select('textarea'), function(elm) { + if (settings.editor_deselector && hasClass(elm, settings.editor_deselector)) { + return; + } + + if (!settings.editor_selector || hasClass(elm, settings.editor_selector)) { + createEditor(createId(elm), settings, elm); + } + }); + break; + } + + // Call onInit when all editors are initialized + if (settings.oninit) { + l = co = 0; + + each(editors, function(ed) { + co++; + + if (!ed.initialized) { + // Wait for it + ed.on('init', function() { + l++; + + // All done + if (l == co) { + execCallback('oninit'); + } + }); + } else { + l++; + } + + // All done + if (l == co) { + execCallback('oninit'); + } + }); + } + } + + self.settings = settings; + + DOM.bind(window, 'ready', readyHandler); + }, + + /** + * Returns a editor instance by id. + * + * @method get + * @param {String/Number} id Editor instance id or index to return. + * @return {tinymce.Editor} Editor instance to return. + * @example + * // Adds an onclick event to an editor by id (shorter version) + * tinymce.get('mytextbox').on('click', function(e) { + * ed.windowManager.alert('Hello world!'); + * }); + * + * // Adds an onclick event to an editor by id (longer version) + * tinymce.EditorManager.get('mytextbox').on('click', function(e) { + * ed.windowManager.alert('Hello world!'); + * }); + */ + get: function(id) { + if (!arguments.length) { + return this.editors; + } + + return id in this.editors ? this.editors[id] : null; + }, + + /** + * Adds an editor instance to the editor collection. This will also set it as the active editor. + * + * @method add + * @param {tinymce.Editor} editor Editor instance to add to the collection. + * @return {tinymce.Editor} The same instance that got passed in. + */ + add: function(editor) { + var self = this, editors = self.editors; + + // Add named and index editor instance + editors[editor.id] = editor; + editors.push(editor); + + // Doesn't call setActive method since we don't want + // to fire a bunch of activate/deactivate calls while initializing + self.activeEditor = editor; + + /** + * Fires when an editor is added to the EditorManager collection. + * + * @event AddEditor + * @param {Object} e Event arguments. + */ + self.fire('AddEditor', {editor: editor}); + + if (!beforeUnloadDelegate) { + beforeUnloadDelegate = function() { + self.fire('BeforeUnload'); + }; + + DOM.bind(window, 'beforeunload', beforeUnloadDelegate); + } + + return editor; + }, + + /** + * Creates an editor instance and adds it to the EditorManager collection. + * + * @method createEditor + * @param {String} id Instance id to use for editor. + * @param {Object} settings Editor instance settings. + * @return {tinymce.Editor} Editor instance that got created. + */ + createEditor: function(id, settings) { + return this.add(new Editor(id, settings, this)); + }, + + /** + * Removes a editor or editors form page. + * + * @example + * // Remove all editors bound to divs + * tinymce.remove('div'); + * + * // Remove all editors bound to textareas + * tinymce.remove('textarea'); + * + * // Remove all editors + * tinymce.remove(); + * + * // Remove specific instance by id + * tinymce.remove('#id'); + * + * @method remove + * @param {tinymce.Editor/String/Object} [selector] CSS selector or editor instance to remove. + * @return {tinymce.Editor} The editor that got passed in will be return if it was found otherwise null. + */ + remove: function(selector) { + var self = this, i, editors = self.editors, editor; + + // Remove all editors + if (!selector) { + for (i = editors.length - 1; i >= 0; i--) { + self.remove(editors[i]); + } + + return; + } + + // Remove editors by selector + if (typeof selector == "string") { + selector = selector.selector || selector; + + each(DOM.select(selector), function(elm) { + editor = editors[elm.id]; + + if (editor) { + self.remove(editor); + } + }); + + return; + } + + // Remove specific editor + editor = selector; + + // Not in the collection + if (!editors[editor.id]) { + return null; + } + + /** + * Fires when an editor is removed from EditorManager collection. + * + * @event RemoveEditor + * @param {Object} e Event arguments. + */ + if (removeEditorFromList(editor)) { + self.fire('RemoveEditor', {editor: editor}); + } + + if (!editors.length) { + DOM.unbind(window, 'beforeunload', beforeUnloadDelegate); + } + + editor.remove(); + + return editor; + }, + + /** + * Executes a specific command on the currently active editor. + * + * @method execCommand + * @param {String} c Command to perform for example Bold. + * @param {Boolean} u Optional boolean state if a UI should be presented for the command or not. + * @param {String} v Optional value parameter like for example an URL to a link. + * @return {Boolean} true/false if the command was executed or not. + */ + execCommand: function(cmd, ui, value) { + var self = this, editor = self.get(value); + + // Manager commands + switch (cmd) { + case "mceAddEditor": + if (!self.get(value)) { + new Editor(value, self.settings, self).render(); + } + + return true; + + case "mceRemoveEditor": + if (editor) { + editor.remove(); + } + + return true; + + case 'mceToggleEditor': + if (!editor) { + self.execCommand('mceAddEditor', 0, value); + return true; + } + + if (editor.isHidden()) { + editor.show(); + } else { + editor.hide(); + } + + return true; + } + + // Run command on active editor + if (self.activeEditor) { + return self.activeEditor.execCommand(cmd, ui, value); + } + + return false; + }, + + /** + * Calls the save method on all editor instances in the collection. This can be useful when a form is to be submitted. + * + * @method triggerSave + * @example + * // Saves all contents + * tinyMCE.triggerSave(); + */ + triggerSave: function() { + each(this.editors, function(editor) { + editor.save(); + }); + }, + + /** + * Adds a language pack, this gets called by the loaded language files like en.js. + * + * @method addI18n + * @param {String} code Optional language code. + * @param {Object} items Name/value object with translations. + */ + addI18n: function(code, items) { + I18n.add(code, items); + }, + + /** + * Translates the specified string using the language pack items. + * + * @method translate + * @param {String/Array/Object} text String to translate + * @return {String} Translated string. + */ + translate: function(text) { + return I18n.translate(text); + }, + + /** + * Sets the active editor instance and fires the deactivate/activate events. + * + * @method setActive + * @param {tinymce.Editor} editor Editor instance to set as the active instance. + */ + setActive: function(editor) { + var activeEditor = this.activeEditor; + + if (this.activeEditor != editor) { + if (activeEditor) { + activeEditor.fire('deactivate', {relatedTarget: editor}); + } + + editor.fire('activate', {relatedTarget: activeEditor}); + } + + this.activeEditor = editor; + } + }; + + extend(EditorManager, Observable); + + EditorManager.setup(); + + // Export EditorManager as tinymce/tinymce in global namespace + window.tinymce = window.tinyMCE = EditorManager; + + return EditorManager; +});