Index: /CKEditor/branches/prototype/_source/core/_bootstrap.js
===================================================================
--- /CKEditor/branches/prototype/_source/core/_bootstrap.js	(revision 2097)
+++ /CKEditor/branches/prototype/_source/core/_bootstrap.js	(revision 2098)
@@ -20,16 +20,19 @@
  */
 
-(function()
-{
-	// Process all pending replacements.
-	var pending = CKEDITOR.replace._pending;
-	if ( pending )
+// Load core plugins.
+CKEDITOR.plugins.load( CKEDITOR.config.corePlugins.split( ',' ), function()
 	{
-		delete CKEDITOR.replace._pending;
+		// Process all pending <textarea> replacements.
+		var pending = CKEDITOR.replace._pending;
+		if ( pending )
+		{
+			delete CKEDITOR.replace._pending;
 
-		CKEDITOR.tools.each( pending, function()
-			{
-				CKEDITOR.replace( this[0], this[1] );
-			} );
-	}
-})();
+			CKEDITOR.tools.each( pending, function( replaceInfo )
+				{
+					// replaceInfo[0] == <textarea> DOM element
+					// replaceInfo[1] == in-page configurations object
+					CKEDITOR.replace( replaceInfo[0], replaceInfo[1] );
+				} );
+		}
+	});
Index: /CKEditor/branches/prototype/_source/core/ckeditor.js
===================================================================
--- /CKEditor/branches/prototype/_source/core/ckeditor.js	(revision 2097)
+++ /CKEditor/branches/prototype/_source/core/ckeditor.js	(revision 2098)
@@ -20,4 +20,7 @@
  */
 
+// Remove the CKEDITOR.loadFullCore reference defined on ckeditor_basic.
+delete CKEDITOR.loadFullCore;
+
 CKEDITOR.instances = {};
 
@@ -28,5 +31,5 @@
 	// instance.
 	textarea = new CKEDITOR.dom.element( textarea );
-	
+
 	// Create the editor instance.
 	CKEDITOR.add( new CKEDITOR.editor( textarea, config ) );
Index: /CKEditor/branches/prototype/_source/core/ckeditor_base.js
===================================================================
--- /CKEditor/branches/prototype/_source/core/ckeditor_base.js	(revision 2097)
+++ /CKEditor/branches/prototype/_source/core/ckeditor_base.js	(revision 2098)
@@ -46,4 +46,5 @@
 			 *			<li><b>unloaded</b>: the API is not yet loaded.</li>
 			 *			<li><b>basic_loaded</b>: the basic API features are available.</li>
+			 *			<li><b>basic_ready</b>: the basic API is ready to load the full core code.</li>
 			 *			<li><b>loading</b>: the full API is being loaded.</li>
 			 *			<li><b>ready</b>: the API can be fully used.</li>
Index: /CKEditor/branches/prototype/_source/core/ckeditor_basic.js
===================================================================
--- /CKEditor/branches/prototype/_source/core/ckeditor_basic.js	(revision 2097)
+++ /CKEditor/branches/prototype/_source/core/ckeditor_basic.js	(revision 2098)
@@ -21,4 +21,15 @@
 
 CKEDITOR.event.implementOn( CKEDITOR );
