570 regels
13 KiB
JavaScript
Executable File
570 regels
13 KiB
JavaScript
Executable File
/**
|
|
* 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 instaces.
|
|
*
|
|
* @example
|
|
* tinymce.EditorManager.init({});
|
|
*
|
|
* @class tinymce.EditorManager
|
|
* @mixes tinymce.util.Observable
|
|
* @static
|
|
*/
|
|
define("tinymce/EditorManager", [
|
|
"tinymce/Editor",
|
|
"tinymce/dom/DOMUtils",
|
|
"tinymce/util/URI",
|
|
"tinymce/Env",
|
|
"tinymce/util/Tools",
|
|
"tinymce/util/Observable",
|
|
"tinymce/util/I18n",
|
|
"tinymce/FocusManager"
|
|
], function(Editor, 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;
|
|
|
|
var EditorManager = {
|
|
/**
|
|
* 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;
|
|
|
|
// Get base URL for the current document
|
|
documentBaseURL = document.location.href.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++) {
|
|
var src = scripts[i].src;
|
|
|
|
if (/tinymce(\.jquery|)(\.min|\.dev|)\.js/.test(src)) {
|
|
if (src.indexOf('.min') != -1) {
|
|
suffix = '.min';
|
|
}
|
|
|
|
baseURL = src.substring(0, src.lastIndexOf('/'));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 = [], editor;
|
|
|
|
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 execCallback(se, n, s) {
|
|
var f = se[n];
|
|
|
|
if (!f) {
|
|
return;
|
|
}
|
|
|
|
return f.apply(s || this, Array.prototype.slice.call(arguments, 2));
|
|
}
|
|
|
|
function hasClass(n, c) {
|
|
return c.constructor === RegExp ? c.test(n.className) : DOM.hasClass(n, c);
|
|
}
|
|
|
|
self.settings = settings;
|
|
|
|
DOM.bind(window, 'ready', function() {
|
|
var l, co;
|
|
|
|
execCallback(settings, 'onpageload');
|
|
|
|
if (settings.types) {
|
|
// Process type specific selector
|
|
each(settings.types, function(type) {
|
|
each(DOM.select(type.selector), function(elm) {
|
|
var editor = new Editor(createId(elm), extend({}, settings, type), self);
|
|
editors.push(editor);
|
|
editor.render(1);
|
|
});
|
|
});
|
|
|
|
return;
|
|
} else if (settings.selector) {
|
|
// Process global selector
|
|
each(DOM.select(settings.selector), function(elm) {
|
|
var editor = new Editor(createId(elm), settings, self);
|
|
editors.push(editor);
|
|
editor.render(1);
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
// Fallback to old setting
|
|
switch (settings.mode) {
|
|
case "exact":
|
|
l = settings.elements || '';
|
|
|
|
if(l.length > 0) {
|
|
each(explode(l), function(v) {
|
|
if (DOM.get(v)) {
|
|
editor = new Editor(v, settings, self);
|
|
editors.push(editor);
|
|
editor.render(true);
|
|
} else {
|
|
each(document.forms, function(f) {
|
|
each(f.elements, function(e) {
|
|
if (e.name === v) {
|
|
v = 'mce_editor_' + instanceCounter++;
|
|
DOM.setAttrib(e, 'id', v);
|
|
|
|
editor = new Editor(v, settings, self);
|
|
editors.push(editor);
|
|
editor.render(1);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}
|
|
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)) {
|
|
editor = new Editor(createId(elm), settings, self);
|
|
editors.push(editor);
|
|
editor.render(true);
|
|
}
|
|
});
|
|
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(settings, 'oninit');
|
|
}
|
|
});
|
|
} else {
|
|
l++;
|
|
}
|
|
|
|
// All done
|
|
if (l == co) {
|
|
execCallback(settings, 'oninit');
|
|
}
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* 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 (id === undefined) {
|
|
return this.editors;
|
|
}
|
|
|
|
return this.editors[id];
|
|
},
|
|
|
|
/**
|
|
* 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);
|
|
|
|
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) {
|
|
self.remove(editors[elm.id]);
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
// Remove specific editor
|
|
editor = selector;
|
|
|
|
// Not in the collection
|
|
if (!editors[editor.id]) {
|
|
return null;
|
|
}
|
|
|
|
delete editors[editor.id];
|
|
|
|
for (i = 0; i < editors.length; i++) {
|
|
if (editors[i] == editor) {
|
|
editors.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Select another editor since the active one was removed
|
|
if (self.activeEditor == editor) {
|
|
self.activeEditor = editors[0];
|
|
}
|
|
|
|
// Don't remove missing editor or removed instances
|
|
if (!editor || editor.removed) {
|
|
return;
|
|
}
|
|
|
|
editor.remove();
|
|
editor.destroy();
|
|
|
|
/**
|
|
* Fires when an editor is removed from EditorManager collection.
|
|
*
|
|
* @event RemoveEditor
|
|
* @param {Object} e Event arguments.
|
|
*/
|
|
self.fire('RemoveEditor', {editor: editor});
|
|
|
|
if (!editors.length) {
|
|
DOM.unbind(window, 'beforeunload', beforeUnloadDelegate);
|
|
}
|
|
|
|
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);
|
|
}
|
|
};
|
|
|
|
extend(EditorManager, Observable);
|
|
|
|
EditorManager.setup();
|
|
|
|
// Export EditorManager as tinymce/tinymce in global namespace
|
|
window.tinymce = window.tinyMCE = EditorManager;
|
|
|
|
return EditorManager;
|
|
});
|