diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2017-01-20 00:55:51 +0100 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2017-01-20 00:55:51 +0100 |
commit | c63493c899de714b05b0521bb38aab60d19030ef (patch) | |
tree | fcb2b261afa0f3c2bd6b48929b64724c71192bae /sources/core/editor.js | |
download | ludivine-ckeditor-component-c63493c899de714b05b0521bb38aab60d19030ef.tar.gz ludivine-ckeditor-component-c63493c899de714b05b0521bb38aab60d19030ef.tar.zst ludivine-ckeditor-component-c63493c899de714b05b0521bb38aab60d19030ef.zip |
Validation initiale4.6.2.1
Diffstat (limited to 'sources/core/editor.js')
-rw-r--r-- | sources/core/editor.js | 2039 |
1 files changed, 2039 insertions, 0 deletions
diff --git a/sources/core/editor.js b/sources/core/editor.js new file mode 100644 index 0000000..8dfce7f --- /dev/null +++ b/sources/core/editor.js | |||
@@ -0,0 +1,2039 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, 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 | * Returns the keystroke that is assigned to a specified {@link CKEDITOR.command}. If no keystroke is assigned, | ||
1328 | * it returns null. | ||
1329 | * | ||
1330 | * @since 4.6.0 | ||
1331 | * @param {CKEDITOR.command} command | ||
1332 | * @returns {Number} The keystroke assigned to the provided command or null if there is no keystroke. | ||
1333 | */ | ||
1334 | getCommandKeystroke: function( command ) { | ||
1335 | var commandName = command.name, | ||
1336 | keystrokes = this.keystrokeHandler.keystrokes, | ||
1337 | key; | ||
1338 | |||
1339 | // Some commands have a fake keystroke - for example CUT/COPY/PASTE commands are handled natively. | ||
1340 | if ( command.fakeKeystroke ) { | ||
1341 | return command.fakeKeystroke; | ||
1342 | } | ||
1343 | |||
1344 | for ( key in keystrokes ) { | ||
1345 | if ( keystrokes.hasOwnProperty( key ) && keystrokes[ key ] == commandName ) { | ||
1346 | return key; | ||
1347 | } | ||
1348 | } | ||
1349 | |||
1350 | return null; | ||
1351 | }, | ||
1352 | |||
1353 | /** | ||
1354 | * Shorthand for {@link CKEDITOR.filter#addFeature}. | ||
1355 | * | ||
1356 | * @since 4.1 | ||
1357 | * @param {CKEDITOR.feature} feature See {@link CKEDITOR.filter#addFeature}. | ||
1358 | * @returns {Boolean} See {@link CKEDITOR.filter#addFeature}. | ||
1359 | */ | ||
1360 | addFeature: function( feature ) { | ||
1361 | return this.filter.addFeature( feature ); | ||
1362 | }, | ||
1363 | |||
1364 | /** | ||
1365 | * Sets the active filter ({@link #activeFilter}). Fires the {@link #activeFilterChange} event. | ||
1366 | * | ||
1367 | * // Set active filter which allows only 4 elements. | ||
1368 | * // Buttons like Bold, Italic will be disabled. | ||
1369 | * var filter = new CKEDITOR.filter( 'p strong em br' ); | ||
1370 | * editor.setActiveFilter( filter ); | ||
1371 | * | ||
1372 | * Setting a new filter will also change the {@link #setActiveEnterMode active Enter modes} to the first values | ||
1373 | * allowed by the new filter (see {@link CKEDITOR.filter#getAllowedEnterMode}). | ||
1374 | * | ||
1375 | * @since 4.3 | ||
1376 | * @param {CKEDITOR.filter} filter Filter instance or a falsy value (e.g. `null`) to reset to the default one. | ||
1377 | */ | ||
1378 | setActiveFilter: function( filter ) { | ||
1379 | if ( !filter ) | ||
1380 | filter = this.filter; | ||
1381 | |||
1382 | if ( this.activeFilter !== filter ) { | ||
1383 | this.activeFilter = filter; | ||
1384 | this.fire( 'activeFilterChange' ); | ||
1385 | |||
1386 | // Reset active filter to the main one - it resets enter modes, too. | ||
1387 | if ( filter === this.filter ) | ||
1388 | this.setActiveEnterMode( null, null ); | ||
1389 | else | ||
1390 | this.setActiveEnterMode( | ||
1391 | filter.getAllowedEnterMode( this.enterMode ), | ||
1392 | filter.getAllowedEnterMode( this.shiftEnterMode, true ) | ||
1393 | ); | ||
1394 | } | ||
1395 | }, | ||
1396 | |||
1397 | /** | ||
1398 | * Sets the active Enter modes: ({@link #enterMode} and {@link #shiftEnterMode}). | ||
1399 | * Fires the {@link #activeEnterModeChange} event. | ||
1400 | * | ||
1401 | * Prior to CKEditor 4.3 Enter modes were static and it was enough to check {@link CKEDITOR.config#enterMode} | ||
1402 | * and {@link CKEDITOR.config#shiftEnterMode} when implementing a feature which should depend on the Enter modes. | ||
1403 | * Since CKEditor 4.3 these options are source of initial: | ||
1404 | * | ||
1405 | * * static {@link #enterMode} and {@link #shiftEnterMode} values, | ||
1406 | * * dynamic {@link #activeEnterMode} and {@link #activeShiftEnterMode} values. | ||
1407 | * | ||
1408 | * However, the dynamic Enter modes can be changed during runtime by using this method, to reflect the selection context. | ||
1409 | * For example, if selection is moved to the {@link CKEDITOR.plugins.widget widget}'s nested editable which | ||
1410 | * is a {@link #blockless blockless one}, then the active Enter modes should be changed to {@link CKEDITOR#ENTER_BR} | ||
1411 | * (in this case [Widget System](#!/guide/dev_widgets) takes care of that). | ||
1412 | * | ||
1413 | * **Note:** This method should not be used to configure the editor – use {@link CKEDITOR.config#enterMode} and | ||
1414 | * {@link CKEDITOR.config#shiftEnterMode} instead. This method should only be used to dynamically change | ||
1415 | * Enter modes during runtime based on selection changes. | ||
1416 | * Keep in mind that changed Enter mode may be overwritten by another plugin/feature when it decided that | ||
1417 | * the changed context requires this. | ||
1418 | * | ||
1419 | * **Note:** In case of blockless editor (inline editor based on an element which cannot contain block elements | ||
1420 | * — see {@link CKEDITOR.editor#blockless}) only {@link CKEDITOR#ENTER_BR} is a valid Enter mode. Therefore | ||
1421 | * this method will not allow to set other values. | ||
1422 | * | ||
1423 | * **Note:** Changing the {@link #activeFilter active filter} may cause the Enter mode to change if default Enter modes | ||
1424 | * are not allowed by the new filter. | ||
1425 | * | ||
1426 | * @since 4.3 | ||
1427 | * @param {Number} enterMode One of {@link CKEDITOR#ENTER_P}, {@link CKEDITOR#ENTER_DIV}, {@link CKEDITOR#ENTER_BR}. | ||
1428 | * Pass falsy value (e.g. `null`) to reset the Enter mode to the default value ({@link #enterMode} and/or {@link #shiftEnterMode}). | ||
1429 | * @param {Number} shiftEnterMode See the `enterMode` argument. | ||
1430 | */ | ||
1431 | setActiveEnterMode: function( enterMode, shiftEnterMode ) { | ||
1432 | // Validate passed modes or use default ones (validated on init). | ||
1433 | enterMode = enterMode ? validateEnterMode( this, enterMode ) : this.enterMode; | ||
1434 | shiftEnterMode = shiftEnterMode ? validateEnterMode( this, shiftEnterMode ) : this.shiftEnterMode; | ||
1435 | |||
1436 | if ( this.activeEnterMode != enterMode || this.activeShiftEnterMode != shiftEnterMode ) { | ||
1437 | this.activeEnterMode = enterMode; | ||
1438 | this.activeShiftEnterMode = shiftEnterMode; | ||
1439 | this.fire( 'activeEnterModeChange' ); | ||
1440 | } | ||
1441 | }, | ||
1442 | |||
1443 | /** | ||
1444 | * Shows a notification to the user. | ||
1445 | * | ||
1446 | * If the [Notification](http://ckeditor.com/addons/notification) plugin is not enabled, this function shows | ||
1447 | * a normal alert with the given `message`. The `type` and `progressOrDuration` parameters are supported | ||
1448 | * only by the Notification plugin. | ||
1449 | * | ||
1450 | * If the Notification plugin is enabled, this method creates and shows a new notification. | ||
1451 | * By default the notification is shown over the editor content, in the viewport if it is possible. | ||
1452 | * | ||
1453 | * See {@link CKEDITOR.plugins.notification}. | ||
1454 | * | ||
1455 | * @since 4.5 | ||
1456 | * @member CKEDITOR.editor | ||
1457 | * @param {String} message The message displayed in the notification. | ||
1458 | * @param {String} [type='info'] The type of the notification. Can be `'info'`, `'warning'`, `'success'` or `'progress'`. | ||
1459 | * @param {Number} [progressOrDuration] If the type is `progress`, the third parameter may be a progress from `0` to `1` | ||
1460 | * (defaults to `0`). Otherwise the third parameter may be a notification duration denoting after how many milliseconds | ||
1461 | * the notification should be closed automatically. `0` means that the notification will not close automatically and the user | ||
1462 | * needs to close it manually. See {@link CKEDITOR.plugins.notification#duration}. | ||
1463 | * Note that `warning` notifications will not be closed automatically. | ||
1464 | * @returns {CKEDITOR.plugins.notification} Created and shown notification. | ||
1465 | */ | ||
1466 | showNotification: function( message ) { | ||
1467 | alert( message ); // jshint ignore:line | ||
1468 | } | ||
1469 | } ); | ||
1470 | } )(); | ||
1471 | |||
1472 | /** | ||
1473 | * The editor has no associated element. | ||
1474 | * | ||
1475 | * @readonly | ||
1476 | * @property {Number} [=0] | ||
1477 | * @member CKEDITOR | ||
1478 | */ | ||
1479 | CKEDITOR.ELEMENT_MODE_NONE = 0; | ||
1480 | |||
1481 | /** | ||
1482 | * The element is to be replaced by the editor instance. | ||
1483 | * | ||
1484 | * @readonly | ||
1485 | * @property {Number} [=1] | ||
1486 | * @member CKEDITOR | ||
1487 | */ | ||
1488 | CKEDITOR.ELEMENT_MODE_REPLACE = 1; | ||
1489 | |||
1490 | /** | ||
1491 | * The editor is to be created inside the element. | ||
1492 | * | ||
1493 | * @readonly | ||
1494 | * @property {Number} [=2] | ||
1495 | * @member CKEDITOR | ||
1496 | */ | ||
1497 | CKEDITOR.ELEMENT_MODE_APPENDTO = 2; | ||
1498 | |||
1499 | /** | ||
1500 | * The editor is to be attached to the element, using it as the editing block. | ||
1501 | * | ||
1502 | * @readonly | ||
1503 | * @property {Number} [=3] | ||
1504 | * @member CKEDITOR | ||
1505 | */ | ||
1506 | CKEDITOR.ELEMENT_MODE_INLINE = 3; | ||
1507 | |||
1508 | /** | ||
1509 | * Whether to escape HTML when the editor updates the original input element. | ||
1510 | * | ||
1511 | * config.htmlEncodeOutput = true; | ||
1512 | * | ||
1513 | * @since 3.1 | ||
1514 | * @cfg {Boolean} [htmlEncodeOutput=false] | ||
1515 | * @member CKEDITOR.config | ||
1516 | */ | ||
1517 | |||
1518 | /** | ||
1519 | * If `true`, makes the editor start in read-only state. Otherwise, it will check | ||
1520 | * if the linked `<textarea>` element has the `disabled` attribute. | ||
1521 | * | ||
1522 | * Read more in the [documentation](#!/guide/dev_readonly) | ||
1523 | * and see the [SDK sample](http://sdk.ckeditor.com/samples/readonly.html). | ||
1524 | * | ||
1525 | * config.readOnly = true; | ||
1526 | * | ||
1527 | * @since 3.6 | ||
1528 | * @cfg {Boolean} [readOnly=false] | ||
1529 | * @member CKEDITOR.config | ||
1530 | * @see CKEDITOR.editor#setReadOnly | ||
1531 | */ | ||
1532 | |||
1533 | /** | ||
1534 | * Whether an editable element should have focus when the editor is loading for the first time. | ||
1535 | * | ||
1536 | * config.startupFocus = true; | ||
1537 | * | ||
1538 | * @cfg {Boolean} [startupFocus=false] | ||
1539 | * @member CKEDITOR.config | ||
1540 | */ | ||
1541 | |||
1542 | /** | ||
1543 | * Customizes the {@link CKEDITOR.editor#title human-readable title} of this editor. This title is displayed in | ||
1544 | * tooltips and impacts various [accessibility aspects](#!/guide/dev_a11y-section-announcing-the-editor-on-the-page), | ||
1545 | * e.g. it is commonly used by screen readers for distinguishing editor instances and for navigation. | ||
1546 | * Accepted values are a string or `false`. | ||
1547 | * | ||
1548 | * **Note:** When `config.title` is set globally, the same value will be applied to all editor instances | ||
1549 | * loaded with this config. This may adversely affect accessibility as screen reader users will be unable | ||
1550 | * to distinguish particular editor instances and navigate between them. | ||
1551 | * | ||
1552 | * **Note:** Setting `config.title = false` may also impair accessibility in a similar way. | ||
1553 | * | ||
1554 | * **Note:** Please do not confuse this property with {@link CKEDITOR.editor#name} | ||
1555 | * which identifies the instance in the {@link CKEDITOR#instances} literal. | ||
1556 | * | ||
1557 | * // Sets the title to 'My WYSIWYG editor.'. The original title of the element (if it exists) | ||
1558 | * // will be restored once the editor instance is destroyed. | ||
1559 | * config.title = 'My WYSIWYG editor.'; | ||
1560 | * | ||
1561 | * // Do not touch the title. If the element already has a title, it remains unchanged. | ||
1562 | * // Also if no `title` attribute exists, nothing new will be added. | ||
1563 | * config.title = false; | ||
1564 | * | ||
1565 | * See also: | ||
1566 | * | ||
1567 | * * CKEDITOR.editor#name | ||
1568 | * * CKEDITOR.editor#title | ||
1569 | * | ||
1570 | * @since 4.2 | ||
1571 | * @cfg {String/Boolean} [title=based on editor.name] | ||
1572 | * @member CKEDITOR.config | ||
1573 | */ | ||
1574 | |||
1575 | /** | ||
1576 | * Sets listeners on editor events. | ||
1577 | * | ||
1578 | * **Note:** This property can only be set in the `config` object passed directly | ||
1579 | * to {@link CKEDITOR#replace}, {@link CKEDITOR#inline}, and other creators. | ||
1580 | * | ||
1581 | * CKEDITOR.replace( 'editor1', { | ||
1582 | * on: { | ||
1583 | * instanceReady: function() { | ||
1584 | * alert( this.name ); // 'editor1' | ||
1585 | * }, | ||
1586 | * | ||
1587 | * key: function() { | ||
1588 | * // ... | ||
1589 | * } | ||
1590 | * } | ||
1591 | * } ); | ||
1592 | * | ||
1593 | * @cfg {Object} on | ||
1594 | * @member CKEDITOR.config | ||
1595 | */ | ||
1596 | |||
1597 | /** | ||
1598 | * The outermost element in the DOM tree in which the editable element resides. It is provided | ||
1599 | * by a specific editor creator after the editor UI is created and is not intended to | ||
1600 | * be modified. | ||
1601 | * | ||
1602 | * var editor = CKEDITOR.instances.editor1; | ||
1603 | * alert( editor.container.getName() ); // 'span' | ||
1604 | * | ||
1605 | * @readonly | ||
1606 | * @property {CKEDITOR.dom.element} container | ||
1607 | */ | ||
1608 | |||
1609 | /** | ||
1610 | * The document that stores the editor content. | ||
1611 | * | ||
1612 | * * For the classic (`iframe`-based) editor it is equal to the document inside the | ||
1613 | * `iframe` containing the editable element. | ||
1614 | * * For the inline editor it is equal to {@link CKEDITOR#document}. | ||
1615 | * | ||
1616 | * The document object is available after the {@link #contentDom} event is fired | ||
1617 | * and may be invalidated when the {@link #contentDomUnload} event is fired | ||
1618 | * (classic editor only). | ||
1619 | * | ||
1620 | * editor.on( 'contentDom', function() { | ||
1621 | * console.log( editor.document ); | ||
1622 | * } ); | ||
1623 | * | ||
1624 | * @readonly | ||
1625 | * @property {CKEDITOR.dom.document} document | ||
1626 | */ | ||
1627 | |||
1628 | /** | ||
1629 | * The window instance related to the {@link #document} property. | ||
1630 | * | ||
1631 | * It is always equal to the `editor.document.getWindow()`. | ||
1632 | * | ||
1633 | * See the {@link #document} property documentation. | ||
1634 | * | ||
1635 | * @readonly | ||
1636 | * @property {CKEDITOR.dom.window} window | ||
1637 | */ | ||
1638 | |||
1639 | /** | ||
1640 | * The main filter instance used for input data filtering, data | ||
1641 | * transformations, and activation of features. | ||
1642 | * | ||
1643 | * It points to a {@link CKEDITOR.filter} instance set up based on | ||
1644 | * editor configuration. | ||
1645 | * | ||
1646 | * @since 4.1 | ||
1647 | * @readonly | ||
1648 | * @property {CKEDITOR.filter} filter | ||
1649 | */ | ||
1650 | |||
1651 | /** | ||
1652 | * The active filter instance which should be used in the current context (location selection). | ||
1653 | * This instance will be used to make a decision which commands, buttons and other | ||
1654 | * {@link CKEDITOR.feature features} can be enabled. | ||
1655 | * | ||
1656 | * By default it equals the {@link #filter} and it can be changed by the {@link #setActiveFilter} method. | ||
1657 | * | ||
1658 | * editor.on( 'activeFilterChange', function() { | ||
1659 | * if ( editor.activeFilter.check( 'cite' ) ) | ||
1660 | * // Do something when <cite> was enabled - e.g. enable a button. | ||
1661 | * else | ||
1662 | * // Otherwise do something else. | ||
1663 | * } ); | ||
1664 | * | ||
1665 | * See also the {@link #setActiveEnterMode} method for an explanation of dynamic settings. | ||
1666 | * | ||
1667 | * @since 4.3 | ||
1668 | * @readonly | ||
1669 | * @property {CKEDITOR.filter} activeFilter | ||
1670 | */ | ||
1671 | |||
1672 | /** | ||
1673 | * The main (static) Enter mode which is a validated version of the {@link CKEDITOR.config#enterMode} setting. | ||
1674 | * Currently only one rule exists — {@link #blockless blockless editors} may have | ||
1675 | * Enter modes set only to {@link CKEDITOR#ENTER_BR}. | ||
1676 | * | ||
1677 | * @since 4.3 | ||
1678 | * @readonly | ||
1679 | * @property {Number} enterMode | ||
1680 | */ | ||
1681 | |||
1682 | /** | ||
1683 | * See the {@link #enterMode} property. | ||
1684 | * | ||
1685 | * @since 4.3 | ||
1686 | * @readonly | ||
1687 | * @property {Number} shiftEnterMode | ||
1688 | */ | ||
1689 | |||
1690 | /** | ||
1691 | * The dynamic Enter mode which should be used in the current context (selection location). | ||
1692 | * By default it equals the {@link #enterMode} and it can be changed by the {@link #setActiveEnterMode} method. | ||
1693 | * | ||
1694 | * See also the {@link #setActiveEnterMode} method for an explanation of dynamic settings. | ||
1695 | * | ||
1696 | * @since 4.3 | ||
1697 | * @readonly | ||
1698 | * @property {Number} activeEnterMode | ||
1699 | */ | ||
1700 | |||
1701 | /** | ||
1702 | * See the {@link #activeEnterMode} property. | ||
1703 | * | ||
1704 | * @since 4.3 | ||
1705 | * @readonly | ||
1706 | * @property {Number} activeShiftEnterMode | ||
1707 | */ | ||
1708 | |||
1709 | /** | ||
1710 | * Event fired by the {@link #setActiveFilter} method when the {@link #activeFilter} is changed. | ||
1711 | * | ||
1712 | * @since 4.3 | ||
1713 | * @event activeFilterChange | ||
1714 | */ | ||
1715 | |||
1716 | /** | ||
1717 | * Event fired by the {@link #setActiveEnterMode} method when any of the active Enter modes is changed. | ||
1718 | * See also the {@link #activeEnterMode} and {@link #activeShiftEnterMode} properties. | ||
1719 | * | ||
1720 | * @since 4.3 | ||
1721 | * @event activeEnterModeChange | ||
1722 | */ | ||
1723 | |||
1724 | /** | ||
1725 | * Event fired when a CKEDITOR instance is created, but still before initializing it. | ||
1726 | * To interact with a fully initialized instance, use the | ||
1727 | * {@link CKEDITOR#instanceReady} event instead. | ||
1728 | * | ||
1729 | * @event instanceCreated | ||
1730 | * @member CKEDITOR | ||
1731 | * @param {CKEDITOR.editor} editor The editor instance that has been created. | ||
1732 | */ | ||
1733 | |||
1734 | /** | ||
1735 | * Event fired when CKEDITOR instance's components (configuration, languages and plugins) are fully | ||
1736 | * loaded and initialized. However, the editor will be fully ready for interaction | ||
1737 | * on {@link CKEDITOR#instanceReady}. | ||
1738 | * | ||
1739 | * @event instanceLoaded | ||
1740 | * @member CKEDITOR | ||
1741 | * @param {CKEDITOR.editor} editor This editor instance that has been loaded. | ||
1742 | */ | ||
1743 | |||
1744 | /** | ||
1745 | * Event fired when a CKEDITOR instance is destroyed. | ||
1746 | * | ||
1747 | * @event instanceDestroyed | ||
1748 | * @member CKEDITOR | ||
1749 | * @param {CKEDITOR.editor} editor The editor instance that has been destroyed. | ||
1750 | */ | ||
1751 | |||
1752 | /** | ||
1753 | * Event fired when a CKEDITOR instance is created, fully initialized and ready for interaction. | ||
1754 | * | ||
1755 | * @event instanceReady | ||
1756 | * @member CKEDITOR | ||
1757 | * @param {CKEDITOR.editor} editor The editor instance that has been created. | ||
1758 | */ | ||
1759 | |||
1760 | /** | ||
1761 | * Event fired when the language is loaded into the editor instance. | ||
1762 | * | ||
1763 | * @since 3.6.1 | ||
1764 | * @event langLoaded | ||
1765 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1766 | */ | ||
1767 | |||
1768 | /** | ||
1769 | * Event fired when all plugins are loaded and initialized into the editor instance. | ||
1770 | * | ||
1771 | * @event pluginsLoaded | ||
1772 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1773 | */ | ||
1774 | |||
1775 | /** | ||
1776 | * Event fired when the styles set is loaded. During the editor initialization | ||
1777 | * phase the {@link #getStylesSet} method returns only styles that | ||
1778 | * are already loaded, which may not include e.g. styles parsed | ||
1779 | * by the `stylesheetparser` plugin. Thus, to be notified when all | ||
1780 | * styles are ready, you can listen on this event. | ||
1781 | * | ||
1782 | * @since 4.1 | ||
1783 | * @event stylesSet | ||
1784 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1785 | * @param {Array} styles An array of styles definitions. | ||
1786 | */ | ||
1787 | |||
1788 | /** | ||
1789 | * Event fired before the command execution when {@link #execCommand} is called. | ||
1790 | * | ||
1791 | * @event beforeCommandExec | ||
1792 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1793 | * @param data | ||
1794 | * @param {String} data.name The command name. | ||
1795 | * @param {Object} data.commandData The data to be sent to the command. This | ||
1796 | * can be manipulated by the event listener. | ||
1797 | * @param {CKEDITOR.command} data.command The command itself. | ||
1798 | */ | ||
1799 | |||
1800 | /** | ||
1801 | * Event fired after the command execution when {@link #execCommand} is called. | ||
1802 | * | ||
1803 | * @event afterCommandExec | ||
1804 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1805 | * @param data | ||
1806 | * @param {String} data.name The command name. | ||
1807 | * @param {Object} data.commandData The data sent to the command. | ||
1808 | * @param {CKEDITOR.command} data.command The command itself. | ||
1809 | * @param {Object} data.returnValue The value returned by the command execution. | ||
1810 | */ | ||
1811 | |||
1812 | /** | ||
1813 | * Event fired when a custom configuration file is loaded, before the final | ||
1814 | * configuration initialization. | ||
1815 | * | ||
1816 | * Custom configuration files can be loaded thorugh the | ||
1817 | * {@link CKEDITOR.config#customConfig} setting. Several files can be loaded | ||
1818 | * by changing this setting. | ||
1819 | * | ||
1820 | * @event customConfigLoaded | ||
1821 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1822 | */ | ||
1823 | |||
1824 | /** | ||
1825 | * Event fired once the editor configuration is ready (loaded and processed). | ||
1826 | * | ||
1827 | * @event configLoaded | ||
1828 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1829 | */ | ||
1830 | |||
1831 | /** | ||
1832 | * Event fired when this editor instance is destroyed. The editor at this | ||
1833 | * point is not usable and this event should be used to perform the clean-up | ||
1834 | * in any plugin. | ||
1835 | * | ||
1836 | * @event destroy | ||
1837 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1838 | */ | ||
1839 | |||
1840 | /** | ||
1841 | * Event fired when the {@link #method-destroy} method is called, | ||
1842 | * but before destroying the editor. | ||
1843 | * | ||
1844 | * @event beforeDestroy | ||
1845 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1846 | */ | ||
1847 | |||
1848 | /** | ||
1849 | * Internal event to get the current data. | ||
1850 | * | ||
1851 | * @event beforeGetData | ||
1852 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1853 | */ | ||
1854 | |||
1855 | /** | ||
1856 | * Internal event to perform the {@link #method-getSnapshot} call. | ||
1857 | * | ||
1858 | * @event getSnapshot | ||
1859 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1860 | */ | ||
1861 | |||
1862 | /** | ||
1863 | * Internal event to perform the {@link #method-loadSnapshot} call. | ||
1864 | * | ||
1865 | * @event loadSnapshot | ||
1866 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1867 | * @param {String} data The data that will be used. | ||
1868 | */ | ||
1869 | |||
1870 | /** | ||
1871 | * Event fired before the {@link #method-getData} call returns, allowing for additional manipulation. | ||
1872 | * | ||
1873 | * @event getData | ||
1874 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1875 | * @param data | ||
1876 | * @param {String} data.dataValue The data that will be returned. | ||
1877 | */ | ||
1878 | |||
1879 | /** | ||
1880 | * Event fired before the {@link #method-setData} call is executed, allowing for additional manipulation. | ||
1881 | * | ||
1882 | * @event setData | ||
1883 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1884 | * @param data | ||
1885 | * @param {String} data.dataValue The data that will be used. | ||
1886 | */ | ||
1887 | |||
1888 | /** | ||
1889 | * Event fired at the end of the {@link #method-setData} call execution. Usually it is better to use the | ||
1890 | * {@link #dataReady} event. | ||
1891 | * | ||
1892 | * @event afterSetData | ||
1893 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1894 | * @param data | ||
1895 | * @param {String} data.dataValue The data that has been set. | ||
1896 | */ | ||
1897 | |||
1898 | /** | ||
1899 | * Event fired as an indicator of the editor data loading. It may be the result of | ||
1900 | * calling {@link #method-setData} explicitly or an internal | ||
1901 | * editor function, like the editor editing mode switching (move to Source and back). | ||
1902 | * | ||
1903 | * @event dataReady | ||
1904 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1905 | */ | ||
1906 | |||
1907 | /** | ||
1908 | * Event fired when the CKEDITOR instance is completely created, fully initialized | ||
1909 | * and ready for interaction. | ||
1910 | * | ||
1911 | * @event instanceReady | ||
1912 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1913 | */ | ||
1914 | |||
1915 | /** | ||
1916 | * Event fired when editor components (configuration, languages and plugins) are fully | ||
1917 | * loaded and initialized. However, the editor will be fully ready to for interaction | ||
1918 | * on {@link #instanceReady}. | ||
1919 | * | ||
1920 | * @event loaded | ||
1921 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1922 | */ | ||
1923 | |||
1924 | /** | ||
1925 | * Event fired by the {@link #method-insertHtml} method. See the method documentation for more information | ||
1926 | * about how this event can be used. | ||
1927 | * | ||
1928 | * @event insertHtml | ||
1929 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1930 | * @param data | ||
1931 | * @param {String} data.mode The mode in which the data is inserted (see {@link #method-insertHtml}). | ||
1932 | * @param {String} data.dataValue The HTML code to insert. | ||
1933 | * @param {CKEDITOR.dom.range} [data.range] See {@link #method-insertHtml}'s `range` parameter. | ||
1934 | */ | ||
1935 | |||
1936 | /** | ||
1937 | * Event fired by the {@link #method-insertText} method. See the method documentation for more information | ||
1938 | * about how this event can be used. | ||
1939 | * | ||
1940 | * @event insertText | ||
1941 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1942 | * @param {String} data The text to insert. | ||
1943 | */ | ||
1944 | |||
1945 | /** | ||
1946 | * Event fired by the {@link #method-insertElement} method. See the method documentation for more information | ||
1947 | * about how this event can be used. | ||
1948 | * | ||
1949 | * @event insertElement | ||
1950 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1951 | * @param {CKEDITOR.dom.element} data The element to insert. | ||
1952 | */ | ||
1953 | |||
1954 | /** | ||
1955 | * Event fired after data insertion using the {@link #method-insertHtml}, {@link CKEDITOR.editable#insertHtml}, | ||
1956 | * or {@link CKEDITOR.editable#insertHtmlIntoRange} methods. | ||
1957 | * | ||
1958 | * @since 4.5 | ||
1959 | * @event afterInsertHtml | ||
1960 | * @param data | ||
1961 | * @param {CKEDITOR.dom.range} [data.intoRange] If set, the HTML was not inserted into the current selection, but into | ||
1962 | * the specified range. This property is set if the {@link CKEDITOR.editable#insertHtmlIntoRange} method was used, | ||
1963 | * but not if for the {@link CKEDITOR.editable#insertHtml} method. | ||
1964 | */ | ||
1965 | |||
1966 | /** | ||
1967 | * Event fired after the {@link #property-readOnly} property changes. | ||
1968 | * | ||
1969 | * @since 3.6 | ||
1970 | * @event readOnly | ||
1971 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1972 | */ | ||
1973 | |||
1974 | /** | ||
1975 | * Event fired when a UI template is added to the editor instance. It makes | ||
1976 | * it possible to bring customizations to the template source. | ||
1977 | * | ||
1978 | * @event template | ||
1979 | * @param {CKEDITOR.editor} editor This editor instance. | ||
1980 | * @param data | ||
1981 | * @param {String} data.name The template name. | ||
1982 | * @param {String} data.source The source data for this template. | ||
1983 | */ | ||
1984 | |||
1985 | /** | ||
1986 | * Event fired when the editor content (its DOM structure) is ready. | ||
1987 | * It is similar to the native `DOMContentLoaded` event, but it applies to | ||
1988 | * the editor content. It is also the first event fired after | ||
1989 | * the {@link CKEDITOR.editable} is initialized. | ||
1990 | * | ||
1991 | * This event is particularly important for classic (`iframe`-based) | ||
1992 | * editor, because on editor initialization and every time the data are set | ||
1993 | * (by {@link CKEDITOR.editor#method-setData}) content DOM structure | ||
1994 | * is rebuilt. Thus, e.g. you need to attach DOM event listeners | ||
1995 | * on editable one more time. | ||
1996 | * | ||
1997 | * For inline editor this event is fired only once — when the | ||
1998 | * editor is initialized for the first time. This is because setting | ||
1999 | * editor content does not cause editable destruction and creation. | ||
2000 | * | ||
2001 | * The {@link #contentDom} event goes along with {@link #contentDomUnload} | ||
2002 | * which is fired before the content DOM structure is destroyed. This is the | ||
2003 | * right moment to detach content DOM event listener. Otherwise | ||
2004 | * browsers like IE or Opera may throw exceptions when accessing | ||
2005 | * elements from the detached document. | ||
2006 | * | ||
2007 | * **Note:** {@link CKEDITOR.editable#attachListener} is a convenient | ||
2008 | * way to attach listeners that will be detached on {@link #contentDomUnload}. | ||
2009 | * | ||
2010 | * editor.on( 'contentDom', function() { | ||
2011 | * var editable = editor.editable(); | ||
2012 | * | ||
2013 | * editable.attachListener( editable, 'click', function() { | ||
2014 | * console.log( 'The editable was clicked.' ); | ||
2015 | * }); | ||
2016 | * }); | ||
2017 | * | ||
2018 | * @event contentDom | ||
2019 | * @param {CKEDITOR.editor} editor This editor instance. | ||
2020 | */ | ||
2021 | |||
2022 | /** | ||
2023 | * Event fired before the content DOM structure is destroyed. | ||
2024 | * See {@link #contentDom} documentation for more details. | ||
2025 | * | ||
2026 | * @event contentDomUnload | ||
2027 | * @param {CKEDITOR.editor} editor This editor instance. | ||
2028 | */ | ||
2029 | |||
2030 | /** | ||
2031 | * Event fired when the content DOM changes and some of the references as well as | ||
2032 | * the native DOM event listeners could be lost. | ||
2033 | * This event is useful when it is important to keep track of references | ||
2034 | * to elements in the editable content from code. | ||
2035 | * | ||
2036 | * @since 4.3 | ||
2037 | * @event contentDomInvalidated | ||
2038 | * @param {CKEDITOR.editor} editor This editor instance. | ||
2039 | */ | ||