]>
Commit | Line | Data |
---|---|---|
3332bebe | 1 | /** |
317f8f8f | 2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. |
3332bebe IB |
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license |
4 | */ | |
5 | ||
6 | /** @class CKEDITOR */ | |
7 | ||
8 | /** | |
9 | * The class name used to identify `<textarea>` elements to be replaced | |
10 | * by CKEditor instances. Set it to empty/`null` to disable this feature. | |
11 | * | |
12 | * CKEDITOR.replaceClass = 'rich_editor'; | |
13 | * | |
14 | * @cfg {String} [replaceClass='ckeditor'] | |
15 | */ | |
16 | CKEDITOR.replaceClass = 'ckeditor'; | |
17 | ||
18 | ( function() { | |
19 | /** | |
20 | * Replaces a `<textarea>` or a DOM element (`<div>`) with a CKEditor | |
21 | * instance. For textareas, the initial value in the editor will be the | |
22 | * textarea value. For DOM elements, their `innerHTML` will be used | |
317f8f8f | 23 | * instead. It is recommended to use `<textarea>` and `<div>` elements only. |
3332bebe IB |
24 | * |
25 | * <textarea id="myfield" name="myfield"></textarea> | |
26 | * ... | |
27 | * CKEDITOR.replace( 'myfield' ); | |
28 | * | |
29 | * var textarea = document.body.appendChild( document.createElement( 'textarea' ) ); | |
30 | * CKEDITOR.replace( textarea ); | |
31 | * | |
32 | * @param {Object/String} element The DOM element (textarea), its ID, or name. | |
33 | * @param {Object} [config] The specific configuration to apply to this | |
34 | * editor instance. Configuration set here will override the global CKEditor settings | |
35 | * (see {@link CKEDITOR.config}). | |
36 | * @returns {CKEDITOR.editor} The editor instance created. | |
37 | */ | |
38 | CKEDITOR.replace = function( element, config ) { | |
39 | return createInstance( element, config, null, CKEDITOR.ELEMENT_MODE_REPLACE ); | |
40 | }; | |
41 | ||
42 | /** | |
43 | * Creates a new editor instance at the end of a specific DOM element. | |
44 | * | |
45 | * <!DOCTYPE html> | |
46 | * <html> | |
47 | * <head> | |
48 | * <meta charset="utf-8"> | |
49 | * <title>CKEditor</title> | |
50 | * <!-- Make sure the path to CKEditor is correct. --> | |
51 | * <script src="/ckeditor/ckeditor.js"></script> | |
52 | * </head> | |
53 | * <body> | |
54 | * <div id="editorSpace"></div> | |
55 | * <script> | |
56 | * CKEDITOR.appendTo( 'editorSpace' ); | |
57 | * </script> | |
58 | * </body> | |
59 | * </html> | |
60 | * | |
61 | * @param {Object/String} element The DOM element, its ID, or name. | |
62 | * @param {Object} [config] The specific configuration to apply to this | |
63 | * editor instance. Configuration set here will override the global CKEditor settings | |
64 | * (see {@link CKEDITOR.config}). | |
65 | * @param {String} [data] Since 3.3. Initial value for the instance. | |
66 | * @returns {CKEDITOR.editor} The editor instance created. | |
67 | */ | |
68 | CKEDITOR.appendTo = function( element, config, data ) { | |
69 | return createInstance( element, config, data, CKEDITOR.ELEMENT_MODE_APPENDTO ); | |
70 | }; | |
71 | ||
72 | /** | |
73 | * Replaces all `<textarea>` elements available in the document with | |
74 | * editor instances. | |
75 | * | |
76 | * // Replace all <textarea> elements in the page. | |
77 | * CKEDITOR.replaceAll(); | |
78 | * | |
79 | * // Replace all <textarea class="myClassName"> elements in the page. | |
80 | * CKEDITOR.replaceAll( 'myClassName' ); | |
81 | * | |
317f8f8f | 82 | * // Selectively replace <textarea> elements, based on a custom evaluation function. |
3332bebe | 83 | * CKEDITOR.replaceAll( function( textarea, config ) { |
317f8f8f IB |
84 | * // A function that needs to be evaluated for the <textarea> |
85 | * // to be replaced. It must explicitly return "false" to ignore a | |
3332bebe IB |
86 | * // specific <textarea>. |
87 | * // You can also customize the editor instance by having the function | |
88 | * // modify the "config" parameter. | |
89 | * } ); | |
90 | * | |
91 | * // Full page example where three <textarea> elements are replaced. | |
92 | * <!DOCTYPE html> | |
93 | * <html> | |
94 | * <head> | |
95 | * <meta charset="utf-8"> | |
96 | * <title>CKEditor</title> | |
97 | * <!-- Make sure the path to CKEditor is correct. --> | |
98 | * <script src="/ckeditor/ckeditor.js"></script> | |
99 | * </head> | |
100 | * <body> | |
101 | * <textarea name="editor1"></textarea> | |
102 | * <textarea name="editor2"></textarea> | |
103 | * <textarea name="editor3"></textarea> | |
104 | * <script> | |
105 | * // Replace all three <textarea> elements above with CKEditor instances. | |
106 | * CKEDITOR.replaceAll(); | |
107 | * </script> | |
108 | * </body> | |
109 | * </html> | |
110 | * | |
111 | * @param {String} [className] The `<textarea>` class name. | |
317f8f8f | 112 | * @param {Function} [evaluator] An evaluation function that must return `true` for a `<textarea>` |
3332bebe IB |
113 | * to be replaced with the editor. If the function returns `false`, the `<textarea>` element |
114 | * will not be replaced. | |
115 | */ | |
116 | CKEDITOR.replaceAll = function() { | |
117 | var textareas = document.getElementsByTagName( 'textarea' ); | |
118 | ||
119 | for ( var i = 0; i < textareas.length; i++ ) { | |
120 | var config = null, | |
121 | textarea = textareas[ i ]; | |
122 | ||
123 | // The "name" and/or "id" attribute must exist. | |
124 | if ( !textarea.name && !textarea.id ) | |
125 | continue; | |
126 | ||
127 | if ( typeof arguments[ 0 ] == 'string' ) { | |
128 | // The textarea class name could be passed as the function | |
129 | // parameter. | |
130 | ||
131 | var classRegex = new RegExp( '(?:^|\\s)' + arguments[ 0 ] + '(?:$|\\s)' ); | |
132 | ||
133 | if ( !classRegex.test( textarea.className ) ) | |
134 | continue; | |
135 | } else if ( typeof arguments[ 0 ] == 'function' ) { | |
317f8f8f | 136 | // An evaluation function could be passed as the function parameter. |
3332bebe IB |
137 | // It must explicitly return "false" to ignore a specific <textarea>. |
138 | config = {}; | |
139 | if ( arguments[ 0 ]( textarea, config ) === false ) | |
140 | continue; | |
141 | } | |
142 | ||
143 | this.replace( textarea, config ); | |
144 | } | |
145 | }; | |
146 | ||
147 | /** @class CKEDITOR.editor */ | |
148 | ||
149 | /** | |
150 | * Registers an editing mode. This function is to be used mainly by plugins. | |
151 | * | |
152 | * @param {String} mode The mode name. | |
153 | * @param {Function} exec The function that performs the actual mode change. | |
154 | */ | |
155 | CKEDITOR.editor.prototype.addMode = function( mode, exec ) { | |
156 | ( this._.modes || ( this._.modes = {} ) )[ mode ] = exec; | |
157 | }; | |
158 | ||
159 | /** | |
160 | * Changes the editing mode of this editor instance. | |
161 | * | |
162 | * **Note:** The mode switch could be asynchronous depending on the mode provider. | |
163 | * Use the `callback` to hook subsequent code. | |
164 | * | |
165 | * // Switch to "source" view. | |
166 | * CKEDITOR.instances.editor1.setMode( 'source' ); | |
167 | * // Switch to "wysiwyg" view and be notified on completion. | |
168 | * CKEDITOR.instances.editor1.setMode( 'wysiwyg', function() { alert( 'wysiwyg mode loaded!' ); } ); | |
169 | * | |
170 | * @param {String} [newMode] If not specified, the {@link CKEDITOR.config#startupMode} will be used. | |
171 | * @param {Function} [callback] Optional callback function which is invoked once the mode switch has succeeded. | |
172 | */ | |
173 | CKEDITOR.editor.prototype.setMode = function( newMode, callback ) { | |
174 | var editor = this; | |
175 | ||
176 | var modes = this._.modes; | |
177 | ||
178 | // Mode loading quickly fails. | |
179 | if ( newMode == editor.mode || !modes || !modes[ newMode ] ) | |
180 | return; | |
181 | ||
182 | editor.fire( 'beforeSetMode', newMode ); | |
183 | ||
184 | if ( editor.mode ) { | |
185 | var isDirty = editor.checkDirty(), | |
186 | previousModeData = editor._.previousModeData, | |
187 | currentData, | |
188 | unlockSnapshot = 0; | |
189 | ||
190 | editor.fire( 'beforeModeUnload' ); | |
191 | ||
192 | // Detach the current editable. While detaching editable will set | |
193 | // cached editor's data (with internal setData call). We use this | |
194 | // data below to avoid two getData() calls in a row. | |
195 | editor.editable( 0 ); | |
196 | ||
197 | editor._.previousMode = editor.mode; | |
198 | // Get cached data, which was set while detaching editable. | |
199 | editor._.previousModeData = currentData = editor.getData( 1 ); | |
200 | ||
201 | // If data has not been modified in the mode which we are currently leaving, | |
202 | // avoid making snapshot right after initializing new mode. | |
203 | // http://dev.ckeditor.com/ticket/5217#comment:20 | |
204 | // Tested by: | |
205 | // 'test switch mode with unrecoreded, inner HTML specific content (boguses)' | |
206 | // 'test switch mode with unrecoreded, inner HTML specific content (boguses) plus changes in source mode' | |
207 | if ( editor.mode == 'source' && previousModeData == currentData ) { | |
208 | // We need to make sure that unlockSnapshot will update the last snapshot | |
209 | // (will not create new one) if lockSnapshot is not called on outdated snapshots stack. | |
210 | // Additionally, forceUpdate prevents from making content image now, which is useless | |
211 | // (because it equals editor data not inner HTML). | |
212 | editor.fire( 'lockSnapshot', { forceUpdate: true } ); | |
213 | unlockSnapshot = 1; | |
214 | } | |
215 | ||
216 | // Clear up the mode space. | |
217 | editor.ui.space( 'contents' ).setHtml( '' ); | |
218 | ||
219 | editor.mode = ''; | |
220 | } else { | |
221 | editor._.previousModeData = editor.getData( 1 ); | |
222 | } | |
223 | ||
224 | // Fire the mode handler. | |
225 | this._.modes[ newMode ]( function() { | |
226 | // Set the current mode. | |
227 | editor.mode = newMode; | |
228 | ||
229 | if ( isDirty !== undefined ) | |
230 | !isDirty && editor.resetDirty(); | |
231 | ||
232 | if ( unlockSnapshot ) | |
233 | editor.fire( 'unlockSnapshot' ); | |
234 | // Since snapshot made on dataReady (which normally catches changes done by setData) | |
235 | // won't work because editor.mode was not set yet (it's set in this function), we need | |
236 | // to make special snapshot for changes done in source mode here. | |
237 | else if ( newMode == 'wysiwyg' ) | |
238 | editor.fire( 'saveSnapshot' ); | |
239 | ||
240 | // Delay to avoid race conditions (setMode inside setMode). | |
241 | setTimeout( function() { | |
242 | editor.fire( 'mode' ); | |
243 | callback && callback.call( editor ); | |
244 | }, 0 ); | |
245 | } ); | |
246 | }; | |
247 | ||
248 | /** | |
249 | * Resizes the editor interface. | |
250 | * | |
251 | * editor.resize( 900, 300 ); | |
252 | * | |
253 | * editor.resize( '100%', 450, true ); | |
254 | * | |
255 | * @param {Number/String} width The new width. It can be an integer denoting a value | |
256 | * in pixels or a CSS size value with unit. | |
257 | * @param {Number/String} height The new height. It can be an integer denoting a value | |
258 | * in pixels or a CSS size value with unit. | |
259 | * @param {Boolean} [isContentHeight] Indicates that the provided height is to | |
260 | * be applied to the editor content area, and not to the entire editor | |
261 | * interface. Defaults to `false`. | |
262 | * @param {Boolean} [resizeInner] Indicates that it is the inner interface | |
263 | * element that must be resized, not the outer element. The default theme | |
264 | * defines the editor interface inside a pair of `<span>` elements | |
265 | * (`<span><span>...</span></span>`). By default the first, | |
266 | * outer `<span>` element receives the sizes. If this parameter is set to | |
267 | * `true`, the second, inner `<span>` is resized instead. | |
268 | */ | |
269 | CKEDITOR.editor.prototype.resize = function( width, height, isContentHeight, resizeInner ) { | |
270 | var container = this.container, | |
271 | contents = this.ui.space( 'contents' ), | |
272 | contentsFrame = CKEDITOR.env.webkit && this.document && this.document.getWindow().$.frameElement, | |
273 | outer; | |
274 | ||
275 | if ( resizeInner ) { | |
276 | outer = this.container.getFirst( function( node ) { | |
277 | return node.type == CKEDITOR.NODE_ELEMENT && node.hasClass( 'cke_inner' ); | |
278 | } ); | |
279 | } else { | |
280 | outer = container; | |
281 | } | |
282 | ||
317f8f8f | 283 | // Set as border box width. (http://dev.ckeditor.com/ticket/5353) |
3332bebe IB |
284 | outer.setSize( 'width', width, true ); |
285 | ||
317f8f8f | 286 | // WebKit needs to refresh the iframe size to avoid rendering issues. (1/2) (http://dev.ckeditor.com/ticket/8348) |
3332bebe IB |
287 | contentsFrame && ( contentsFrame.style.width = '1%' ); |
288 | ||
289 | // Get the height delta between the outer table and the content area. | |
290 | var contentsOuterDelta = ( outer.$.offsetHeight || 0 ) - ( contents.$.clientHeight || 0 ), | |
291 | ||
292 | // If we're setting the content area's height, then we don't need the delta. | |
293 | resultContentsHeight = Math.max( height - ( isContentHeight ? 0 : contentsOuterDelta ), 0 ), | |
294 | resultOuterHeight = ( isContentHeight ? height + contentsOuterDelta : height ); | |
295 | ||
296 | contents.setStyle( 'height', resultContentsHeight + 'px' ); | |
297 | ||
317f8f8f | 298 | // WebKit needs to refresh the iframe size to avoid rendering issues. (2/2) (http://dev.ckeditor.com/ticket/8348) |
3332bebe IB |
299 | contentsFrame && ( contentsFrame.style.width = '100%' ); |
300 | ||
301 | // Emit a resize event. | |
302 | this.fire( 'resize', { | |
303 | outerHeight: resultOuterHeight, | |
304 | contentsHeight: resultContentsHeight, | |
305 | // Sometimes width is not provided. | |
306 | outerWidth: width || outer.getSize( 'width' ) | |
307 | } ); | |
308 | }; | |
309 | ||
310 | /** | |
311 | * Gets the element that can be used to check the editor size. This method | |
317f8f8f IB |
312 | * is mainly used by the [Editor Resize](http://ckeditor.com/addon/resize) plugin, which adds |
313 | * a UI handle that can be used to resize the editor. | |
3332bebe IB |
314 | * |
315 | * @param {Boolean} forContents Whether to return the "contents" part of the theme instead of the container. | |
316 | * @returns {CKEDITOR.dom.element} The resizable element. | |
317 | */ | |
318 | CKEDITOR.editor.prototype.getResizable = function( forContents ) { | |
319 | return forContents ? this.ui.space( 'contents' ) : this.container; | |
320 | }; | |
321 | ||
322 | function createInstance( element, config, data, mode ) { | |
323 | if ( !CKEDITOR.env.isCompatible ) | |
324 | return null; | |
325 | ||
326 | element = CKEDITOR.dom.element.get( element ); | |
327 | ||
328 | // Avoid multiple inline editor instances on the same element. | |
329 | if ( element.getEditor() ) | |
330 | throw 'The editor instance "' + element.getEditor().name + '" is already attached to the provided element.'; | |
331 | ||
332 | // Create the editor instance. | |
333 | var editor = new CKEDITOR.editor( config, element, mode ); | |
334 | ||
335 | if ( mode == CKEDITOR.ELEMENT_MODE_REPLACE ) { | |
336 | // Do not replace the textarea right now, just hide it. The effective | |
337 | // replacement will be done later in the editor creation lifecycle. | |
338 | element.setStyle( 'visibility', 'hidden' ); | |
339 | ||
317f8f8f | 340 | // http://dev.ckeditor.com/ticket/8031 Remember if textarea was required and remove the attribute. |
3332bebe IB |
341 | editor._.required = element.hasAttribute( 'required' ); |
342 | element.removeAttribute( 'required' ); | |
343 | } | |
344 | ||
345 | data && editor.setData( data, null, true ); | |
346 | ||
347 | // Once the editor is loaded, start the UI. | |
348 | editor.on( 'loaded', function() { | |
349 | loadTheme( editor ); | |
350 | ||
351 | if ( mode == CKEDITOR.ELEMENT_MODE_REPLACE && editor.config.autoUpdateElement && element.$.form ) | |
352 | editor._attachToForm(); | |
353 | ||
354 | editor.setMode( editor.config.startupMode, function() { | |
355 | // Clean on startup. | |
356 | editor.resetDirty(); | |
357 | ||
358 | // Editor is completely loaded for interaction. | |
359 | editor.status = 'ready'; | |
360 | editor.fireOnce( 'instanceReady' ); | |
361 | CKEDITOR.fire( 'instanceReady', null, editor ); | |
362 | } ); | |
363 | } ); | |
364 | ||
365 | editor.on( 'destroy', destroy ); | |
366 | return editor; | |
367 | } | |
368 | ||
369 | function destroy() { | |
370 | var editor = this, | |
371 | container = editor.container, | |
372 | element = editor.element; | |
373 | ||
374 | if ( container ) { | |
375 | container.clearCustomData(); | |
376 | container.remove(); | |
377 | } | |
378 | ||
379 | if ( element ) { | |
380 | element.clearCustomData(); | |
381 | if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) { | |
382 | element.show(); | |
383 | if ( editor._.required ) | |
384 | element.setAttribute( 'required', 'required' ); | |
385 | } | |
386 | delete editor.element; | |
387 | } | |
388 | } | |
389 | ||
390 | function loadTheme( editor ) { | |
391 | var name = editor.name, | |
392 | element = editor.element, | |
393 | elementMode = editor.elementMode; | |
394 | ||
395 | // Get the HTML for the predefined spaces. | |
396 | var topHtml = editor.fire( 'uiSpace', { space: 'top', html: '' } ).html; | |
397 | var bottomHtml = editor.fire( 'uiSpace', { space: 'bottom', html: '' } ).html; | |
398 | ||
399 | var themedTpl = new CKEDITOR.template( | |
400 | '<{outerEl}' + | |
401 | ' id="cke_{name}"' + | |
402 | ' class="{id} cke cke_reset cke_chrome cke_editor_{name} cke_{langDir} ' + CKEDITOR.env.cssClass + '" ' + | |
403 | ' dir="{langDir}"' + | |
404 | ' lang="{langCode}"' + | |
405 | ' role="application"' + | |
406 | ( editor.title ? ' aria-labelledby="cke_{name}_arialbl"' : '' ) + | |
407 | '>' + | |
408 | ( editor.title ? '<span id="cke_{name}_arialbl" class="cke_voice_label">{voiceLabel}</span>' : '' ) + | |
409 | '<{outerEl} class="cke_inner cke_reset" role="presentation">' + | |
410 | '{topHtml}' + | |
411 | '<{outerEl} id="{contentId}" class="cke_contents cke_reset" role="presentation"></{outerEl}>' + | |
412 | '{bottomHtml}' + | |
413 | '</{outerEl}>' + | |
414 | '</{outerEl}>' ); | |
415 | ||
416 | var container = CKEDITOR.dom.element.createFromHtml( themedTpl.output( { | |
417 | id: editor.id, | |
418 | name: name, | |
419 | langDir: editor.lang.dir, | |
420 | langCode: editor.langCode, | |
421 | voiceLabel: editor.title, | |
422 | topHtml: topHtml ? '<span id="' + editor.ui.spaceId( 'top' ) + '" class="cke_top cke_reset_all" role="presentation" style="height:auto">' + topHtml + '</span>' : '', | |
423 | contentId: editor.ui.spaceId( 'contents' ), | |
424 | bottomHtml: bottomHtml ? '<span id="' + editor.ui.spaceId( 'bottom' ) + '" class="cke_bottom cke_reset_all" role="presentation">' + bottomHtml + '</span>' : '', | |
317f8f8f | 425 | outerEl: CKEDITOR.env.ie ? 'span' : 'div' // http://dev.ckeditor.com/ticket/9571 |
3332bebe IB |
426 | } ) ); |
427 | ||
428 | if ( elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) { | |
429 | element.hide(); | |
430 | container.insertAfter( element ); | |
431 | } else { | |
432 | element.append( container ); | |
433 | } | |
434 | ||
435 | editor.container = container; | |
436 | editor.ui.contentsElement = editor.ui.space( 'contents' ); | |
437 | ||
438 | // Make top and bottom spaces unelectable, but not content space, | |
439 | // otherwise the editable area would be affected. | |
440 | topHtml && editor.ui.space( 'top' ).unselectable(); | |
441 | bottomHtml && editor.ui.space( 'bottom' ).unselectable(); | |
442 | ||
443 | var width = editor.config.width, height = editor.config.height; | |
444 | if ( width ) | |
445 | container.setStyle( 'width', CKEDITOR.tools.cssLength( width ) ); | |
446 | ||
447 | // The editor height is applied to the contents space. | |
448 | if ( height ) | |
449 | editor.ui.space( 'contents' ).setStyle( 'height', CKEDITOR.tools.cssLength( height ) ); | |
450 | ||
451 | // Disable browser context menu for editor's chrome. | |
452 | container.disableContextMenu(); | |
453 | ||
317f8f8f | 454 | // Redirect the focus into editor for webkit. (http://dev.ckeditor.com/ticket/5713) |
3332bebe IB |
455 | CKEDITOR.env.webkit && container.on( 'focus', function() { |
456 | editor.focus(); | |
457 | } ); | |
458 | ||
459 | editor.fireOnce( 'uiReady' ); | |
460 | } | |
461 | ||
462 | // Replace all textareas with the default class name. | |
463 | CKEDITOR.domReady( function() { | |
464 | CKEDITOR.replaceClass && CKEDITOR.replaceAll( CKEDITOR.replaceClass ); | |
465 | } ); | |
466 | } )(); | |
467 | ||
468 | /** | |
469 | * The current editing mode. An editing mode basically provides | |
317f8f8f | 470 | * different ways of editing or viewing the editor content. |
3332bebe IB |
471 | * |
472 | * alert( CKEDITOR.instances.editor1.mode ); // (e.g.) 'wysiwyg' | |
473 | * | |
474 | * @readonly | |
475 | * @property {String} mode | |
476 | */ | |
477 | ||
478 | /** | |
479 | * The mode to load at the editor startup. It depends on the plugins | |
480 | * loaded. By default, the `wysiwyg` and `source` modes are available. | |
481 | * | |
482 | * config.startupMode = 'source'; | |
483 | * | |
484 | * @cfg {String} [startupMode='wysiwyg'] | |
485 | * @member CKEDITOR.config | |
486 | */ | |
487 | CKEDITOR.config.startupMode = 'wysiwyg'; | |
488 | ||
489 | /** | |
490 | * Fired after the editor instance is resized through | |
491 | * the {@link CKEDITOR.editor#method-resize CKEDITOR.resize} method. | |
492 | * | |
493 | * @event resize | |
494 | * @param {CKEDITOR.editor} editor This editor instance. | |
495 | * @param {Object} data Available since CKEditor 4.5. | |
496 | * @param {Number} data.outerHeight The height of the entire area that the editor covers. | |
497 | * @param {Number} data.contentsHeight Editable area height in pixels. | |
498 | * @param {Number} data.outerWidth The width of the entire area that the editor covers. | |
499 | */ | |
500 | ||
501 | /** | |
502 | * Fired before changing the editing mode. See also | |
503 | * {@link #beforeSetMode} and {@link #event-mode}. | |
504 | * | |
505 | * @event beforeModeUnload | |
506 | * @param {CKEDITOR.editor} editor This editor instance. | |
507 | */ | |
508 | ||
509 | /** | |
510 | * Fired before the editor mode is set. See also | |
511 | * {@link #event-mode} and {@link #beforeModeUnload}. | |
512 | * | |
513 | * @since 3.5.3 | |
514 | * @event beforeSetMode | |
515 | * @param {CKEDITOR.editor} editor This editor instance. | |
516 | * @param {String} data The name of the mode which is about to be set. | |
517 | */ | |
518 | ||
519 | /** | |
520 | * Fired after setting the editing mode. See also {@link #beforeSetMode} and {@link #beforeModeUnload} | |
521 | * | |
522 | * @event mode | |
523 | * @param {CKEDITOR.editor} editor This editor instance. | |
524 | */ | |
525 | ||
526 | /** | |
527 | * Fired when the editor (replacing a `<textarea>` which has a `required` attribute) is empty during form submission. | |
528 | * | |
529 | * This event replaces native required fields validation that the browsers cannot | |
530 | * perform when CKEditor replaces `<textarea>` elements. | |
531 | * | |
532 | * You can cancel this event to prevent the page from submitting data. | |
533 | * | |
534 | * editor.on( 'required', function( evt ) { | |
535 | * alert( 'Article content is required.' ); | |
536 | * evt.cancel(); | |
537 | * } ); | |
538 | * | |
539 | * @event required | |
540 | * @param {CKEDITOR.editor} editor This editor instance. | |
541 | */ |