JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.6.1
[ckeditor.git] / _source / core / editor.js
1 /*\r
2 Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.\r
3 For licensing, see LICENSE.html or http://ckeditor.com/license\r
4 */\r
5 \r
6 /**\r
7  * @fileOverview Defines the {@link CKEDITOR.editor} class, which represents an\r
8  *              editor instance.\r
9  */\r
10 \r
11 (function()\r
12 {\r
13         // The counter for automatic instance names.\r
14         var nameCounter = 0;\r
15 \r
16         var getNewName = function()\r
17         {\r
18                 var name = 'editor' + ( ++nameCounter );\r
19                 return ( CKEDITOR.instances && CKEDITOR.instances[ name ] ) ? getNewName() : name;\r
20         };\r
21 \r
22         // ##### START: Config Privates\r
23 \r
24         // These function loads custom configuration files and cache the\r
25         // CKEDITOR.editorConfig functions defined on them, so there is no need to\r
26         // download them more than once for several instances.\r
27         var loadConfigLoaded = {};\r
28         var loadConfig = function( editor )\r
29         {\r
30                 var customConfig = editor.config.customConfig;\r
31 \r
32                 // Check if there is a custom config to load.\r
33                 if ( !customConfig )\r
34                         return false;\r
35 \r
36                 customConfig = CKEDITOR.getUrl( customConfig );\r
37 \r
38                 var loadedConfig = loadConfigLoaded[ customConfig ] || ( loadConfigLoaded[ customConfig ] = {} );\r
39 \r
40                 // If the custom config has already been downloaded, reuse it.\r
41                 if ( loadedConfig.fn )\r
42                 {\r
43                         // Call the cached CKEDITOR.editorConfig defined in the custom\r
44                         // config file for the editor instance depending on it.\r
45                         loadedConfig.fn.call( editor, editor.config );\r
46 \r
47                         // If there is no other customConfig in the chain, fire the\r
48                         // "configLoaded" event.\r
49                         if ( CKEDITOR.getUrl( editor.config.customConfig ) == customConfig || !loadConfig( editor ) )\r
50                                 editor.fireOnce( 'customConfigLoaded' );\r
51                 }\r
52                 else\r
53                 {\r
54                         // Load the custom configuration file.\r
55                         CKEDITOR.scriptLoader.load( customConfig, function()\r
56                                 {\r
57                                         // If the CKEDITOR.editorConfig function has been properly\r
58                                         // defined in the custom configuration file, cache it.\r
59                                         if ( CKEDITOR.editorConfig )\r
60                                                 loadedConfig.fn = CKEDITOR.editorConfig;\r
61                                         else\r
62                                                 loadedConfig.fn = function(){};\r
63 \r
64                                         // Call the load config again. This time the custom\r
65                                         // config is already cached and so it will get loaded.\r
66                                         loadConfig( editor );\r
67                                 });\r
68                 }\r
69 \r
70                 return true;\r
71         };\r
72 \r
73         var initConfig = function( editor, instanceConfig )\r
74         {\r
75                 // Setup the lister for the "customConfigLoaded" event.\r
76                 editor.on( 'customConfigLoaded', function()\r
77                         {\r
78                                 if ( instanceConfig )\r
79                                 {\r
80                                         // Register the events that may have been set at the instance\r
81                                         // configuration object.\r
82                                         if ( instanceConfig.on )\r
83                                         {\r
84                                                 for ( var eventName in instanceConfig.on )\r
85                                                 {\r
86                                                         editor.on( eventName, instanceConfig.on[ eventName ] );\r
87                                                 }\r
88                                         }\r
89 \r
90                                         // Overwrite the settings from the in-page config.\r
91                                         CKEDITOR.tools.extend( editor.config, instanceConfig, true );\r
92 \r
93                                         delete editor.config.on;\r
94                                 }\r
95 \r
96                                 onConfigLoaded( editor );\r
97                         });\r
98 \r
99                 // The instance config may override the customConfig setting to avoid\r
100                 // loading the default ~/config.js file.\r
101                 if ( instanceConfig && instanceConfig.customConfig != undefined )\r
102                         editor.config.customConfig = instanceConfig.customConfig;\r
103 \r
104                 // Load configs from the custom configuration files.\r
105                 if ( !loadConfig( editor ) )\r
106                         editor.fireOnce( 'customConfigLoaded' );\r
107         };\r
108 \r
109         // ##### END: Config Privates\r
110 \r
111         var onConfigLoaded = function( editor )\r
112         {\r
113                 // Set config related properties.\r
114 \r
115                 var skin = editor.config.skin.split( ',' ),\r
116                         skinName = skin[ 0 ],\r
117                         skinPath = CKEDITOR.getUrl( skin[ 1 ] || (\r
118                                 '_source/' +    // @Packager.RemoveLine\r
119                                 'skins/' + skinName + '/' ) );\r
120 \r
121                 /**\r
122                  * The name of the skin used by this editor instance. The skin name can\r
123                  * be set through the <code>{@link CKEDITOR.config.skin}</code> setting.\r
124                  * @name CKEDITOR.editor.prototype.skinName\r
125                  * @type String\r
126                  * @example\r
127                  * alert( editor.skinName );  // E.g. "kama"\r
128                  */\r
129                 editor.skinName = skinName;\r
130 \r
131                 /**\r
132                  * The full URL of the skin directory.\r
133                  * @name CKEDITOR.editor.prototype.skinPath\r
134                  * @type String\r
135                  * @example\r
136                  * alert( editor.skinPath );  // E.g. "http://example.com/ckeditor/skins/kama/"\r
137                  */\r
138                 editor.skinPath = skinPath;\r
139 \r
140                 /**\r
141                  * The CSS class name used for skin identification purposes.\r
142                  * @name CKEDITOR.editor.prototype.skinClass\r
143                  * @type String\r
144                  * @example\r
145                  * alert( editor.skinClass );  // E.g. "cke_skin_kama"\r
146                  */\r
147                 editor.skinClass = 'cke_skin_' + skinName;\r
148 \r
149                 /**\r
150                  * The <a href="http://en.wikipedia.org/wiki/Tabbing_navigation">tabbing\r
151                  * navigation</a> order that has been calculated for this editor\r
152                  * instance. This can be set by the <code>{@link CKEDITOR.config.tabIndex}</code>\r
153                  * setting or taken from the <code>tabindex</code> attribute of the\r
154                  * <code>{@link #element}</code> associated with the editor.\r
155                  * @name CKEDITOR.editor.prototype.tabIndex\r
156                  * @type Number\r
157                  * @default 0 (zero)\r
158                  * @example\r
159                  * alert( editor.tabIndex );  // E.g. "0"\r
160                  */\r
161                 editor.tabIndex = editor.config.tabIndex || editor.element.getAttribute( 'tabindex' ) || 0;\r
162 \r
163                 /**\r
164                  * Indicates the read-only state of this editor. This is a read-only property.\r
165                  * @name CKEDITOR.editor.prototype.readOnly\r
166                  * @type Boolean\r
167                  * @since 3.6\r
168                  * @see CKEDITOR.editor#setReadOnly\r
169                  */\r
170                 editor.readOnly = !!( editor.config.readOnly || editor.element.getAttribute( 'disabled' ) );\r
171 \r
172                 // Fire the "configLoaded" event.\r
173                 editor.fireOnce( 'configLoaded' );\r
174 \r
175                 // Load language file.\r
176                 loadSkin( editor );\r
177         };\r
178 \r
179         var loadLang = function( editor )\r
180         {\r
181                 CKEDITOR.lang.load( editor.config.language, editor.config.defaultLanguage, function( languageCode, lang )\r
182                         {\r
183                                 /**\r
184                                  * The code for the language resources that have been loaded\r
185                                  * for the user interface elements of this editor instance.\r
186                                  * @name CKEDITOR.editor.prototype.langCode\r
187                                  * @type String\r
188                                  * @example\r
189                                  * alert( editor.langCode );  // E.g. "en"\r
190                                  */\r
191                                 editor.langCode = languageCode;\r
192 \r
193                                 /**\r
194                                  * An object that contains all language strings used by the editor\r
195                                  * interface.\r
196                                  * @name CKEDITOR.editor.prototype.lang\r
197                                  * @type CKEDITOR.lang\r
198                                  * @example\r
199                                  * alert( editor.lang.bold );  // E.g. "Negrito" (if the language is set to Portuguese)\r
200                                  */\r
201                                 // As we'll be adding plugin specific entries that could come\r
202                                 // from different language code files, we need a copy of lang,\r
203                                 // not a direct reference to it.\r
204                                 editor.lang = CKEDITOR.tools.prototypedCopy( lang );\r
205 \r
206                                 // We're not able to support RTL in Firefox 2 at this time.\r
207                                 if ( CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 && editor.lang.dir == 'rtl' )\r
208                                         editor.lang.dir = 'ltr';\r
209 \r
210                                 editor.fire( 'langLoaded' );\r
211 \r
212                                 var config = editor.config;\r
213                                 config.contentsLangDirection == 'ui' && ( config.contentsLangDirection = editor.lang.dir );\r
214 \r
215                                 loadPlugins( editor );\r
216                         });\r
217         };\r
218 \r
219         var loadPlugins = function( editor )\r
220         {\r
221                 var config                      = editor.config,\r
222                         plugins                 = config.plugins,\r
223                         extraPlugins    = config.extraPlugins,\r
224                         removePlugins   = config.removePlugins;\r
225 \r
226                 if ( extraPlugins )\r
227                 {\r
228                         // Remove them first to avoid duplications.\r
229                         var removeRegex = new RegExp( '(?:^|,)(?:' + extraPlugins.replace( /\s*,\s*/g, '|' ) + ')(?=,|$)' , 'g' );\r
230                         plugins = plugins.replace( removeRegex, '' );\r
231 \r
232                         plugins += ',' + extraPlugins;\r
233                 }\r
234 \r
235                 if ( removePlugins )\r
236                 {\r
237                         removeRegex = new RegExp( '(?:^|,)(?:' + removePlugins.replace( /\s*,\s*/g, '|' ) + ')(?=,|$)' , 'g' );\r
238                         plugins = plugins.replace( removeRegex, '' );\r
239                 }\r
240 \r
241                 // Load the Adobe AIR plugin conditionally.\r
242                 CKEDITOR.env.air && ( plugins += ',adobeair' );\r
243 \r
244                 // Load all plugins defined in the "plugins" setting.\r
245                 CKEDITOR.plugins.load( plugins.split( ',' ), function( plugins )\r
246                         {\r
247                                 // The list of plugins.\r
248                                 var pluginsArray = [];\r
249 \r
250                                 // The language code to get loaded for each plugin. Null\r
251                                 // entries will be appended for plugins with no language files.\r
252                                 var languageCodes = [];\r
253 \r
254                                 // The list of URLs to language files.\r
255                                 var languageFiles = [];\r
256 \r
257                                 /**\r
258                                  * An object that contains references to all plugins used by this\r
259                                  * editor instance.\r
260                                  * @name CKEDITOR.editor.prototype.plugins\r
261                                  * @type Object\r
262                                  * @example\r
263                                  * alert( editor.plugins.dialog.path );  // E.g. "http://example.com/ckeditor/plugins/dialog/"\r
264                                  */\r
265                                 editor.plugins = plugins;\r
266 \r
267                                 // Loop through all plugins, to build the list of language\r
268                                 // files to get loaded.\r
269                                 for ( var pluginName in plugins )\r
270                                 {\r
271                                         var plugin = plugins[ pluginName ],\r
272                                                 pluginLangs = plugin.lang,\r
273                                                 pluginPath = CKEDITOR.plugins.getPath( pluginName ),\r
274                                                 lang = null;\r
275 \r
276                                         // Set the plugin path in the plugin.\r
277                                         plugin.path = pluginPath;\r
278 \r
279                                         // If the plugin has "lang".\r
280                                         if ( pluginLangs )\r
281                                         {\r
282                                                 // Resolve the plugin language. If the current language\r
283                                                 // is not available, get the first one (default one).\r
284                                                 lang = ( CKEDITOR.tools.indexOf( pluginLangs, editor.langCode ) >= 0 ? editor.langCode : pluginLangs[ 0 ] );\r
285 \r
286                                                 if ( !plugin.langEntries || !plugin.langEntries[ lang ] )\r
287                                                 {\r
288                                                         // Put the language file URL into the list of files to\r
289                                                         // get downloaded.\r
290                                                         languageFiles.push( CKEDITOR.getUrl( pluginPath + 'lang/' + lang + '.js' ) );\r
291                                                 }\r
292                                                 else\r
293                                                 {\r
294                                                         CKEDITOR.tools.extend( editor.lang, plugin.langEntries[ lang ] );\r
295                                                         lang = null;\r
296                                                 }\r
297                                         }\r
298 \r
299                                         // Save the language code, so we know later which\r
300                                         // language has been resolved to this plugin.\r
301                                         languageCodes.push( lang );\r
302 \r
303                                         pluginsArray.push( plugin );\r
304                                 }\r
305 \r
306                                 // Load all plugin specific language files in a row.\r
307                                 CKEDITOR.scriptLoader.load( languageFiles, function()\r
308                                         {\r
309                                                 // Initialize all plugins that have the "beforeInit" and "init" methods defined.\r
310                                                 var methods = [ 'beforeInit', 'init', 'afterInit' ];\r
311                                                 for ( var m = 0 ; m < methods.length ; m++ )\r
312                                                 {\r
313                                                         for ( var i = 0 ; i < pluginsArray.length ; i++ )\r
314                                                         {\r
315                                                                 var plugin = pluginsArray[ i ];\r
316 \r
317                                                                 // Uses the first loop to update the language entries also.\r
318                                                                 if ( m === 0 && languageCodes[ i ] && plugin.lang )\r
319                                                                         CKEDITOR.tools.extend( editor.lang, plugin.langEntries[ languageCodes[ i ] ] );\r
320 \r
321                                                                 // Call the plugin method (beforeInit and init).\r
322                                                                 if ( plugin[ methods[ m ] ] )\r
323                                                                         plugin[ methods[ m ] ]( editor );\r
324                                                         }\r
325                                                 }\r
326 \r
327                                                 // Load the editor skin.\r
328                                                 editor.fire( 'pluginsLoaded' );\r
329                                                 loadTheme( editor );\r
330                                         });\r
331                         });\r
332         };\r
333 \r
334         var loadSkin = function( editor )\r
335         {\r
336                 CKEDITOR.skins.load( editor, 'editor', function()\r
337                         {\r
338                                 loadLang( editor );\r
339                         });\r
340         };\r
341 \r
342         var loadTheme = function( editor )\r
343         {\r
344                 var theme = editor.config.theme;\r
345                 CKEDITOR.themes.load( theme, function()\r
346                         {\r
347                                 /**\r
348                                  * The theme used by this editor instance.\r
349                                  * @name CKEDITOR.editor.prototype.theme\r
350                                  * @type CKEDITOR.theme\r
351                                  * @example\r
352                                  * alert( editor.theme );  // E.g. "http://example.com/ckeditor/themes/default/"\r
353                                  */\r
354                                 var editorTheme = editor.theme = CKEDITOR.themes.get( theme );\r
355                                 editorTheme.path = CKEDITOR.themes.getPath( theme );\r
356                                 editorTheme.build( editor );\r
357 \r
358                                 if ( editor.config.autoUpdateElement )\r
359                                         attachToForm( editor );\r
360                         });\r
361         };\r
362 \r
363         var attachToForm = function( editor )\r
364         {\r
365                 var element = editor.element;\r
366 \r
367                 // If are replacing a textarea, we must\r
368                 if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE && element.is( 'textarea' ) )\r
369                 {\r
370                         var form = element.$.form && new CKEDITOR.dom.element( element.$.form );\r
371                         if ( form )\r
372                         {\r
373                                 function onSubmit()\r
374                                 {\r
375                                         editor.updateElement();\r
376                                 }\r
377                                 form.on( 'submit',onSubmit );\r
378 \r
379                                 // Setup the submit function because it doesn't fire the\r
380                                 // "submit" event.\r
381                                 if ( !form.$.submit.nodeName && !form.$.submit.length )\r
382                                 {\r
383                                         form.$.submit = CKEDITOR.tools.override( form.$.submit, function( originalSubmit )\r
384                                                 {\r
385                                                         return function()\r
386                                                                 {\r
387                                                                         editor.updateElement();\r
388 \r
389                                                                         // For IE, the DOM submit function is not a\r
390                                                                         // function, so we need thid check.\r
391                                                                         if ( originalSubmit.apply )\r
392                                                                                 originalSubmit.apply( this, arguments );\r
393                                                                         else\r
394                                                                                 originalSubmit();\r
395                                                                 };\r
396                                                 });\r
397                                 }\r
398 \r
399                                 // Remove 'submit' events registered on form element before destroying.(#3988)\r
400                                 editor.on( 'destroy', function()\r
401                                 {\r
402                                         form.removeListener( 'submit', onSubmit );\r
403                                 } );\r
404                         }\r
405                 }\r
406         };\r
407 \r
408         function updateCommands()\r
409         {\r
410                 var command,\r
411                         commands = this._.commands,\r
412                         mode = this.mode;\r
413 \r
414                 if ( !mode )\r
415                         return;\r
416 \r
417                 for ( var name in commands )\r
418                 {\r
419                         command = commands[ name ];\r
420                         command[ command.startDisabled ? 'disable' :\r
421                                          this.readOnly && !command.readOnly ? 'disable' : command.modes[ mode ] ? 'enable' : 'disable' ]();\r
422                 }\r
423         }\r
424 \r
425         /**\r
426          * Initializes the editor instance. This function is called by the editor\r
427          * contructor (<code>editor_basic.js</code>).\r
428          * @private\r
429          */\r
430         CKEDITOR.editor.prototype._init = function()\r
431                 {\r
432                         // Get the properties that have been saved in the editor_base\r
433                         // implementation.\r
434                         var element                     = CKEDITOR.dom.element.get( this._.element ),\r
435                                 instanceConfig  = this._.instanceConfig;\r
436                         delete this._.element;\r
437                         delete this._.instanceConfig;\r
438 \r
439                         this._.commands = {};\r
440                         this._.styles = [];\r
441 \r
442                         /**\r
443                          * The DOM element that was replaced by this editor instance. This\r
444                          * element stores the editor data on load and post.\r
445                          * @name CKEDITOR.editor.prototype.element\r
446                          * @type CKEDITOR.dom.element\r
447                          * @example\r
448                          * var editor = CKEDITOR.instances.editor1;\r
449                          * alert( <strong>editor.element</strong>.getName() );  // E.g. "textarea"\r
450                          */\r
451                         this.element = element;\r
452 \r
453                         /**\r
454                          * The editor instance name. It may be the replaced element ID, name, or\r
455                          * a default name using the progressive counter (<code>editor1</code>,\r
456                          * <code>editor2</code>, ...).\r
457                          * @name CKEDITOR.editor.prototype.name\r
458                          * @type String\r
459                          * @example\r
460                          * var editor = CKEDITOR.instances.editor1;\r
461                          * alert( <strong>editor.name</strong> );  // "editor1"\r
462                          */\r
463                         this.name = ( element && ( this.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE )\r
464                                                         && ( element.getId() || element.getNameAtt() ) )\r
465                                                 || getNewName();\r
466 \r
467                         if ( this.name in CKEDITOR.instances )\r
468                                 throw '[CKEDITOR.editor] The instance "' + this.name + '" already exists.';\r
469 \r
470                         /**\r
471                          * A unique random string assigned to each editor instance on the page.\r
472                          * @name CKEDITOR.editor.prototype.id\r
473                          * @type String\r
474                          */\r
475                         this.id = CKEDITOR.tools.getNextId();\r
476 \r
477                         /**\r
478                          * The configurations for this editor instance. It inherits all\r
479                          * settings defined in <code>(@link CKEDITOR.config}</code>, combined with settings\r
480                          * loaded from custom configuration files and those defined inline in\r
481                          * the page when creating the editor.\r
482                          * @name CKEDITOR.editor.prototype.config\r
483                          * @type Object\r
484                          * @example\r
485                          * var editor = CKEDITOR.instances.editor1;\r
486                          * alert( <strong>editor.config.theme</strong> );  // E.g. "default"\r
487                          */\r
488                         this.config = CKEDITOR.tools.prototypedCopy( CKEDITOR.config );\r
489 \r
490                         /**\r
491                          * The namespace containing UI features related to this editor instance.\r
492                          * @name CKEDITOR.editor.prototype.ui\r
493                          * @type CKEDITOR.ui\r
494                          * @example\r
495                          */\r
496                         this.ui = new CKEDITOR.ui( this );\r
497 \r
498                         /**\r
499                          * Controls the focus state of this editor instance. This property\r
500                          * is rarely used for normal API operations. It is mainly\r
501                          * intended for developers adding UI elements to the editor interface.\r
502                          * @name CKEDITOR.editor.prototype.focusManager\r
503                          * @type CKEDITOR.focusManager\r
504                          * @example\r
505                          */\r
506                         this.focusManager = new CKEDITOR.focusManager( this );\r
507 \r
508                         CKEDITOR.fire( 'instanceCreated', null, this );\r
509 \r
510                         this.on( 'mode', updateCommands, null, null, 1 );\r
511                         this.on( 'readOnly', updateCommands, null, null, 1 );\r
512 \r
513                         initConfig( this, instanceConfig );\r
514                 };\r
515 })();\r
516 \r
517 CKEDITOR.tools.extend( CKEDITOR.editor.prototype,\r
518         /** @lends CKEDITOR.editor.prototype */\r
519         {\r
520                 /**\r
521                  * Adds a command definition to the editor instance. Commands added with\r
522                  * this function can be executed later with the <code>{@link #execCommand}</code> method.\r
523                  * @param {String} commandName The indentifier name of the command.\r
524                  * @param {CKEDITOR.commandDefinition} commandDefinition The command definition.\r
525                  * @example\r
526                  * editorInstance.addCommand( 'sample',\r
527                  * {\r
528                  *     exec : function( editor )\r
529                  *     {\r
530                  *         alert( 'Executing a command for the editor name "' + editor.name + '"!' );\r
531                  *     }\r
532                  * });\r
533                  */\r
534                 addCommand : function( commandName, commandDefinition )\r
535                 {\r
536                         return this._.commands[ commandName ] = new CKEDITOR.command( this, commandDefinition );\r
537                 },\r
538 \r
539                 /**\r
540                  * Adds a piece of CSS code to the editor which will be applied to the WYSIWYG editing document.\r
541                  * This CSS would not be added to the output, and is there mainly for editor-specific editing requirements.\r
542                  * Note: This function should be called before the editor is loaded to take effect.\r
543                  * @param css {String} CSS text.\r
544                  * @example\r
545                  * editorInstance.addCss( 'body { background-color: grey; }' );\r
546                  */\r
547                 addCss : function( css )\r
548                 {\r
549                         this._.styles.push( css );\r
550                 },\r
551 \r
552                 /**\r
553                  * Destroys the editor instance, releasing all resources used by it.\r
554                  * If the editor replaced an element, the element will be recovered.\r
555                  * @param {Boolean} [noUpdate] If the instance is replacing a DOM\r
556                  *              element, this parameter indicates whether or not to update the\r
557                  *              element with the instance contents.\r
558                  * @example\r
559                  * alert( CKEDITOR.instances.editor1 );  //  E.g "object"\r
560                  * <strong>CKEDITOR.instances.editor1.destroy()</strong>;\r
561                  * alert( CKEDITOR.instances.editor1 );  // "undefined"\r
562                  */\r
563                 destroy : function( noUpdate )\r
564                 {\r
565                         if ( !noUpdate )\r
566                                 this.updateElement();\r
567 \r
568                         this.fire( 'destroy' );\r
569                         this.theme && this.theme.destroy( this );\r
570 \r
571                         CKEDITOR.remove( this );\r
572                         CKEDITOR.fire( 'instanceDestroyed', null, this );\r
573                 },\r
574 \r
575                 /**\r
576                  * Executes a command associated with the editor.\r
577                  * @param {String} commandName The indentifier name of the command.\r
578                  * @param {Object} [data] Data to be passed to the command.\r
579                  * @returns {Boolean} <code>true</code> if the command was executed\r
580                  *              successfully, otherwise <code>false</code>.\r
581                  * @see CKEDITOR.editor.addCommand\r
582                  * @example\r
583                  * editorInstance.execCommand( 'bold' );\r
584                  */\r
585                 execCommand : function( commandName, data )\r
586                 {\r
587                         var command = this.getCommand( commandName );\r
588 \r
589                         var eventData =\r
590                         {\r
591                                 name: commandName,\r
592                                 commandData: data,\r
593                                 command: command\r
594                         };\r
595 \r
596                         if ( command && command.state != CKEDITOR.TRISTATE_DISABLED )\r
597                         {\r
598                                 if ( this.fire( 'beforeCommandExec', eventData ) !== true )\r
599                                 {\r
600                                         eventData.returnValue = command.exec( eventData.commandData );\r
601 \r
602                                         // Fire the 'afterCommandExec' immediately if command is synchronous.\r
603                                         if ( !command.async && this.fire( 'afterCommandExec', eventData ) !== true )\r
604                                                 return eventData.returnValue;\r
605                                 }\r
606                         }\r
607 \r
608                         // throw 'Unknown command name "' + commandName + '"';\r
609                         return false;\r
610                 },\r
611 \r
612                 /**\r
613                  * Gets one of the registered commands. Note that after registering a\r
614                  * command definition with <code>{@link #addCommand}</code>, it is\r
615                  * transformed internally into an instance of\r
616                  * <code>{@link CKEDITOR.command}</code>, which will then be returned\r
617                  * by this function.\r
618                  * @param {String} commandName The name of the command to be returned.\r
619                  * This is the same name that is used to register the command with\r
620                  *              <code>addCommand</code>.\r
621                  * @returns {CKEDITOR.command} The command object identified by the\r
622                  * provided name.\r
623                  */\r
624                 getCommand : function( commandName )\r
625                 {\r
626                         return this._.commands[ commandName ];\r
627                 },\r
628 \r
629                 /**\r
630                  * Gets the editor data. The data will be in raw format. It is the same\r
631                  * data that is posted by the editor.\r
632                  * @type String\r
633                  * @returns (String) The editor data.\r
634                  * @example\r
635                  * if ( CKEDITOR.instances.editor1.<strong>getData()</strong> == '' )\r
636                  *     alert( 'There is no data available' );\r
637                  */\r
638                 getData : function()\r
639                 {\r
640                         this.fire( 'beforeGetData' );\r
641 \r
642                         var eventData = this._.data;\r
643 \r
644                         if ( typeof eventData != 'string' )\r
645                         {\r
646                                 var element = this.element;\r
647                                 if ( element && this.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE )\r
648                                         eventData = element.is( 'textarea' ) ? element.getValue() : element.getHtml();\r
649                                 else\r
650                                         eventData = '';\r
651                         }\r
652 \r
653                         eventData = { dataValue : eventData };\r
654 \r
655                         // Fire "getData" so data manipulation may happen.\r
656                         this.fire( 'getData', eventData );\r
657 \r
658                         return eventData.dataValue;\r
659                 },\r
660 \r
661                 /**\r
662                  * Gets the "raw data" currently available in the editor. This is a\r
663                  * fast method which returns the data as is, without processing, so it is\r
664                  * not recommended to use it on resulting pages. Instead it can be used\r
665                  * combined with the <code>{@link #loadSnapshot}</code> method in order\r
666                  * to be able to automatically save the editor data from time to time\r
667                  * while the user is using the editor, to avoid data loss, without risking\r
668                  * performance issues.\r
669                  * @see CKEDITOR.editor.getData\r
670                  * @example\r
671                  * alert( editor.getSnapshot() );\r
672                  */\r
673                 getSnapshot : function()\r
674                 {\r
675                         var data = this.fire( 'getSnapshot' );\r
676 \r
677                         if ( typeof data != 'string' )\r
678                         {\r
679                                 var element = this.element;\r
680                                 if ( element && this.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE )\r
681                                         data = element.is( 'textarea' ) ? element.getValue() : element.getHtml();\r
682                         }\r
683 \r
684                         return data;\r
685                 },\r
686 \r
687                 /**\r
688                  * Loads "raw data" into the editor. The data is loaded with processing\r
689                  * straight to the editing area. It should not be used as a way to load\r
690                  * any kind of data, but instead in combination with\r
691                  * <code>{@link #getSnapshot}</code> produced data.\r
692                  * @see CKEDITOR.editor.setData\r
693                  * @example\r
694                  * var data = editor.getSnapshot();\r
695                  * editor.<strong>loadSnapshot( data )</strong>;\r
696                  */\r
697                 loadSnapshot : function( snapshot )\r
698                 {\r
699                         this.fire( 'loadSnapshot', snapshot );\r
700                 },\r
701 \r
702                 /**\r
703                  * Sets the editor data. The data must be provided in the raw format (HTML).<br />\r
704                  * <br />\r
705                  * Note that this method is asynchronous. The <code>callback</code> parameter must\r
706                  * be used if interaction with the editor is needed after setting the data.\r
707                  * @param {String} data HTML code to replace the curent content in the\r
708                  *              editor.\r
709                  * @param {Function} callback Function to be called after the <code>setData</code>\r
710                  *              is completed.\r
711                  *@param {Boolean} internal Whether to suppress any event firing when copying data\r
712                  *              internally inside the editor.\r
713                  * @example\r
714                  * CKEDITOR.instances.editor1.<strong>setData</strong>( '&lt;p&gt;This is the editor data.&lt;/p&gt;' );\r
715                  * @example\r
716                  * CKEDITOR.instances.editor1.<strong>setData</strong>( '&lt;p&gt;Some other editor data.&lt;/p&gt;', function()\r
717                  *     {\r
718                  *         this.checkDirty();  // true\r
719                  *     });\r
720                  */\r
721                 setData : function( data , callback, internal )\r
722                 {\r
723                         if( callback )\r
724                         {\r
725                                 this.on( 'dataReady', function( evt )\r
726                                 {\r
727                                         evt.removeListener();\r
728                                         callback.call( evt.editor );\r
729                                 } );\r
730                         }\r
731 \r
732                         // Fire "setData" so data manipulation may happen.\r
733                         var eventData = { dataValue : data };\r
734                         !internal && this.fire( 'setData', eventData );\r
735 \r
736                         this._.data = eventData.dataValue;\r
737 \r
738                         !internal && this.fire( 'afterSetData', eventData );\r
739                 },\r
740 \r
741                 /**\r
742                  * Puts or restores the editor into read-only state. When in read-only,\r
743                  * the user is not able to change the editor contents, but can still use\r
744                  * some editor features. This function sets the <code>{@link CKEDITOR.config.readOnly}</code>\r
745                  * property of the editor, firing the <code>{@link CKEDITOR.editor#readOnly}</code> event.<br><br>\r
746                  * <strong>Note:</strong> the current editing area will be reloaded.\r
747                  * @param {Boolean} [isReadOnly] Indicates that the editor must go\r
748                  *              read-only (<code>true</code>, default) or be restored and made editable\r
749                  *              (<code>false</code>).\r
750                  * @since 3.6\r
751                  */\r
752                 setReadOnly : function( isReadOnly )\r
753                 {\r
754                         isReadOnly = ( isReadOnly == undefined ) || isReadOnly;\r
755 \r
756                         if ( this.readOnly != isReadOnly )\r
757                         {\r
758                                 this.readOnly = isReadOnly;\r
759 \r
760                                 // Fire the readOnly event so the editor features can update\r
761                                 // their state accordingly.\r
762                                 this.fire( 'readOnly' );\r
763                         }\r
764                 },\r
765 \r
766                 /**\r
767                  * Inserts HTML code into the currently selected position in the editor in WYSIWYG mode.\r
768                  * @param {String} data HTML code to be inserted into the editor.\r
769                  * @example\r
770                  * CKEDITOR.instances.editor1.<strong>insertHtml( '&lt;p&gt;This is a new paragraph.&lt;/p&gt;' )</strong>;\r
771                  */\r
772                 insertHtml : function( data )\r
773                 {\r
774                         this.fire( 'insertHtml', data );\r
775                 },\r
776 \r
777                 /**\r
778                  * Insert text content into the currently selected position in the\r
779                  * editor in WYSIWYG mode. The styles of the selected element will be applied to the inserted text.\r
780                  * Spaces around the text will be leaving untouched.\r
781                  * <strong>Note:</strong> two subsequent line-breaks will introduce one paragraph. This depends on <code>{@link CKEDITOR.config.enterMode}</code>;\r
782                  * A single line-break will be instead translated into one &lt;br /&gt;.\r
783                  * @since 3.5\r
784                  * @param {String} text Text to be inserted into the editor.\r
785                  * @example\r
786                  * CKEDITOR.instances.editor1.<strong>insertText( ' line1 \n\n line2' )</strong>;\r
787                  */\r
788                 insertText : function( text )\r
789                 {\r
790                         this.fire( 'insertText', text );\r
791                 },\r
792 \r
793                 /**\r
794                  * Inserts an element into the currently selected position in the\r
795                  * editor in WYSIWYG mode.\r
796                  * @param {CKEDITOR.dom.element} element The element to be inserted\r
797                  *              into the editor.\r
798                  * @example\r
799                  * var element = CKEDITOR.dom.element.createFromHtml( '&lt;img src="hello.png" border="0" title="Hello" /&gt;' );\r
800                  * CKEDITOR.instances.editor1.<strong>insertElement( element )</strong>;\r
801                  */\r
802                 insertElement : function( element )\r
803                 {\r
804                         this.fire( 'insertElement', element );\r
805                 },\r
806 \r
807                 /**\r
808                  * Checks whether the current editor contents contain changes when\r
809                  * compared to the contents loaded into the editor at startup, or to\r
810                  * the contents available in the editor when <code>{@link #resetDirty}</code>\r
811                  * was called.\r
812                  * @returns {Boolean} "true" is the contents contain changes.\r
813                  * @example\r
814                  * function beforeUnload( e )\r
815                  * {\r
816                  *     if ( CKEDITOR.instances.editor1.<strong>checkDirty()</strong> )\r
817                  *              return e.returnValue = "You will lose the changes made in the editor.";\r
818                  * }\r
819                  *\r
820                  * if ( window.addEventListener )\r
821                  *     window.addEventListener( 'beforeunload', beforeUnload, false );\r
822                  * else\r
823                  *     window.attachEvent( 'onbeforeunload', beforeUnload );\r
824                  */\r
825                 checkDirty : function()\r
826                 {\r
827                         return ( this.mayBeDirty && this._.previousValue !== this.getSnapshot() );\r
828                 },\r
829 \r
830                 /**\r
831                  * Resets the "dirty state" of the editor so subsequent calls to\r
832                  * <code>{@link #checkDirty}</code> will return <code>false</code> if the user will not\r
833                  * have made further changes to the contents.\r
834                  * @example\r
835                  * alert( editor.checkDirty() );  // E.g. "true"\r
836                  * editor.<strong>resetDirty()</strong>;\r
837                  * alert( editor.checkDirty() );  // "false"\r
838                  */\r
839                 resetDirty : function()\r
840                 {\r
841                         if ( this.mayBeDirty )\r
842                                 this._.previousValue = this.getSnapshot();\r
843                 },\r
844 \r
845                 /**\r
846                  * Updates the <code>&lt;textarea&gt;</code> element that was replaced by the editor with\r
847                  * the current data available in the editor.\r
848                  * @see CKEDITOR.editor.element\r
849                  * @example\r
850                  * CKEDITOR.instances.editor1.updateElement();\r
851                  * alert( document.getElementById( 'editor1' ).value );  // The current editor data.\r
852                  */\r
853                 updateElement : function()\r
854                 {\r
855                         var element = this.element;\r
856                         if ( element && this.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE )\r
857                         {\r
858                                 var data = this.getData();\r
859 \r
860                                 if ( this.config.htmlEncodeOutput )\r
861                                         data = CKEDITOR.tools.htmlEncode( data );\r
862 \r
863                                 if ( element.is( 'textarea' ) )\r
864                                         element.setValue( data );\r
865                                 else\r
866                                         element.setHtml( data );\r
867                         }\r
868                 }\r
869         });\r
870 \r
871 CKEDITOR.on( 'loaded', function()\r
872         {\r
873                 // Run the full initialization for pending editors.\r
874                 var pending = CKEDITOR.editor._pending;\r
875                 if ( pending )\r
876                 {\r
877                         delete CKEDITOR.editor._pending;\r
878 \r
879                         for ( var i = 0 ; i < pending.length ; i++ )\r
880                                 pending[ i ]._init();\r
881                 }\r
882         });\r
883 \r
884 /**\r
885  * Whether to escape HTML when the editor updates the original input element.\r
886  * @name CKEDITOR.config.htmlEncodeOutput\r
887  * @since 3.1\r
888  * @type Boolean\r
889  * @default false\r
890  * @example\r
891  * config.htmlEncodeOutput = true;\r
892  */\r
893 \r
894 /**\r
895  * If <code>true</code>, makes the editor start in read-only state. Otherwise, it will check\r
896  * if the linked <code>&lt;textarea&gt;</code> element has the <code>disabled</code> attribute.\r
897  * @name CKEDITOR.config.readOnly\r
898  * @see CKEDITOR.editor#setReadOnly\r
899  * @type Boolean\r
900  * @default false\r
901  * @since 3.6\r
902  * @example\r
903  * config.readOnly = true;\r
904  */\r
905 \r
906 /**\r
907  * Fired when a CKEDITOR instance is created, but still before initializing it.\r
908  * To interact with a fully initialized instance, use the\r
909  * <code>{@link CKEDITOR#instanceReady}</code> event instead.\r
910  * @name CKEDITOR#instanceCreated\r
911  * @event\r
912  * @param {CKEDITOR.editor} editor The editor instance that has been created.\r
913  */\r
914 \r
915 /**\r
916  * Fired when a CKEDITOR instance is destroyed.\r
917  * @name CKEDITOR#instanceDestroyed\r
918  * @event\r
919  * @param {CKEDITOR.editor} editor The editor instance that has been destroyed.\r
920  */\r
921 \r
922 /**\r
923  * Fired when the language is loaded into the editor instance.\r
924  * @name CKEDITOR.editor#langLoaded\r
925  * @event\r
926  * @since 3.6.1\r
927  * @param {CKEDITOR.editor} editor This editor instance.\r
928  */\r
929 \r
930 /**\r
931  * Fired when all plugins are loaded and initialized into the editor instance.\r
932  * @name CKEDITOR.editor#pluginsLoaded\r
933  * @event\r
934  * @param {CKEDITOR.editor} editor This editor instance.\r
935  */\r
936 \r
937 /**\r
938  * Fired before the command execution when <code>{@link #execCommand}</code> is called.\r
939  * @name CKEDITOR.editor#beforeCommandExec\r
940  * @event\r
941  * @param {CKEDITOR.editor} editor This editor instance.\r
942  * @param {String} data.name The command name.\r
943  * @param {Object} data.commandData The data to be sent to the command. This\r
944  *              can be manipulated by the event listener.\r
945  * @param {CKEDITOR.command} data.command The command itself.\r
946  */\r
947 \r
948 /**\r
949  * Fired after the command execution when <code>{@link #execCommand}</code> is called.\r
950  * @name CKEDITOR.editor#afterCommandExec\r
951  * @event\r
952  * @param {CKEDITOR.editor} editor This editor instance.\r
953  * @param {String} data.name The command name.\r
954  * @param {Object} data.commandData The data sent to the command.\r
955  * @param {CKEDITOR.command} data.command The command itself.\r
956  * @param {Object} data.returnValue The value returned by the command execution.\r
957  */\r
958 \r
959 /**\r
960  * Fired when the custom configuration file is loaded, before the final\r
961  * configurations initialization.<br />\r
962  * <br />\r
963  * Custom configuration files can be loaded thorugh the\r
964  * <code>{@link CKEDITOR.config.customConfig}</code> setting. Several files can be loaded\r
965  * by changing this setting.\r
966  * @name CKEDITOR.editor#customConfigLoaded\r
967  * @event\r
968  * @param {CKEDITOR.editor} editor This editor instance.\r
969  */\r
970 \r
971 /**\r
972  * Fired once the editor configuration is ready (loaded and processed).\r
973  * @name CKEDITOR.editor#configLoaded\r
974  * @event\r
975  * @param {CKEDITOR.editor} editor This editor instance.\r
976  */\r
977 \r
978 /**\r
979  * Fired when this editor instance is destroyed. The editor at this\r
980  * point is not usable and this event should be used to perform the clean-up\r
981  * in any plugin.\r
982  * @name CKEDITOR.editor#destroy\r
983  * @event\r
984  */\r
985 \r
986 /**\r
987  * Internal event to get the current data.\r
988  * @name CKEDITOR.editor#beforeGetData\r
989  * @event\r
990  */\r
991 \r
992 /**\r
993  * Internal event to perform the <code>#getSnapshot</code> call.\r
994  * @name CKEDITOR.editor#getSnapshot\r
995  * @event\r
996  */\r
997 \r
998 /**\r
999  * Internal event to perform the <code>#loadSnapshot</code> call.\r
1000  * @name CKEDITOR.editor#loadSnapshot\r
1001  * @event\r
1002  */\r
1003 \r
1004 /**\r
1005  * Event fired before the <code>#getData</code> call returns allowing additional manipulation.\r
1006  * @name CKEDITOR.editor#getData\r
1007  * @event\r
1008  * @param {CKEDITOR.editor} editor This editor instance.\r
1009  * @param {String} data.dataValue The data that will be returned.\r
1010  */\r
1011 \r
1012 /**\r
1013  * Event fired before the <code>#setData</code> call is executed allowing additional manipulation.\r
1014  * @name CKEDITOR.editor#setData\r
1015  * @event\r
1016  * @param {CKEDITOR.editor} editor This editor instance.\r
1017  * @param {String} data.dataValue The data that will be used.\r
1018  */\r
1019 \r
1020 /**\r
1021  * Event fired at the end of the <code>#setData</code> call execution. Usually it is better to use the\r
1022  * <code>{@link CKEDITOR.editor.prototype.dataReady}</code> event.\r
1023  * @name CKEDITOR.editor#afterSetData\r
1024  * @event\r
1025  * @param {CKEDITOR.editor} editor This editor instance.\r
1026  * @param {String} data.dataValue The data that has been set.\r
1027  */\r
1028 \r
1029 /**\r
1030  * Internal event to perform the <code>#insertHtml</code> call\r
1031  * @name CKEDITOR.editor#insertHtml\r
1032  * @event\r
1033  * @param {CKEDITOR.editor} editor This editor instance.\r
1034  * @param {String} data The HTML to insert.\r
1035  */\r
1036 \r
1037 /**\r
1038  * Internal event to perform the <code>#insertText</code> call\r
1039  * @name CKEDITOR.editor#insertText\r
1040  * @event\r
1041  * @param {CKEDITOR.editor} editor This editor instance.\r
1042  * @param {String} text The text to insert.\r
1043  */\r
1044 \r
1045 /**\r
1046  * Internal event to perform the <code>#insertElement</code> call\r
1047  * @name CKEDITOR.editor#insertElement\r
1048  * @event\r
1049  * @param {CKEDITOR.editor} editor This editor instance.\r
1050  * @param {Object} element The element to insert.\r
1051  */\r
1052 \r
1053 /**\r
1054  * Event fired after the <code>{@link CKEDITOR.editor#readOnly}</code> property changes.\r
1055  * @name CKEDITOR.editor#readOnly\r
1056  * @event\r
1057  * @since 3.6\r
1058  * @param {CKEDITOR.editor} editor This editor instance.\r
1059  */\r