]>
Commit | Line | Data |
---|---|---|
1 | /** | |
2 | * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved. | |
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | |
4 | */ | |
5 | ||
6 | /** | |
7 | * @fileOverview Defines the {@link CKEDITOR.editor} class that represents an | |
8 | * editor instance. | |
9 | */ | |
10 | ||
11 | ( function() { | |
12 | // Override the basic constructor defined at editor_basic.js. | |
13 | Editor.prototype = CKEDITOR.editor.prototype; | |
14 | CKEDITOR.editor = Editor; | |
15 | ||
16 | /** | |
17 | * Represents an editor instance. This constructor should be rarely | |
18 | * used in favor of the {@link CKEDITOR} editor creation functions. | |
19 | * | |
20 | * @class CKEDITOR.editor | |
21 | * @mixins CKEDITOR.event | |
22 | * @constructor Creates an editor class instance. | |
23 | * @param {Object} [instanceConfig] Configuration values for this specific instance. | |
24 | * @param {CKEDITOR.dom.element} [element] The DOM element upon which this editor | |
25 | * will be created. | |
26 | * @param {Number} [mode] The element creation mode to be used by this editor. | |
27 | */ | |
28 | function Editor( instanceConfig, element, mode ) { | |
29 | // Call the CKEDITOR.event constructor to initialize this instance. | |
30 | CKEDITOR.event.call( this ); | |
31 | ||
32 | // Make a clone of the config object, to avoid having it touched by our code. (#9636) | |
33 | instanceConfig = instanceConfig && CKEDITOR.tools.clone( instanceConfig ); | |
34 | ||
35 | // if editor is created off one page element. | |
36 | if ( element !== undefined ) { | |
37 | // Asserting element and mode not null. | |
38 | if ( !( element instanceof CKEDITOR.dom.element ) ) | |
39 | throw new Error( 'Expect element of type CKEDITOR.dom.element.' ); | |
40 | else if ( !mode ) | |
41 | throw new Error( 'One of the element modes must be specified.' ); | |
42 | ||
43 | if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && mode == CKEDITOR.ELEMENT_MODE_INLINE ) | |
44 | throw new Error( 'Inline element mode is not supported on IE quirks.' ); | |
45 | ||
46 | if ( !isSupportedElement( element, mode ) ) | |
47 | throw new Error( 'The specified element mode is not supported on element: "' + element.getName() + '".' ); | |
48 | ||
49 | /** | |
50 | * The original host page element upon which the editor is created. It is only | |
51 | * supposed to be provided by the particular editor creator and is not subject to | |
52 | * be modified. | |
53 | * | |
54 | * @readonly | |
55 | * @property {CKEDITOR.dom.element} | |
56 | */ | |
57 | this.element = element; | |
58 | ||
59 | /** | |
60 | * This property indicates the way this instance is associated with the {@link #element}. | |
61 | * See also {@link CKEDITOR#ELEMENT_MODE_INLINE} and {@link CKEDITOR#ELEMENT_MODE_REPLACE}. | |
62 | * | |
63 | * @readonly | |
64 | * @property {Number} | |
65 | */ | |
66 | this.elementMode = mode; | |
67 | ||
68 | this.name = ( this.elementMode != CKEDITOR.ELEMENT_MODE_APPENDTO ) && ( element.getId() || element.getNameAtt() ); | |
69 | } else { | |
70 | this.elementMode = CKEDITOR.ELEMENT_MODE_NONE; | |
71 | } | |
72 | ||
73 | // Declare the private namespace. | |
74 | this._ = {}; | |
75 | ||
76 | this.commands = {}; | |
77 | ||
78 | /** | |
79 | * Contains all UI templates created for this editor instance. | |
80 | * | |
81 | * @readonly | |
82 | * @property {Object} | |
83 | */ | |
84 | this.templates = {}; | |
85 | ||
86 | /** | |
87 | * A unique identifier of this editor instance. | |
88 | * | |
89 | * **Note:** It will be originated from the `id` or `name` | |
90 | * attribute of the {@link #element}, otherwise a name pattern of | |
91 | * `'editor{n}'` will be used. | |
92 | * | |
93 | * @readonly | |
94 | * @property {String} | |
95 | */ | |
96 | this.name = this.name || genEditorName(); | |
97 | ||
98 | /** | |
99 | * A unique random string assigned to each editor instance on the page. | |
100 | * | |
101 | * @readonly | |
102 | * @property {String} | |
103 | */ | |
104 | this.id = CKEDITOR.tools.getNextId(); | |
105 | ||
106 | /** | |
107 | * Indicates editor initialization status. The following statuses are available: | |
108 | * | |
109 | * * **unloaded**: The initial state — the editor instance was initialized, | |
110 | * but its components (configuration, plugins, language files) are not loaded yet. | |
111 | * * **loaded**: The editor components were loaded — see the {@link CKEDITOR.editor#loaded} event. | |
112 | * * **ready**: The editor is fully initialized and ready — see the {@link CKEDITOR.editor#instanceReady} event. | |
113 | * * **destroyed**: The editor was destroyed — see the {@link CKEDITOR.editor#method-destroy} method. | |
114 | * | |
115 | * @since 4.1 | |
116 | * @readonly | |
117 | * @property {String} | |
118 | */ | |
119 | this.status = 'unloaded'; | |
120 | ||
121 | /** | |
122 | * The configuration for this editor instance. It inherits all | |
123 | * settings defined in {@link CKEDITOR.config}, combined with settings | |
124 | * loaded from custom configuration files and those defined inline in | |
125 | * the page when creating the editor. | |
126 | * | |
127 | * var editor = CKEDITOR.instances.editor1; | |
128 | * alert( editor.config.skin ); // e.g. 'moono' | |
129 | * | |
130 | * @readonly | |
131 | * @property {CKEDITOR.config} | |
132 | */ | |
133 | this.config = CKEDITOR.tools.prototypedCopy( CKEDITOR.config ); | |
134 | ||
135 | /** | |
136 | * The namespace containing UI features related to this editor instance. | |
137 | * | |
138 | * @readonly | |
139 | * @property {CKEDITOR.ui} | |
140 | */ | |
141 | this.ui = new CKEDITOR.ui( this ); | |
142 | ||
143 | /** | |
144 | * Controls the focus state of this editor instance. This property | |
145 | * is rarely used for normal API operations. It is mainly | |
146 | * targeted at developers adding UI elements to the editor interface. | |
147 | * | |
148 | * @readonly | |
149 | * @property {CKEDITOR.focusManager} | |
150 | */ | |
151 | this.focusManager = new CKEDITOR.focusManager( this ); | |
152 | ||
153 | /** | |
154 | * Controls keystroke typing in this editor instance. | |
155 | * | |
156 | * @readonly | |
157 | * @property {CKEDITOR.keystrokeHandler} | |
158 | */ | |
159 | this.keystrokeHandler = new CKEDITOR.keystrokeHandler( this ); | |
160 | ||
161 | // Make the editor update its command states on mode change. | |
162 | this.on( 'readOnly', updateCommands ); | |
163 | this.on( 'selectionChange', function( evt ) { | |
164 | updateCommandsContext( this, evt.data.path ); | |
165 | } ); | |
166 | this.on( 'activeFilterChange', function() { | |
167 | updateCommandsContext( this, this.elementPath(), true ); | |
168 | } ); | |
169 | this.on( 'mode', updateCommands ); | |
170 | ||
171 | // Handle startup focus. | |
172 | this.on( 'instanceReady', function() { | |
173 | this.config.startupFocus && this.focus(); | |
174 | } ); | |
175 | ||
176 | CKEDITOR.fire( 'instanceCreated', null, this ); | |
177 | ||
178 | // Add this new editor to the CKEDITOR.instances collections. | |
179 | CKEDITOR.add( this ); | |
180 | ||
181 | // Return the editor instance immediately to enable early stage event registrations. | |
182 | CKEDITOR.tools.setTimeout( function() { | |
183 | if ( this.status !== 'destroyed' ) { | |
184 | initConfig( this, instanceConfig ); | |
185 | } else { | |
186 | CKEDITOR.warn( 'editor-incorrect-destroy' ); | |
187 | } | |
188 | }, 0, this ); | |
189 | } | |
190 | ||
191 | var nameCounter = 0; | |
192 | ||
193 | function genEditorName() { | |
194 | do { | |
195 | var name = 'editor' + ( ++nameCounter ); | |
196 | } | |
197 | while ( CKEDITOR.instances[ name ] ); | |
198 | ||
199 | return name; | |
200 | } | |
201 | ||
202 | // Asserting element DTD depending on mode. | |
203 | function isSupportedElement( element, mode ) { | |
204 | if ( mode == CKEDITOR.ELEMENT_MODE_INLINE ) | |
205 | return element.is( CKEDITOR.dtd.$editable ) || element.is( 'textarea' ); | |
206 | else if ( mode == CKEDITOR.ELEMENT_MODE_REPLACE ) | |
207 | return !element.is( CKEDITOR.dtd.$nonBodyContent ); | |
208 | return 1; | |
209 | } | |
210 | ||
211 | function updateCommands() { | |
212 | var commands = this.commands, | |
213 | name; | |
214 | ||
215 | for ( name in commands ) | |
216 | updateCommand( this, commands[ name ] ); | |
217 | } | |
218 | ||
219 | function updateCommand( editor, cmd ) { | |
220 | cmd[ cmd.startDisabled ? 'disable' : editor.readOnly && !cmd.readOnly ? 'disable' : cmd.modes[ editor.mode ] ? 'enable' : 'disable' ](); | |
221 | } | |
222 | ||
223 | function updateCommandsContext( editor, path, forceRefresh ) { | |
224 | // Commands cannot be refreshed without a path. In edge cases | |
225 | // it may happen that there's no selection when this function is executed. | |
226 | // For example when active filter is changed in #10877. | |
227 | if ( !path ) | |
228 | return; | |
229 | ||
230 | var command, | |
231 | name, | |
232 | commands = editor.commands; | |
233 | ||
234 | for ( name in commands ) { | |
235 | command = commands[ name ]; | |
236 | ||
237 | if ( forceRefresh || command.contextSensitive ) | |
238 | command.refresh( editor, path ); | |
239 | } | |
240 | } | |
241 | ||
242 | // ##### START: Config Privates | |
243 | ||
244 | // These function loads custom configuration files and cache the | |
245 | // CKEDITOR.editorConfig functions defined on them, so there is no need to | |
246 | // download them more than once for several instances. | |
247 | var loadConfigLoaded = {}; | |
248 | ||
249 | function loadConfig( editor ) { | |
250 | var customConfig = editor.config.customConfig; | |
251 | ||
252 | // Check if there is a custom config to load. | |
253 | if ( !customConfig ) | |
254 | return false; | |
255 | ||
256 | customConfig = CKEDITOR.getUrl( customConfig ); | |
257 | ||
258 | var loadedConfig = loadConfigLoaded[ customConfig ] || ( loadConfigLoaded[ customConfig ] = {} ); | |
259 | ||
260 | // If the custom config has already been downloaded, reuse it. | |
261 | if ( loadedConfig.fn ) { | |
262 | // Call the cached CKEDITOR.editorConfig defined in the custom | |
263 | // config file for the editor instance depending on it. | |
264 | loadedConfig.fn.call( editor, editor.config ); | |
265 | ||
266 | // If there is no other customConfig in the chain, fire the | |
267 | // "configLoaded" event. | |
268 | if ( CKEDITOR.getUrl( editor.config.customConfig ) == customConfig || !loadConfig( editor ) ) | |
269 | editor.fireOnce( 'customConfigLoaded' ); | |
270 | } else { | |
271 | // Load the custom configuration file. | |
272 | // To resolve customConfig race conflicts, use scriptLoader#queue | |
273 | // instead of scriptLoader#load (#6504). | |
274 | CKEDITOR.scriptLoader.queue( customConfig, function() { | |
275 | // If the CKEDITOR.editorConfig function has been properly | |
276 | // defined in the custom configuration file, cache it. | |
277 | if ( CKEDITOR.editorConfig ) | |
278 | loadedConfig.fn = CKEDITOR.editorConfig; | |
279 | else | |
280 | loadedConfig.fn = function() {}; | |
281 | ||
282 | // Call the load config again. This time the custom | |
283 | // config is already cached and so it will get loaded. | |
284 | loadConfig( editor ); | |
285 | } ); | |
286 | } | |
287 | ||
288 | return true; | |
289 | } | |
290 | ||
291 | function initConfig( editor, instanceConfig ) { | |
292 | // Setup the lister for the "customConfigLoaded" event. | |
293 | editor.on( 'customConfigLoaded', function() { | |
294 | if ( instanceConfig ) { | |
295 | // Register the events that may have been set at the instance | |
296 | // configuration object. | |
297 | if ( instanceConfig.on ) { | |
298 | for ( var eventName in instanceConfig.on ) { | |
299 | editor.on( eventName, instanceConfig.on[ eventName ] ); | |
300 | } | |
301 | } | |
302 | ||
303 | // Overwrite the settings from the in-page config. | |
304 | CKEDITOR.tools.extend( editor.config, instanceConfig, true ); | |
305 | ||
306 | delete editor.config.on; | |
307 | } | |
308 | ||
309 | onConfigLoaded( editor ); | |
310 | } ); | |
311 | ||
312 | // The instance config may override the customConfig setting to avoid | |
313 | // loading the default ~/config.js file. | |
314 | if ( instanceConfig && instanceConfig.customConfig != null ) | |
315 | editor.config.customConfig = instanceConfig.customConfig; | |
316 | ||
317 | // Load configs from the custom configuration files. | |
318 | if ( !loadConfig( editor ) ) | |
319 | editor.fireOnce( 'customConfigLoaded' ); | |
320 | } | |
321 | ||
322 | // ##### END: Config Privates | |
323 | ||
324 | // Set config related properties. | |
325 | function onConfigLoaded( editor ) { | |
326 | var config = editor.config; | |
327 | ||
328 | /** | |
329 | * Indicates the read-only state of this editor. This is a read-only property. | |
330 | * See also {@link CKEDITOR.editor#setReadOnly}. | |
331 | * | |
332 | * @since 3.6 | |
333 | * @readonly | |
334 | * @property {Boolean} | |
335 | */ | |
336 | editor.readOnly = isEditorReadOnly(); | |
337 | ||
338 | function isEditorReadOnly() { | |
339 | if ( config.readOnly ) { | |
340 | return true; | |
341 | } | |
342 | ||
343 | if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ) { | |
344 | if ( editor.element.is( 'textarea' ) ) { | |
345 | return editor.element.hasAttribute( 'disabled' ) || editor.element.hasAttribute( 'readonly' ); | |
346 | } else { | |
347 | return editor.element.isReadOnly(); | |
348 | } | |
349 | } else if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) { | |
350 | return editor.element.hasAttribute( 'disabled' ) || editor.element.hasAttribute( 'readonly' ); | |
351 | } | |
352 | ||
353 | return false; | |
354 | } | |
355 | ||
356 | /** | |
357 | * Indicates that the editor is running in an environment where | |
358 | * no block elements are accepted inside the content. | |
359 | * | |
360 | * This can be for example inline editor based on an `<h1>` element. | |
361 | * | |
362 | * @readonly | |
363 | * @property {Boolean} | |
364 | */ | |
365 | editor.blockless = editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ? | |
366 | !( editor.element.is( 'textarea' ) || CKEDITOR.dtd[ editor.element.getName() ].p ) : | |
367 | false; | |
368 | ||
369 | /** | |
370 | * The [tabbing navigation](http://en.wikipedia.org/wiki/Tabbing_navigation) order determined for this editor instance. | |
371 | * This can be set by the <code>{@link CKEDITOR.config#tabIndex}</code> | |
372 | * setting or taken from the `tabindex` attribute of the | |
373 | * {@link #element} associated with the editor. | |
374 | * | |
375 | * alert( editor.tabIndex ); // e.g. 0 | |
376 | * | |
377 | * @readonly | |
378 | * @property {Number} [=0] | |
379 | */ | |
380 | editor.tabIndex = config.tabIndex || editor.element && editor.element.getAttribute( 'tabindex' ) || 0; | |
381 | ||
382 | editor.activeEnterMode = editor.enterMode = validateEnterMode( editor, config.enterMode ); | |
383 | editor.activeShiftEnterMode = editor.shiftEnterMode = validateEnterMode( editor, config.shiftEnterMode ); | |
384 | ||
385 | // Set CKEDITOR.skinName. Note that it is not possible to have | |
386 | // different skins on the same page, so the last one to set it "wins". | |
387 | if ( config.skin ) | |
388 | CKEDITOR.skinName = config.skin; | |
389 | ||
390 | // Fire the "configLoaded" event. | |
391 | editor.fireOnce( 'configLoaded' ); | |
392 | ||
393 | initComponents( editor ); | |
394 | } | |
395 | ||
396 | // Various other core components that read editor configuration. | |
397 | function initComponents( editor ) { | |
398 | // Documented in dataprocessor.js. | |
399 | editor.dataProcessor = new CKEDITOR.htmlDataProcessor( editor ); | |
400 | ||
401 | // Set activeFilter directly to avoid firing event. | |
402 | editor.filter = editor.activeFilter = new CKEDITOR.filter( editor ); | |
403 | ||
404 | loadSkin( editor ); | |
405 | } | |
406 | ||
407 | function loadSkin( editor ) { | |
408 | CKEDITOR.skin.loadPart( 'editor', function() { | |
409 | loadLang( editor ); | |
410 | } ); | |
411 | } | |
412 | ||
413 | function loadLang( editor ) { | |
414 | CKEDITOR.lang.load( editor.config.language, editor.config.defaultLanguage, function( languageCode, lang ) { | |
415 | var configTitle = editor.config.title; | |
416 | ||
417 | /** | |
418 | * The code for the language resources that have been loaded | |
419 | * for the user interface elements of this editor instance. | |
420 | * | |
421 | * alert( editor.langCode ); // e.g. 'en' | |
422 | * | |
423 | * @readonly | |
424 | * @property {String} | |
425 | */ | |
426 | editor.langCode = languageCode; | |
427 | ||
428 | /** | |
429 | * An object that contains all language strings used by the editor interface. | |
430 | * | |
431 | * alert( editor.lang.basicstyles.bold ); // e.g. 'Negrito' (if the language is set to Portuguese) | |
432 | * | |
433 | * @readonly | |
434 | * @property {Object} lang | |
435 | */ | |
436 | // As we'll be adding plugin specific entries that could come | |
437 | // from different language code files, we need a copy of lang, | |
438 | // not a direct reference to it. | |
439 | editor.lang = CKEDITOR.tools.prototypedCopy( lang ); | |
440 | ||
441 | /** | |
442 | * Indicates the human-readable title of this editor. Although this is a read-only property, | |
443 | * it can be initialized with {@link CKEDITOR.config#title}. | |
444 | * | |
445 | * **Note:** Please do not confuse this property with {@link CKEDITOR.editor#name editor.name} | |
446 | * which identifies the instance in the {@link CKEDITOR#instances} literal. | |
447 | * | |
448 | * @since 4.2 | |
449 | * @readonly | |
450 | * @property {String/Boolean} | |
451 | */ | |
452 | editor.title = typeof configTitle == 'string' || configTitle === false ? configTitle : [ editor.lang.editor, editor.name ].join( ', ' ); | |
453 | ||
454 | if ( !editor.config.contentsLangDirection ) { | |
455 | // Fallback to either the editable element direction or editor UI direction depending on creators. | |
456 | editor.config.contentsLangDirection = editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ? editor.element.getDirection( 1 ) : editor.lang.dir; | |
457 | } | |
458 | ||
459 | editor.fire( 'langLoaded' ); | |
460 | ||
461 | preloadStylesSet( editor ); | |
462 | } ); | |
463 | } | |
464 | ||
465 | // Preloads styles set file (config.stylesSet). | |
466 | // If stylesSet was defined directly (by an array) | |
467 | // this function will call loadPlugins fully synchronously. | |
468 | // If stylesSet is a string (path) loadPlugins will | |
469 | // be called asynchronously. | |
470 | // In both cases - styles will be preload before plugins initialization. | |
471 | function preloadStylesSet( editor ) { | |
472 | editor.getStylesSet( function( styles ) { | |
473 | // Wait for editor#loaded, so plugins could add their listeners. | |
474 | // But listen with high priority to fire editor#stylesSet before editor#uiReady and editor#setData. | |
475 | editor.once( 'loaded', function() { | |
476 | // Note: we can't use fireOnce because this event may canceled and fired again. | |
477 | editor.fire( 'stylesSet', { styles: styles } ); | |
478 | }, null, null, 1 ); | |
479 | ||
480 | loadPlugins( editor ); | |
481 | } ); | |
482 | } | |
483 | ||
484 | function loadPlugins( editor ) { | |
485 | var config = editor.config, | |
486 | plugins = config.plugins, | |
487 | extraPlugins = config.extraPlugins, | |
488 | removePlugins = config.removePlugins; | |
489 | ||
490 | if ( extraPlugins ) { | |
491 | // Remove them first to avoid duplications. | |
492 | var extraRegex = new RegExp( '(?:^|,)(?:' + extraPlugins.replace( /\s*,\s*/g, '|' ) + ')(?=,|$)', 'g' ); | |
493 | plugins = plugins.replace( extraRegex, '' ); | |
494 | ||
495 | plugins += ',' + extraPlugins; | |
496 | } | |
497 | ||
498 | if ( removePlugins ) { | |
499 | var removeRegex = new RegExp( '(?:^|,)(?:' + removePlugins.replace( /\s*,\s*/g, '|' ) + ')(?=,|$)', 'g' ); | |
500 | plugins = plugins.replace( removeRegex, '' ); | |
501 | } | |
502 | ||
503 | // Load the Adobe AIR plugin conditionally. | |
504 | CKEDITOR.env.air && ( plugins += ',adobeair' ); | |
505 | ||
506 | // Load all plugins defined in the "plugins" setting. | |
507 | CKEDITOR.plugins.load( plugins.split( ',' ), function( plugins ) { | |
508 | // The list of plugins. | |
509 | var pluginsArray = []; | |
510 | ||
511 | // The language code to get loaded for each plugin. Null | |
512 | // entries will be appended for plugins with no language files. | |
513 | var languageCodes = []; | |
514 | ||
515 | // The list of URLs to language files. | |
516 | var languageFiles = []; | |
517 | ||
518 | /** | |
519 | * An object that contains references to all plugins used by this | |
520 | * editor instance. | |
521 | * | |
522 | * alert( editor.plugins.dialog.path ); // e.g. 'http://example.com/ckeditor/plugins/dialog/' | |
523 | * | |
524 | * // Check if a plugin is available. | |
525 | * if ( editor.plugins.image ) { | |
526 | * ... | |
527 | * } | |
528 | * | |
529 | * @readonly | |
530 | * @property {Object} | |
531 | */ | |
532 | editor.plugins = plugins; | |
533 | ||
534 | // Loop through all plugins, to build the list of language | |
535 | // files to get loaded. | |
536 | // | |
537 | // Check also whether any of loaded plugins doesn't require plugins | |
538 | // defined in config.removePlugins. Throw non-blocking error if this happens. | |
539 | for ( var pluginName in plugins ) { | |
540 | var plugin = plugins[ pluginName ], | |
541 | pluginLangs = plugin.lang, | |
542 | lang = null, | |
543 | requires = plugin.requires, | |
544 | match, name; | |
545 | ||
546 | // Transform it into a string, if it's not one. | |
547 | if ( CKEDITOR.tools.isArray( requires ) ) | |
548 | requires = requires.join( ',' ); | |
549 | ||
550 | if ( requires && ( match = requires.match( removeRegex ) ) ) { | |
551 | while ( ( name = match.pop() ) ) { | |
552 | CKEDITOR.error( 'editor-plugin-required', { plugin: name.replace( ',', '' ), requiredBy: pluginName } ); | |
553 | } | |
554 | } | |
555 | ||
556 | // If the plugin has "lang". | |
557 | if ( pluginLangs && !editor.lang[ pluginName ] ) { | |
558 | // Trasnform the plugin langs into an array, if it's not one. | |
559 | if ( pluginLangs.split ) | |
560 | pluginLangs = pluginLangs.split( ',' ); | |
561 | ||
562 | // Resolve the plugin language. If the current language | |
563 | // is not available, get English or the first one. | |
564 | if ( CKEDITOR.tools.indexOf( pluginLangs, editor.langCode ) >= 0 ) | |
565 | lang = editor.langCode; | |
566 | else { | |
567 | // The language code may have the locale information (zh-cn). | |
568 | // Fall back to locale-less in that case (zh). | |
569 | var langPart = editor.langCode.replace( /-.*/, '' ); | |
570 | if ( langPart != editor.langCode && CKEDITOR.tools.indexOf( pluginLangs, langPart ) >= 0 ) | |
571 | lang = langPart; | |
572 | // Try the only "generic" option we have: English. | |
573 | else if ( CKEDITOR.tools.indexOf( pluginLangs, 'en' ) >= 0 ) | |
574 | lang = 'en'; | |
575 | else | |
576 | lang = pluginLangs[ 0 ]; | |
577 | } | |
578 | ||
579 | if ( !plugin.langEntries || !plugin.langEntries[ lang ] ) { | |
580 | // Put the language file URL into the list of files to | |
581 | // get downloaded. | |
582 | languageFiles.push( CKEDITOR.getUrl( plugin.path + 'lang/' + lang + '.js' ) ); | |
583 | } else { | |
584 | editor.lang[ pluginName ] = plugin.langEntries[ lang ]; | |
585 | lang = null; | |
586 | } | |
587 | } | |
588 | ||
589 | // Save the language code, so we know later which | |
590 | // language has been resolved to this plugin. | |
591 | languageCodes.push( lang ); | |
592 | ||
593 | pluginsArray.push( plugin ); | |
594 | } | |
595 | ||
596 | // Load all plugin specific language files in a row. | |
597 | CKEDITOR.scriptLoader.load( languageFiles, function() { | |
598 | // Initialize all plugins that have the "beforeInit" and "init" methods defined. | |
599 | var methods = [ 'beforeInit', 'init', 'afterInit' ]; | |
600 | for ( var m = 0; m < methods.length; m++ ) { | |
601 | for ( var i = 0; i < pluginsArray.length; i++ ) { | |
602 | var plugin = pluginsArray[ i ]; | |
603 | ||
604 | // Uses the first loop to update the language entries also. | |
605 | if ( m === 0 && languageCodes[ i ] && plugin.lang && plugin.langEntries ) | |
606 | editor.lang[ plugin.name ] = plugin.langEntries[ languageCodes[ i ] ]; | |
607 | ||
608 | // Call the plugin method (beforeInit and init). | |
609 | if ( plugin[ methods[ m ] ] ) | |
610 | plugin[ methods[ m ] ]( editor ); | |
611 | } | |
612 | } | |
613 | ||
614 | editor.fireOnce( 'pluginsLoaded' ); | |
615 | ||
616 | // Setup the configured keystrokes. | |
617 | config.keystrokes && editor.setKeystroke( editor.config.keystrokes ); | |
618 | ||
619 | // Setup the configured blocked keystrokes. | |
620 | for ( i = 0; i < editor.config.blockedKeystrokes.length; i++ ) | |
621 | editor.keystrokeHandler.blockedKeystrokes[ editor.config.blockedKeystrokes[ i ] ] = 1; | |
622 | ||
623 | editor.status = 'loaded'; | |
624 | editor.fireOnce( 'loaded' ); | |
625 | CKEDITOR.fire( 'instanceLoaded', null, editor ); | |
626 | } ); | |
627 | } ); | |
628 | } | |
629 | ||
630 | // Send to data output back to editor's associated element. | |
631 | function updateEditorElement() { | |
632 | var element = this.element; | |
633 | ||
634 | // Some editor creation mode will not have the | |
635 | // associated element. | |
636 | if ( element && this.elementMode != CKEDITOR.ELEMENT_MODE_APPENDTO ) { | |
637 | var data = this.getData(); | |
638 | ||
639 | if ( this.config.htmlEncodeOutput ) | |
640 | data = CKEDITOR.tools.htmlEncode( data ); | |
641 | ||
642 | if ( element.is( 'textarea' ) ) | |
643 | element.setValue( data ); | |
644 | else | |
645 | element.setHtml( data ); | |
646 | ||
647 | return true; | |
648 | } | |
649 | return false; | |
650 | } | |
651 | ||
652 | // Always returns ENTER_BR in case of blockless editor. | |
653 | function validateEnterMode( editor, enterMode ) { | |
654 | return editor.blockless ? CKEDITOR.ENTER_BR : enterMode; | |
655 | } | |
656 | ||
657 | // Create DocumentFragment from specified ranges. For now it handles only tables in Firefox | |
658 | // and returns DocumentFragment from the 1. range for other cases. (#13884) | |
659 | function createDocumentFragmentFromRanges( ranges, editable ) { | |
660 | var docFragment = new CKEDITOR.dom.documentFragment(), | |
661 | tableClone, | |
662 | currentRow, | |
663 | currentRowClone; | |
664 | ||
665 | for ( var i = 0; i < ranges.length; i++ ) { | |
666 | var range = ranges[ i ], | |
667 | container = range.startContainer; | |
668 | ||
669 | if ( container.getName && container.getName() == 'tr' ) { | |
670 | if ( !tableClone ) { | |
671 | tableClone = container.getAscendant( 'table' ).clone(); | |
672 | tableClone.append( container.getAscendant( 'tbody' ).clone() ); | |
673 | docFragment.append( tableClone ); | |
674 | tableClone = tableClone.findOne( 'tbody' ); | |
675 | } | |
676 | ||
677 | if ( !( currentRow && currentRow.equals( container ) ) ) { | |
678 | currentRow = container; | |
679 | currentRowClone = container.clone(); | |
680 | tableClone.append( currentRowClone ); | |
681 | } | |
682 | ||
683 | currentRowClone.append( range.cloneContents() ); | |
684 | } else { | |
685 | // If there was something else copied with table, | |
686 | // append it to DocumentFragment. | |
687 | docFragment.append( range.cloneContents() ); | |
688 | } | |
689 | } | |
690 | ||
691 | if ( !tableClone ) { | |
692 | return editable.getHtmlFromRange( ranges[ 0 ] ); | |
693 | } | |
694 | ||
695 | return docFragment; | |
696 | } | |
697 | ||
698 | CKEDITOR.tools.extend( CKEDITOR.editor.prototype, { | |
699 | /** | |
700 | * Adds a command definition to the editor instance. Commands added with | |
701 | * this function can be executed later with the <code>{@link #execCommand}</code> method. | |
702 | * | |
703 | * editorInstance.addCommand( 'sample', { | |
704 | * exec: function( editor ) { | |
705 | * alert( 'Executing a command for the editor name "' + editor.name + '"!' ); | |
706 | * } | |
707 | * } ); | |
708 | * | |
709 | * @param {String} commandName The indentifier name of the command. | |
710 | * @param {CKEDITOR.commandDefinition} commandDefinition The command definition. | |
711 | */ | |
712 | addCommand: function( commandName, commandDefinition ) { | |
713 | commandDefinition.name = commandName.toLowerCase(); | |
714 | var cmd = new CKEDITOR.command( this, commandDefinition ); | |
715 | ||
716 | // Update command when mode is set. | |
717 | // This guarantees that commands added before first editor#mode | |
718 | // aren't immediately updated, but waits for editor#mode and that | |
719 | // commands added later are immediately refreshed, even when added | |
720 | // before instanceReady. #10103, #10249 | |
721 | if ( this.mode ) | |
722 | updateCommand( this, cmd ); | |
723 | ||
724 | return this.commands[ commandName ] = cmd; | |
725 | }, | |
726 | ||
727 | /** | |
728 | * Attaches the editor to a form to call {@link #updateElement} before form submission. | |
729 | * This method is called by both creators ({@link CKEDITOR#replace replace} and | |
730 | * {@link CKEDITOR#inline inline}), so there is no reason to call it manually. | |
731 | * | |
732 | * @private | |
733 | */ | |
734 | _attachToForm: function() { | |
735 | var editor = this, | |
736 | element = editor.element, | |
737 | form = new CKEDITOR.dom.element( element.$.form ); | |
738 | ||
739 | // If are replacing a textarea, we must | |
740 | if ( element.is( 'textarea' ) ) { | |
741 | if ( form ) { | |
742 | form.on( 'submit', onSubmit ); | |
743 | ||
744 | // Check if there is no element/elements input with name == "submit". | |
745 | // If they exists they will overwrite form submit function (form.$.submit). | |
746 | // If form.$.submit is overwritten we can not do anything with it. | |
747 | if ( isFunction( form.$.submit ) ) { | |
748 | // Setup the submit function because it doesn't fire the | |
749 | // "submit" event. | |
750 | form.$.submit = CKEDITOR.tools.override( form.$.submit, function( originalSubmit ) { | |
751 | return function() { | |
752 | onSubmit(); | |
753 | ||
754 | // For IE, the DOM submit function is not a | |
755 | // function, so we need third check. | |
756 | if ( originalSubmit.apply ) | |
757 | originalSubmit.apply( this ); | |
758 | else | |
759 | originalSubmit(); | |
760 | }; | |
761 | } ); | |
762 | } | |
763 | ||
764 | // Remove 'submit' events registered on form element before destroying.(#3988) | |
765 | editor.on( 'destroy', function() { | |
766 | form.removeListener( 'submit', onSubmit ); | |
767 | } ); | |
768 | } | |
769 | } | |
770 | ||
771 | function onSubmit( evt ) { | |
772 | editor.updateElement(); | |
773 | ||
774 | // #8031 If textarea had required attribute and editor is empty fire 'required' event and if | |
775 | // it was cancelled, prevent submitting the form. | |
776 | if ( editor._.required && !element.getValue() && editor.fire( 'required' ) === false ) { | |
777 | // When user press save button event (evt) is undefined (see save plugin). | |
778 | // This method works because it throws error so originalSubmit won't be called. | |
779 | // Also this error won't be shown because it will be caught in save plugin. | |
780 | evt.data.preventDefault(); | |
781 | } | |
782 | } | |
783 | ||
784 | function isFunction( f ) { | |
785 | // For IE8 typeof fun == object so we cannot use it. | |
786 | return !!( f && f.call && f.apply ); | |
787 | } | |
788 | }, | |
789 | ||
790 | /** | |
791 | * Destroys the editor instance, releasing all resources used by it. | |
792 | * If the editor replaced an element, the element will be recovered. | |
793 | * | |
794 | * alert( CKEDITOR.instances.editor1 ); // e.g. object | |
795 | * CKEDITOR.instances.editor1.destroy(); | |
796 | * alert( CKEDITOR.instances.editor1 ); // undefined | |
797 | * | |
798 | * @param {Boolean} [noUpdate] If the instance is replacing a DOM | |
799 | * element, this parameter indicates whether or not to update the | |
800 | * element with the instance content. | |
801 | */ | |
802 | destroy: function( noUpdate ) { | |
803 | this.fire( 'beforeDestroy' ); | |
804 | ||
805 | !noUpdate && updateEditorElement.call( this ); | |
806 | ||
807 | this.editable( null ); | |
808 | ||
809 | if ( this.filter ) { | |
810 | this.filter.destroy(); | |
811 | delete this.filter; | |
812 | } | |
813 | ||
814 | delete this.activeFilter; | |
815 | ||
816 | this.status = 'destroyed'; | |
817 | ||
818 | this.fire( 'destroy' ); | |
819 | ||
820 | // Plug off all listeners to prevent any further events firing. | |
821 | this.removeAllListeners(); | |
822 | ||
823 | CKEDITOR.remove( this ); | |
824 | CKEDITOR.fire( 'instanceDestroyed', null, this ); | |
825 | }, | |
826 | ||
827 | /** | |
828 | * Returns an {@link CKEDITOR.dom.elementPath element path} for the selection in the editor. | |
829 | * | |
830 | * @param {CKEDITOR.dom.node} [startNode] From which the path should start, | |
831 | * if not specified defaults to editor selection's | |
832 | * start element yielded by {@link CKEDITOR.dom.selection#getStartElement}. | |
833 | * @returns {CKEDITOR.dom.elementPath} | |
834 | */ | |
835 | elementPath: function( startNode ) { | |
836 | if ( !startNode ) { | |
837 | var sel = this.getSelection(); | |
838 | if ( !sel ) | |
839 | return null; | |
840 | ||
841 | startNode = sel.getStartElement(); | |
842 | } | |
843 | ||
844 | return startNode ? new CKEDITOR.dom.elementPath( startNode, this.editable() ) : null; | |
845 | }, | |
846 | ||
847 | /** | |
848 | * Shortcut to create a {@link CKEDITOR.dom.range} instance from the editable element. | |
849 | * | |
850 | * @returns {CKEDITOR.dom.range} The DOM range created if the editable has presented. | |
851 | * @see CKEDITOR.dom.range | |
852 | */ | |
853 | createRange: function() { | |
854 | var editable = this.editable(); | |
855 | return editable ? new CKEDITOR.dom.range( editable ) : null; | |
856 | }, | |
857 | ||
858 | /** | |
859 | * Executes a command associated with the editor. | |
860 | * | |
861 | * editorInstance.execCommand( 'bold' ); | |
862 | * | |
863 | * @param {String} commandName The indentifier name of the command. | |
864 | * @param {Object} [data] The data to be passed to the command. | |
865 | * @returns {Boolean} `true` if the command was executed | |
866 | * successfully, otherwise `false`. | |
867 | * @see CKEDITOR.editor#addCommand | |
868 | */ | |
869 | execCommand: function( commandName, data ) { | |
870 | var command = this.getCommand( commandName ); | |
871 | ||
872 | var eventData = { | |
873 | name: commandName, | |
874 | commandData: data, | |
875 | command: command | |
876 | }; | |
877 | ||
878 | if ( command && command.state != CKEDITOR.TRISTATE_DISABLED ) { | |
879 | if ( this.fire( 'beforeCommandExec', eventData ) !== false ) { | |
880 | eventData.returnValue = command.exec( eventData.commandData ); | |
881 | ||
882 | // Fire the 'afterCommandExec' immediately if command is synchronous. | |
883 | if ( !command.async && this.fire( 'afterCommandExec', eventData ) !== false ) | |
884 | return eventData.returnValue; | |
885 | } | |
886 | } | |
887 | ||
888 | // throw 'Unknown command name "' + commandName + '"'; | |
889 | return false; | |
890 | }, | |
891 | ||
892 | /** | |
893 | * Gets one of the registered commands. Note that after registering a | |
894 | * command definition with {@link #addCommand}, it is | |
895 | * transformed internally into an instance of | |
896 | * {@link CKEDITOR.command}, which will then be returned by this function. | |
897 | * | |
898 | * @param {String} commandName The name of the command to be returned. | |
899 | * This is the same name that is used to register the command with `addCommand`. | |
900 | * @returns {CKEDITOR.command} The command object identified by the provided name. | |
901 | */ | |
902 | getCommand: function( commandName ) { | |
903 | return this.commands[ commandName ]; | |
904 | }, | |
905 | ||
906 | /** | |
907 | * Gets the editor data. The data will be in "raw" format. It is the same | |
908 | * data that is posted by the editor. | |
909 | * | |
910 | * if ( CKEDITOR.instances.editor1.getData() == '' ) | |
911 | * alert( 'There is no data available.' ); | |
912 | * | |
913 | * @param {Boolean} internal If set to `true`, it will prevent firing the | |
914 | * {@link CKEDITOR.editor#beforeGetData} and {@link CKEDITOR.editor#event-getData} events, so | |
915 | * the real content of the editor will not be read and cached data will be returned. The method will work | |
916 | * much faster, but this may result in the editor returning the data that is not up to date. This parameter | |
917 | * should thus only be set to `true` when you are certain that the cached data is up to date. | |
918 | * | |
919 | * @returns {String} The editor data. | |
920 | */ | |
921 | getData: function( internal ) { | |
922 | !internal && this.fire( 'beforeGetData' ); | |
923 | ||
924 | var eventData = this._.data; | |
925 | ||
926 | if ( typeof eventData != 'string' ) { | |
927 | var element = this.element; | |
928 | if ( element && this.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) | |
929 | eventData = element.is( 'textarea' ) ? element.getValue() : element.getHtml(); | |
930 | else | |
931 | eventData = ''; | |
932 | } | |
933 | ||
934 | eventData = { dataValue: eventData }; | |
935 | ||
936 | // Fire "getData" so data manipulation may happen. | |
937 | !internal && this.fire( 'getData', eventData ); | |
938 | ||
939 | return eventData.dataValue; | |
940 | }, | |
941 | ||
942 | /** | |
943 | * Gets the "raw data" currently available in the editor. This is a | |
944 | * fast method which returns the data as is, without processing, so it is | |
945 | * not recommended to use it on resulting pages. Instead it can be used | |
946 | * combined with the {@link #method-loadSnapshot} method in order | |
947 | * to automatically save the editor data from time to time | |
948 | * while the user is using the editor, to avoid data loss, without risking | |
949 | * performance issues. | |
950 | * | |
951 | * alert( editor.getSnapshot() ); | |
952 | * | |
953 | * See also: | |
954 | * | |
955 | * * {@link CKEDITOR.editor#method-getData}. | |
956 | * | |
957 | * @returns {String} Editor "raw data". | |
958 | */ | |
959 | getSnapshot: function() { | |
960 | var data = this.fire( 'getSnapshot' ); | |
961 | ||
962 | if ( typeof data != 'string' ) { | |
963 | var element = this.element; | |
964 | ||
965 | if ( element && this.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) { | |
966 | data = element.is( 'textarea' ) ? element.getValue() : element.getHtml(); | |
967 | } | |
968 | else { | |
969 | // If we don't have a proper element, set data to an empty string, | |
970 | // as this method is expected to return a string. (#13385) | |
971 | data = ''; | |
972 | } | |
973 | } | |
974 | ||
975 | return data; | |
976 | }, | |
977 | ||
978 | /** | |
979 | * Loads "raw data" into the editor. The data is loaded with processing | |
980 | * straight to the editing area. It should not be used as a way to load | |
981 | * any kind of data, but instead in combination with | |
982 | * {@link #method-getSnapshot}-produced data. | |
983 | * | |
984 | * var data = editor.getSnapshot(); | |
985 | * editor.loadSnapshot( data ); | |
986 | * | |
987 | * @see CKEDITOR.editor#setData | |
988 | */ | |
989 | loadSnapshot: function( snapshot ) { | |
990 | this.fire( 'loadSnapshot', snapshot ); | |
991 | }, | |
992 | ||
993 | /** | |
994 | * Sets the editor data. The data must be provided in the "raw" format (HTML). | |
995 | * | |
996 | * Note that this method is asynchronous. The `callback` parameter must | |
997 | * be used if interaction with the editor is needed after setting the data. | |
998 | * | |
999 | * CKEDITOR.instances.editor1.setData( '<p>This is the editor data.</p>' ); | |
1000 | * | |
1001 | * CKEDITOR.instances.editor1.setData( '<p>Some other editor data.</p>', { | |
1002 | * callback: function() { | |
1003 | * this.checkDirty(); // true | |
1004 | * } | |
1005 | * } ); | |
1006 | * | |
1007 | * Note: In **CKEditor 4.4.2** the signature of this method has changed. All arguments | |
1008 | * except `data` were wrapped into the `options` object. However, backward compatibility | |
1009 | * was preserved and it is still possible to use the `data, callback, internal` arguments. | |
1010 | * | |
1011 | * | |
1012 | * @param {String} data The HTML code to replace current editor content. | |
1013 | * @param {Object} [options] | |
1014 | * @param {Boolean} [options.internal=false] Whether to suppress any event firing when copying data internally inside the editor. | |
1015 | * @param {Function} [options.callback] Function to be called after `setData` is completed (on {@link #dataReady}). | |
1016 | * @param {Boolean} [options.noSnapshot=false] If set to `true`, it will prevent recording an undo snapshot. | |
1017 | * Introduced in CKEditor 4.4.2. | |
1018 | */ | |
1019 | setData: function( data, options, internal ) { | |
1020 | var fireSnapshot = true, | |
1021 | // Backward compatibility. | |
1022 | callback = options, | |
1023 | eventData; | |
1024 | ||
1025 | if ( options && typeof options == 'object' ) { | |
1026 | internal = options.internal; | |
1027 | callback = options.callback; | |
1028 | fireSnapshot = !options.noSnapshot; | |
1029 | } | |
1030 | ||
1031 | if ( !internal && fireSnapshot ) | |
1032 | this.fire( 'saveSnapshot' ); | |
1033 | ||
1034 | if ( callback || !internal ) { | |
1035 | this.once( 'dataReady', function( evt ) { | |
1036 | if ( !internal && fireSnapshot ) | |
1037 | this.fire( 'saveSnapshot' ); | |
1038 | ||
1039 | if ( callback ) | |
1040 | callback.call( evt.editor ); | |
1041 | } ); | |
1042 | } | |
1043 | ||
1044 | // Fire "setData" so data manipulation may happen. | |
1045 | eventData = { dataValue: data }; | |
1046 | !internal && this.fire( 'setData', eventData ); | |
1047 | ||
1048 | this._.data = eventData.dataValue; | |
1049 | ||
1050 | !internal && this.fire( 'afterSetData', eventData ); | |
1051 | }, | |
1052 | ||
1053 | /** | |
1054 | * Puts or restores the editor into the read-only state. When in read-only, | |
1055 | * the user is not able to change the editor content, but can still use | |
1056 | * some editor features. This function sets the {@link #property-readOnly} | |
1057 | * property of the editor, firing the {@link #event-readOnly} event. | |
1058 | * | |
1059 | * **Note:** The current editing area will be reloaded. | |
1060 | * | |
1061 | * @since 3.6 | |
1062 | * @param {Boolean} [isReadOnly] Indicates that the editor must go | |
1063 | * read-only (`true`, default) or be restored and made editable (`false`). | |
1064 | */ | |
1065 | setReadOnly: function( isReadOnly ) { | |
1066 | isReadOnly = ( isReadOnly == null ) || isReadOnly; | |
1067 | ||
1068 | if ( this.readOnly != isReadOnly ) { | |
1069 | this.readOnly = isReadOnly; | |
1070 | ||
1071 | // Block or release BACKSPACE key according to current read-only | |
1072 | // state to prevent browser's history navigation (#9761). | |
1073 | this.keystrokeHandler.blockedKeystrokes[ 8 ] = +isReadOnly; | |
1074 | ||
1075 | this.editable().setReadOnly( isReadOnly ); | |
1076 | ||
1077 | // Fire the readOnly event so the editor features can update | |
1078 | // their state accordingly. | |
1079 | this.fire( 'readOnly' ); | |
1080 | } | |
1081 | }, | |
1082 | ||
1083 | /** | |
1084 | * Inserts HTML code into the currently selected position in the editor in WYSIWYG mode. | |
1085 | * | |
1086 | * Example: | |
1087 | * | |
1088 | * CKEDITOR.instances.editor1.insertHtml( '<p>This is a new paragraph.</p>' ); | |
1089 | * | |
1090 | * Fires the {@link #event-insertHtml} and {@link #event-afterInsertHtml} events. The HTML is inserted | |
1091 | * in the {@link #event-insertHtml} event's listener with a default priority (10) so you can add listeners with | |
1092 | * lower or higher priorities in order to execute some code before or after the HTML is inserted. | |
1093 | * | |
1094 | * @param {String} html HTML code to be inserted into the editor. | |
1095 | * @param {String} [mode='html'] The mode in which the HTML code will be inserted. One of the following: | |
1096 | * | |
1097 | * * `'html'` – The inserted content will completely override the styles at the selected position. | |
1098 | * * `'unfiltered_html'` – Like `'html'` but the content is not filtered with {@link CKEDITOR.filter}. | |
1099 | * * `'text'` – The inserted content will inherit the styles applied in | |
1100 | * the selected position. This mode should be used when inserting "htmlified" plain text | |
1101 | * (HTML without inline styles and styling elements like `<b>`, `<strong>`, `<span style="...">`). | |
1102 | * | |
1103 | * @param {CKEDITOR.dom.range} [range] If specified, the HTML will be inserted into the range | |
1104 | * instead of into the selection. The selection will be placed at the end of the insertion (like in the normal case). | |
1105 | * Introduced in CKEditor 4.5. | |
1106 | */ | |
1107 | insertHtml: function( html, mode, range ) { | |
1108 | this.fire( 'insertHtml', { dataValue: html, mode: mode, range: range } ); | |
1109 | }, | |
1110 | ||
1111 | /** | |
1112 | * Inserts text content into the currently selected position in the | |
1113 | * editor in WYSIWYG mode. The styles of the selected element will be applied to the inserted text. | |
1114 | * Spaces around the text will be left untouched. | |
1115 | * | |
1116 | * CKEDITOR.instances.editor1.insertText( ' line1 \n\n line2' ); | |
1117 | * | |
1118 | * Fires the {@link #event-insertText} and {@link #event-afterInsertHtml} events. The text is inserted | |
1119 | * in the {@link #event-insertText} event's listener with a default priority (10) so you can add listeners with | |
1120 | * lower or higher priorities in order to execute some code before or after the text is inserted. | |
1121 | * | |
1122 | * @since 3.5 | |
1123 | * @param {String} text Text to be inserted into the editor. | |
1124 | */ | |
1125 | insertText: function( text ) { | |
1126 | this.fire( 'insertText', text ); | |
1127 | }, | |
1128 | ||
1129 | /** | |
1130 | * Inserts an element into the currently selected position in the editor in WYSIWYG mode. | |
1131 | * | |
1132 | * var element = CKEDITOR.dom.element.createFromHtml( '<img src="hello.png" border="0" title="Hello" />' ); | |
1133 | * CKEDITOR.instances.editor1.insertElement( element ); | |
1134 | * | |
1135 | * Fires the {@link #event-insertElement} event. The element is inserted in the listener with a default priority (10), | |
1136 | * so you can add listeners with lower or higher priorities in order to execute some code before or after | |
1137 | * the element is inserted. | |
1138 | * | |
1139 | * @param {CKEDITOR.dom.element} element The element to be inserted into the editor. | |
1140 | */ | |
1141 | insertElement: function( element ) { | |
1142 | this.fire( 'insertElement', element ); | |
1143 | }, | |
1144 | ||
1145 | /** | |
1146 | * Gets the selected HTML (it is returned as a {@link CKEDITOR.dom.documentFragment document fragment} | |
1147 | * or a string). This method is designed to work as the user would expect the copy functionality to work. | |
1148 | * For instance, if the following selection was made: | |
1149 | * | |
1150 | * <p>a<b>b{c}d</b>e</p> | |
1151 | * | |
1152 | * The following HTML will be returned: | |
1153 | * | |
1154 | * <b>c</b> | |
1155 | * | |
1156 | * As you can see, the information about the bold formatting was preserved, even though the selection was | |
1157 | * anchored inside the `<b>` element. | |
1158 | * | |
1159 | * See also: | |
1160 | * | |
1161 | * * the {@link #extractSelectedHtml} method, | |
1162 | * * the {@link CKEDITOR.editable#getHtmlFromRange} method. | |
1163 | * | |
1164 | * @since 4.5 | |
1165 | * @param {Boolean} [toString] If `true`, then stringified HTML will be returned. | |
1166 | * @returns {CKEDITOR.dom.documentFragment/String} | |
1167 | */ | |
1168 | getSelectedHtml: function( toString ) { | |
1169 | var editable = this.editable(), | |
1170 | selection = this.getSelection(), | |
1171 | ranges = selection && selection.getRanges(); | |
1172 | ||
1173 | if ( !editable || !ranges || ranges.length === 0 ) { | |
1174 | return null; | |
1175 | } | |
1176 | ||
1177 | var docFragment = createDocumentFragmentFromRanges( ranges, editable ); | |
1178 | ||
1179 | return toString ? docFragment.getHtml() : docFragment; | |
1180 | }, | |
1181 | ||
1182 | /** | |
1183 | * Gets the selected HTML (it is returned as a {@link CKEDITOR.dom.documentFragment document fragment} | |
1184 | * or a string) and removes the selected part of the DOM. This method is designed to work as the user would | |
1185 | * expect the cut and delete functionalities to work. | |
1186 | * | |
1187 | * See also: | |
1188 | * | |
1189 | * * the {@link #getSelectedHtml} method, | |
1190 | * * the {@link CKEDITOR.editable#extractHtmlFromRange} method. | |
1191 | * | |
1192 | * @since 4.5 | |
1193 | * @param {Boolean} [toString] If `true`, then stringified HTML will be returned. | |
1194 | * @param {Boolean} [removeEmptyBlock=false] Default `false` means that the function will keep an empty block (if the | |
1195 | * entire content was removed) or it will create it (if a block element was removed) and set the selection in that block. | |
1196 | * If `true`, the empty block will be removed or not created. In this case the function will not handle the selection. | |
1197 | * @returns {CKEDITOR.dom.documentFragment/String/null} | |
1198 | */ | |
1199 | extractSelectedHtml: function( toString, removeEmptyBlock ) { | |
1200 | var editable = this.editable(), | |
1201 | ranges = this.getSelection().getRanges(); | |
1202 | ||
1203 | if ( !editable || ranges.length === 0 ) { | |
1204 | return null; | |
1205 | } | |
1206 | ||
1207 | var range = ranges[ 0 ], | |
1208 | docFragment = editable.extractHtmlFromRange( range, removeEmptyBlock ); | |
1209 | ||
1210 | if ( !removeEmptyBlock ) { | |
1211 | this.getSelection().selectRanges( [ range ] ); | |
1212 | } | |
1213 | ||
1214 | return toString ? docFragment.getHtml() : docFragment; | |
1215 | }, | |
1216 | ||
1217 | /** | |
1218 | * Moves the selection focus to the editing area space in the editor. | |
1219 | */ | |
1220 | focus: function() { | |
1221 | this.fire( 'beforeFocus' ); | |
1222 | }, | |
1223 | ||
1224 | /** | |
1225 | * Checks whether the current editor content contains changes when | |
1226 | * compared to the content loaded into the editor at startup, or to | |
1227 | * the content available in the editor when {@link #resetDirty} | |
1228 | * was called. | |
1229 | * | |
1230 | * function beforeUnload( evt ) { | |
1231 | * if ( CKEDITOR.instances.editor1.checkDirty() ) | |
1232 | * return evt.returnValue = "You will lose the changes made in the editor."; | |
1233 | * } | |
1234 | * | |
1235 | * if ( window.addEventListener ) | |
1236 | * window.addEventListener( 'beforeunload', beforeUnload, false ); | |
1237 | * else | |
1238 | * window.attachEvent( 'onbeforeunload', beforeUnload ); | |
1239 | * | |
1240 | * @returns {Boolean} `true` if the content contains changes. | |
1241 | */ | |
1242 | checkDirty: function() { | |
1243 | return this.status == 'ready' && this._.previousValue !== this.getSnapshot(); | |
1244 | }, | |
1245 | ||
1246 | /** | |
1247 | * Resets the "dirty state" of the editor so subsequent calls to | |
1248 | * {@link #checkDirty} will return `false` if the user will not | |
1249 | * have made further changes to the content. | |
1250 | * | |
1251 | * alert( editor.checkDirty() ); // e.g. true | |
1252 | * editor.resetDirty(); | |
1253 | * alert( editor.checkDirty() ); // false | |
1254 | */ | |
1255 | resetDirty: function() { | |
1256 | this._.previousValue = this.getSnapshot(); | |
1257 | }, | |
1258 | ||
1259 | /** | |
1260 | * Updates the `<textarea>` element that was replaced by the editor with | |
1261 | * the current data available in the editor. | |
1262 | * | |
1263 | * **Note:** This method will only affect those editor instances created | |
1264 | * with the {@link CKEDITOR#ELEMENT_MODE_REPLACE} element mode or inline instances | |
1265 | * bound to `<textarea>` elements. | |
1266 | * | |
1267 | * CKEDITOR.instances.editor1.updateElement(); | |
1268 | * alert( document.getElementById( 'editor1' ).value ); // The current editor data. | |
1269 | * | |
1270 | * @see CKEDITOR.editor#element | |
1271 | */ | |
1272 | updateElement: function() { | |
1273 | return updateEditorElement.call( this ); | |
1274 | }, | |
1275 | ||
1276 | /** | |
1277 | * Assigns keystrokes associated with editor commands. | |
1278 | * | |
1279 | * editor.setKeystroke( CKEDITOR.CTRL + 115, 'save' ); // Assigned Ctrl+S to the "save" command. | |
1280 | * editor.setKeystroke( CKEDITOR.CTRL + 115, false ); // Disabled Ctrl+S keystroke assignment. | |
1281 | * editor.setKeystroke( [ | |
1282 | * [ CKEDITOR.ALT + 122, false ], | |
1283 | * [ CKEDITOR.CTRL + 121, 'link' ], | |
1284 | * [ CKEDITOR.SHIFT + 120, 'bold' ] | |
1285 | * ] ); | |
1286 | * | |
1287 | * This method may be used in the following cases: | |
1288 | * | |
1289 | * * By plugins (like `link` or `basicstyles`) to set their keystrokes when plugins are being loaded. | |
1290 | * * During the runtime to modify existing keystrokes. | |
1291 | * | |
1292 | * The editor handles keystroke configuration in the following order: | |
1293 | * | |
1294 | * 1. Plugins use this method to define default keystrokes. | |
1295 | * 2. Editor extends default keystrokes with {@link CKEDITOR.config#keystrokes}. | |
1296 | * 3. Editor blocks keystrokes defined in {@link CKEDITOR.config#blockedKeystrokes}. | |
1297 | * | |
1298 | * You can then set new keystrokes using this method during the runtime. | |
1299 | * | |
1300 | * @since 4.0 | |
1301 | * @param {Number/Array} keystroke A keystroke or an array of keystroke definitions. | |
1302 | * @param {String/Boolean} [behavior] A command to be executed on the keystroke. | |
1303 | */ | |
1304 | setKeystroke: function() { | |
1305 | var keystrokes = this.keystrokeHandler.keystrokes, | |
1306 | newKeystrokes = CKEDITOR.tools.isArray( arguments[ 0 ] ) ? arguments[ 0 ] : [ [].slice.call( arguments, 0 ) ], | |
1307 | keystroke, behavior; | |
1308 | ||
1309 | for ( var i = newKeystrokes.length; i--; ) { | |
1310 | keystroke = newKeystrokes[ i ]; | |
1311 | behavior = 0; | |
1312 | ||
1313 | // It may be a pair of: [ key, command ] | |
1314 | if ( CKEDITOR.tools.isArray( keystroke ) ) { | |
1315 | behavior = keystroke[ 1 ]; | |
1316 | keystroke = keystroke[ 0 ]; | |
1317 | } | |
1318 | ||
1319 | if ( behavior ) | |
1320 | keystrokes[ keystroke ] = behavior; | |
1321 | else | |
1322 | delete keystrokes[ keystroke ]; | |
1323 | } | |
1324 | }, | |
1325 | ||
1326 | /** | |
1327 | * Shorthand for {@link CKEDITOR.filter#addFeature}. | |
1328 | * | |
1329 | * @since 4.1 | |
1330 | * @param {CKEDITOR.feature} feature See {@link CKEDITOR.filter#addFeature}. | |
1331 | * @returns {Boolean} See {@link CKEDITOR.filter#addFeature}. | |
1332 | */ | |
1333 | addFeature: function( feature ) { | |
1334 | return this.filter.addFeature( feature ); | |
1335 | }, | |
1336 | ||
1337 | /** | |
1338 | * Sets the active filter ({@link #activeFilter}). Fires the {@link #activeFilterChange} event. | |
1339 | * | |
1340 | * // Set active filter which allows only 4 elements. | |
1341 | * // Buttons like Bold, Italic will be disabled. | |
1342 | * var filter = new CKEDITOR.filter( 'p strong em br' ); | |
1343 | * editor.setActiveFilter( filter ); | |
1344 | * | |
1345 | * Setting a new filter will also change the {@link #setActiveEnterMode active Enter modes} to the first values | |
1346 | * allowed by the new filter (see {@link CKEDITOR.filter#getAllowedEnterMode}). | |
1347 | * | |
1348 | * @since 4.3 | |
1349 | * @param {CKEDITOR.filter} filter Filter instance or a falsy value (e.g. `null`) to reset to the default one. | |
1350 | */ | |
1351 | setActiveFilter: function( filter ) { | |
1352 | if ( !filter ) | |
1353 | filter = this.filter; | |
1354 | ||
1355 | if ( this.activeFilter !== filter ) { | |
1356 | this.activeFilter = filter; | |
1357 | this.fire( 'activeFilterChange' ); | |
1358 | ||
1359 | // Reset active filter to the main one - it resets enter modes, too. | |
1360 | if ( filter === this.filter ) | |
1361 | this.setActiveEnterMode( null, null ); | |
1362 | else | |
1363 | this.setActiveEnterMode( | |
1364 | filter.getAllowedEnterMode( this.enterMode ), | |
1365 | filter.getAllowedEnterMode( this.shiftEnterMode, true ) | |
1366 | ); | |
1367 | } | |
1368 | }, | |
1369 | ||
1370 | /** | |
1371 | * Sets the active Enter modes: ({@link #enterMode} and {@link #shiftEnterMode}). | |
1372 | * Fires the {@link #activeEnterModeChange} event. | |
1373 | * | |
1374 | * Prior to CKEditor 4.3 Enter modes were static and it was enough to check {@link CKEDITOR.config#enterMode} | |
1375 | * and {@link CKEDITOR.config#shiftEnterMode} when implementing a feature which should depend on the Enter modes. | |
1376 | * Since CKEditor 4.3 these options are source of initial: | |
1377 | * | |
1378 | * * static {@link #enterMode} and {@link #shiftEnterMode} values, | |
1379 | * * dynamic {@link #activeEnterMode} and {@link #activeShiftEnterMode} values. | |
1380 | * | |
1381 | * However, the dynamic Enter modes can be changed during runtime by using this method, to reflect the selection context. | |
1382 | * For example, if selection is moved to the {@link CKEDITOR.plugins.widget widget}'s nested editable which | |
1383 | * is a {@link #blockless blockless one}, then the active Enter modes should be changed to {@link CKEDITOR#ENTER_BR} | |
1384 | * (in this case [Widget System](#!/guide/dev_widgets) takes care of that). | |
1385 | * | |
1386 | * **Note:** This method should not be used to configure the editor – use {@link CKEDITOR.config#enterMode} and | |
1387 | * {@link CKEDITOR.config#shiftEnterMode} instead. This method should only be used to dynamically change | |
1388 | * Enter modes during runtime based on selection changes. | |
1389 | * Keep in mind that changed Enter mode may be overwritten by another plugin/feature when it decided that | |
1390 | * the changed context requires this. | |
1391 | * | |
1392 | * **Note:** In case of blockless editor (inline editor based on an element which cannot contain block elements | |
1393 | * — see {@link CKEDITOR.editor#blockless}) only {@link CKEDITOR#ENTER_BR} is a valid Enter mode. Therefore | |
1394 | * this method will not allow to set other values. | |
1395 | * | |
1396 | * **Note:** Changing the {@link #activeFilter active filter} may cause the Enter mode to change if default Enter modes | |
1397 | * are not allowed by the new filter. | |
1398 | * | |
1399 | * @since 4.3 | |
1400 | * @param {Number} enterMode One of {@link CKEDITOR#ENTER_P}, {@link CKEDITOR#ENTER_DIV}, {@link CKEDITOR#ENTER_BR}. | |
1401 | * Pass falsy value (e.g. `null`) to reset the Enter mode to the default value ({@link #enterMode} and/or {@link #shiftEnterMode}). | |
1402 | * @param {Number} shiftEnterMode See the `enterMode` argument. | |
1403 | */ | |
1404 | setActiveEnterMode: function( enterMode, shiftEnterMode ) { | |
1405 | // Validate passed modes or use default ones (validated on init). | |
1406 | enterMode = enterMode ? validateEnterMode( this, enterMode ) : this.enterMode; | |
1407 | shiftEnterMode = shiftEnterMode ? validateEnterMode( this, shiftEnterMode ) : this.shiftEnterMode; | |
1408 | ||
1409 | if ( this.activeEnterMode != enterMode || this.activeShiftEnterMode != shiftEnterMode ) { | |
1410 | this.activeEnterMode = enterMode; | |
1411 | this.activeShiftEnterMode = shiftEnterMode; | |
1412 | this.fire( 'activeEnterModeChange' ); | |
1413 | } | |
1414 | }, | |
1415 | ||
1416 | /** | |
1417 | * Shows a notification to the user. | |
1418 | * | |
1419 | * If the [Notification](http://ckeditor.com/addons/notification) plugin is not enabled, this function shows | |
1420 | * a normal alert with the given `message`. The `type` and `progressOrDuration` parameters are supported | |
1421 | * only by the Notification plugin. | |
1422 | * | |
1423 | * If the Notification plugin is enabled, this method creates and shows a new notification. | |
1424 | * By default the notification is shown over the editor content, in the viewport if it is possible. | |
1425 | * | |
1426 | * See {@link CKEDITOR.plugins.notification}. | |
1427 | * | |
1428 | * @since 4.5 | |
1429 | * @member CKEDITOR.editor | |
1430 | * @param {String} message The message displayed in the notification. | |
1431 | * @param {String} [type='info'] The type of the notification. Can be `'info'`, `'warning'`, `'success'` or `'progress'`. | |
1432 | * @param {Number} [progressOrDuration] If the type is `progress`, the third parameter may be a progress from `0` to `1` | |
1433 | * (defaults to `0`). Otherwise the third parameter may be a notification duration denoting after how many milliseconds | |
1434 | * the notification should be closed automatically. `0` means that the notification will not close automatically and the user | |
1435 | * needs to close it manually. See {@link CKEDITOR.plugins.notification#duration}. | |
1436 | * Note that `warning` notifications will not be closed automatically. | |
1437 | * @returns {CKEDITOR.plugins.notification} Created and shown notification. | |
1438 | */ | |
1439 | showNotification: function( message ) { | |
1440 | alert( message ); // jshint ignore:line | |
1441 | } | |
1442 | } ); | |
1443 | } )(); | |
1444 | ||
1445 | /** | |
1446 | * The editor has no associated element. | |
1447 | * | |
1448 | * @readonly | |
1449 | * @property {Number} [=0] | |
1450 | * @member CKEDITOR | |
1451 | */ | |
1452 | CKEDITOR.ELEMENT_MODE_NONE = 0; | |
1453 | ||
1454 | /** | |
1455 | * The element is to be replaced by the editor instance. | |
1456 | * | |
1457 | * @readonly | |
1458 | * @property {Number} [=1] | |
1459 | * @member CKEDITOR | |
1460 | */ | |
1461 | CKEDITOR.ELEMENT_MODE_REPLACE = 1; | |
1462 | ||
1463 | /** | |
1464 | * The editor is to be created inside the element. | |
1465 | * | |
1466 | * @readonly | |
1467 | * @property {Number} [=2] | |
1468 | * @member CKEDITOR | |
1469 | */ | |
1470 | CKEDITOR.ELEMENT_MODE_APPENDTO = 2; | |
1471 | ||
1472 | /** | |
1473 | * The editor is to be attached to the element, using it as the editing block. | |
1474 | * | |
1475 | * @readonly | |
1476 | * @property {Number} [=3] | |
1477 | * @member CKEDITOR | |
1478 | */ | |
1479 | CKEDITOR.ELEMENT_MODE_INLINE = 3; | |
1480 | ||
1481 | /** | |
1482 | * Whether to escape HTML when the editor updates the original input element. | |
1483 | * | |
1484 | * config.htmlEncodeOutput = true; | |
1485 | * | |
1486 | * @since 3.1 | |
1487 | * @cfg {Boolean} [htmlEncodeOutput=false] | |
1488 | * @member CKEDITOR.config | |
1489 | */ | |
1490 | ||
1491 | /** | |
1492 | * If `true`, makes the editor start in read-only state. Otherwise, it will check | |
1493 | * if the linked `<textarea>` element has the `disabled` attribute. | |
1494 | * | |
1495 | * Read more in the [documentation](#!/guide/dev_readonly) | |
1496 | * and see the [SDK sample](http://sdk.ckeditor.com/samples/readonly.html). | |
1497 | * | |
1498 | * config.readOnly = true; | |
1499 | * | |
1500 | * @since 3.6 | |
1501 | * @cfg {Boolean} [readOnly=false] | |
1502 | * @member CKEDITOR.config | |
1503 | * @see CKEDITOR.editor#setReadOnly | |
1504 | */ | |
1505 | ||
1506 | /** | |
1507 | * Whether an editable element should have focus when the editor is loading for the first time. | |
1508 | * | |
1509 | * config.startupFocus = true; | |
1510 | * | |
1511 | * @cfg {Boolean} [startupFocus=false] | |
1512 | * @member CKEDITOR.config | |
1513 | */ | |
1514 | ||
1515 | /** | |
1516 | * Customizes the {@link CKEDITOR.editor#title human-readable title} of this editor. This title is displayed in | |
1517 | * tooltips and impacts various [accessibility aspects](#!/guide/dev_a11y-section-announcing-the-editor-on-the-page), | |
1518 | * e.g. it is commonly used by screen readers for distinguishing editor instances and for navigation. | |
1519 | * Accepted values are a string or `false`. | |
1520 | * | |
1521 | * **Note:** When `config.title` is set globally, the same value will be applied to all editor instances | |
1522 | * loaded with this config. This may adversely affect accessibility as screen reader users will be unable | |
1523 | * to distinguish particular editor instances and navigate between them. | |
1524 | * | |
1525 | * **Note:** Setting `config.title = false` may also impair accessibility in a similar way. | |
1526 | * | |
1527 | * **Note:** Please do not confuse this property with {@link CKEDITOR.editor#name} | |
1528 | * which identifies the instance in the {@link CKEDITOR#instances} literal. | |
1529 | * | |
1530 | * // Sets the title to 'My WYSIWYG editor.'. The original title of the element (if it exists) | |
1531 | * // will be restored once the editor instance is destroyed. | |
1532 | * config.title = 'My WYSIWYG editor.'; | |
1533 | * | |
1534 | * // Do not touch the title. If the element already has a title, it remains unchanged. | |
1535 | * // Also if no `title` attribute exists, nothing new will be added. | |
1536 | * config.title = false; | |
1537 | * | |
1538 | * See also: | |
1539 | * | |
1540 | * * CKEDITOR.editor#name | |
1541 | * * CKEDITOR.editor#title | |
1542 | * | |
1543 | * @since 4.2 | |
1544 | * @cfg {String/Boolean} [title=based on editor.name] | |
1545 | * @member CKEDITOR.config | |
1546 | */ | |
1547 | ||
1548 | /** | |
1549 | * Sets listeners on editor events. | |
1550 | * | |
1551 | * **Note:** This property can only be set in the `config` object passed directly | |
1552 | * to {@link CKEDITOR#replace}, {@link CKEDITOR#inline}, and other creators. | |
1553 | * | |
1554 | * CKEDITOR.replace( 'editor1', { | |
1555 | * on: { | |
1556 | * instanceReady: function() { | |
1557 | * alert( this.name ); // 'editor1' | |
1558 | * }, | |
1559 | * | |
1560 | * key: function() { | |
1561 | * // ... | |
1562 | * } | |
1563 | * } | |
1564 | * } ); | |
1565 | * | |
1566 | * @cfg {Object} on | |
1567 | * @member CKEDITOR.config | |
1568 | */ | |
1569 | ||
1570 | /** | |
1571 | * The outermost element in the DOM tree in which the editable element resides. It is provided | |
1572 | * by a specific editor creator after the editor UI is created and is not intended to | |
1573 | * be modified. | |
1574 | * | |
1575 | * var editor = CKEDITOR.instances.editor1; | |
1576 | * alert( editor.container.getName() ); // 'span' | |
1577 | * | |
1578 | * @readonly | |
1579 | * @property {CKEDITOR.dom.element} container | |
1580 | */ | |
1581 | ||
1582 | /** | |
1583 | * The document that stores the editor content. | |
1584 | * | |
1585 | * * For the classic (`iframe`-based) editor it is equal to the document inside the | |
1586 | * `iframe` containing the editable element. | |
1587 | * * For the inline editor it is equal to {@link CKEDITOR#document}. | |
1588 | * | |
1589 | * The document object is available after the {@link #contentDom} event is fired | |
1590 | * and may be invalidated when the {@link #contentDomUnload} event is fired | |
1591 | * (classic editor only). | |
1592 | * | |
1593 | * editor.on( 'contentDom', function() { | |
1594 | * console.log( editor.document ); | |
1595 | * } ); | |
1596 | * | |
1597 | * @readonly | |
1598 | * @property {CKEDITOR.dom.document} document | |
1599 | */ | |
1600 | ||
1601 | /** | |
1602 | * The window instance related to the {@link #document} property. | |
1603 | * | |
1604 | * It is always equal to the `editor.document.getWindow()`. | |
1605 | * | |
1606 | * See the {@link #document} property documentation. | |
1607 | * | |
1608 | * @readonly | |
1609 | * @property {CKEDITOR.dom.window} window | |
1610 | */ | |
1611 | ||
1612 | /** | |
1613 | * The main filter instance used for input data filtering, data | |
1614 | * transformations, and activation of features. | |
1615 | * | |
1616 | * It points to a {@link CKEDITOR.filter} instance set up based on | |
1617 | * editor configuration. | |
1618 | * | |
1619 | * @since 4.1 | |
1620 | * @readonly | |
1621 | * @property {CKEDITOR.filter} filter | |
1622 | */ | |
1623 | ||
1624 | /** | |
1625 | * The active filter instance which should be used in the current context (location selection). | |
1626 | * This instance will be used to make a decision which commands, buttons and other | |
1627 | * {@link CKEDITOR.feature features} can be enabled. | |
1628 | * | |
1629 | * By default it equals the {@link #filter} and it can be changed by the {@link #setActiveFilter} method. | |
1630 | * | |
1631 | * editor.on( 'activeFilterChange', function() { | |
1632 | * if ( editor.activeFilter.check( 'cite' ) ) | |
1633 | * // Do something when <cite> was enabled - e.g. enable a button. | |
1634 | * else | |
1635 | * // Otherwise do something else. | |
1636 | * } ); | |
1637 | * | |
1638 | * See also the {@link #setActiveEnterMode} method for an explanation of dynamic settings. | |
1639 | * | |
1640 | * @since 4.3 | |
1641 | * @readonly | |
1642 | * @property {CKEDITOR.filter} activeFilter | |
1643 | */ | |
1644 | ||
1645 | /** | |
1646 | * The main (static) Enter mode which is a validated version of the {@link CKEDITOR.config#enterMode} setting. | |
1647 | * Currently only one rule exists — {@link #blockless blockless editors} may have | |
1648 | * Enter modes set only to {@link CKEDITOR#ENTER_BR}. | |
1649 | * | |
1650 | * @since 4.3 | |
1651 | * @readonly | |
1652 | * @property {Number} enterMode | |
1653 | */ | |
1654 | ||
1655 | /** | |
1656 | * See the {@link #enterMode} property. | |
1657 | * | |
1658 | * @since 4.3 | |
1659 | * @readonly | |
1660 | * @property {Number} shiftEnterMode | |
1661 | */ | |
1662 | ||
1663 | /** | |
1664 | * The dynamic Enter mode which should be used in the current context (selection location). | |
1665 | * By default it equals the {@link #enterMode} and it can be changed by the {@link #setActiveEnterMode} method. | |
1666 | * | |
1667 | * See also the {@link #setActiveEnterMode} method for an explanation of dynamic settings. | |
1668 | * | |
1669 | * @since 4.3 | |
1670 | * @readonly | |
1671 | * @property {Number} activeEnterMode | |
1672 | */ | |
1673 | ||
1674 | /** | |
1675 | * See the {@link #activeEnterMode} property. | |
1676 | * | |
1677 | * @since 4.3 | |
1678 | * @readonly | |
1679 | * @property {Number} activeShiftEnterMode | |
1680 | */ | |
1681 | ||
1682 | /** | |
1683 | * Event fired by the {@link #setActiveFilter} method when the {@link #activeFilter} is changed. | |
1684 | * | |
1685 | * @since 4.3 | |
1686 | * @event activeFilterChange | |
1687 | */ | |
1688 | ||
1689 | /** | |
1690 | * Event fired by the {@link #setActiveEnterMode} method when any of the active Enter modes is changed. | |
1691 | * See also the {@link #activeEnterMode} and {@link #activeShiftEnterMode} properties. | |
1692 | * | |
1693 | * @since 4.3 | |
1694 | * @event activeEnterModeChange | |
1695 | */ | |
1696 | ||
1697 | /** | |
1698 | * Event fired when a CKEDITOR instance is created, but still before initializing it. | |
1699 | * To interact with a fully initialized instance, use the | |
1700 | * {@link CKEDITOR#instanceReady} event instead. | |
1701 | * | |
1702 | * @event instanceCreated | |
1703 | * @member CKEDITOR | |
1704 | * @param {CKEDITOR.editor} editor The editor instance that has been created. | |
1705 | */ | |
1706 | ||
1707 | /** | |
1708 | * Event fired when CKEDITOR instance's components (configuration, languages and plugins) are fully | |
1709 | * loaded and initialized. However, the editor will be fully ready for interaction | |
1710 | * on {@link CKEDITOR#instanceReady}. | |
1711 | * | |
1712 | * @event instanceLoaded | |
1713 | * @member CKEDITOR | |
1714 | * @param {CKEDITOR.editor} editor This editor instance that has been loaded. | |
1715 | */ | |
1716 | ||
1717 | /** | |
1718 | * Event fired when a CKEDITOR instance is destroyed. | |
1719 | * | |
1720 | * @event instanceDestroyed | |
1721 | * @member CKEDITOR | |
1722 | * @param {CKEDITOR.editor} editor The editor instance that has been destroyed. | |
1723 | */ | |
1724 | ||
1725 | /** | |
1726 | * Event fired when a CKEDITOR instance is created, fully initialized and ready for interaction. | |
1727 | * | |
1728 | * @event instanceReady | |
1729 | * @member CKEDITOR | |
1730 | * @param {CKEDITOR.editor} editor The editor instance that has been created. | |
1731 | */ | |
1732 | ||
1733 | /** | |
1734 | * Event fired when the language is loaded into the editor instance. | |
1735 | * | |
1736 | * @since 3.6.1 | |
1737 | * @event langLoaded | |
1738 | * @param {CKEDITOR.editor} editor This editor instance. | |
1739 | */ | |
1740 | ||
1741 | /** | |
1742 | * Event fired when all plugins are loaded and initialized into the editor instance. | |
1743 | * | |
1744 | * @event pluginsLoaded | |
1745 | * @param {CKEDITOR.editor} editor This editor instance. | |
1746 | */ | |
1747 | ||
1748 | /** | |
1749 | * Event fired when the styles set is loaded. During the editor initialization | |
1750 | * phase the {@link #getStylesSet} method returns only styles that | |
1751 | * are already loaded, which may not include e.g. styles parsed | |
1752 | * by the `stylesheetparser` plugin. Thus, to be notified when all | |
1753 | * styles are ready, you can listen on this event. | |
1754 | * | |
1755 | * @since 4.1 | |
1756 | * @event stylesSet | |
1757 | * @param {CKEDITOR.editor} editor This editor instance. | |
1758 | * @param {Array} styles An array of styles definitions. | |
1759 | */ | |
1760 | ||
1761 | /** | |
1762 | * Event fired before the command execution when {@link #execCommand} is called. | |
1763 | * | |
1764 | * @event beforeCommandExec | |
1765 | * @param {CKEDITOR.editor} editor This editor instance. | |
1766 | * @param data | |
1767 | * @param {String} data.name The command name. | |
1768 | * @param {Object} data.commandData The data to be sent to the command. This | |
1769 | * can be manipulated by the event listener. | |
1770 | * @param {CKEDITOR.command} data.command The command itself. | |
1771 | */ | |
1772 | ||
1773 | /** | |
1774 | * Event fired after the command execution when {@link #execCommand} is called. | |
1775 | * | |
1776 | * @event afterCommandExec | |
1777 | * @param {CKEDITOR.editor} editor This editor instance. | |
1778 | * @param data | |
1779 | * @param {String} data.name The command name. | |
1780 | * @param {Object} data.commandData The data sent to the command. | |
1781 | * @param {CKEDITOR.command} data.command The command itself. | |
1782 | * @param {Object} data.returnValue The value returned by the command execution. | |
1783 | */ | |
1784 | ||
1785 | /** | |
1786 | * Event fired when a custom configuration file is loaded, before the final | |
1787 | * configuration initialization. | |
1788 | * | |
1789 | * Custom configuration files can be loaded thorugh the | |
1790 | * {@link CKEDITOR.config#customConfig} setting. Several files can be loaded | |
1791 | * by changing this setting. | |
1792 | * | |
1793 | * @event customConfigLoaded | |
1794 | * @param {CKEDITOR.editor} editor This editor instance. | |
1795 | */ | |
1796 | ||
1797 | /** | |
1798 | * Event fired once the editor configuration is ready (loaded and processed). | |
1799 | * | |
1800 | * @event configLoaded | |
1801 | * @param {CKEDITOR.editor} editor This editor instance. | |
1802 | */ | |
1803 | ||
1804 | /** | |
1805 | * Event fired when this editor instance is destroyed. The editor at this | |
1806 | * point is not usable and this event should be used to perform the clean-up | |
1807 | * in any plugin. | |
1808 | * | |
1809 | * @event destroy | |
1810 | * @param {CKEDITOR.editor} editor This editor instance. | |
1811 | */ | |
1812 | ||
1813 | /** | |
1814 | * Internal event to get the current data. | |
1815 | * | |
1816 | * @event beforeGetData | |
1817 | * @param {CKEDITOR.editor} editor This editor instance. | |
1818 | */ | |
1819 | ||
1820 | /** | |
1821 | * Internal event to perform the {@link #method-getSnapshot} call. | |
1822 | * | |
1823 | * @event getSnapshot | |
1824 | * @param {CKEDITOR.editor} editor This editor instance. | |
1825 | */ | |
1826 | ||
1827 | /** | |
1828 | * Internal event to perform the {@link #method-loadSnapshot} call. | |
1829 | * | |
1830 | * @event loadSnapshot | |
1831 | * @param {CKEDITOR.editor} editor This editor instance. | |
1832 | * @param {String} data The data that will be used. | |
1833 | */ | |
1834 | ||
1835 | /** | |
1836 | * Event fired before the {@link #method-getData} call returns, allowing for additional manipulation. | |
1837 | * | |
1838 | * @event getData | |
1839 | * @param {CKEDITOR.editor} editor This editor instance. | |
1840 | * @param data | |
1841 | * @param {String} data.dataValue The data that will be returned. | |
1842 | */ | |
1843 | ||
1844 | /** | |
1845 | * Event fired before the {@link #method-setData} call is executed, allowing for additional manipulation. | |
1846 | * | |
1847 | * @event setData | |
1848 | * @param {CKEDITOR.editor} editor This editor instance. | |
1849 | * @param data | |
1850 | * @param {String} data.dataValue The data that will be used. | |
1851 | */ | |
1852 | ||
1853 | /** | |
1854 | * Event fired at the end of the {@link #method-setData} call execution. Usually it is better to use the | |
1855 | * {@link #dataReady} event. | |
1856 | * | |
1857 | * @event afterSetData | |
1858 | * @param {CKEDITOR.editor} editor This editor instance. | |
1859 | * @param data | |
1860 | * @param {String} data.dataValue The data that has been set. | |
1861 | */ | |
1862 | ||
1863 | /** | |
1864 | * Event fired as an indicator of the editor data loading. It may be the result of | |
1865 | * calling {@link #method-setData} explicitly or an internal | |
1866 | * editor function, like the editor editing mode switching (move to Source and back). | |
1867 | * | |
1868 | * @event dataReady | |
1869 | * @param {CKEDITOR.editor} editor This editor instance. | |
1870 | */ | |
1871 | ||
1872 | /** | |
1873 | * Event fired when the CKEDITOR instance is completely created, fully initialized | |
1874 | * and ready for interaction. | |
1875 | * | |
1876 | * @event instanceReady | |
1877 | * @param {CKEDITOR.editor} editor This editor instance. | |
1878 | */ | |
1879 | ||
1880 | /** | |
1881 | * Event fired when editor components (configuration, languages and plugins) are fully | |
1882 | * loaded and initialized. However, the editor will be fully ready to for interaction | |
1883 | * on {@link #instanceReady}. | |
1884 | * | |
1885 | * @event loaded | |
1886 | * @param {CKEDITOR.editor} editor This editor instance. | |
1887 | */ | |
1888 | ||
1889 | /** | |
1890 | * Event fired by the {@link #method-insertHtml} method. See the method documentation for more information | |
1891 | * about how this event can be used. | |
1892 | * | |
1893 | * @event insertHtml | |
1894 | * @param {CKEDITOR.editor} editor This editor instance. | |
1895 | * @param data | |
1896 | * @param {String} data.mode The mode in which the data is inserted (see {@link #method-insertHtml}). | |
1897 | * @param {String} data.dataValue The HTML code to insert. | |
1898 | * @param {CKEDITOR.dom.range} [data.range] See {@link #method-insertHtml}'s `range` parameter. | |
1899 | */ | |
1900 | ||
1901 | /** | |
1902 | * Event fired by the {@link #method-insertText} method. See the method documentation for more information | |
1903 | * about how this event can be used. | |
1904 | * | |
1905 | * @event insertText | |
1906 | * @param {CKEDITOR.editor} editor This editor instance. | |
1907 | * @param {String} data The text to insert. | |
1908 | */ | |
1909 | ||
1910 | /** | |
1911 | * Event fired by the {@link #method-insertElement} method. See the method documentation for more information | |
1912 | * about how this event can be used. | |
1913 | * | |
1914 | * @event insertElement | |
1915 | * @param {CKEDITOR.editor} editor This editor instance. | |
1916 | * @param {CKEDITOR.dom.element} data The element to insert. | |
1917 | */ | |
1918 | ||
1919 | /** | |
1920 | * Event fired after data insertion using the {@link #method-insertHtml}, {@link CKEDITOR.editable#insertHtml}, | |
1921 | * or {@link CKEDITOR.editable#insertHtmlIntoRange} methods. | |
1922 | * | |
1923 | * @since 4.5 | |
1924 | * @event afterInsertHtml | |
1925 | * @param data | |
1926 | * @param {CKEDITOR.dom.range} [data.intoRange] If set, the HTML was not inserted into the current selection, but into | |
1927 | * the specified range. This property is set if the {@link CKEDITOR.editable#insertHtmlIntoRange} method was used, | |
1928 | * but not if for the {@link CKEDITOR.editable#insertHtml} method. | |
1929 | */ | |
1930 | ||
1931 | /** | |
1932 | * Event fired after the {@link #property-readOnly} property changes. | |
1933 | * | |
1934 | * @since 3.6 | |
1935 | * @event readOnly | |
1936 | * @param {CKEDITOR.editor} editor This editor instance. | |
1937 | */ | |
1938 | ||
1939 | /** | |
1940 | * Event fired when a UI template is added to the editor instance. It makes | |
1941 | * it possible to bring customizations to the template source. | |
1942 | * | |
1943 | * @event template | |
1944 | * @param {CKEDITOR.editor} editor This editor instance. | |
1945 | * @param data | |
1946 | * @param {String} data.name The template name. | |
1947 | * @param {String} data.source The source data for this template. | |
1948 | */ | |
1949 | ||
1950 | /** | |
1951 | * Event fired when the editor content (its DOM structure) is ready. | |
1952 | * It is similar to the native `DOMContentLoaded` event, but it applies to | |
1953 | * the editor content. It is also the first event fired after | |
1954 | * the {@link CKEDITOR.editable} is initialized. | |
1955 | * | |
1956 | * This event is particularly important for classic (`iframe`-based) | |
1957 | * editor, because on editor initialization and every time the data are set | |
1958 | * (by {@link CKEDITOR.editor#method-setData}) content DOM structure | |
1959 | * is rebuilt. Thus, e.g. you need to attach DOM event listeners | |
1960 | * on editable one more time. | |
1961 | * | |
1962 | * For inline editor this event is fired only once — when the | |
1963 | * editor is initialized for the first time. This is because setting | |
1964 | * editor content does not cause editable destruction and creation. | |
1965 | * | |
1966 | * The {@link #contentDom} event goes along with {@link #contentDomUnload} | |
1967 | * which is fired before the content DOM structure is destroyed. This is the | |
1968 | * right moment to detach content DOM event listener. Otherwise | |
1969 | * browsers like IE or Opera may throw exceptions when accessing | |
1970 | * elements from the detached document. | |
1971 | * | |
1972 | * **Note:** {@link CKEDITOR.editable#attachListener} is a convenient | |
1973 | * way to attach listeners that will be detached on {@link #contentDomUnload}. | |
1974 | * | |
1975 | * editor.on( 'contentDom', function() { | |
1976 | * var editable = editor.editable(); | |
1977 | * | |
1978 | * editable.attachListener( editable, 'click', function() { | |
1979 | * console.log( 'The editable was clicked.' ); | |
1980 | * }); | |
1981 | * }); | |
1982 | * | |
1983 | * @event contentDom | |
1984 | * @param {CKEDITOR.editor} editor This editor instance. | |
1985 | */ | |
1986 | ||
1987 | /** | |
1988 | * Event fired before the content DOM structure is destroyed. | |
1989 | * See {@link #contentDom} documentation for more details. | |
1990 | * | |
1991 | * @event contentDomUnload | |
1992 | * @param {CKEDITOR.editor} editor This editor instance. | |
1993 | */ | |
1994 | ||
1995 | /** | |
1996 | * Event fired when the content DOM changes and some of the references as well as | |
1997 | * the native DOM event listeners could be lost. | |
1998 | * This event is useful when it is important to keep track of references | |
1999 | * to elements in the editable content from code. | |
2000 | * | |
2001 | * @since 4.3 | |
2002 | * @event contentDomInvalidated | |
2003 | * @param {CKEDITOR.editor} editor This editor instance. | |
2004 | */ |