D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
home
/
shubmkcj
/
designpitara.com
/
admin
/
ckeditor
/
core
/
Filename :
editor.js
back
Copy
/** * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ /** * @fileOverview Defines the {@link CKEDITOR.editor} class that represents an * editor instance. */ ( function() { // Override the basic constructor defined at editor_basic.js. Editor.prototype = CKEDITOR.editor.prototype; CKEDITOR.editor = Editor; /** * Represents an editor instance. This constructor should be rarely * used in favor of the {@link CKEDITOR} editor creation functions. * * @class CKEDITOR.editor * @mixins CKEDITOR.event * @constructor Creates an editor class instance. * @param {Object} [instanceConfig] Configuration values for this specific instance. * @param {CKEDITOR.dom.element} [element] The DOM element upon which this editor * will be created. * @param {Number} [mode] The element creation mode to be used by this editor. */ function Editor( instanceConfig, element, mode ) { // Call the CKEDITOR.event constructor to initialize this instance. CKEDITOR.event.call( this ); // Make a clone of the config object, to avoid having it touched by our code. (https://dev.ckeditor.com/ticket/9636) instanceConfig = instanceConfig && CKEDITOR.tools.clone( instanceConfig ); // if editor is created off one page element. if ( element !== undefined ) { // Asserting element and mode not null. if ( !( element instanceof CKEDITOR.dom.element ) ) throw new Error( 'Expect element of type CKEDITOR.dom.element.' ); else if ( !mode ) throw new Error( 'One of the element modes must be specified.' ); if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && mode == CKEDITOR.ELEMENT_MODE_INLINE ) throw new Error( 'Inline element mode is not supported on IE quirks.' ); if ( !isSupportedElement( element, mode ) ) throw new Error( 'The specified element mode is not supported on element: "' + element.getName() + '".' ); /** * The original host page element upon which the editor is created. It is only * supposed to be provided by the particular editor creator and is not subject to * be modified. * * @readonly * @property {CKEDITOR.dom.element} */ this.element = element; /** * This property indicates the way this instance is associated with the {@link #element}. * See also {@link CKEDITOR#ELEMENT_MODE_INLINE} and {@link CKEDITOR#ELEMENT_MODE_REPLACE}. * * @readonly * @property {Number} */ this.elementMode = mode; this.name = ( this.elementMode != CKEDITOR.ELEMENT_MODE_APPENDTO ) && ( element.getId() || element.getNameAtt() ); } else { this.elementMode = CKEDITOR.ELEMENT_MODE_NONE; } // Declare the private namespace. this._ = {}; this.commands = {}; /** * Contains all UI templates created for this editor instance. * * @readonly * @property {Object} */ this.templates = {}; /** * A unique identifier of this editor instance. * * **Note:** It will be originated from the `id` or `name` * attribute of the {@link #element}, otherwise a name pattern of * `'editor{n}'` will be used. * * @readonly * @property {String} */ this.name = this.name || genEditorName(); /** * A unique random string assigned to each editor instance on the page. * * @readonly * @property {String} */ this.id = CKEDITOR.tools.getNextId(); /** * Indicates editor initialization status. The following statuses are available: * * * **unloaded**: The initial state — the editor instance was initialized, * but its components (configuration, plugins, language files) are not loaded yet. * * **loaded**: The editor components were loaded — see the {@link CKEDITOR.editor#loaded} event. * * **ready**: The editor is fully initialized and ready — see the {@link CKEDITOR.editor#instanceReady} event. * * **destroyed**: The editor was destroyed — see the {@link CKEDITOR.editor#method-destroy} method. * * @since 4.1.0 * @readonly * @property {String} */ this.status = 'unloaded'; /** * The configuration for this editor instance. It inherits all * settings defined in {@link CKEDITOR.config}, combined with settings * loaded from custom configuration files and those defined inline in * the page when creating the editor. * * var editor = CKEDITOR.instances.editor1; * alert( editor.config.skin ); // e.g. 'moono' * * @readonly * @property {CKEDITOR.config} */ this.config = CKEDITOR.tools.prototypedCopy( CKEDITOR.config ); /** * The namespace containing UI features related to this editor instance. * * @readonly * @property {CKEDITOR.ui} */ this.ui = new CKEDITOR.ui( this ); /** * Controls the focus state of this editor instance. This property * is rarely used for normal API operations. It is mainly * targeted at developers adding UI elements to the editor interface. * * @readonly * @property {CKEDITOR.focusManager} */ this.focusManager = new CKEDITOR.focusManager( this ); /** * Controls keystroke typing in this editor instance. * * @readonly * @property {CKEDITOR.keystrokeHandler} */ this.keystrokeHandler = new CKEDITOR.keystrokeHandler( this ); // Make the editor update its command states on mode change. this.on( 'readOnly', updateCommands ); this.on( 'selectionChange', function( evt ) { updateCommandsContext( this, evt.data.path ); } ); this.on( 'activeFilterChange', function() { updateCommandsContext( this, this.elementPath(), true ); } ); this.on( 'mode', updateCommands ); // Optimize selection starting/ending on element boundaries (#3175). CKEDITOR.dom.selection.setupEditorOptimization( this ); // Handle startup focus. this.on( 'instanceReady', function() { if ( this.config.startupFocus ) { if ( this.config.startupFocus === 'end' ) { var range = this.createRange(); range.selectNodeContents( this.editable() ); range.shrink( CKEDITOR.SHRINK_ELEMENT, true ); range.collapse(); this.getSelection().selectRanges( [ range ] ); } this.focus(); } } ); CKEDITOR.fire( 'instanceCreated', null, this ); // Add this new editor to the CKEDITOR.instances collections. CKEDITOR.add( this ); // Return the editor instance immediately to enable early stage event registrations. CKEDITOR.tools.setTimeout( function() { if ( !this.isDestroyed() && !this.isDetached() ) { initConfig( this, instanceConfig ); } }, 0, this ); } var nameCounter = 0; function genEditorName() { do { var name = 'editor' + ( ++nameCounter ); } while ( CKEDITOR.instances[ name ] ); return name; } // Asserting element DTD depending on mode. function isSupportedElement( element, mode ) { if ( mode == CKEDITOR.ELEMENT_MODE_INLINE ) return element.is( CKEDITOR.dtd.$editable ) || element.is( 'textarea' ); else if ( mode == CKEDITOR.ELEMENT_MODE_REPLACE ) return !element.is( CKEDITOR.dtd.$nonBodyContent ); return 1; } function updateCommands() { var commands = this.commands, name; for ( name in commands ) updateCommand( this, commands[ name ] ); } function updateCommand( editor, cmd ) { cmd[ cmd.startDisabled ? 'disable' : editor.readOnly && !cmd.readOnly ? 'disable' : cmd.modes[ editor.mode ] ? 'enable' : 'disable' ](); } function updateCommandsContext( editor, path, forceRefresh ) { // Commands cannot be refreshed without a path. In edge cases // it may happen that there's no selection when this function is executed. // For example when active filter is changed in https://dev.ckeditor.com/ticket/10877. if ( !path ) return; var command, name, commands = editor.commands; for ( name in commands ) { command = commands[ name ]; if ( forceRefresh || command.contextSensitive ) command.refresh( editor, path ); } } // ##### START: Config Privates // These function loads custom configuration files and cache the // CKEDITOR.editorConfig functions defined on them, so there is no need to // download them more than once for several instances. var loadConfigLoaded = {}; function loadConfig( editor ) { var customConfig = editor.config.customConfig; // Check if there is a custom config to load. if ( !customConfig ) return false; customConfig = CKEDITOR.getUrl( customConfig ); var loadedConfig = loadConfigLoaded[ customConfig ] || ( loadConfigLoaded[ customConfig ] = {} ); // If the custom config has already been downloaded, reuse it. if ( loadedConfig.fn ) { // Call the cached CKEDITOR.editorConfig defined in the custom // config file for the editor instance depending on it. loadedConfig.fn.call( editor, editor.config ); // If there is no other customConfig in the chain, fire the // "configLoaded" event. if ( CKEDITOR.getUrl( editor.config.customConfig ) == customConfig || !loadConfig( editor ) ) editor.fireOnce( 'customConfigLoaded' ); } else { // Load the custom configuration file. // To resolve customConfig race conflicts, use scriptLoader#queue // instead of scriptLoader#load (https://dev.ckeditor.com/ticket/6504). CKEDITOR.scriptLoader.queue( customConfig, function() { // If the CKEDITOR.editorConfig function has been properly // defined in the custom configuration file, cache it. if ( CKEDITOR.editorConfig ) loadedConfig.fn = CKEDITOR.editorConfig; else loadedConfig.fn = function() {}; // Call the load config again. This time the custom // config is already cached and so it will get loaded. loadConfig( editor ); } ); } return true; } function initConfig( editor, instanceConfig ) { // Setup the lister for the "customConfigLoaded" event. editor.on( 'customConfigLoaded', function() { if ( instanceConfig ) { // Register the events that may have been set at the instance // configuration object. if ( instanceConfig.on ) { for ( var eventName in instanceConfig.on ) { editor.on( eventName, instanceConfig.on[ eventName ] ); } } // Overwrite the settings from the in-page config. CKEDITOR.tools.extend( editor.config, instanceConfig, true ); delete editor.config.on; } onConfigLoaded( editor ); } ); // The instance config may override the customConfig setting to avoid // loading the default ~/config.js file. if ( instanceConfig && instanceConfig.customConfig != null ) editor.config.customConfig = instanceConfig.customConfig; // Load configs from the custom configuration files. if ( !loadConfig( editor ) ) editor.fireOnce( 'customConfigLoaded' ); } // ##### END: Config Privates // Set config related properties. function onConfigLoaded( editor ) { var config = editor.config; /** * Indicates the read-only state of this editor. This is a read-only property. * See also {@link CKEDITOR.editor#setReadOnly}. * * @since 3.6.0 * @readonly * @property {Boolean} */ editor.readOnly = isEditorReadOnly(); function isEditorReadOnly() { if ( config.readOnly ) { return true; } if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ) { if ( editor.element.is( 'textarea' ) ) { return editor.element.hasAttribute( 'disabled' ) || editor.element.hasAttribute( 'readonly' ); } else { return editor.element.isReadOnly(); } } else if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) { return editor.element.hasAttribute( 'disabled' ) || editor.element.hasAttribute( 'readonly' ); } return false; } /** * Indicates that the editor is running in an environment where * no block elements are accepted inside the content. * * This can be for example inline editor based on an `<h1>` element. * * @readonly * @property {Boolean} */ editor.blockless = editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ? !( editor.element.is( 'textarea' ) || CKEDITOR.dtd[ editor.element.getName() ].p ) : false; /** * The [tabbing navigation](http://en.wikipedia.org/wiki/Tabbing_navigation) order determined for this editor instance. * This can be set by the <code>{@link CKEDITOR.config#tabIndex}</code> * setting or taken from the `tabindex` attribute of the * {@link #element} associated with the editor. * * alert( editor.tabIndex ); // e.g. 0 * * @readonly * @property {Number} [=0] */ editor.tabIndex = config.tabIndex || editor.element && editor.element.getAttribute( 'tabindex' ) || 0; editor.activeEnterMode = editor.enterMode = validateEnterMode( editor, config.enterMode ); editor.activeShiftEnterMode = editor.shiftEnterMode = validateEnterMode( editor, config.shiftEnterMode ); // Set CKEDITOR.skinName. Note that it is not possible to have // different skins on the same page, so the last one to set it "wins". if ( config.skin ) CKEDITOR.skinName = config.skin; // Fire the "configLoaded" event. editor.fireOnce( 'configLoaded' ); initComponents( editor ); } // Various other core components that read editor configuration. function initComponents( editor ) { // Documented in dataprocessor.js. editor.dataProcessor = new CKEDITOR.htmlDataProcessor( editor ); // Set activeFilter directly to avoid firing event. editor.filter = editor.activeFilter = new CKEDITOR.filter( editor ); loadSkin( editor ); } function loadSkin( editor ) { CKEDITOR.skin.loadPart( 'editor', function() { loadLang( editor ); } ); } function loadLang( editor ) { CKEDITOR.lang.load( editor.config.language, editor.config.defaultLanguage, function( languageCode, lang ) { var configTitle = editor.config.title; /** * The code for the language resources that have been loaded * for the user interface elements of this editor instance. * * alert( editor.langCode ); // e.g. 'en' * * @readonly * @property {String} */ editor.langCode = languageCode; /** * An object that contains all language strings used by the editor interface. * * alert( editor.lang.basicstyles.bold ); // e.g. 'Negrito' (if the language is set to Portuguese) * * @readonly * @property {Object} lang */ // As we'll be adding plugin specific entries that could come // from different language code files, we need a copy of lang, // not a direct reference to it. editor.lang = CKEDITOR.tools.prototypedCopy( lang ); /** * Indicates the human-readable title of this editor. Although this is a read-only property, * it can be initialized with {@link CKEDITOR.config#title}. * * **Note:** Please do not confuse this property with {@link CKEDITOR.editor#name editor.name} * which identifies the instance in the {@link CKEDITOR#instances} literal. * * @since 4.2.0 * @readonly * @property {String/Boolean} */ editor.title = typeof configTitle == 'string' || configTitle === false ? configTitle : [ editor.lang.editor, editor.name ].join( ', ' ); if ( !editor.config.contentsLangDirection ) { // Fallback to either the editable element direction or editor UI direction depending on creators. editor.config.contentsLangDirection = editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ? editor.element.getDirection( 1 ) : editor.lang.dir; } editor.fire( 'langLoaded' ); preloadStylesSet( editor ); } ); } // Preloads styles set file (config.stylesSet). // If stylesSet was defined directly (by an array) // this function will call loadPlugins fully synchronously. // If stylesSet is a string (path) loadPlugins will // be called asynchronously. // In both cases - styles will be preload before plugins initialization. function preloadStylesSet( editor ) { editor.getStylesSet( function( styles ) { // Wait for editor#loaded, so plugins could add their listeners. // But listen with high priority to fire editor#stylesSet before editor#uiReady and editor#setData. editor.once( 'loaded', function() { // Note: we can't use fireOnce because this event may canceled and fired again. editor.fire( 'stylesSet', { styles: styles } ); }, null, null, 1 ); loadPlugins( editor ); } ); } function loadPlugins( editor ) { var config = editor.config, plugins = parsePluginsOption( config.plugins ), extraPlugins = parsePluginsOption( config.extraPlugins ), removePlugins = parsePluginsOption( config.removePlugins ); if ( extraPlugins ) { // Remove them first to avoid duplications. var extraRegex = new RegExp( '(?:^|,)(?:' + extraPlugins.replace( /,/g, '|' ) + ')(?=,|$)', 'g' ); plugins = plugins.replace( extraRegex, '' ); plugins += ',' + extraPlugins; } if ( removePlugins ) { var removeRegex = new RegExp( '(?:^|,)(?:' + removePlugins.replace( /,/g, '|' ) + ')(?=,|$)', 'g' ); plugins = plugins.replace( removeRegex, '' ); } // Load the Adobe AIR plugin conditionally. CKEDITOR.env.air && ( plugins += ',adobeair' ); // Load all plugins defined in the "plugins" setting. CKEDITOR.plugins.load( plugins.split( ',' ), function( plugins ) { // The list of plugins. var pluginsArray = []; // The language code to get loaded for each plugin. Null // entries will be appended for plugins with no language files. var languageCodes = []; // The list of URLs to language files. var languageFiles = []; editor.plugins = CKEDITOR.tools.extend( {}, editor.plugins, plugins ); // Loop through all plugins, to build the list of language // files to get loaded. // // Check also whether any of loaded plugins doesn't require plugins // defined in config.removePlugins. Throw non-blocking error if this happens. for ( var pluginName in plugins ) { var plugin = plugins[ pluginName ], pluginLangs = plugin.lang, lang = null, requires = plugin.requires, match, name; // Transform it into a string, if it's not one. if ( CKEDITOR.tools.isArray( requires ) ) requires = requires.join( ',' ); if ( requires && ( match = requires.match( removeRegex ) ) ) { while ( ( name = match.pop() ) ) { CKEDITOR.error( 'editor-plugin-required', { plugin: name.replace( ',', '' ), requiredBy: pluginName } ); } } // If the plugin has "lang". if ( pluginLangs && !editor.lang[ pluginName ] ) { // Trasnform the plugin langs into an array, if it's not one. if ( pluginLangs.split ) pluginLangs = pluginLangs.split( ',' ); // Resolve the plugin language. If the current language // is not available, get English or the first one. if ( CKEDITOR.tools.indexOf( pluginLangs, editor.langCode ) >= 0 ) lang = editor.langCode; else { // The language code may have the locale information (zh-cn). // Fall back to locale-less in that case (zh). var langPart = editor.langCode.replace( /-.*/, '' ); if ( langPart != editor.langCode && CKEDITOR.tools.indexOf( pluginLangs, langPart ) >= 0 ) lang = langPart; // Try the only "generic" option we have: English. else if ( CKEDITOR.tools.indexOf( pluginLangs, 'en' ) >= 0 ) lang = 'en'; else lang = pluginLangs[ 0 ]; } if ( !plugin.langEntries || !plugin.langEntries[ lang ] ) { // Put the language file URL into the list of files to // get downloaded. languageFiles.push( CKEDITOR.getUrl( plugin.path + 'lang/' + lang + '.js' ) ); } else { editor.lang[ pluginName ] = plugin.langEntries[ lang ]; lang = null; } } // Save the language code, so we know later which // language has been resolved to this plugin. languageCodes.push( lang ); pluginsArray.push( plugin ); } // Load all plugin specific language files in a row. CKEDITOR.scriptLoader.load( languageFiles, function() { if ( editor.isDestroyed() || editor.isDetached() ) { return; } // Initialize all plugins that have the "beforeInit" and "init" methods defined. var methods = [ 'beforeInit', 'init', 'afterInit' ]; for ( var m = 0; m < methods.length; m++ ) { for ( var i = 0; i < pluginsArray.length; i++ ) { var plugin = pluginsArray[ i ]; // Uses the first loop to update the language entries also. if ( m === 0 && languageCodes[ i ] && plugin.lang && plugin.langEntries ) editor.lang[ plugin.name ] = plugin.langEntries[ languageCodes[ i ] ]; // Call the plugin method (beforeInit and init). if ( plugin[ methods[ m ] ] ) { plugin[ methods[ m ] ]( editor ); } } } editor.fireOnce( 'pluginsLoaded' ); // Setup the configured keystrokes. config.keystrokes && editor.setKeystroke( editor.config.keystrokes ); // Setup the configured blocked keystrokes. for ( i = 0; i < editor.config.blockedKeystrokes.length; i++ ) editor.keystrokeHandler.blockedKeystrokes[ editor.config.blockedKeystrokes[ i ] ] = 1; editor.status = 'loaded'; editor.fireOnce( 'loaded' ); CKEDITOR.fire( 'instanceLoaded', null, editor ); } ); } ); // Parse *plugins option into a string (#1802). function parsePluginsOption( option ) { if ( !option ) { return ''; } if ( CKEDITOR.tools.isArray( option ) ) { option = option.join( ',' ); } // We have to remove whitespaces (#1712). return option.replace( /\s/g, '' ); } } // Send to data output back to editor's associated element. function updateEditorElement() { var element = this.element; // Some editor creation mode will not have the // associated element. if ( element && this.elementMode != CKEDITOR.ELEMENT_MODE_APPENDTO ) { var data = this.getData(); if ( this.config.htmlEncodeOutput ) data = CKEDITOR.tools.htmlEncode( data ); if ( element.is( 'textarea' ) ) element.setValue( data ); else element.setHtml( data ); return true; } return false; } // Always returns ENTER_BR in case of blockless editor. function validateEnterMode( editor, enterMode ) { return editor.blockless ? CKEDITOR.ENTER_BR : enterMode; } // Create DocumentFragment from specified ranges. For now it handles only tables // and returns DocumentFragment from the 1. range for other cases. (https://dev.ckeditor.com/ticket/13884) function createDocumentFragmentFromRanges( ranges, editable ) { var docFragment = new CKEDITOR.dom.documentFragment(), tableClone, currentRow, currentRowClone; // We must handle two cases here: // 1. <tr>[<td>Cell</td>]</tr> (IE9+, Edge, Chrome, Firefox) // 2. <td>[Cell]</td> (IE8-, Safari) function isSelectedCell( range ) { var start = range.startContainer, end = range.endContainer; if ( start.is && ( start.is( 'tr' ) || ( start.is( 'td' ) && start.equals( end ) && range.endOffset === start.getChildCount() ) ) ) { return true; } return false; } function cloneCell( range ) { var start = range.startContainer; if ( start.is( 'tr' ) ) { return range.cloneContents(); } return start.clone( true ); } for ( var i = 0; i < ranges.length; i++ ) { var range = ranges[ i ], container = range.startContainer.getAscendant( 'tr', true ); if ( isSelectedCell( range ) ) { if ( !tableClone ) { tableClone = container.getAscendant( 'table' ).clone(); tableClone.append( container.getAscendant( { thead: 1, tbody: 1, tfoot: 1 } ).clone() ); docFragment.append( tableClone ); tableClone = tableClone.findOne( 'thead, tbody, tfoot' ); } if ( !( currentRow && currentRow.equals( container ) ) ) { currentRow = container; currentRowClone = container.clone(); tableClone.append( currentRowClone ); } currentRowClone.append( cloneCell( range ) ); } else { // If there was something else copied with table, // append it to DocumentFragment. docFragment.append( range.cloneContents() ); } } if ( !tableClone ) { return editable.getHtmlFromRange( ranges[ 0 ] ); } return docFragment; } CKEDITOR.tools.extend( CKEDITOR.editor.prototype, { /** * An object that contains references to all plugins used by this * editor instance. * * alert( editor.plugins.dialog.path ); // e.g. 'http://example.com/ckeditor/plugins/dialog/' * * // Check if a plugin is available. * if ( editor.plugins.image ) { * ... * } * * @readonly * @property {CKEDITOR.editor.plugins} */ plugins: { /** * Checks the plugin for conflicts with other plugins. * * If a conflict occurs, this function will send a {@link CKEDITOR#warn console warning} * with the `editor-plugin-conflict` error code. The order of the `conflicted` names is respected * where the first conflicted plugin has the highest priority and will be used in a warning * message. * * ```js * editor.plugins.detectConflict( 'image', [ 'image2', 'easyimage' ] ); * ``` * * @member CKEDITOR.editor.plugins * @since 4.10.1 * @param {String} plugin Current plugin name. * @param {String[]} conflicted Names of plugins that conflict with the current plugin. * @return {Boolean} Returns `true` if there is a conflict. Returns `false` otherwise. */ detectConflict: function( plugin, conflicted ) { for ( var i = 0; i < conflicted.length; i++ ) { var pluginName = conflicted[ i ]; if ( this[ pluginName ] ) { CKEDITOR.warn( 'editor-plugin-conflict', { plugin: plugin, replacedWith: pluginName } ); return true; } } return false; } }, /** * Adds a command definition to the editor instance. Commands added with * this function can be executed later with the {@link #execCommand} method. * * editorInstance.addCommand( 'sample', { * exec: function( editor ) { * alert( 'Executing a command for the editor name "' + editor.name + '"!' ); * } * } ); * * Since 4.10.0 this method also accepts a {@link CKEDITOR.command} instance as a parameter. * * @param {String} commandName The indentifier name of the command. * @param {CKEDITOR.commandDefinition/CKEDITOR.command} commandDefinition The command definition or a `CKEDITOR.command` instance. */ addCommand: function( commandName, commandDefinition ) { commandDefinition.name = commandName.toLowerCase(); var cmd = commandDefinition instanceof CKEDITOR.command ? commandDefinition : new CKEDITOR.command( this, commandDefinition ); // Update command when mode is set. // This guarantees that commands added before first editor#mode // aren't immediately updated, but waits for editor#mode and that // commands added later are immediately refreshed, even when added // before instanceReady. https://dev.ckeditor.com/ticket/10103, https://dev.ckeditor.com/ticket/10249 if ( this.mode ) updateCommand( this, cmd ); return this.commands[ commandName ] = cmd; }, /** * Attaches the editor to a form to call {@link #updateElement} before form submission. * This method is called by both creators ({@link CKEDITOR#replace replace} and * {@link CKEDITOR#inline inline}), so there is no reason to call it manually. * * @private */ _attachToForm: function() { var editor = this, element = editor.element, form = new CKEDITOR.dom.element( element.$.form ); // If are replacing a textarea, we must if ( element.is( 'textarea' ) ) { if ( form ) { form.on( 'submit', onSubmit ); // Check if there is no element/elements input with name == "submit". // If they exists they will overwrite form submit function (form.$.submit). // If form.$.submit is overwritten we can not do anything with it. if ( isFunction( form.$.submit ) ) { // Setup the submit function because it doesn't fire the // "submit" event. form.$.submit = CKEDITOR.tools.override( form.$.submit, function( originalSubmit ) { return function() { onSubmit(); // For IE, the DOM submit function is not a // function, so we need third check. if ( originalSubmit.apply ) originalSubmit.apply( this ); else originalSubmit(); }; } ); } // Remove 'submit' events registered on form element before destroying.(https://dev.ckeditor.com/ticket/3988) editor.on( 'destroy', function() { form.removeListener( 'submit', onSubmit ); } ); } } function onSubmit( evt ) { editor.updateElement(); // https://dev.ckeditor.com/ticket/8031 If textarea had required attribute and editor is empty fire 'required' event and if // it was cancelled, prevent submitting the form. if ( editor._.required && !element.getValue() && editor.fire( 'required' ) === false ) { // When user press save button event (evt) is undefined (see save plugin). // This method works because it throws error so originalSubmit won't be called. // Also this error won't be shown because it will be caught in save plugin. evt.data.preventDefault(); } } function isFunction( f ) { // For IE8 typeof fun == object so we cannot use it. return !!( f && f.call && f.apply ); } }, /** * Destroys the editor instance, releasing all resources used by it. * If the editor replaced an element, the element will be recovered. * * alert( CKEDITOR.instances.editor1 ); // e.g. object * CKEDITOR.instances.editor1.destroy(); * alert( CKEDITOR.instances.editor1 ); // undefined * * @param {Boolean} [noUpdate] If the instance is replacing a DOM * element, this parameter indicates whether or not to update the * element with the instance content. */ destroy: function( noUpdate ) { var filters = CKEDITOR.filter.instances, self = this; this.fire( 'beforeDestroy' ); !noUpdate && updateEditorElement.call( this ); this.editable( null ); if ( this.filter ) { delete this.filter; } // Destroy filters attached to the editor (#1722). CKEDITOR.tools.array.forEach( CKEDITOR.tools.object.keys( filters ), function( id ) { var filter = filters[ id ]; if ( self === filter.editor ) { filter.destroy(); } } ); delete this.activeFilter; this.status = 'destroyed'; this.fire( 'destroy' ); // Plug off all listeners to prevent any further events firing. this.removeAllListeners(); CKEDITOR.remove( this ); CKEDITOR.fire( 'instanceDestroyed', null, this ); }, /** * Returns an {@link CKEDITOR.dom.elementPath element path} for the selection in the editor. * * @param {CKEDITOR.dom.node} [startNode] From which the path should start, * if not specified defaults to editor selection's * start element yielded by {@link CKEDITOR.dom.selection#getStartElement}. * @returns {CKEDITOR.dom.elementPath} */ elementPath: function( startNode ) { if ( !startNode ) { var sel = this.getSelection(); if ( !sel ) return null; startNode = sel.getStartElement(); } return startNode ? new CKEDITOR.dom.elementPath( startNode, this.editable() ) : null; }, /** * Shortcut to create a {@link CKEDITOR.dom.range} instance from the editable element. * * @returns {CKEDITOR.dom.range} The DOM range created if the editable has presented. * @see CKEDITOR.dom.range */ createRange: function() { var editable = this.editable(); return editable ? new CKEDITOR.dom.range( editable ) : null; }, /** * Executes a command associated with the editor. * * editorInstance.execCommand( 'bold' ); * * @param {String} commandName The identifier name of the command. * @param {Object} [data] The data to be passed to the command. It defaults to * an empty object starting from 4.7.0. * @returns {Boolean} `true` if the command was executed successfully, `false` otherwise. * @see CKEDITOR.editor#addCommand */ execCommand: function( commandName, data ) { var command = this.getCommand( commandName ); var eventData = { name: commandName, commandData: data || {}, command: command }; if ( command && command.state != CKEDITOR.TRISTATE_DISABLED ) { if ( this.fire( 'beforeCommandExec', eventData ) !== false ) { eventData.returnValue = command.exec( eventData.commandData ); // Fire the 'afterCommandExec' immediately if command is synchronous. if ( !command.async && this.fire( 'afterCommandExec', eventData ) !== false ) return eventData.returnValue; } } // throw 'Unknown command name "' + commandName + '"'; return false; }, /** * Gets one of the registered commands. Note that after registering a * command definition with {@link #addCommand}, it is * transformed internally into an instance of * {@link CKEDITOR.command}, which will then be returned by this function. * * @param {String} commandName The name of the command to be returned. * This is the same name that is used to register the command with `addCommand`. * @returns {CKEDITOR.command} The command object identified by the provided name. */ getCommand: function( commandName ) { return this.commands[ commandName ]; }, /** * Gets the editor data. The data will be in "raw" format. It is the same * data that is posted by the editor. * * if ( CKEDITOR.instances.editor1.getData() == '' ) * alert( 'There is no data available.' ); * * @param {Boolean} internal If set to `true`, it will prevent firing the * {@link CKEDITOR.editor#beforeGetData} and {@link CKEDITOR.editor#event-getData} events, so * the real content of the editor will not be read and cached data will be returned. The method will work * much faster, but this may result in the editor returning the data that is not up to date. This parameter * should thus only be set to `true` when you are certain that the cached data is up to date. * * @returns {String} The editor data. */ getData: function( internal ) { !internal && this.fire( 'beforeGetData' ); var eventData = this._.data; if ( typeof eventData != 'string' ) { var element = this.element; if ( element && this.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) eventData = element.is( 'textarea' ) ? element.getValue() : element.getHtml(); else eventData = ''; } eventData = { dataValue: eventData }; // Fire "getData" so data manipulation may happen. !internal && this.fire( 'getData', eventData ); return eventData.dataValue; }, /** * Gets the "raw data" currently available in the editor. This is a * fast method which returns the data as is, without processing, so it is * not recommended to use it on resulting pages. Instead it can be used * combined with the {@link #method-loadSnapshot} method in order * to automatically save the editor data from time to time * while the user is using the editor, to avoid data loss, without risking * performance issues. * * alert( editor.getSnapshot() ); * * See also: * * * {@link CKEDITOR.editor#method-getData}. * * @returns {String} Editor "raw data". */ getSnapshot: function() { var data = this.fire( 'getSnapshot' ); if ( typeof data != 'string' ) { var element = this.element; if ( element && this.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) { data = element.is( 'textarea' ) ? element.getValue() : element.getHtml(); } else { // If we don't have a proper element, set data to an empty string, // as this method is expected to return a string. (https://dev.ckeditor.com/ticket/13385) data = ''; } } return data; }, /** * Loads "raw data" into the editor. The data is loaded with processing * straight to the editing area. It should not be used as a way to load * any kind of data, but instead in combination with * {@link #method-getSnapshot}-produced data. * * var data = editor.getSnapshot(); * editor.loadSnapshot( data ); * * @see CKEDITOR.editor#setData */ loadSnapshot: function( snapshot ) { this.fire( 'loadSnapshot', snapshot ); }, /** * Sets the editor data. The data must be provided in the "raw" format (HTML). * * Note that this method is asynchronous. The `callback` parameter must * be used if interaction with the editor is needed after setting the data. * * CKEDITOR.instances.editor1.setData( '<p>This is the editor data.</p>' ); * * CKEDITOR.instances.editor1.setData( '<p>Some other editor data.</p>', { * callback: function() { * this.checkDirty(); // true * } * } ); * * Note: In **CKEditor 4.4.2** the signature of this method has changed. All arguments * except `data` were wrapped into the `options` object. However, backward compatibility * was preserved and it is still possible to use the `data, callback, internal` arguments. * * * @param {String} data The HTML code to replace current editor content. * @param {Object} [options] * @param {Boolean} [options.internal=false] Whether to suppress any event firing when copying data internally inside the editor. * @param {Function} [options.callback] Function to be called after `setData` is completed (on {@link #dataReady}). * @param {Boolean} [options.noSnapshot=false] If set to `true`, it will prevent recording an undo snapshot. * Introduced in CKEditor 4.4.2. */ setData: function( data, options, internal ) { var fireSnapshot = true, // Backward compatibility. callback = options, eventData; if ( options && typeof options == 'object' ) { internal = options.internal; callback = options.callback; fireSnapshot = !options.noSnapshot; } if ( !internal && fireSnapshot ) this.fire( 'saveSnapshot' ); if ( callback || !internal ) { this.once( 'dataReady', function( evt ) { if ( !internal && fireSnapshot ) this.fire( 'saveSnapshot' ); if ( callback ) callback.call( evt.editor ); } ); } // Fire "setData" so data manipulation may happen. eventData = { dataValue: data }; !internal && this.fire( 'setData', eventData ); this._.data = eventData.dataValue; !internal && this.fire( 'afterSetData', eventData ); }, /** * Puts or restores the editor into the read-only state. When in read-only, * the user is not able to change the editor content, but can still use * some editor features. This function sets the {@link #property-readOnly} * property of the editor, firing the {@link #event-readOnly} event. * * **Note:** The current editing area will be reloaded. * * @since 3.6.0 * @param {Boolean} [isReadOnly] Indicates that the editor must go * read-only (`true`, default) or be restored and made editable (`false`). */ setReadOnly: function( isReadOnly ) { isReadOnly = ( isReadOnly == null ) || isReadOnly; if ( this.readOnly != isReadOnly ) { this.readOnly = isReadOnly; // Block or release BACKSPACE key according to current read-only // state to prevent browser's history navigation (https://dev.ckeditor.com/ticket/9761). this.keystrokeHandler.blockedKeystrokes[ 8 ] = +isReadOnly; this.editable().setReadOnly( isReadOnly ); // Fire the readOnly event so the editor features can update // their state accordingly. this.fire( 'readOnly' ); } }, /** * Inserts HTML code into the currently selected position in the editor in WYSIWYG mode. * * Example: * * CKEDITOR.instances.editor1.insertHtml( '<p>This is a new paragraph.</p>' ); * * Fires the {@link #event-insertHtml} and {@link #event-afterInsertHtml} events. The HTML is inserted * in the {@link #event-insertHtml} event's listener with a default priority (10) so you can add listeners with * lower or higher priorities in order to execute some code before or after the HTML is inserted. * * @param {String} html HTML code to be inserted into the editor. * @param {String} [mode='html'] The mode in which the HTML code will be inserted. One of the following: * * * `'html'` – The inserted content will completely override the styles at the selected position. * * `'unfiltered_html'` – Like `'html'` but the content is not filtered with {@link CKEDITOR.filter}. * * `'text'` – The inserted content will inherit the styles applied in * the selected position. This mode should be used when inserting "htmlified" plain text * (HTML without inline styles and styling elements like `<b>`, `<strong>`, `<span style="...">`). * * @param {CKEDITOR.dom.range} [range] If specified, the HTML will be inserted into the range * instead of into the selection. The selection will be placed at the end of the insertion (like in the normal case). * Introduced in CKEditor 4.5. */ insertHtml: function( html, mode, range ) { this.fire( 'insertHtml', { dataValue: html, mode: mode, range: range } ); }, /** * Inserts text content into the currently selected position in the * editor in WYSIWYG mode. The styles of the selected element will be applied to the inserted text. * Spaces around the text will be left untouched. * * CKEDITOR.instances.editor1.insertText( ' line1 \n\n line2' ); * * Fires the {@link #event-insertText} and {@link #event-afterInsertHtml} events. The text is inserted * in the {@link #event-insertText} event's listener with a default priority (10) so you can add listeners with * lower or higher priorities in order to execute some code before or after the text is inserted. * * @since 3.5.0 * @param {String} text Text to be inserted into the editor. */ insertText: function( text ) { this.fire( 'insertText', text ); }, /** * Inserts an element into the currently selected position in the editor in WYSIWYG mode. * * var element = CKEDITOR.dom.element.createFromHtml( '<img src="hello.png" border="0" title="Hello" />' ); * CKEDITOR.instances.editor1.insertElement( element ); * * Fires the {@link #event-insertElement} event. The element is inserted in the listener with a default priority (10), * so you can add listeners with lower or higher priorities in order to execute some code before or after * the element is inserted. * * @param {CKEDITOR.dom.element} element The element to be inserted into the editor. */ insertElement: function( element ) { this.fire( 'insertElement', element ); }, /** * Gets the selected HTML (it is returned as a {@link CKEDITOR.dom.documentFragment document fragment} * or a string). This method is designed to work as the user would expect the copy functionality to work. * For instance, if the following selection was made: * * <p>a<b>b{c}d</b>e</p> * * The following HTML will be returned: * * <b>c</b> * * As you can see, the information about the bold formatting was preserved, even though the selection was * anchored inside the `<b>` element. * * See also: * * * the {@link #extractSelectedHtml} method, * * the {@link CKEDITOR.editable#getHtmlFromRange} method. * * @since 4.5.0 * @param {Boolean} [toString] If `true`, then stringified HTML will be returned. * @returns {CKEDITOR.dom.documentFragment/String} */ getSelectedHtml: function( toString ) { var editable = this.editable(), selection = this.getSelection(), ranges = selection && selection.getRanges(); if ( !editable || !ranges || ranges.length === 0 ) { return null; } var docFragment = createDocumentFragmentFromRanges( ranges, editable ); return toString ? docFragment.getHtml() : docFragment; }, /** * Gets the selected HTML (it is returned as a {@link CKEDITOR.dom.documentFragment document fragment} * or a string) and removes the selected part of the DOM. This method is designed to work as the user would * expect the cut and delete functionalities to work. * * See also: * * * the {@link #getSelectedHtml} method, * * the {@link CKEDITOR.editable#extractHtmlFromRange} method. * * @since 4.5.0 * @param {Boolean} [toString] If `true`, then stringified HTML will be returned. * @param {Boolean} [removeEmptyBlock=false] Default `false` means that the function will keep an empty block (if the * entire content was removed) or it will create it (if a block element was removed) and set the selection in that block. * If `true`, the empty block will be removed or not created. In this case the function will not handle the selection. * @returns {CKEDITOR.dom.documentFragment/String/null} */ extractSelectedHtml: function( toString, removeEmptyBlock ) { var editable = this.editable(), ranges = this.getSelection().getRanges(), docFragment = new CKEDITOR.dom.documentFragment(), i; if ( !editable || ranges.length === 0 ) { return null; } for ( i = 0; i < ranges.length; i++ ) { docFragment.append( editable.extractHtmlFromRange( ranges[ i ], removeEmptyBlock ) ); } if ( !removeEmptyBlock ) { this.getSelection().selectRanges( [ ranges[ 0 ] ] ); } return toString ? docFragment.getHtml() : docFragment; }, /** * Moves the selection focus to the editing area space in the editor. */ focus: function() { this.fire( 'beforeFocus' ); }, /** * Checks whether the current editor content contains changes when * compared to the content loaded into the editor at startup, or to * the content available in the editor when {@link #resetDirty} * was called. * * function beforeUnload( evt ) { * if ( CKEDITOR.instances.editor1.checkDirty() ) * return evt.returnValue = "You will lose the changes made in the editor."; * } * * if ( window.addEventListener ) * window.addEventListener( 'beforeunload', beforeUnload, false ); * else * window.attachEvent( 'onbeforeunload', beforeUnload ); * * @returns {Boolean} `true` if the content contains changes. */ checkDirty: function() { return this.status == 'ready' && this._.previousValue !== this.getSnapshot(); }, /** * Resets the "dirty state" of the editor so subsequent calls to * {@link #checkDirty} will return `false` if the user will not * have made further changes to the content. * * alert( editor.checkDirty() ); // e.g. true * editor.resetDirty(); * alert( editor.checkDirty() ); // false */ resetDirty: function() { this._.previousValue = this.getSnapshot(); }, /** * Updates the `<textarea>` element that was replaced by the editor with * the current data available in the editor. * * **Note:** This method will only affect those editor instances created * with the {@link CKEDITOR#ELEMENT_MODE_REPLACE} element mode or inline instances * bound to `<textarea>` elements. * * CKEDITOR.instances.editor1.updateElement(); * alert( document.getElementById( 'editor1' ).value ); // The current editor data. * * @see CKEDITOR.editor#element */ updateElement: function() { return updateEditorElement.call( this ); }, /** * Assigns keystrokes associated with editor commands. * * editor.setKeystroke( CKEDITOR.CTRL + 115, 'save' ); // Assigned Ctrl+S to the "save" command. * editor.setKeystroke( CKEDITOR.CTRL + 115, false ); // Disabled Ctrl+S keystroke assignment. * editor.setKeystroke( [ * [ CKEDITOR.ALT + 122, false ], * [ CKEDITOR.CTRL + 121, 'link' ], * [ CKEDITOR.SHIFT + 120, 'bold' ] * ] ); * * This method may be used in the following cases: * * * By plugins (like `link` or `basicstyles`) to set their keystrokes when plugins are being loaded. * * During the runtime to modify existing keystrokes. * * The editor handles keystroke configuration in the following order: * * 1. Plugins use this method to define default keystrokes. * 2. Editor extends default keystrokes with {@link CKEDITOR.config#keystrokes}. * 3. Editor blocks keystrokes defined in {@link CKEDITOR.config#blockedKeystrokes}. * * You can then set new keystrokes using this method during the runtime. * * @since 4.0.0 * @param {Number/Array} keystroke A keystroke or an array of keystroke definitions. * @param {String/Boolean} [behavior] A command to be executed on the keystroke. */ setKeystroke: function() { var keystrokes = this.keystrokeHandler.keystrokes, newKeystrokes = CKEDITOR.tools.isArray( arguments[ 0 ] ) ? arguments[ 0 ] : [ [].slice.call( arguments, 0 ) ], keystroke, behavior; for ( var i = newKeystrokes.length; i--; ) { keystroke = newKeystrokes[ i ]; behavior = 0; // It may be a pair of: [ key, command ] if ( CKEDITOR.tools.isArray( keystroke ) ) { behavior = keystroke[ 1 ]; keystroke = keystroke[ 0 ]; } if ( behavior ) keystrokes[ keystroke ] = behavior; else delete keystrokes[ keystroke ]; } }, /** * Returns the keystroke that is assigned to a specified {@link CKEDITOR.command}. If no keystroke is assigned, * it returns `null`. * * Since version 4.7.0 this function also accepts a `command` parameter as a string. * * @since 4.6.0 * @param {CKEDITOR.command/String} command The {@link CKEDITOR.command} instance or a string with the command name. * @param {Boolean} [all=false] If `true`, the function will return an array of assigned keystrokes. * Available since 4.11.0. * @returns {Number/Number[]/null} Depending on the `all` parameter value: * * * `false` – The first keystroke assigned to the provided command or `null` if there is no keystroke. * * `true` – An array of all assigned keystrokes or an empty array if there is no keystroke. */ getCommandKeystroke: function( command, all ) { var commandInstance = ( typeof command === 'string' ? this.getCommand( command ) : command ), ret = []; if ( commandInstance ) { var commandName = CKEDITOR.tools.object.findKey( this.commands, commandInstance ), keystrokes = this.keystrokeHandler.keystrokes; // Some commands have a fake keystroke - for example CUT/COPY/PASTE commands are handled natively. // If fake key was used, the regular keystrokes should be skipped. if ( commandInstance.fakeKeystroke ) { ret.push( commandInstance.fakeKeystroke ); } else { for ( var i in keystrokes ) { if ( keystrokes[ i ] === commandName ) { ret.push( i ); } } } } return all ? ret : ( ret[ 0 ] || null ); }, /** * Shorthand for {@link CKEDITOR.filter#addFeature}. * * @since 4.1.0 * @param {CKEDITOR.feature} feature See {@link CKEDITOR.filter#addFeature}. * @returns {Boolean} See {@link CKEDITOR.filter#addFeature}. */ addFeature: function( feature ) { return this.filter.addFeature( feature ); }, /** * Sets the active filter ({@link #activeFilter}). Fires the {@link #activeFilterChange} event. * * // Set active filter which allows only 4 elements. * // Buttons like Bold, Italic will be disabled. * var filter = new CKEDITOR.filter( 'p strong em br' ); * editor.setActiveFilter( filter ); * * Setting a new filter will also change the {@link #setActiveEnterMode active Enter modes} to the first values * allowed by the new filter (see {@link CKEDITOR.filter#getAllowedEnterMode}). * * @since 4.3.0 * @param {CKEDITOR.filter} filter Filter instance or a falsy value (e.g. `null`) to reset to the default one. */ setActiveFilter: function( filter ) { if ( !filter ) filter = this.filter; if ( this.activeFilter !== filter ) { this.activeFilter = filter; this.fire( 'activeFilterChange' ); // Reset active filter to the main one - it resets enter modes, too. if ( filter === this.filter ) this.setActiveEnterMode( null, null ); else this.setActiveEnterMode( filter.getAllowedEnterMode( this.enterMode ), filter.getAllowedEnterMode( this.shiftEnterMode, true ) ); } }, /** * Sets the active Enter modes: ({@link #enterMode} and {@link #shiftEnterMode}). * Fires the {@link #activeEnterModeChange} event. * * Prior to CKEditor 4.3.0 Enter modes were static and it was enough to check {@link CKEDITOR.config#enterMode} * and {@link CKEDITOR.config#shiftEnterMode} when implementing a feature which should depend on the Enter modes. * Since CKEditor 4.3.0 these options are source of initial: * * * static {@link #enterMode} and {@link #shiftEnterMode} values, * * dynamic {@link #activeEnterMode} and {@link #activeShiftEnterMode} values. * * However, the dynamic Enter modes can be changed during runtime by using this method, to reflect the selection context. * For example, if selection is moved to the {@link CKEDITOR.plugins.widget widget}'s nested editable which * is a {@link #blockless blockless one}, then the active Enter modes should be changed to {@link CKEDITOR#ENTER_BR} * (in this case {@glink guide/dev_widgets Widget System} takes care of that). * * **Note:** This method should not be used to configure the editor – use {@link CKEDITOR.config#enterMode} and * {@link CKEDITOR.config#shiftEnterMode} instead. This method should only be used to dynamically change * Enter modes during runtime based on selection changes. * Keep in mind that changed Enter mode may be overwritten by another plugin/feature when it decided that * the changed context requires this. * * **Note:** In case of blockless editor (inline editor based on an element which cannot contain block elements * — see {@link CKEDITOR.editor#blockless}) only {@link CKEDITOR#ENTER_BR} is a valid Enter mode. Therefore * this method will not allow to set other values. * * **Note:** Changing the {@link #activeFilter active filter} may cause the Enter mode to change if default Enter modes * are not allowed by the new filter. * * @since 4.3.0 * @param {Number} enterMode One of {@link CKEDITOR#ENTER_P}, {@link CKEDITOR#ENTER_DIV}, {@link CKEDITOR#ENTER_BR}. * Pass falsy value (e.g. `null`) to reset the Enter mode to the default value ({@link #enterMode} and/or {@link #shiftEnterMode}). * @param {Number} shiftEnterMode See the `enterMode` argument. */ setActiveEnterMode: function( enterMode, shiftEnterMode ) { // Validate passed modes or use default ones (validated on init). enterMode = enterMode ? validateEnterMode( this, enterMode ) : this.enterMode; shiftEnterMode = shiftEnterMode ? validateEnterMode( this, shiftEnterMode ) : this.shiftEnterMode; if ( this.activeEnterMode != enterMode || this.activeShiftEnterMode != shiftEnterMode ) { this.activeEnterMode = enterMode; this.activeShiftEnterMode = shiftEnterMode; this.fire( 'activeEnterModeChange' ); } }, /** * Shows a notification to the user. * * If the [Notification](https://ckeditor.com/cke4/addon/notification) plugin is not enabled, this function shows * a normal alert with the given `message`. The `type` and `progressOrDuration` parameters are supported * only by the Notification plugin. * * If the Notification plugin is enabled, this method creates and shows a new notification. * By default the notification is shown over the editor content, in the viewport if it is possible. * * See {@link CKEDITOR.plugins.notification}. * * @since 4.5.0 * @member CKEDITOR.editor * @param {String} message The message displayed in the notification. * @param {String} [type='info'] The type of the notification. Can be `'info'`, `'warning'`, `'success'` or `'progress'`. * @param {Number} [progressOrDuration] If the type is `progress`, the third parameter may be a progress from `0` to `1` * (defaults to `0`). Otherwise the third parameter may be a notification duration denoting after how many milliseconds * the notification should be closed automatically. `0` means that the notification will not close automatically and the user * needs to close it manually. See {@link CKEDITOR.plugins.notification#duration}. * Note that `warning` notifications will not be closed automatically. * @returns {CKEDITOR.plugins.notification} Created and shown notification. */ showNotification: function( message ) { alert( message ); // jshint ignore:line }, /** * Provides information whether the editor's {@link CKEDITOR.editor#container container} * {@link CKEDITOR.dom.element#isDetached is detached}. * * @since 4.13.0 * @returns {Boolean} true if the editor's container is detached. */ isDetached: function() { return !!this.container && this.container.isDetached(); }, /** * Determines if the current editor instance is destroyed. * * @since 4.13.0 * @returns {Boolean} true if the editor is destroyed. */ isDestroyed: function() { return this.status === 'destroyed'; } } ); /** * Gets the element from the DOM and checks if the editor can be instantiated on it. * This function is available for internal use only. * * @private * @since 4.12.0 * @static * @param {String/CKEDITOR.dom.element} elementOrId * @member CKEDITOR.editor * @returns {CKEDITOR.dom.element/null} */ CKEDITOR.editor._getEditorElement = function( elementOrId ) { if ( !CKEDITOR.env.isCompatible ) { return null; } var element = CKEDITOR.dom.element.get( elementOrId ); // Throw error on missing target element. if ( !element ) { CKEDITOR.error( 'editor-incorrect-element', { element: elementOrId } ); return null; } // Avoid multiple inline editor instances on the same element. if ( element.getEditor() ) { CKEDITOR.error( 'editor-element-conflict', { editorName: element.getEditor().name } ); return null; } return element; }; } )(); /** * The editor has no associated element. * * @readonly * @property {Number} [=0] * @member CKEDITOR */ CKEDITOR.ELEMENT_MODE_NONE = 0; /** * The element is to be replaced by the editor instance. * * @readonly * @property {Number} [=1] * @member CKEDITOR */ CKEDITOR.ELEMENT_MODE_REPLACE = 1; /** * The editor is to be created inside the element. * * @readonly * @property {Number} [=2] * @member CKEDITOR */ CKEDITOR.ELEMENT_MODE_APPENDTO = 2; /** * The editor is to be attached to the element, using it as the editing block. * * @readonly * @property {Number} [=3] * @member CKEDITOR */ CKEDITOR.ELEMENT_MODE_INLINE = 3; /** * Whether to escape HTML when the editor updates the original input element. * * config.htmlEncodeOutput = true; * * @since 3.1.0 * @cfg {Boolean} [htmlEncodeOutput=false] * @member CKEDITOR.config */ /** * If `true`, makes the editor start in read-only state. Otherwise, it will check * if the linked `<textarea>` element has the `disabled` attribute. * * Read more in the {@glink features/readonly documentation} * and see the {@glink examples/readonly example}. * * config.readOnly = true; * * @since 3.6.0 * @cfg {Boolean} [readOnly=false] * @member CKEDITOR.config * @see CKEDITOR.editor#setReadOnly */ /** * Whether an editable element should have focus when the editor is loading for the first time. * * // Focus at the beginning of the editable. * config.startupFocus = true; * * Since CKEditor 4.9.0, `startupFocus` can be explicitly set to either the `start` or the `end` * of the editable: * * // Focus at the beginning of the editable. * config.startupFocus = 'start'; * * // Focus at the end of the editable. * config.startupFocus = 'end'; * * @cfg {String/Boolean} [startupFocus=false] * @member CKEDITOR.config */ /** * Customizes the {@link CKEDITOR.editor#title human-readable title} of this editor. This title is displayed in * tooltips and impacts various [accessibility aspects](#!/guide/dev_a11y-section-announcing-the-editor-on-the-page), * e.g. it is commonly used by screen readers for distinguishing editor instances and for navigation. * Accepted values are a string or `false`. * * **Note:** When `config.title` is set globally, the same value will be applied to all editor instances * loaded with this config. This may adversely affect accessibility as screen reader users will be unable * to distinguish particular editor instances and navigate between them. * * **Note:** Setting `config.title = false` may also impair accessibility in a similar way. * * **Note:** Please do not confuse this property with {@link CKEDITOR.editor#name} * which identifies the instance in the {@link CKEDITOR#instances} literal. * * // Sets the title to 'My WYSIWYG editor.'. The original title of the element (if it exists) * // will be restored once the editor instance is destroyed. * config.title = 'My WYSIWYG editor.'; * * // Do not touch the title. If the element already has a title, it remains unchanged. * // Also if no `title` attribute exists, nothing new will be added. * config.title = false; * * See also: * * * CKEDITOR.editor#name * * CKEDITOR.editor#title * * @since 4.2.0 * @cfg {String/Boolean} [title=based on editor.name] * @member CKEDITOR.config */ /** * Sets listeners on editor events. * * **Note:** This property can only be set in the `config` object passed directly * to {@link CKEDITOR#replace}, {@link CKEDITOR#inline}, and other creators. * * CKEDITOR.replace( 'editor1', { * on: { * instanceReady: function() { * alert( this.name ); // 'editor1' * }, * * key: function() { * // ... * } * } * } ); * * @cfg {Object} on * @member CKEDITOR.config */ /** * The outermost element in the DOM tree in which the editable element resides. It is provided * by a specific editor creator after the editor UI is created and is not intended to * be modified. * * var editor = CKEDITOR.instances.editor1; * alert( editor.container.getName() ); // 'span' * * @readonly * @property {CKEDITOR.dom.element} container */ /** * The document that stores the editor content. * * * For the classic (`iframe`-based) editor it is equal to the document inside the * `iframe` containing the editable element. * * For the inline editor it is equal to {@link CKEDITOR#document}. * * The document object is available after the {@link #contentDom} event is fired * and may be invalidated when the {@link #contentDomUnload} event is fired * (classic editor only). * * editor.on( 'contentDom', function() { * console.log( editor.document ); * } ); * * @readonly * @property {CKEDITOR.dom.document} document */ /** * The window instance related to the {@link #document} property. * * It is always equal to the `editor.document.getWindow()`. * * See the {@link #document} property documentation. * * @readonly * @property {CKEDITOR.dom.window} window */ /** * The main filter instance used for input data filtering, data * transformations, and activation of features. * * It points to a {@link CKEDITOR.filter} instance set up based on * editor configuration. * * @since 4.1.0 * @readonly * @property {CKEDITOR.filter} filter */ /** * The active filter instance which should be used in the current context (location selection). * This instance will be used to make a decision which commands, buttons and other * {@link CKEDITOR.feature features} can be enabled. * * By default it equals the {@link #filter} and it can be changed by the {@link #setActiveFilter} method. * * editor.on( 'activeFilterChange', function() { * if ( editor.activeFilter.check( 'cite' ) ) * // Do something when <cite> was enabled - e.g. enable a button. * else * // Otherwise do something else. * } ); * * See also the {@link #setActiveEnterMode} method for an explanation of dynamic settings. * * @since 4.3.0 * @readonly * @property {CKEDITOR.filter} activeFilter */ /** * The main (static) Enter mode which is a validated version of the {@link CKEDITOR.config#enterMode} setting. * Currently only one rule exists — {@link #blockless blockless editors} may have * Enter modes set only to {@link CKEDITOR#ENTER_BR}. * * @since 4.3.0 * @readonly * @property {Number} enterMode */ /** * See the {@link #enterMode} property. * * @since 4.3.0 * @readonly * @property {Number} shiftEnterMode */ /** * The dynamic Enter mode which should be used in the current context (selection location). * By default it equals the {@link #enterMode} and it can be changed by the {@link #setActiveEnterMode} method. * * See also the {@link #setActiveEnterMode} method for an explanation of dynamic settings. * * @since 4.3.0 * @readonly * @property {Number} activeEnterMode */ /** * See the {@link #activeEnterMode} property. * * @since 4.3.0 * @readonly * @property {Number} activeShiftEnterMode */ /** * Event fired by the {@link #setActiveFilter} method when the {@link #activeFilter} is changed. * * @since 4.3.0 * @event activeFilterChange */ /** * Event fired by the {@link #setActiveEnterMode} method when any of the active Enter modes is changed. * See also the {@link #activeEnterMode} and {@link #activeShiftEnterMode} properties. * * @since 4.3.0 * @event activeEnterModeChange */ /** * Event fired when a CKEDITOR instance is created, but still before initializing it. * To interact with a fully initialized instance, use the * {@link CKEDITOR#instanceReady} event instead. * * @event instanceCreated * @member CKEDITOR * @param {CKEDITOR.editor} editor The editor instance that has been created. */ /** * Event fired when CKEDITOR instance's components (configuration, languages and plugins) are fully * loaded and initialized. However, the editor will be fully ready for interaction * on {@link CKEDITOR#instanceReady}. * * @event instanceLoaded * @member CKEDITOR * @param {CKEDITOR.editor} editor This editor instance that has been loaded. */ /** * Event fired when a CKEDITOR instance is destroyed. * * @event instanceDestroyed * @member CKEDITOR * @param {CKEDITOR.editor} editor The editor instance that has been destroyed. */ /** * Event fired when a CKEDITOR instance is created, fully initialized and ready for interaction. * * @event instanceReady * @member CKEDITOR * @param {CKEDITOR.editor} editor The editor instance that has been created. */ /** * Event fired when the language is loaded into the editor instance. * * @since 3.6.1 * @event langLoaded * @param {CKEDITOR.editor} editor This editor instance. */ /** * Event fired when all plugins are loaded and initialized into the editor instance. * * @event pluginsLoaded * @param {CKEDITOR.editor} editor This editor instance. */ /** * Event fired when the styles set is loaded. During the editor initialization * phase the {@link #getStylesSet} method returns only styles that * are already loaded, which may not include e.g. styles parsed * by the `stylesheetparser` plugin. Thus, to be notified when all * styles are ready, you can listen on this event. * * @since 4.1.0 * @event stylesSet * @param {CKEDITOR.editor} editor This editor instance. * @param {Array} styles An array of styles definitions. */ /** * Event fired before the command execution when {@link #execCommand} is called. * * @event beforeCommandExec * @param {CKEDITOR.editor} editor This editor instance. * @param data * @param {String} data.name The command name. * @param {Object} data.commandData The data to be sent to the command. This * can be manipulated by the event listener. * @param {CKEDITOR.command} data.command The command itself. */ /** * Event fired after the command execution when {@link #execCommand} is called. * * @event afterCommandExec * @param {CKEDITOR.editor} editor This editor instance. * @param data * @param {String} data.name The command name. * @param {Object} data.commandData The data sent to the command. * @param {CKEDITOR.command} data.command The command itself. * @param {Object} data.returnValue The value returned by the command execution. */ /** * Event fired when a custom configuration file is loaded, before the final * configuration initialization. * * Custom configuration files can be loaded thorugh the * {@link CKEDITOR.config#customConfig} setting. Several files can be loaded * by changing this setting. * * @event customConfigLoaded * @param {CKEDITOR.editor} editor This editor instance. */ /** * Event fired once the editor configuration is ready (loaded and processed). * * @event configLoaded * @param {CKEDITOR.editor} editor This editor instance. */ /** * Event fired when this editor instance is destroyed. The editor at this * point is not usable and this event should be used to perform the clean-up * in any plugin. * * @event destroy * @param {CKEDITOR.editor} editor This editor instance. */ /** * Event fired when the {@link #method-destroy} method is called, * but before destroying the editor. * * @event beforeDestroy * @param {CKEDITOR.editor} editor This editor instance. */ /** * Internal event to get the current data. * * @event beforeGetData * @param {CKEDITOR.editor} editor This editor instance. */ /** * Internal event to perform the {@link #method-getSnapshot} call. * * @event getSnapshot * @param {CKEDITOR.editor} editor This editor instance. */ /** * Internal event to perform the {@link #method-loadSnapshot} call. * * @event loadSnapshot * @param {CKEDITOR.editor} editor This editor instance. * @param {String} data The data that will be used. */ /** * Event fired before the {@link #method-getData} call returns, allowing for additional manipulation. * * @event getData * @param {CKEDITOR.editor} editor This editor instance. * @param data * @param {String} data.dataValue The data that will be returned. */ /** * Event fired before the {@link #method-setData} call is executed, allowing for additional manipulation. * * @event setData * @param {CKEDITOR.editor} editor This editor instance. * @param data * @param {String} data.dataValue The data that will be used. */ /** * Event fired at the end of the {@link #method-setData} call execution. Usually it is better to use the * {@link #dataReady} event. * * @event afterSetData * @param {CKEDITOR.editor} editor This editor instance. * @param data * @param {String} data.dataValue The data that has been set. */ /** * Event fired as an indicator of the editor data loading. It may be the result of * calling {@link #method-setData} explicitly or an internal * editor function, like the editor editing mode switching (move to Source and back). * * @event dataReady * @param {CKEDITOR.editor} editor This editor instance. */ /** * Event fired when the CKEDITOR instance is completely created, fully initialized * and ready for interaction. * * @event instanceReady * @param {CKEDITOR.editor} editor This editor instance. */ /** * Event fired when editor components (configuration, languages and plugins) are fully * loaded and initialized. However, the editor will be fully ready to for interaction * on {@link #instanceReady}. * * @event loaded * @param {CKEDITOR.editor} editor This editor instance. */ /** * Event fired by the {@link #method-insertHtml} method. See the method documentation for more information * about how this event can be used. * * @event insertHtml * @param {CKEDITOR.editor} editor This editor instance. * @param data * @param {String} data.mode The mode in which the data is inserted (see {@link #method-insertHtml}). * @param {String} data.dataValue The HTML code to insert. * @param {CKEDITOR.dom.range} [data.range] See {@link #method-insertHtml}'s `range` parameter. */ /** * Event fired by the {@link #method-insertText} method. See the method documentation for more information * about how this event can be used. * * @event insertText * @param {CKEDITOR.editor} editor This editor instance. * @param {String} data The text to insert. */ /** * Event fired by the {@link #method-insertElement} method. See the method documentation for more information * about how this event can be used. * * @event insertElement * @param {CKEDITOR.editor} editor This editor instance. * @param {CKEDITOR.dom.element} data The element to insert. */ /** * Event fired after data insertion using the {@link #method-insertHtml}, {@link CKEDITOR.editable#insertHtml}, * or {@link CKEDITOR.editable#insertHtmlIntoRange} methods. * * @since 4.5.0 * @event afterInsertHtml * @param data * @param {CKEDITOR.dom.range} [data.intoRange] If set, the HTML was not inserted into the current selection, but into * the specified range. This property is set if the {@link CKEDITOR.editable#insertHtmlIntoRange} method was used, * but not if for the {@link CKEDITOR.editable#insertHtml} method. */ /** * Event fired after the {@link #property-readOnly} property changes. * * @since 3.6.0 * @event readOnly * @param {CKEDITOR.editor} editor This editor instance. */ /** * Event fired when a UI template is added to the editor instance. It makes * it possible to bring customizations to the template source. * * @event template * @param {CKEDITOR.editor} editor This editor instance. * @param data * @param {String} data.name The template name. * @param {String} data.source The source data for this template. */ /** * Event fired when the editor content (its DOM structure) is ready. * It is similar to the native `DOMContentLoaded` event, but it applies to * the editor content. It is also the first event fired after * the {@link CKEDITOR.editable} is initialized. * * This event is particularly important for classic (`iframe`-based) * editor, because on editor initialization and every time the data are set * (by {@link CKEDITOR.editor#method-setData}) content DOM structure * is rebuilt. Thus, e.g. you need to attach DOM event listeners * on editable one more time. * * For inline editor this event is fired only once — when the * editor is initialized for the first time. This is because setting * editor content does not cause editable destruction and creation. * * The {@link #contentDom} event goes along with {@link #contentDomUnload} * which is fired before the content DOM structure is destroyed. This is the * right moment to detach content DOM event listener. Otherwise * browsers like IE or Opera may throw exceptions when accessing * elements from the detached document. * * **Note:** {@link CKEDITOR.editable#attachListener} is a convenient * way to attach listeners that will be detached on {@link #contentDomUnload}. * * editor.on( 'contentDom', function() { * var editable = editor.editable(); * * editable.attachListener( editable, 'click', function() { * console.log( 'The editable was clicked.' ); * }); * }); * * @event contentDom * @param {CKEDITOR.editor} editor This editor instance. */ /** * Event fired before the content DOM structure is destroyed. * See {@link #contentDom} documentation for more details. * * @event contentDomUnload * @param {CKEDITOR.editor} editor This editor instance. */ /** * Event fired when the content DOM changes and some of the references as well as * the native DOM event listeners could be lost. * This event is useful when it is important to keep track of references * to elements in the editable content from code. * * @since 4.3.0 * @event contentDomInvalidated * @param {CKEDITOR.editor} editor This editor instance. */