src/pyams_skin/resources/js/ext/tinymce/dev/classes/EditorManager.js
changeset 566 a1707c607eec
parent 565 318533413200
child 567 bca1726b1d85
equal deleted inserted replaced
565:318533413200 566:a1707c607eec
     1 /**
       
     2  * EditorManager.js
       
     3  *
       
     4  * Copyright, Moxiecode Systems AB
       
     5  * Released under LGPL License.
       
     6  *
       
     7  * License: http://www.tinymce.com/license
       
     8  * Contributing: http://www.tinymce.com/contributing
       
     9  */
       
    10 
       
    11 /**
       
    12  * This class used as a factory for manager for tinymce.Editor instances.
       
    13  *
       
    14  * @example
       
    15  * tinymce.EditorManager.init({});
       
    16  *
       
    17  * @class tinymce.EditorManager
       
    18  * @mixes tinymce.util.Observable
       
    19  * @static
       
    20  */
       
    21 define("tinymce/EditorManager", [
       
    22 	"tinymce/Editor",
       
    23 	"tinymce/dom/DomQuery",
       
    24 	"tinymce/dom/DOMUtils",
       
    25 	"tinymce/util/URI",
       
    26 	"tinymce/Env",
       
    27 	"tinymce/util/Tools",
       
    28 	"tinymce/util/Observable",
       
    29 	"tinymce/util/I18n",
       
    30 	"tinymce/FocusManager"
       
    31 ], function(Editor, DomQuery, DOMUtils, URI, Env, Tools, Observable, I18n, FocusManager) {
       
    32 	var DOM = DOMUtils.DOM;
       
    33 	var explode = Tools.explode, each = Tools.each, extend = Tools.extend;
       
    34 	var instanceCounter = 0, beforeUnloadDelegate, EditorManager;
       
    35 
       
    36 	function removeEditorFromList(editor) {
       
    37 		var editors = EditorManager.editors, removedFromList;
       
    38 
       
    39 		delete editors[editor.id];
       
    40 
       
    41 		for (var i = 0; i < editors.length; i++) {
       
    42 			if (editors[i] == editor) {
       
    43 				editors.splice(i, 1);
       
    44 				removedFromList = true;
       
    45 				break;
       
    46 			}
       
    47 		}
       
    48 
       
    49 		// Select another editor since the active one was removed
       
    50 		if (EditorManager.activeEditor == editor) {
       
    51 			EditorManager.activeEditor = editors[0];
       
    52 		}
       
    53 
       
    54 		// Clear focusedEditor if necessary, so that we don't try to blur the destroyed editor
       
    55 		if (EditorManager.focusedEditor == editor) {
       
    56 			EditorManager.focusedEditor = null;
       
    57 		}
       
    58 
       
    59 		return removedFromList;
       
    60 	}
       
    61 
       
    62 	function purgeDestroyedEditor(editor) {
       
    63 		// User has manually destroyed the editor lets clean up the mess
       
    64 		if (editor && !(editor.getContainer() || editor.getBody()).parentNode) {
       
    65 			removeEditorFromList(editor);
       
    66 			editor.unbindAllNativeEvents();
       
    67 			editor.destroy(true);
       
    68 			editor = null;
       
    69 		}
       
    70 
       
    71 		return editor;
       
    72 	}
       
    73 
       
    74 	EditorManager = {
       
    75 		/**
       
    76 		 * Dom query instance.
       
    77 		 *
       
    78 		 * @property $
       
    79 		 * @type tinymce.dom.DomQuery
       
    80 		 */
       
    81 		$: DomQuery,
       
    82 
       
    83 		/**
       
    84 		 * Major version of TinyMCE build.
       
    85 		 *
       
    86 		 * @property majorVersion
       
    87 		 * @type String
       
    88 		 */
       
    89 		majorVersion: '@@majorVersion@@',
       
    90 
       
    91 		/**
       
    92 		 * Minor version of TinyMCE build.
       
    93 		 *
       
    94 		 * @property minorVersion
       
    95 		 * @type String
       
    96 		 */
       
    97 		minorVersion: '@@minorVersion@@',
       
    98 
       
    99 		/**
       
   100 		 * Release date of TinyMCE build.
       
   101 		 *
       
   102 		 * @property releaseDate
       
   103 		 * @type String
       
   104 		 */
       
   105 		releaseDate: '@@releaseDate@@',
       
   106 
       
   107 		/**
       
   108 		 * Collection of editor instances.
       
   109 		 *
       
   110 		 * @property editors
       
   111 		 * @type Object
       
   112 		 * @example
       
   113 		 * for (edId in tinymce.editors)
       
   114 		 *     tinymce.editors[edId].save();
       
   115 		 */
       
   116 		editors: [],
       
   117 
       
   118 		/**
       
   119 		 * Collection of language pack data.
       
   120 		 *
       
   121 		 * @property i18n
       
   122 		 * @type Object
       
   123 		 */
       
   124 		i18n: I18n,
       
   125 
       
   126 		/**
       
   127 		 * Currently active editor instance.
       
   128 		 *
       
   129 		 * @property activeEditor
       
   130 		 * @type tinymce.Editor
       
   131 		 * @example
       
   132 		 * tinyMCE.activeEditor.selection.getContent();
       
   133 		 * tinymce.EditorManager.activeEditor.selection.getContent();
       
   134 		 */
       
   135 		activeEditor: null,
       
   136 
       
   137 		setup: function() {
       
   138 			var self = this, baseURL, documentBaseURL, suffix = "", preInit, src;
       
   139 
       
   140 			// Get base URL for the current document
       
   141 			documentBaseURL = document.location.href;
       
   142 
       
   143 			// Check if the URL is a document based format like: http://site/dir/file and file:///
       
   144 			// leave other formats like applewebdata://... intact
       
   145 			if (/^[^:]+:\/\/\/?[^\/]+\//.test(documentBaseURL)) {
       
   146 				documentBaseURL = documentBaseURL.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
       
   147 
       
   148 				if (!/[\/\\]$/.test(documentBaseURL)) {
       
   149 					documentBaseURL += '/';
       
   150 				}
       
   151 			}
       
   152 
       
   153 			// If tinymce is defined and has a base use that or use the old tinyMCEPreInit
       
   154 			preInit = window.tinymce || window.tinyMCEPreInit;
       
   155 			if (preInit) {
       
   156 				baseURL = preInit.base || preInit.baseURL;
       
   157 				suffix = preInit.suffix;
       
   158 			} else {
       
   159 				// Get base where the tinymce script is located
       
   160 				var scripts = document.getElementsByTagName('script');
       
   161 				for (var i = 0; i < scripts.length; i++) {
       
   162 					src = scripts[i].src;
       
   163 
       
   164 					// Script types supported:
       
   165 					// tinymce.js tinymce.min.js tinymce.dev.js
       
   166 					// tinymce.jquery.js tinymce.jquery.min.js tinymce.jquery.dev.js
       
   167 					// tinymce.full.js tinymce.full.min.js tinymce.full.dev.js
       
   168 					if (/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(src)) {
       
   169 						if (src.indexOf('.min') != -1) {
       
   170 							suffix = '.min';
       
   171 						}
       
   172 
       
   173 						baseURL = src.substring(0, src.lastIndexOf('/'));
       
   174 						break;
       
   175 					}
       
   176 				}
       
   177 
       
   178 				// We didn't find any baseURL by looking at the script elements
       
   179 				// Try to use the document.currentScript as a fallback
       
   180 				if (!baseURL && document.currentScript) {
       
   181 					src = document.currentScript.src;
       
   182 
       
   183 					if (src.indexOf('.min') != -1) {
       
   184 						suffix = '.min';
       
   185 					}
       
   186 
       
   187 					baseURL = src.substring(0, src.lastIndexOf('/'));
       
   188 				}
       
   189 			}
       
   190 
       
   191 			/**
       
   192 			 * Base URL where the root directory if TinyMCE is located.
       
   193 			 *
       
   194 			 * @property baseURL
       
   195 			 * @type String
       
   196 			 */
       
   197 			self.baseURL = new URI(documentBaseURL).toAbsolute(baseURL);
       
   198 
       
   199 			/**
       
   200 			 * Document base URL where the current document is located.
       
   201 			 *
       
   202 			 * @property documentBaseURL
       
   203 			 * @type String
       
   204 			 */
       
   205 			self.documentBaseURL = documentBaseURL;
       
   206 
       
   207 			/**
       
   208 			 * Absolute baseURI for the installation path of TinyMCE.
       
   209 			 *
       
   210 			 * @property baseURI
       
   211 			 * @type tinymce.util.URI
       
   212 			 */
       
   213 			self.baseURI = new URI(self.baseURL);
       
   214 
       
   215 			/**
       
   216 			 * Current suffix to add to each plugin/theme that gets loaded for example ".min".
       
   217 			 *
       
   218 			 * @property suffix
       
   219 			 * @type String
       
   220 			 */
       
   221 			self.suffix = suffix;
       
   222 
       
   223 			self.focusManager = new FocusManager(self);
       
   224 		},
       
   225 
       
   226 		/**
       
   227 		 * Initializes a set of editors. This method will create editors based on various settings.
       
   228 		 *
       
   229 		 * @method init
       
   230 		 * @param {Object} settings Settings object to be passed to each editor instance.
       
   231 		 * @example
       
   232 		 * // Initializes a editor using the longer method
       
   233 		 * tinymce.EditorManager.init({
       
   234 		 *    some_settings : 'some value'
       
   235 		 * });
       
   236 		 *
       
   237 		 * // Initializes a editor instance using the shorter version
       
   238 		 * tinyMCE.init({
       
   239 		 *    some_settings : 'some value'
       
   240 		 * });
       
   241 		 */
       
   242 		init: function(settings) {
       
   243 			var self = this, editors = [];
       
   244 
       
   245 			function createId(elm) {
       
   246 				var id = elm.id;
       
   247 
       
   248 				// Use element id, or unique name or generate a unique id
       
   249 				if (!id) {
       
   250 					id = elm.name;
       
   251 
       
   252 					if (id && !DOM.get(id)) {
       
   253 						id = elm.name;
       
   254 					} else {
       
   255 						// Generate unique name
       
   256 						id = DOM.uniqueId();
       
   257 					}
       
   258 
       
   259 					elm.setAttribute('id', id);
       
   260 				}
       
   261 
       
   262 				return id;
       
   263 			}
       
   264 
       
   265 			function createEditor(id, settings, targetElm) {
       
   266 				if (!purgeDestroyedEditor(self.get(id))) {
       
   267 					var editor = new Editor(id, settings, self);
       
   268 
       
   269 					editor.targetElm = editor.targetElm || targetElm;
       
   270 					editors.push(editor);
       
   271 					editor.render();
       
   272 				}
       
   273 			}
       
   274 
       
   275 			function execCallback(name) {
       
   276 				var callback = settings[name];
       
   277 
       
   278 				if (!callback) {
       
   279 					return;
       
   280 				}
       
   281 
       
   282 				return callback.apply(self, Array.prototype.slice.call(arguments, 2));
       
   283 			}
       
   284 
       
   285 			function hasClass(elm, className) {
       
   286 				return className.constructor === RegExp ? className.test(elm.className) : DOM.hasClass(elm, className);
       
   287 			}
       
   288 
       
   289 			function readyHandler() {
       
   290 				var l, co;
       
   291 
       
   292 				DOM.unbind(window, 'ready', readyHandler);
       
   293 
       
   294 				execCallback('onpageload');
       
   295 
       
   296 				if (settings.types) {
       
   297 					// Process type specific selector
       
   298 					each(settings.types, function(type) {
       
   299 						each(DOM.select(type.selector), function(elm) {
       
   300 							createEditor(createId(elm), extend({}, settings, type), elm);
       
   301 						});
       
   302 					});
       
   303 
       
   304 					return;
       
   305 				} else if (settings.selector) {
       
   306 					// Process global selector
       
   307 					each(DOM.select(settings.selector), function(elm) {
       
   308 						createEditor(createId(elm), settings, elm);
       
   309 					});
       
   310 
       
   311 					return;
       
   312 				} else if (settings.target) {
       
   313 					createEditor(createId(settings.target), settings);
       
   314 				}
       
   315 
       
   316 				// Fallback to old setting
       
   317 				switch (settings.mode) {
       
   318 					case "exact":
       
   319 						l = settings.elements || '';
       
   320 
       
   321 						if (l.length > 0) {
       
   322 							each(explode(l), function(id) {
       
   323 								var elm;
       
   324 
       
   325 								if ((elm = DOM.get(id))) {
       
   326 									createEditor(id, settings, elm);
       
   327 								} else {
       
   328 									each(document.forms, function(f) {
       
   329 										each(f.elements, function(e) {
       
   330 											if (e.name === id) {
       
   331 												id = 'mce_editor_' + instanceCounter++;
       
   332 												DOM.setAttrib(e, 'id', id);
       
   333 												createEditor(id, settings, e);
       
   334 											}
       
   335 										});
       
   336 									});
       
   337 								}
       
   338 							});
       
   339 						}
       
   340 						break;
       
   341 
       
   342 					case "textareas":
       
   343 					case "specific_textareas":
       
   344 						each(DOM.select('textarea'), function(elm) {
       
   345 							if (settings.editor_deselector && hasClass(elm, settings.editor_deselector)) {
       
   346 								return;
       
   347 							}
       
   348 
       
   349 							if (!settings.editor_selector || hasClass(elm, settings.editor_selector)) {
       
   350 								createEditor(createId(elm), settings, elm);
       
   351 							}
       
   352 						});
       
   353 						break;
       
   354 				}
       
   355 
       
   356 				// Call onInit when all editors are initialized
       
   357 				if (settings.oninit) {
       
   358 					l = co = 0;
       
   359 
       
   360 					each(editors, function(ed) {
       
   361 						co++;
       
   362 
       
   363 						if (!ed.initialized) {
       
   364 							// Wait for it
       
   365 							ed.on('init', function() {
       
   366 								l++;
       
   367 
       
   368 								// All done
       
   369 								if (l == co) {
       
   370 									execCallback('oninit');
       
   371 								}
       
   372 							});
       
   373 						} else {
       
   374 							l++;
       
   375 						}
       
   376 
       
   377 						// All done
       
   378 						if (l == co) {
       
   379 							execCallback('oninit');
       
   380 						}
       
   381 					});
       
   382 				}
       
   383 			}
       
   384 
       
   385 			self.settings = settings;
       
   386 
       
   387 			DOM.bind(window, 'ready', readyHandler);
       
   388 		},
       
   389 
       
   390 		/**
       
   391 		 * Returns a editor instance by id.
       
   392 		 *
       
   393 		 * @method get
       
   394 		 * @param {String/Number} id Editor instance id or index to return.
       
   395 		 * @return {tinymce.Editor} Editor instance to return.
       
   396 		 * @example
       
   397 		 * // Adds an onclick event to an editor by id (shorter version)
       
   398 		 * tinymce.get('mytextbox').on('click', function(e) {
       
   399 		 *    ed.windowManager.alert('Hello world!');
       
   400 		 * });
       
   401 		 *
       
   402 		 * // Adds an onclick event to an editor by id (longer version)
       
   403 		 * tinymce.EditorManager.get('mytextbox').on('click', function(e) {
       
   404 		 *    ed.windowManager.alert('Hello world!');
       
   405 		 * });
       
   406 		 */
       
   407 		get: function(id) {
       
   408 			if (!arguments.length) {
       
   409 				return this.editors;
       
   410 			}
       
   411 
       
   412 			return id in this.editors ? this.editors[id] : null;
       
   413 		},
       
   414 
       
   415 		/**
       
   416 		 * Adds an editor instance to the editor collection. This will also set it as the active editor.
       
   417 		 *
       
   418 		 * @method add
       
   419 		 * @param {tinymce.Editor} editor Editor instance to add to the collection.
       
   420 		 * @return {tinymce.Editor} The same instance that got passed in.
       
   421 		 */
       
   422 		add: function(editor) {
       
   423 			var self = this, editors = self.editors;
       
   424 
       
   425 			// Add named and index editor instance
       
   426 			editors[editor.id] = editor;
       
   427 			editors.push(editor);
       
   428 
       
   429 			// Doesn't call setActive method since we don't want
       
   430 			// to fire a bunch of activate/deactivate calls while initializing
       
   431 			self.activeEditor = editor;
       
   432 
       
   433 			/**
       
   434 			 * Fires when an editor is added to the EditorManager collection.
       
   435 			 *
       
   436 			 * @event AddEditor
       
   437 			 * @param {Object} e Event arguments.
       
   438 			 */
       
   439 			self.fire('AddEditor', {editor: editor});
       
   440 
       
   441 			if (!beforeUnloadDelegate) {
       
   442 				beforeUnloadDelegate = function() {
       
   443 					self.fire('BeforeUnload');
       
   444 				};
       
   445 
       
   446 				DOM.bind(window, 'beforeunload', beforeUnloadDelegate);
       
   447 			}
       
   448 
       
   449 			return editor;
       
   450 		},
       
   451 
       
   452 		/**
       
   453 		 * Creates an editor instance and adds it to the EditorManager collection.
       
   454 		 *
       
   455 		 * @method createEditor
       
   456 		 * @param {String} id Instance id to use for editor.
       
   457 		 * @param {Object} settings Editor instance settings.
       
   458 		 * @return {tinymce.Editor} Editor instance that got created.
       
   459 		 */
       
   460 		createEditor: function(id, settings) {
       
   461 			return this.add(new Editor(id, settings, this));
       
   462 		},
       
   463 
       
   464 		/**
       
   465 		 * Removes a editor or editors form page.
       
   466 		 *
       
   467 		 * @example
       
   468 		 * // Remove all editors bound to divs
       
   469 		 * tinymce.remove('div');
       
   470 		 *
       
   471 		 * // Remove all editors bound to textareas
       
   472 		 * tinymce.remove('textarea');
       
   473 		 *
       
   474 		 * // Remove all editors
       
   475 		 * tinymce.remove();
       
   476 		 *
       
   477 		 * // Remove specific instance by id
       
   478 		 * tinymce.remove('#id');
       
   479 		 *
       
   480 		 * @method remove
       
   481 		 * @param {tinymce.Editor/String/Object} [selector] CSS selector or editor instance to remove.
       
   482 		 * @return {tinymce.Editor} The editor that got passed in will be return if it was found otherwise null.
       
   483 		 */
       
   484 		remove: function(selector) {
       
   485 			var self = this, i, editors = self.editors, editor;
       
   486 
       
   487 			// Remove all editors
       
   488 			if (!selector) {
       
   489 				for (i = editors.length - 1; i >= 0; i--) {
       
   490 					self.remove(editors[i]);
       
   491 				}
       
   492 
       
   493 				return;
       
   494 			}
       
   495 
       
   496 			// Remove editors by selector
       
   497 			if (typeof selector == "string") {
       
   498 				selector = selector.selector || selector;
       
   499 
       
   500 				each(DOM.select(selector), function(elm) {
       
   501 					editor = editors[elm.id];
       
   502 
       
   503 					if (editor) {
       
   504 						self.remove(editor);
       
   505 					}
       
   506 				});
       
   507 
       
   508 				return;
       
   509 			}
       
   510 
       
   511 			// Remove specific editor
       
   512 			editor = selector;
       
   513 
       
   514 			// Not in the collection
       
   515 			if (!editors[editor.id]) {
       
   516 				return null;
       
   517 			}
       
   518 
       
   519 			/**
       
   520 			 * Fires when an editor is removed from EditorManager collection.
       
   521 			 *
       
   522 			 * @event RemoveEditor
       
   523 			 * @param {Object} e Event arguments.
       
   524 			 */
       
   525 			if (removeEditorFromList(editor)) {
       
   526 				self.fire('RemoveEditor', {editor: editor});
       
   527 			}
       
   528 
       
   529 			if (!editors.length) {
       
   530 				DOM.unbind(window, 'beforeunload', beforeUnloadDelegate);
       
   531 			}
       
   532 
       
   533 			editor.remove();
       
   534 
       
   535 			return editor;
       
   536 		},
       
   537 
       
   538 		/**
       
   539 		 * Executes a specific command on the currently active editor.
       
   540 		 *
       
   541 		 * @method execCommand
       
   542 		 * @param {String} c Command to perform for example Bold.
       
   543 		 * @param {Boolean} u Optional boolean state if a UI should be presented for the command or not.
       
   544 		 * @param {String} v Optional value parameter like for example an URL to a link.
       
   545 		 * @return {Boolean} true/false if the command was executed or not.
       
   546 		 */
       
   547 		execCommand: function(cmd, ui, value) {
       
   548 			var self = this, editor = self.get(value);
       
   549 
       
   550 			// Manager commands
       
   551 			switch (cmd) {
       
   552 				case "mceAddEditor":
       
   553 					if (!self.get(value)) {
       
   554 						new Editor(value, self.settings, self).render();
       
   555 					}
       
   556 
       
   557 					return true;
       
   558 
       
   559 				case "mceRemoveEditor":
       
   560 					if (editor) {
       
   561 						editor.remove();
       
   562 					}
       
   563 
       
   564 					return true;
       
   565 
       
   566 				case 'mceToggleEditor':
       
   567 					if (!editor) {
       
   568 						self.execCommand('mceAddEditor', 0, value);
       
   569 						return true;
       
   570 					}
       
   571 
       
   572 					if (editor.isHidden()) {
       
   573 						editor.show();
       
   574 					} else {
       
   575 						editor.hide();
       
   576 					}
       
   577 
       
   578 					return true;
       
   579 			}
       
   580 
       
   581 			// Run command on active editor
       
   582 			if (self.activeEditor) {
       
   583 				return self.activeEditor.execCommand(cmd, ui, value);
       
   584 			}
       
   585 
       
   586 			return false;
       
   587 		},
       
   588 
       
   589 		/**
       
   590 		 * Calls the save method on all editor instances in the collection. This can be useful when a form is to be submitted.
       
   591 		 *
       
   592 		 * @method triggerSave
       
   593 		 * @example
       
   594 		 * // Saves all contents
       
   595 		 * tinyMCE.triggerSave();
       
   596 		 */
       
   597 		triggerSave: function() {
       
   598 			each(this.editors, function(editor) {
       
   599 				editor.save();
       
   600 			});
       
   601 		},
       
   602 
       
   603 		/**
       
   604 		 * Adds a language pack, this gets called by the loaded language files like en.js.
       
   605 		 *
       
   606 		 * @method addI18n
       
   607 		 * @param {String} code Optional language code.
       
   608 		 * @param {Object} items Name/value object with translations.
       
   609 		 */
       
   610 		addI18n: function(code, items) {
       
   611 			I18n.add(code, items);
       
   612 		},
       
   613 
       
   614 		/**
       
   615 		 * Translates the specified string using the language pack items.
       
   616 		 *
       
   617 		 * @method translate
       
   618 		 * @param {String/Array/Object} text String to translate
       
   619 		 * @return {String} Translated string.
       
   620 		 */
       
   621 		translate: function(text) {
       
   622 			return I18n.translate(text);
       
   623 		},
       
   624 
       
   625 		/**
       
   626 		 * Sets the active editor instance and fires the deactivate/activate events.
       
   627 		 *
       
   628 		 * @method setActive
       
   629 		 * @param {tinymce.Editor} editor Editor instance to set as the active instance.
       
   630 		 */
       
   631 		setActive: function(editor) {
       
   632 			var activeEditor = this.activeEditor;
       
   633 
       
   634 			if (this.activeEditor != editor) {
       
   635 				if (activeEditor) {
       
   636 					activeEditor.fire('deactivate', {relatedTarget: editor});
       
   637 				}
       
   638 
       
   639 				editor.fire('activate', {relatedTarget: activeEditor});
       
   640 			}
       
   641 
       
   642 			this.activeEditor = editor;
       
   643 		}
       
   644 	};
       
   645 
       
   646 	extend(EditorManager, Observable);
       
   647 
       
   648 	EditorManager.setup();
       
   649 
       
   650 	// Export EditorManager as tinymce/tinymce in global namespace
       
   651 	window.tinymce = window.tinyMCE = EditorManager;
       
   652 
       
   653 	return EditorManager;
       
   654 });