1 /*
  2  * CKEditor - The text editor for Internet - http://ckeditor.com
  3  * Copyright (C) 2003-2008 Frederico Caldeira Knabben
  4  *
  5  * == BEGIN LICENSE ==
  6  *
  7  * Licensed under the terms of any of the following licenses at your
  8  * choice:
  9  *
 10  *  - GNU General Public License Version 2 or later (the "GPL")
 11  *    http://www.gnu.org/licenses/gpl.html
 12  *
 13  *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
 14  *    http://www.gnu.org/licenses/lgpl.html
 15  *
 16  *  - Mozilla Public License Version 1.1 or later (the "MPL")
 17  *    http://www.mozilla.org/MPL/MPL-1.1.html
 18  *
 19  * == END LICENSE ==
 20  */
 21
 22 /**
 23  * @fileOverview Defines the {@link CKEDITOR.editor} class, which represents an
 24  *		editor instance.
 25  */
 26
 27  /**
 28  * Represents an editor instance. This constructor should be rarely used, being
 29  * the standard replacement methods preferible.
 30  * @constructor
 31  * @param {CKEDITOR.dom.element} element The original element replaced by this
 32  *		editor instance.
 33  * @augments CKEDITOR.event
 34  * @example
 35  * var myTextarea = CKEDITOR.document.getById( 'myTextarea' );
 36  * var myEditor = <b>new CKEDITOR.editor( myTextarea )</b>;
 37  * CKEDITOR.add( myEditor );
 38  */
 39 CKEDITOR.editor = ( function()
 40 {
 41 	// The counter for automatic instance names.
 42 	var nameCounter = 0;
 43
 44 	var getNewName = function()
 45 	{
 46 		var name = 'editor' + ( ++nameCounter );
 47 		return CKEDITOR.instances[ name ] ? getNewName() : name;
 48 	};
 49
 50 	// ##### START: Config Privates
 51
 52 	// These function loads custom configuration files and cache the
 53 	// CKEDITOR.editorConfig functions defined on them, so there is no need to
 54 	// download them more than once for several instances.
 55 	var loadConfigLoaded = {};
 56 	var loadConfig = function( editor )
 57 	{
 58 		var customConfig = editor.config.customConfig;
 59
 60 		// Check if there is a custom config to load.
 61 		if ( !customConfig )
 62 			return false;
 63
 64 		var loadedConfig = loadConfigLoaded[ customConfig ] || ( loadConfigLoaded[ customConfig ] = { editors : [] } );
 65
 66 		// If the custom config has already been downloaded, reuse it.
 67 		if ( loadedConfig.fn )
 68 		{
 69 			// Call the cached CKEDITOR.editorConfig defined in the custom
 70 			// config file for the editor instance depending on it.
 71 			loadedConfig.fn.call( editor, editor );
 72
 73 			// If there is no other customConfig in the chain, fire the
 74 			// "configLoaded" event.
 75 			if ( editor.config.customConfig == customConfig || !loadConfig( editor ) )
 76 				editor.fireOnce( 'customConfigLoaded' );
 77 		}
 78 		else
 79 		{
 80 			// Add the editor to the list of editors waiting for this config.
 81 			loadedConfig.editors.push( editor );
 82
 83 			// Load the custom configuration file.
 84 			CKEDITOR.scriptLoader.load( customConfig, function()
 85 				{
 86 					// If the CKEDITOR.editorConfig function has been properly
 87 					// defined in the custom configuration file, cache it.
 88 					if ( CKEDITOR.editorConfig )
 89 						loadedConfig.fn = CKEDITOR.editorConfig;
 90 					else
 91 						loadedConfig.fn = function(){};
 92
 93 					delete CKEDITOR.editorConfig;
 94
 95 					for ( var i = 0, length = loadedConfig.editors.length ; i < length ; i++ )
 96 					{
 97 						// Call the load config again. This time the custom
 98 						// config is already cached and so it will get loaded.
 99 						loadConfig( loadedConfig.editors[ i ] );
100 					}
101
102 					delete loadedConfig.editors;
103 				});
104 		}
105
106 		return true;
107 	};
108
109 	var initConfig = function( editor, instanceConfig )
110 	{
111 		// Setup the lister for the "customConfigLoaded" event.
112 		editor.on( 'customConfigLoaded', function()
113 			{
114 				// Overwrite the settings from the in-page config.
115 				if ( instanceConfig )
116 					CKEDITOR.tools.extend( editor.config, instanceConfig, true );
117
118 				// Fire the "configLoaded" event.
119 				editor.fireOnce( 'configLoaded' );
120
121 				// Start loading the plugins.
122 				loadPlugins( editor );
123 			});
124
125 		// The instance config may override the customConfig setting to avoid
126 		// loading the default ~/config.js file.
127 		if ( instanceConfig && instanceConfig.customConfig != undefined )
128 			editor.config.customConfig = instanceConfig.customConfig;
129
130 		// Load configs from the custom configuration files.
131 		if ( !loadConfig( editor ) )
132 			editor.fireOnce( 'customConfigLoaded' );
133 	};
134
135 	// Basic config class to inherit the default settings from CKEDITOR.config.
136 	var config = function()
137 	{};
138 	config.prototype = CKEDITOR.config;
139
140 	// ##### END: Config Privates
141
142 	var loadPlugins = function( editor )
143 	{
144 		// Load all plugins defined in the "plugins" setting.
145 		CKEDITOR.plugins.load( editor.config.plugins.split( ',' ), function( plugins )
146 			{
147 				// Cache the loaded plugin names.
148 				editor.plugins = plugins;
149
150 				// Initialize all plugins that have the "init" method defined.
151 				for ( var i = 0 ; i < plugins.length ; i++ )
152 				{
153 					var pluginName = plugins[ i ];
154 					var plugin = CKEDITOR.plugins.get( pluginName );
155 					if ( plugin && plugin.init )
156 						plugin.init( editor, CKEDITOR.plugins.getPath( pluginName ) );
157 				}
158
159 				// Load the editor skin and theme.
160 				loadSkinTheme( editor );
161 			});
162 	};
163
164 	var loadSkinTheme = function( editor )
165 	{
166 		// Load the skin.
167 		CKEDITOR.skins.load( editor.config.skin, 'editor' );
168
169 		// Load the theme.
170 		var theme = editor.config.theme;
171 		CKEDITOR.themes.load( theme, function()
172 			{
173 				CKEDITOR.themes.get( theme ).build( editor, CKEDITOR.themes.getPath( theme ) );
174 			});
175 	};
176
177 	return function( element, instanceConfig )
178 	{
179 		this._ =
180 		{
181 			commands : {}
182 		};
183
184 		// Call the base constructor.
185 		CKEDITOR.event.call( this );
186
187 		/**
188 		 * The DOM element that has been replaced by this editor instance. This
189 		 * element holds the editor data on load and post.
190 		 * @name CKEDITOR.editor.prototype.element
191 		 * @type CKEDITOR.dom.element
192 		 * @example
193 		 * var editor = CKEDITOR.instances.editor1;
194 		 * alert( <b>editor.element</b>.getName() );  "textarea"
195 		 */
196 		this.element = element;
197
198 		/**
199 		 * The editor instance name. It hay be the replaced element id, name or
200 		 * a default name using a progressive counter (editor1, editor2, ...).
201 		 * @name CKEDITOR.editor.prototype.name
202 		 * @type String
203 		 * @example
204 		 * var editor = CKEDITOR.instances.editor1;
205 		 * alert( <b>editor.name</b> );  "editor1"
206 		 */
207 		this.name = element.getId() || element.getNameAtt() || getNewName();
208
209 		/**
210 		 * The configurations for this editor instance. It inherits all
211 		 * settings defined in (@link CKEDITOR.config}, combined with settings
212 		 * loaded from custom configuration files and those defined inline in
213 		 * the page when creating the editor.
214 		 * @name CKEDITOR.editor.prototype.config
215 		 * @type Object
216 		 * @example
217 		 * var editor = CKEDITOR.instances.editor1;
218 		 * alert( <b>editor.config.theme</b> );  "default" e.g.
219 		 */
220 		this.config = new config();
221
222 		// Call initConfig using events, to be sure that instanceCreated is
223 		// fired first.
224 		this.on( 'instanceCreated', function()
225 			{
226 				initConfig( this, instanceConfig );
227 			});
228 	};
229 })();
230
231 CKEDITOR.editor.prototype =
232 {
233 	addCommand : function( commandName, commandDefinition )
234 	{
235 		this._.commands[ commandName ] = commandDefinition;
236 	},
237
238 	execCommand : function( commandName, data )
239 	{
240 		var command = this.getCommand( commandName );
241 		if ( command )
242 			return command.exec( data );
243
244 		throw 'Unknown command name "' + commandName + '"';
245 	},
246 	
247 	getCommand : function( commandName )
248 	{
249 		return this._.commands[ commandName ] || null;
250 	},
251 	
252 	// Both fire and fireOnce will always pass this editor instance as the
253 	// "editor" param in CKEDITOR.event.fire. So, we override it to do that
254 	// automaticaly.
255
256 	/** @ignore */
257 	fire : function( eventName, data )
258 	{
259 		return CKEDITOR.event.prototype.fire.call( this, eventName, data, this );
260 	},
261
262 	/** @ignore */
263 	fireOnce : function( eventName, data )
264 	{
265 		return CKEDITOR.event.prototype.fireOnce.call( this, eventName, data, this );
266 	},
267
268 	/**
269 	 * Gets the editor data. The data will be in raw format. It is the same
270 	 * data that is posted by the editor.
271 	 * @type String
272 	 * @returns (String) The editor data.
273 	 * @example
274 	 * if ( CKEDITOR.instances.editor1.<b>getData()</b> == '' )
275 	 *     alert( 'There is no data available' );
276 	 */
277 	getData : function()
278 	{
279 		this.fire( 'beforeGetData' );
280
281 		// Fire "getData" so data manipulation may happen.
282 		var eventData = { dataValue : this._.data || this.element.$.value };
283 		this.fire( 'getData', eventData );
284
285 		return eventData.dataValue;
286 	},
287
288 	/**
289 	 * Sets the editor data. The data must be provided in raw format.
290 	 * @example
291 	 * CKEDITOR.instances.editor1.<b>setData( '<p>This is the editor data.</p>' )</b>;
292 	 */
293 	setData : function( data )
294 	{
295 		// Fire "setData" so data manipulation may happen.
296 		var eventData = { dataValue : data };
297 		this.fire( 'setData', eventData );
298
299 		this._.data = eventData.dataValue;
300
301 		this.fire( 'afterSetData' );
302 	},
303
304 	/**
305 	 * Updates the <textarea> element that has been replaced by the editor with
306 	 * the current data available in the editor.
307 	 * @example
308 	 * CKEDITOR.instances.editor1.updateElement();
309 	 * alert( document.getElementById( 'editor1' ).value );  // The current editor data.
310 	 */
311 	updateElement : function()
312 	{
313 		this.element.$.value = this.getData();
314 	}
315 };
316
317 // "Inherit" (copy actually) from CKEDITOR.event.
318 CKEDITOR.event.implementOn( CKEDITOR.editor.prototype );
319