+
+CKEDITOR.loadFullCore = function()
+{
+	delete CKEDITOR.loadFullCore;
+
+	var script = document.createElement( 'script' );
+	script.type = 'text/javascript';
+	script.src = CKEDITOR.basePath + 'ckeditor.js';
+	
+	document.getElementsByTagName( 'head' )[0].appendChild( script );	
+};
 
 /**
@@ -100,4 +111,8 @@
 	var pending = CKEDITOR.replace._pending || ( CKEDITOR.replace._pending = [] );
 	pending.push( [ textarea, config ] );
+
+	// Check if it is time to load the full core code.
+	if ( CKEDITOR.loadFullCore && CKEDITOR.status == 'basic_ready' )
+		CKEDITOR.loadFullCore();
 };
 
@@ -176,4 +191,9 @@
 			if ( CKEDITOR.replaceByClassEnabled )
 				CKEDITOR.replaceAll( CKEDITOR.replaceClass );
+
+			if ( CKEDITOR.replace._pending && CKEDITOR.status == 'basic_loaded' && CKEDITOR.loadFullCore )
+				CKEDITOR.loadFullCore();
+
+			CKEDITOR.status = 'basic_ready';
 		};
 
Index: /CKEditor/branches/prototype/_source/core/config.js
===================================================================
--- /CKEditor/branches/prototype/_source/core/config.js	(revision 2097)
+++ /CKEditor/branches/prototype/_source/core/config.js	(revision 2098)
@@ -39,4 +39,8 @@
 	baseHref : '',
 
+	corePlugins : '',
+
+	plugins : '',
+
 	/**
 	 * The theme to be used to build the UI.
Index: /CKEditor/branches/prototype/_source/core/dom/element.js
===================================================================
--- /CKEditor/branches/prototype/_source/core/dom/element.js	(revision 2097)
+++ /CKEditor/branches/prototype/_source/core/dom/element.js	(revision 2098)
@@ -54,4 +54,14 @@
 		element.append( this );
 	},
+	
+	insertAfter : function( element )
+	{
+		element.$.parentNode.insertBefore( this.$, element.$.nextSibling );
+	},
+
+	insertBefore : function( element )
+	{
+		element.$.parentNode.insertBefore( this.$, element.$ );
+	},
 
 	appendText : function( text )
@@ -63,4 +73,9 @@
 	{
 		this.$.text = text;
+	},
+
+	setHtml : function( html )
+	{
+		this.$.innerHTML = html;
 	},
 
Index: /CKEditor/branches/prototype/_source/core/editor.js
===================================================================
--- /CKEditor/branches/prototype/_source/core/editor.js	(revision 2097)
+++ /CKEditor/branches/prototype/_source/core/editor.js	(revision 2098)
@@ -36,4 +36,6 @@
 		return CKEDITOR.instances[ name ] ? getNewName() : name;
 	};
+	
+	// ##### START: Config Privates
 
 	// These function loads custom configuration files and cache the
@@ -104,5 +106,8 @@
 
 				// Fire the "configloaded" event.
-				editor.fire( 'configloaded' );
+				editor.fireOnce( 'configloaded' );
+				
+				// Start loading the plugins.
+				loadPlugins( editor );
 			});
 
@@ -121,4 +126,24 @@
 	{}
 	config.prototype = CKEDITOR.config;
+
+	// ##### END: Config Privates
+
+	var loadPlugins = function( editor )
+	{
+		// Load all plugins defined in the "plugins" setting.
+		CKEDITOR.plugins.load( editor.config.plugins.split( ',' ), function( plugins )
+			{
+				// Cache the loaded plugin names.
+				editor.plugins = plugins;
+				
+				// Initialize all plugins that have the "init" method defined.
+				CKEDITOR.tools.each( plugins, function( plugin )
+					{
+						var plugin = CKEDITOR.plugins.get( plugin );
+						if ( plugin && plugin.init )
+							plugin.init( editor );
+					});
+			});
+	};
 
 	return function( element, instanceConfig )
Index: /CKEditor/branches/prototype/_source/core/loader.js
===================================================================
--- /CKEditor/branches/prototype/_source/core/loader.js	(revision 2097)
+++ /CKEditor/branches/prototype/_source/core/loader.js	(revision 2098)
@@ -33,5 +33,5 @@
 	var scripts =
 	{
-		'core/_bootstrap'		: [ 'core/config', 'core/ckeditor', 'core/scriptLoader', 'core/tools' ],
+		'core/_bootstrap'		: [ 'core/config', 'core/ckeditor', 'core/plugins', 'core/scriptLoader', 'core/tools' ],
 		'core/ajax'				: [ 'core/xml' ],
 		'core/ckeditor'			: [ 'core/ajax', 'core/ckeditor_basic', 'core/dom', 'core/editor', 'core/dom/element', 'core/event', 'core/tools' ],
@@ -44,4 +44,5 @@
 		'core/env'				: [],
 		'core/event'			: [],
+		'core/plugins'			: [ 'core/scriptLoader', 'core/tools' ],
 		'core/scriptLoader'		: [ 'core/dom/element', 'core/env' ],
 		'core/tools'			: [ 'core/env' ],
@@ -118,6 +119,17 @@
 			this.loadedScripts.push( scriptName );
 
+			var scriptSrc = this.basePath + '_source/' + scriptName + '.js';
+
 			// Append the <script> element to the DOM.
-			document.write( '<script src="' + this.basePath + '_source/' + scriptName + '.js" type="text/javascript"><\/script>' );
+			if ( document.body )
+			{
+				var script = document.createElement( 'script' );
+				script.type = 'text/javascript';
+				script.src = scriptSrc;
+				
+				document.body.appendChild( script );	
+			}
+			else
+				document.write( '<script src="' + scriptSrc + '" type="text/javascript"><\/script>' );
 		}
 	};
Index: /CKEditor/branches/prototype/_source/core/plugins.js
===================================================================
--- /CKEditor/branches/prototype/_source/core/plugins.js	(revision 2098)
+++ /CKEditor/branches/prototype/_source/core/plugins.js	(revision 2098)
@@ -0,0 +1,119 @@
+﻿/*
+ * CKEditor - The text editor for Internet - http://ckeditor.com
+ * Copyright (C) 2003-2008 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ *  - GNU General Public License Version 2 or later (the "GPL")
+ *    http://www.gnu.org/licenses/gpl.html
+ *
+ *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ *    http://www.gnu.org/licenses/lgpl.html
+ *
+ *  - Mozilla Public License Version 1.1 or later (the "MPL")
+ *    http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ */
+
+ /**
+ * Manages plugins registration and loading.
+ * @namespace
+ */
+CKEDITOR.plugins = (function()
+{
+	// List of callbacks waiting for plugins to be loaded.
+	var waitingList = {};
+
+	return {
+		registeredPlugins : {},
+
+		loadedPlugins : {},
+
+		add : function( pluginName, pluginDefinition )
+		{
+			if ( this.registeredPlugins[ pluginName ] )
+				throw 'The plugin name "' + pluginName + '" is already registered.';
+
+			this.registeredPlugins[ pluginName ] = pluginDefinition;
+		},
+
+		get : function( pluginName )
+		{
+			return this.registeredPlugins[ pluginName ];
+		},
+
+		/**
+		 * Loads one or more plugins.
+		 * @param {String|Array} name The name of one or more plugins to load.
+		 * @param {Function} callback A function to be called when all plugins are loaded.
+		 * @param {Object} [scope] The scope object to be used for the callback call.
+		 * @type {Undefined}
+		 */
+		load : function( name, callback, scope )
+		{
+			// Ensure that we have an Array of names.
+			var names = CKEDITOR.tools.isArray( name ) ? name : [ name ];
+
+			var total = names.length;
+
+			// Nothing to load, just call the callback.
+			if ( total == 0 )
+			{
+				callback.call( scope || window, names );
+				return;
+			}
+
+			// This function is used to count the loaded plugins and call the
+			// callback when finished loading.
+			callback._loaded = 0;
+			callback._total = total;
+			var loadCheck = function( callback )
+			{
+				if ( ++callback._loaded == callback._total )
+					callback.call( scope || window, names );
+			};
+
+			var loadedPlugins = this.loadedPlugins;
+
+			// Loop through all names.
+			CKEDITOR.tools.each( names, function( pluginName )
+				{
+					// If not loaded already.
+					if ( pluginName && !loadedPlugins[ pluginName ] )
+					{
+						var waitingInfo = waitingList[ pluginName ] || ( waitingList[ pluginName ] = [] );
+						waitingInfo.push( callback );
+
+						// If this is the first call for it, go ahead loading.
+						if ( waitingInfo.length == 1 )
+						{
+							// Calculate the plugin script path.
+							var pluginPath = CKEDITOR.basePath + '_source/plugins/' + pluginName + '/';
+
+							// Load the plugin script.
+							CKEDITOR.scriptLoader.load( pluginPath + 'plugin.js', function( success )
+								{
+									if ( !success )
+										throw '[CKEDITOR.plugins.load] Plugin name "' + pluginName + '" was not found at "' + pluginPath + 'plugin.js".';
+
+									loadedPlugins[ pluginName ] = pluginPath;
+
+									CKEDITOR.tools.each( waitingList[ pluginName ], function( waitingCallback )
+										{
+											loadCheck( waitingCallback );
+										});
+
+									delete waitingList[ pluginName ];
+								});
+						}
+					}
+					else
+						loadCheck( callback );
+				});
+		}
+	};
+})();
Index: /CKEditor/branches/prototype/_source/core/scriptloader.js
===================================================================
--- /CKEditor/branches/prototype/_source/core/scriptloader.js	(revision 2097)
+++ /CKEditor/branches/prototype/_source/core/scriptloader.js	(revision 2098)
@@ -50,8 +50,13 @@
 				if ( CKEDITOR.env.ie )
 				{
+					// FIXME: For IE, we are not able to return false on error (like 404).
+
 					script.$.onreadystatechange = function ()
 					{
 						if ( script.$.readyState == 'loaded' || script.$.readyState == 'complete' )
-							callback.call( scope || CKEDITOR );
+						{
+							script.$.onreadystatechange = null;
+							callback.call( scope || CKEDITOR, true );
+						}
 					}
 				}
@@ -60,5 +65,12 @@
 					script.$.onload = function()
 					{
-						callback.call( scope || CKEDITOR );
+						callback.call( scope || CKEDITOR, true );
+					}
+
+					// FIXME: Opera and Safari will not fire onerror.
+
+					script.$.onerror = function()
+					{
+						callback.call( scope || CKEDITOR, false );
 					}
 				}
Index: /CKEditor/branches/prototype/_source/core/tools.js
===================================================================
--- /CKEditor/branches/prototype/_source/core/tools.js	(revision 2097)
+++ /CKEditor/branches/prototype/_source/core/tools.js	(revision 2098)
@@ -123,4 +123,9 @@
 			{}
 		}
+	},
+	
+	isArray : function( object )
+	{
+		return ( object && object instanceof Array );
 	}
 };
Index: /CKEditor/branches/prototype/_source/plugins/sample/plugin.js
===================================================================
--- /CKEditor/branches/prototype/_source/plugins/sample/plugin.js	(revision 2098)
+++ /CKEditor/branches/prototype/_source/plugins/sample/plugin.js	(revision 2098)
@@ -0,0 +1,32 @@
+﻿/*
+ * CKEditor - The text editor for Internet - http://ckeditor.com
+ * Copyright (C) 2003-2008 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ *  - GNU General Public License Version 2 or later (the "GPL")
+ *    http://www.gnu.org/licenses/gpl.html
+ *
+ *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ *    http://www.gnu.org/licenses/lgpl.html
+ *
+ *  - Mozilla Public License Version 1.1 or later (the "MPL")
+ *    http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ */
+ 
+CKEDITOR.plugins.add( 'sample',
+{
+	init : function( editor, pluginPath )
+	{
+		editor.element.hide();
+
+		var div = new CKEDITOR.dom.element( 'div' );
+		div.setHtml( 'Plugin init for "' + editor.name + '"' );
+		div.insertAfter( editor.element );
+	}
+});
Index: /CKEditor/branches/prototype/ckeditor.js
===================================================================
--- /CKEditor/branches/prototype/ckeditor.js	(revision 2097)
+++ /CKEditor/branches/prototype/ckeditor.js	(revision 2098)
@@ -23,8 +23,13 @@
 if (!window.CKEDITOR){window.CKEDITOR=(function(){return {status:'unloaded',basePath:(function(){var A='';var B=document.getElementsByTagName('script');for (var i=0;i<B.length;i++){var C=B[i].src.match(/(^|.*[\\\/])ckeditor(?:_basic)?.js(?:\?.*)?$/i);if (C){A=C[1];break;}};if (A.indexOf('://')==-1){if (A.indexOf('/')==0) A=location.href.match(/^.*?:\/\/[^\/]*/)[0]+A;else A=location.href.match(/^[^\?]*\//)[0]+A;};return A;})()};})();};
 
-// Set the script name to be loaded by the loader.
-CKEDITOR._autoLoad = 'core/ckeditor';
+if ( CKEDITOR.loader )
+	CKEDITOR.loader.load( 'core/ckeditor' );
+else
+{
+	// Set the script name to be loaded by the loader.
+	CKEDITOR._autoLoad = 'core/ckeditor';
 
-// Include the loader script.
-document.write(
-	'<script type="text/javascript" src="' + CKEDITOR.basePath + '_source/core/loader.js"></script>' );
+	// Include the loader script.
+	document.write(
+		'<script type="text/javascript" src="' + CKEDITOR.basePath + '_source/core/loader.js"></script>' );
+}
Index: /CKEditor/branches/prototype/config.js
===================================================================
--- /CKEditor/branches/prototype/config.js	(revision 2097)
+++ /CKEditor/branches/prototype/config.js	(revision 2098)
@@ -1,3 +1,3 @@
-/*
+﻿/*
  * CKEditor - The text editor for Internet - http://ckeditor.com
  * Copyright (C) 2003-2008 Frederico Caldeira Knabben
