Index: /CKEditor/trunk/_source/core/config.js
===================================================================
--- /CKEditor/trunk/_source/core/config.js	(revision 3112)
+++ /CKEditor/trunk/_source/core/config.js	(revision 3113)
@@ -148,5 +148,5 @@
 	 */
 
-	plugins : 'basicstyles,blockquote,button,clipboard,elementspath,find,flash,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,newpage,pagebreak,pastefromword,pastetext,preview,print,removeformat,smiley,showblocks,sourcearea,table,specialchar,tab,templates,toolbar,undo,wysiwygarea',
+	plugins : 'basicstyles,blockquote,button,clipboard,elementspath,find,flash,format,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,newpage,pagebreak,pastefromword,pastetext,preview,print,removeformat,smiley,showblocks,sourcearea,table,specialchar,tab,templates,toolbar,undo,wysiwygarea',
 
 	/**
Index: /CKEditor/trunk/_source/core/dom/domobject.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/domobject.js	(revision 3112)
+++ /CKEditor/trunk/_source/core/dom/domobject.js	(revision 3113)
@@ -148,5 +148,5 @@
 	domObjectProto.setCustomData = function( key, value )
 	{
-		var expandoNumber = this.$._cke_expando || ( this.$._cke_expando = CKEDITOR.tools.getNextNumber() ),
+		var expandoNumber = this.getUniqueId(),
 			dataSlot = customData[ expandoNumber ] || ( customData[ expandoNumber ] = {} );
 
@@ -187,4 +187,9 @@
 	};
 
+	domObjectProto.getUniqueId = function()
+	{
+		return this.$._cke_expando || ( this.$._cke_expando = CKEDITOR.tools.getNextNumber() );
+	};
+
 	// Implement CKEDITOR.event.
 	CKEDITOR.event.implementOn( domObjectProto );
Index: /CKEditor/trunk/_source/core/dom/element.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/element.js	(revision 3112)
+++ /CKEditor/trunk/_source/core/dom/element.js	(revision 3113)
@@ -168,4 +168,10 @@
 		},
 
+		hasClass : function( className )
+		{
+			var regex = new RegExp( '(?:^|\\s+)' + className + '(?=\\s|$)', '' );
+			return regex.test( this.$.className );
+		},
+
 		/**
 		 * Append a node as a child of this element.
@@ -196,4 +202,11 @@
 
 			return node;
+		},
+
+		appendHtml : function( html )
+		{
+			var temp = new CKEDITOR.dom.element( 'div', this.getDocument() );
+			temp.setHtml( html );
+			temp.moveChildren( this );
 		},
 
Index: /CKEditor/trunk/_source/core/editor.js
===================================================================
--- /CKEditor/trunk/_source/core/editor.js	(revision 3112)
+++ /CKEditor/trunk/_source/core/editor.js	(revision 3113)
@@ -79,8 +79,5 @@
 					CKEDITOR.tools.extend( editor.config, instanceConfig, true );
 
-				// Fire the "configLoaded" event.
-				editor.fireOnce( 'configLoaded' );
-
-				loadLang( editor );
+				onConfigLoaded( editor );
 			});
 
@@ -96,4 +93,19 @@
 
 	// ##### END: Config Privates
+
+	var onConfigLoaded = function( editor )
+	{
+		// Set config related properties.
+
+		editor.skinPath = CKEDITOR.getUrl(
+			'_source/' +	// %REMOVE_LINE%
+			'skins/' + editor.config.skin + '/' );
+
+		// Fire the "configLoaded" event.
+		editor.fireOnce( 'configLoaded' );
+
+		// Load language file.
+		loadLang( editor );
+	};
 
 	var loadLang = function( editor )
Index: /CKEditor/trunk/_source/core/plugins.js
===================================================================
--- /CKEditor/trunk/_source/core/plugins.js	(revision 3112)
+++ /CKEditor/trunk/_source/core/plugins.js	(revision 3113)
@@ -49,6 +49,21 @@
 						if ( requiredPlugins.length )
 							loadPlugins.call( this, requiredPlugins );
-						else if ( callback )
-							callback.call( scope || window, allPlugins );
+						else
+						{
+							// Call the "onLoad" function for all plugins.
+							for ( pluginName in allPlugins )
+							{
+								plugin = allPlugins[ pluginName ];
+								if ( plugin.onLoad && !plugin.onLoad._called )
+								{
+									plugin.onLoad();
+									plugin.onLoad._called = 1;
+								}
+							}
+
+							// Call the callback.
+							if ( callback )
+								callback.call( scope || window, allPlugins );
+						}
 					}
 					, this);
Index: /CKEditor/trunk/_source/core/tools.js
===================================================================
--- /CKEditor/trunk/_source/core/tools.js	(revision 3112)
+++ /CKEditor/trunk/_source/core/tools.js	(revision 3113)
@@ -9,339 +9,409 @@
  */
 
-/**
- * Utility functions.
- * @namespace
- * @example
- */
-CKEDITOR.tools =
+(function()
 {
-	arrayCompare : function( arrayA, arrayB )
+	var functions = [];
+
+	/**
+	 * Utility functions.
+	 * @namespace
+	 * @example
+	 */
+	CKEDITOR.tools =
 	{
-		if ( !arrayA && !arrayB )
+		arrayCompare : function( arrayA, arrayB )
+		{
+			if ( !arrayA && !arrayB )
+				return true;
+
+			if ( !arrayA || !arrayB || arrayA.length != arrayB.length )
+				return false;
+
+			for ( var i = 0 ; i < arrayA.length ; i++ )
+			{
+				if ( arrayA[ i ] != arrayB[ i ] )
+					return false;
+			}
+
 			return true;
-
-		if ( !arrayA || !arrayB || arrayA.length != arrayB.length )
-			return false;
-
-		for ( var i = 0 ; i < arrayA.length ; i++ )
-		{
-			if ( arrayA[ i ] != arrayB[ i ] )
-				return false;
+		},
+
+		/**
+		 * Copy the properties from one object to another. By default, properties
+		 * already present in the target object <strong>are not</strong> overwritten.
+		 * @param {Object} target The object to be extended.
+		 * @param {Object} source[,souce(n)] The objects from which copy
+		 *		properties. Any number of objects can be passed to this function.
+		 * @param {Boolean} [overwrite] Indicates that properties already present
+		 *		in the target object must be overwritten. This must be the last
+		 *		parameter in the function call.
+		 * @returns {Object} the extended object (target).
+		 * @example
+		 * // Create the sample object.
+		 * var myObject =
+		 * {
+		 *     prop1 : true
+		 * };
+		 *
+		 * // Extend the above object with two properties.
+		 * CKEDITOR.tools.extend( myObject,
+		 *     {
+		 *         prop2 : true,
+		 *         prop3 : true
+		 *     } );
+		 *
+		 * // Alert "prop1", "prop2" and "prop3".
+		 * for ( var p in myObject )
+		 *     alert( p );
+		 */
+		extend : function( target )
+		{
+			var argsLength = arguments.length,
+				overwrite = arguments[ argsLength - 1 ];
+
+			if ( typeof overwrite == 'boolean' )
+				argsLength--;
+			else
+				overwrite = false;
+
+			for ( var i = 1 ; i < argsLength ; i++ )
+			{
+				var source = arguments[ i ];
+
+				for ( var propertyName in source )
+				{
+					if ( overwrite || target[ propertyName ] == undefined )
+						target[ propertyName ] = source[ propertyName ];
+				}
+			}
+
+			return target;
+		},
+
+		/**
+		 * Creates an object which is an instance of a class which prototype is a
+		 * predefined object. All properties defined in the source object are
+		 * automatically inherited by the resulting object, including future
+		 * changes to it.
+		 * @param {Object} source The source object to be used as the prototype for
+		 *		the final object.
+		 * @returns {Object} The resulting copy.
+		 */
+		prototypedCopy : function( source )
+		{
+			var copy = function()
+			{};
+			copy.prototype = source;
+			return new copy();
+		},
+
+		/**
+		 * Checks if an object is an Array.
+		 * @param {Object} object The object to be checked.
+		 * @type Boolean
+		 * @returns <i>true</i> if the object is an Array, otherwise <i>false</i>.
+		 * @example
+		 * alert( CKEDITOR.tools.isArray( [] ) );      // "true"
+		 * alert( CKEDITOR.tools.isArray( 'Test' ) );  // "false"
+		 */
+		isArray : function( object )
+		{
+			return ( !!object && object instanceof Array );
+		},
+
+		/**
+		 * Transforms a CSS property name to its relative DOM style name.
+		 * @param {String} cssName The CSS property name.
+		 * @returns {String} The transformed name.
+		 * @example
+		 * alert( CKEDITOR.tools.cssStyleToDomStyle( 'background-color' ) );  // "backgroundColor"
+		 * alert( CKEDITOR.tools.cssStyleToDomStyle( 'float' ) );             // "cssFloat"
+		 */
+		cssStyleToDomStyle : function( cssName )
+		{
+			if ( cssName == 'float' )
+				return 'cssFloat';
+			else
+			{
+				return cssName.replace( /-./g, function( match )
+					{
+						return match.substr( 1 ).toUpperCase();
+					});
+			}
+		},
+
+		/**
+		 * Replace special HTML characters in a string with their relative HTML
+		 * entity values.
+		 * @param {String} text The string to be encoded.
+		 * @returns {String} The encode string.
+		 * @example
+		 * alert( CKEDITOR.tools.htmlEncode( 'A > B & C < D' ) );  // "A &amp;gt; B &amp;amp; C &amp;lt; D"
+		 */
+		htmlEncode : function( text )
+		{
+			var standard = function( text )
+			{
+				var span = new CKEDITOR.dom.element( 'span' );
+				span.setText( text );
+				return span.getHtml();
+			};
+
+			this.htmlEncode = ( standard( '>' ) == '>' ) ?
+				function( text )
+				{
+					// WebKit does't encode the ">" character, which makes sense, but
+					// it's different than other browsers.
+					return standard( text ).replace( />/g, '&gt;' );
+				} :
+				standard;
+
+			return this.htmlEncode( text );
+		},
+
+		/**
+		 * Gets a unique number for this CKEDITOR execution session. It returns
+		 * progressive numbers starting at 1.
+		 * @function
+		 * @returns {Number} A unique number.
+		 * @example
+		 * alert( CKEDITOR.tools.<b>getNextNumber()</b> );  // "1" (e.g.)
+		 * alert( CKEDITOR.tools.<b>getNextNumber()</b> );  // "2"
+		 */
+		getNextNumber : (function()
+		{
+			var last = 0;
+			return function()
+			{
+				return ++last;
+			};
+		})(),
+
+		/**
+		 * Creates a function override.
+		 * @param {Function} originalFunction The function to be overridden.
+		 * @param {Function} functionBuilder A function that returns the new
+		 *		function. The original function reference will be passed to this
+		 *		function.
+		 * @returns {Function} The new function.
+		 * @example
+		 * var example =
+		 * {
+		 *     myFunction : function( name )
+		 *     {
+		 *         alert( 'Name: ' + name );
+		 *     }
+		 * };
+		 *
+		 * example.myFunction = CKEDITOR.tools.override( example.myFunction, function( myFunctionOriginal )
+		 *     {
+		 *         return function( name )
+		 *             {
+		 *                 alert( 'Override Name: ' + name );
+		 *                 myFunctionOriginal.call( this, name );
+		 *             };
+		 *     });
+		 */
+		override : function( originalFunction, functionBuilder )
+		{
+			return functionBuilder( originalFunction );
+		},
+
+		/**
+		 * Executes a function after specified delay.
+		 * @param {Function} func The function to be executed.
+		 * @param {Number} [milliseconds] The amount of time (millisecods) to wait
+		 *		to fire the function execution. Defaults to zero.
+		 * @param {Object} [scope] The object to hold the function execution scope
+		 *		(the "this" object). By default the "window" object.
+		 * @param {Object|Array} [args] A single object, or an array of objects, to
+		 *		pass as arguments to the function.
+		 * @param {Object} [ownerWindow] The window that will be used to set the
+		 *		timeout. By default the current "window".
+		 * @returns {Object} A value that can be used to cancel the function execution.
+		 * @example
+		 * CKEDITOR.tools.<b>setTimeout(
+		 *     function()
+		 *     {
+		 *         alert( 'Executed after 2 seconds' );
+		 *     },
+		 *     2000 )</b>;
+		 */
+		setTimeout : function( func, milliseconds, scope, args, ownerWindow )
+		{
+			if ( !ownerWindow )
+				ownerWindow = window;
+
+			if ( !scope )
+				scope = ownerWindow;
+
+			return ownerWindow.setTimeout(
+				function()
+				{
+					if ( args )
+						func.apply( scope, [].concat( args ) ) ;
+					else
+						func.apply( scope ) ;
+				},
+				milliseconds || 0 );
+		},
+
+		/**
+		 * Remove spaces from the start and the end of a string. The following
+		 * characters are removed: space, tab, line break, line feed.
+		 * @function
+		 * @param {String} str The text from which remove the spaces.
+		 * @returns {String} The modified string without the boundary spaces.
+		 * @example
+		 * alert( CKEDITOR.tools.trim( '  example ' );  // "example"
+		 */
+		trim : (function()
+		{
+			// We are not using \s because we don't want "non-breaking spaces" to be caught.
+			var trimRegex = /(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g;
+			return function( str )
+			{
+				return str.replace( trimRegex, '' ) ;
+			};
+		})(),
+
+		/**
+		 * Remove spaces from the start (left) of a string. The following
+		 * characters are removed: space, tab, line break, line feed.
+		 * @function
+		 * @param {String} str The text from which remove the spaces.
+		 * @returns {String} The modified string excluding the removed spaces.
+		 * @example
+		 * alert( CKEDITOR.tools.ltrim( '  example ' );  // "example "
+		 */
+		ltrim : (function()
+		{
+			// We are not using \s because we don't want "non-breaking spaces" to be caught.
+			var trimRegex = /^[ \t\n\r]+/g;
+			return function( str )
+			{
+				return str.replace( trimRegex, '' ) ;
+			};
+		})(),
+
+		/**
+		 * Remove spaces from the end (right) of a string. The following
+		 * characters are removed: space, tab, line break, line feed.
+		 * @function
+		 * @param {String} str The text from which remove the spaces.
+		 * @returns {String} The modified string excluding the removed spaces.
+		 * @example
+		 * alert( CKEDITOR.tools.ltrim( '  example ' );  // "  example"
+		 */
+		rtrim : (function()
+		{
+			// We are not using \s because we don't want "non-breaking spaces" to be caught.
+			var trimRegex = /[ \t\n\r]+$/g;
+			return function( str )
+			{
+				return str.replace( trimRegex, '' ) ;
+			};
+		})(),
+
+		/**
+		 * Returns the index of an element in an array.
+		 * @param {Array} array The array to be searched.
+		 * @param {Object} entry The element to be found.
+		 * @returns {Number} The (zero based) index of the first entry that matches
+		 *		the entry, or -1 if not found.
+		 * @example
+		 * var letters = [ 'a', 'b', 0, 'c', false ]; 
+		 * alert( CKEDITOR.tools.indexOf( letters, '0' ) );  "-1" because 0 !== '0' 
+		 * alert( CKEDITOR.tools.indexOf( letters, false ) );  "4" because 0 !== false 
+		 */
+		indexOf :
+			// #2514: We should try to use Array.indexOf if it does exist.
+			( Array.prototype.indexOf ) ?
+				function( array, entry )
+					{
+						return array.indexOf( entry );
+					}
+			:
+				function( array, entry )
+				{
+					for ( var i = 0, len = array.length ; i < len ; i++ )
+					{
+						if ( array[ i ] === entry )
+							return i;
+					}
+					return -1;
+				},
+
+		bind : function( func, obj )
+		{
+			return function() { return func.apply( obj, arguments ); };
+		},
+
+		createClass : function( definition )
+		{
+			var $ = definition.$,
+				baseClass = definition.base,
+				privates = definition.privates || definition._,
+				proto = definition.proto,
+				statics = definition.statics;
+
+			if ( privates )
+			{
+				var originalConstructor = $;
+				$ = function()
+				{
+					originalConstructor.apply( this, arguments );
+					
+					// Create (and get) the private namespace.
+					var _ = this._ || ( this._ = {} );
+					
+					// Make some magic so "this" will refer to the main
+					// instance when coding private functions.
+					for ( var privateName in privates ) 
+					{
+						var priv = privates[ privateName ];
+						
+						_[ privateName ] = 
+							( typeof priv == 'function' ) ? CKEDITOR.tools.bind( priv, this ) : priv;
+					}
+				};
+			}
+
+			if ( baseClass )
+			{
+				$.prototype = this.prototypedCopy( baseClass.prototype );
+
+				$.prototype.base = function()
+				{
+					this.base = baseClass.prototype.base;
+					baseClass.apply( this, arguments );
+					this.base = arguments.callee;
+				};
+			}
+
+			if ( proto )
+				this.extend( $.prototype, proto, true );
+
+			if ( statics )
+				this.extend( $, statics, true );
+
+			return $;
+		},
+
+		addFunction : function( fn, scope )
+		{
+			return functions.push( function()
+				{
+					fn.apply( scope || this, arguments );
+				}) - 1;
+		},
+
+		callFunction : function( index )
+		{
+			var fn = functions[ index ];
+			return fn.apply( window, Array.prototype.slice.call( arguments, 1 ) );
 		}
-
-		return true;
-	},
-
-	/**
-	 * Copy the properties from one object to another. By default, properties
-	 * already present in the target object <strong>are not</strong> overwritten.
-	 * @param {Object} target The object to be extended.
-	 * @param {Object} source[,souce(n)] The objects from which copy
-	 *		properties. Any number of objects can be passed to this function.
-	 * @param {Boolean} [overwrite] Indicates that properties already present
-	 *		in the target object must be overwritten. This must be the last
-	 *		parameter in the function call.
-	 * @returns {Object} the extended object (target).
-	 * @example
-	 * // Create the sample object.
-	 * var myObject =
-	 * {
-	 *     prop1 : true
-	 * };
-	 *
-	 * // Extend the above object with two properties.
-	 * CKEDITOR.tools.extend( myObject,
-	 *     {
-	 *         prop2 : true,
-	 *         prop3 : true
-	 *     } );
-	 *
-	 * // Alert "prop1", "prop2" and "prop3".
-	 * for ( var p in myObject )
-	 *     alert( p );
-	 */
-	extend : function( target )
-	{
-		var argsLength = arguments.length,
-			overwrite = arguments[ argsLength - 1 ];
-
-		if ( typeof overwrite == 'boolean' )
-			argsLength--;
-		else
-			overwrite = false;
-
-		for ( var i = 1 ; i < argsLength ; i++ )
-		{
-			var source = arguments[ i ];
-
-			for ( var propertyName in source )
-			{
-				if ( overwrite || target[ propertyName ] == undefined )
-					target[ propertyName ] = source[ propertyName ];
-			}
-		}
-
-		return target;
-	},
-
-	/**
-	 * Creates an object which is an instance of a class which prototype is a
-	 * predefined object. All properties defined in the source object are
-	 * automatically inherited by the resulting object, including future
-	 * changes to it.
-	 * @param {Object} source The source object to be used as the prototype for
-	 *		the final object.
-	 * @returns {Object} The resulting copy.
-	 */
-	prototypedCopy : function( source )
-	{
-		var copy = function()
-		{};
-		copy.prototype = source;
-		return new copy();
-	},
-
-	/**
-	 * Checks if an object is an Array.
-	 * @param {Object} object The object to be checked.
-	 * @type Boolean
-	 * @returns <i>true</i> if the object is an Array, otherwise <i>false</i>.
-	 * @example
-	 * alert( CKEDITOR.tools.isArray( [] ) );      // "true"
-	 * alert( CKEDITOR.tools.isArray( 'Test' ) );  // "false"
-	 */
-	isArray : function( object )
-	{
-		return ( !!object && object instanceof Array );
-	},
-
-	/**
-	 * Transforms a CSS property name to its relative DOM style name.
-	 * @param {String} cssName The CSS property name.
-	 * @returns {String} The transformed name.
-	 * @example
-	 * alert( CKEDITOR.tools.cssStyleToDomStyle( 'background-color' ) );  // "backgroundColor"
-	 * alert( CKEDITOR.tools.cssStyleToDomStyle( 'float' ) );             // "cssFloat"
-	 */
-	cssStyleToDomStyle : function( cssName )
-	{
-		if ( cssName == 'float' )
-			return 'cssFloat';
-		else
-		{
-			return cssName.replace( /-./g, function( match )
-				{
-					return match.substr( 1 ).toUpperCase();
-				});
-		}
-	},
-
-	/**
-	 * Replace special HTML characters in a string with their relative HTML
-	 * entity values.
-	 * @param {String} text The string to be encoded.
-	 * @returns {String} The encode string.
-	 * @example
-	 * alert( CKEDITOR.tools.htmlEncode( 'A > B & C < D' ) );  // "A &amp;gt; B &amp;amp; C &amp;lt; D"
-	 */
-	htmlEncode : function( text )
-	{
-		var standard = function( text )
-		{
-			var span = new CKEDITOR.dom.element( 'span' );
-			span.setText( text );
-			return span.getHtml();
-		};
-
-		this.htmlEncode = ( standard( '>' ) == '>' ) ?
-			function( text )
-			{
-				// WebKit does't encode the ">" character, which makes sense, but
-				// it's different than other browsers.
-				return standard( text ).replace( />/g, '&gt;' );
-			} :
-			standard;
-
-		return this.htmlEncode( text );
-	},
-
-	/**
-	 * Gets a unique number for this CKEDITOR execution session. It returns
-	 * progressive numbers starting at 1.
-	 * @function
-	 * @returns {Number} A unique number.
-	 * @example
-	 * alert( CKEDITOR.tools.<b>getNextNumber()</b> );  // "1" (e.g.)
-	 * alert( CKEDITOR.tools.<b>getNextNumber()</b> );  // "2"
-	 */
-	getNextNumber : (function()
-	{
-		var last = 0;
-		return function()
-		{
-			return ++last;
-		};
-	})(),
-
-	/**
-	 * Creates a function override.
-	 * @param {Function} originalFunction The function to be overridden.
-	 * @param {Function} functionBuilder A function that returns the new
-	 *		function. The original function reference will be passed to this
-	 *		function.
-	 * @returns {Function} The new function.
-	 * @example
-	 * var example =
-	 * {
-	 *     myFunction : function( name )
-	 *     {
-	 *         alert( 'Name: ' + name );
-	 *     }
-	 * };
-	 *
-	 * example.myFunction = CKEDITOR.tools.override( example.myFunction, function( myFunctionOriginal )
-	 *     {
-	 *         return function( name )
-	 *             {
-	 *                 alert( 'Override Name: ' + name );
-	 *                 myFunctionOriginal.call( this, name );
-	 *             };
-	 *     });
-	 */
-	override : function( originalFunction, functionBuilder )
-	{
-		return functionBuilder( originalFunction );
-	},
-
-	/**
-	 * Executes a function after specified delay.
-	 * @param {Function} func The function to be executed.
-	 * @param {Number} [milliseconds] The amount of time (millisecods) to wait
-	 *		to fire the function execution. Defaults to zero.
-	 * @param {Object} [scope] The object to hold the function execution scope
-	 *		(the "this" object). By default the "window" object.
-	 * @param {Object|Array} [args] A single object, or an array of objects, to
-	 *		pass as arguments to the function.
-	 * @param {Object} [ownerWindow] The window that will be used to set the
-	 *		timeout. By default the current "window".
-	 * @returns {Object} A value that can be used to cancel the function execution.
-	 * @example
-	 * CKEDITOR.tools.<b>setTimeout(
-	 *     function()
-	 *     {
-	 *         alert( 'Executed after 2 seconds' );
-	 *     },
-	 *     2000 )</b>;
-	 */
-	setTimeout : function( func, milliseconds, scope, args, ownerWindow )
-	{
-		if ( !ownerWindow )
-			ownerWindow = window;
-
-		if ( !scope )
-			scope = ownerWindow;
-
-		return ownerWindow.setTimeout(
-			function()
-			{
-				if ( args )
-					func.apply( scope, [].concat( args ) ) ;
-				else
-					func.apply( scope ) ;
-			},
-			milliseconds || 0 );
-	},
-
-	/**
-	 * Remove spaces from the start and the end of a string. The following
-	 * characters are removed: space, tab, line break, line feed.
-	 * @function
-	 * @param {String} str The text from which remove the spaces.
-	 * @returns {String} The modified string without the boundary spaces.
-	 * @example
-	 * alert( CKEDITOR.tools.trim( '  example ' );  // "example"
-	 */
-	trim : (function()
-	{
-		// We are not using \s because we don't want "non-breaking spaces" to be caught.
-		var trimRegex = /(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g;
-		return function( str )
-		{
-			return str.replace( trimRegex, '' ) ;
-		};
-	})(),
-
-	/**
-	 * Remove spaces from the start (left) of a string. The following
-	 * characters are removed: space, tab, line break, line feed.
-	 * @function
-	 * @param {String} str The text from which remove the spaces.
-	 * @returns {String} The modified string excluding the removed spaces.
-	 * @example
-	 * alert( CKEDITOR.tools.ltrim( '  example ' );  // "example "
-	 */
-	ltrim : (function()
-	{
-		// We are not using \s because we don't want "non-breaking spaces" to be caught.
-		var trimRegex = /^[ \t\n\r]+/g;
-		return function( str )
-		{
-			return str.replace( trimRegex, '' ) ;
-		};
-	})(),
-
-	/**
-	 * Remove spaces from the end (right) of a string. The following
-	 * characters are removed: space, tab, line break, line feed.
-	 * @function
-	 * @param {String} str The text from which remove the spaces.
-	 * @returns {String} The modified string excluding the removed spaces.
-	 * @example
-	 * alert( CKEDITOR.tools.ltrim( '  example ' );  // "  example"
-	 */
-	rtrim : (function()
-	{
-		// We are not using \s because we don't want "non-breaking spaces" to be caught.
-		var trimRegex = /[ \t\n\r]+$/g;
-		return function( str )
-		{
-			return str.replace( trimRegex, '' ) ;
-		};
-	})(),
-
-	/**
-	 * Returns the index of an element in an array.
-	 * @param {Array} array The array to be searched.
-	 * @param {Object} entry The element to be found.
-	 * @returns {Number} The (zero based) index of the first entry that matches
-	 *		the entry, or -1 if not found.
-	 * @example
-	 * var letters = [ 'a', 'b', 0, 'c', false ]; 
-	 * alert( CKEDITOR.tools.indexOf( letters, '0' ) );  "-1" because 0 !== '0' 
-	 * alert( CKEDITOR.tools.indexOf( letters, false ) );  "4" because 0 !== false 
-	 */
-	indexOf :
-		// #2514: We should try to use Array.indexOf if it does exist.
-		( Array.prototype.indexOf ) ?
-			function( array, entry )
-				{
-					return array.indexOf( entry );
-				}
-		:
-			function( array, entry )
-			{
-				for ( var i = 0, len = array.length ; i < len ; i++ )
-				{
-					if ( array[ i ] === entry )
-						return i;
-				}
-				return -1;
-			},
-
-	bind : function( func, obj )
-	{
-		return function() { return func.apply( obj, arguments ); };
-	}
-};
+	};
+})();
 
 // PACKAGER_RENAME( CKEDITOR.tools )
Index: /CKEditor/trunk/_source/core/ui.js
===================================================================
--- /CKEditor/trunk/_source/core/ui.js	(revision 3112)
+++ /CKEditor/trunk/_source/core/ui.js	(revision 3113)
@@ -49,7 +49,9 @@
 	add : function( name, type, definition )
 	{
-		var item = this._.handlers[ type ].create( definition );
-		item.name = name;
-		this._.items[ name ] = item;
+		this._.items[ name ] =
+		{
+			type : type,
+			args : Array.prototype.slice.call( arguments, 2 )
+		};
 	},
 
@@ -59,7 +61,10 @@
 	 * @example
 	 */
-	get : function( name )
+	create : function( name )
 	{
-		return this._.items[ name ] || null;
+		var item	= this._.items[ name ],
+			handler	= item && this._.handlers[ item.type ];
+		
+		return handler && handler.create.apply( this, item.args );
 	},
 
Index: /CKEditor/trunk/_source/lang/en.js
===================================================================
--- /CKEditor/trunk/_source/lang/en.js	(revision 3112)
+++ /CKEditor/trunk/_source/lang/en.js	(revision 3113)
@@ -437,4 +437,21 @@
 	},
 
-	showBlocks : 'Show Blocks'
+	showBlocks : 'Show Blocks',
+
+	format :
+	{
+		label : 'Format',
+		panelTitle : 'Paragraph Format',
+
+		tag_p : 'Normal',
+		tag_pre : 'Formatted',
+		tag_address : 'Address',
+		tag_h1 : 'Heading 1',
+		tag_h2 : 'Heading 2',
+		tag_h3 : 'Heading 3',
+		tag_h4 : 'Heading 4',
+		tag_h5 : 'Heading 5',
+		tag_h6 : 'Heading 6',
+		tag_div : 'Normal (DIV)'
+	}
 };
Index: /CKEditor/trunk/_source/plugins/floatpanel/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/floatpanel/plugin.js	(revision 3113)
+++ /CKEditor/trunk/_source/plugins/floatpanel/plugin.js	(revision 3113)
@@ -0,0 +1,126 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.plugins.add( 'floatpanel',
+{
+	requires : [ 'panel' ]
+});
+
+(function()
+{
+	var panels = {};
+
+	function getPanel( doc, parentElement, definition )
+	{
+		// Generates the panel key: docId-eleId-CSSs
+		var key =
+			doc.getUniqueId() +
+			'-' + parentElement.getUniqueId() +
+			( ( definition.css && ( '-' + definition.css ) ) || '' );
+
+		var panel = panels[ key ];
+
+		if ( !panel )
+		{
+			panel = panels[ key ] = new CKEDITOR.ui.panel( doc, definition );
+			panel.element = parentElement.append( CKEDITOR.dom.element.createFromHtml( panel.renderHtml(), doc ) );
+
+			panel.element.setStyles(
+				{
+					display : 'none',
+					position : 'absolute'
+				});
+		}
+
+		return panel;
+	}
+
+	CKEDITOR.ui.floatPanel = CKEDITOR.tools.createClass(
+	{
+		$ : function( parentElement, definition )
+		{
+			definition.forceIFrame = true;
+
+			var doc = parentElement.getDocument(),
+				panel = getPanel( doc, parentElement, definition ),
+				element = panel.element,
+				iframe = element.getFirst();
+
+			this.element = element;
+
+			this._ =
+			{
+				// The panel that will be floating.
+				panel : panel,
+				document : doc,
+				iframe : iframe
+			}
+		},
+
+		proto :
+		{
+			addBlock : function( name, block )
+			{
+				return this._.panel.addBlock( name, block );
+			},
+
+			addListBlock : function( name, multiSelect )
+			{
+				return this._.panel.addListBlock( name, multiSelect );
+			},
+
+			showBlock : function( name, offsetParent, corner, offsetX, offsetY )
+			{
+				this._.panel.showBlock( name );
+
+				var element = this.element,
+					iframe = this._.iframe,
+					position = offsetParent.getDocumentPosition();
+
+				var left	= position.x + ( offsetX || 0 ),
+					top		= position.y + ( offsetY || 0 );
+
+				if ( corner == 2 || corner == 3 )
+					left += offsetParent.$.offsetWidth - 1;
+
+				if ( corner == 3 || corner == 4 )
+					top += offsetParent.$.offsetHeight - 1;
+
+				element.setStyles(
+					{
+						left	: left + 'px',
+						top		: top + 'px',
+						display	: ''
+					});
+
+				// Configure the IFrame blur event. Do that only once.
+				if ( !this._.blurSet )
+				{
+					// Non IE prefer the event into a window object.
+					var focused = CKEDITOR.env.ie ? iframe : new CKEDITOR.dom.window( iframe.$.contentWindow );
+
+					focused.on( 'blur', CKEDITOR.tools.bind( this.hide, this ) );
+
+					this._.blurSet = 1;
+				}
+
+				// Set the IFrame focus, so the blur event gets fired.
+				setTimeout( function()
+					{
+						iframe.$.contentWindow.focus();
+					}, 0);
+
+				if ( this.onShow )
+					this.onShow.call( this );
+			},
+
+			hide : function()
+			{
+				if ( !this.onHide || this.onHide.call( this ) !== true )
+					this.element.setStyle( 'display', 'none' );
+			}
+		}
+	});
+})();
Index: /CKEditor/trunk/_source/plugins/format/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/format/plugin.js	(revision 3113)
+++ /CKEditor/trunk/_source/plugins/format/plugin.js	(revision 3113)
@@ -0,0 +1,119 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.plugins.add( 'format',
+{
+	requires : [ 'richcombo' ],
+
+	init : function( editor )
+	{
+		var config = editor.config,
+			lang = editor.lang.format;
+
+		var saveRanges;
+
+		// Gets the list of tags from the settings.
+		var tags = config.format_tags.split( ',' );
+
+		// Create style objects for all defined styles.
+		var styles = {};
+		for ( var i = 0 ; i < tags.length ; i++ )
+		{
+			var tag = tags[ i ];
+			styles[ tag ] = new CKEDITOR.style( config[ 'format_' + tag ] );
+		}
+
+		editor.ui.addRichCombo( 'Format',
+			{
+				label : lang.label,
+				title : lang.panelTitle,
+				className : 'cke_format',
+				multiSelect : false,
+
+				panel :
+				{
+					css : [ config.contentsCss, editor.skinPath + 'editor.css' ],
+					className : 'cke_skin_default'
+				},
+
+				init : function()
+				{
+					this.startGroup( lang.panelTitle );
+
+					for ( var tag in styles )
+					{
+						var label = lang[ 'tag_' + tag ];
+
+						// Add the tag entry to the panel list.
+						this.add( tag, '<' + tag + '>' + label + '</' + tag + '>', label );
+					}
+				},
+
+				onClick : function( value )
+				{
+					editor.focus();
+
+					if ( saveRanges )
+					{
+						editor.getSelection().selectRanges( saveRanges );
+						saveRanges = false;
+					}
+
+					styles[ value ].apply( editor.document );
+				},
+
+				onRender : function()
+				{
+					editor.on( 'selectionChange', function( ev )
+						{
+							var currentTag = this.getValue();
+
+							var elementPath = ev.data.path;
+
+							for ( var tag in styles )
+							{
+								if ( styles[ tag ].checkActive( elementPath ) )
+								{
+									if ( tag != currentTag )
+										this.setValue( tag, editor.lang.format[ 'tag_' + tag ] );
+									return;
+								}
+							}
+
+							// If no styles match, just empty it.
+							this.setValue( '' );
+						},
+						this);
+				},
+
+				onOpen : function()
+				{
+					if ( CKEDITOR.env.ie )
+					{
+						editor.focus();
+						saveRanges = editor.getSelection().getRanges();
+					}
+				},
+
+				onClose : function()
+				{
+					saveRanges = null;
+				}
+			});
+	}
+});
+
+CKEDITOR.config.format_tags = 'p,h1,h2,h3,h4,h5,h6,pre,address,div';
+
+CKEDITOR.config.format_p		= { element : 'p' };
+CKEDITOR.config.format_div		= { element : 'div' };
+CKEDITOR.config.format_pre		= { element : 'pre' };
+CKEDITOR.config.format_address	= { element : 'address' };
+CKEDITOR.config.format_h1		= { element : 'h1' };
+CKEDITOR.config.format_h2		= { element : 'h2' };
+CKEDITOR.config.format_h3		= { element : 'h3' };
+CKEDITOR.config.format_h4		= { element : 'h4' };
+CKEDITOR.config.format_h5		= { element : 'h5' };
+CKEDITOR.config.format_h6		= { element : 'h6' };
Index: /CKEditor/trunk/_source/plugins/listblock/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/listblock/plugin.js	(revision 3113)
+++ /CKEditor/trunk/_source/plugins/listblock/plugin.js	(revision 3113)
@@ -0,0 +1,143 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.plugins.add( 'listblock',
+{
+	requires : [ 'panel' ],
+	
+	onLoad : function()
+	{
+		CKEDITOR.ui.panel.prototype.addListBlock = function( name, multiSelect )
+		{
+			return this.addBlock( name, new CKEDITOR.ui.listBlock( this.getHolderElement(), multiSelect ) );
+		};
+
+		CKEDITOR.ui.listBlock = CKEDITOR.tools.createClass(
+			{
+				base : CKEDITOR.ui.panel.block,
+
+				$ : function( blockHolder, multiSelect )
+				{
+					// Call the base contructor.
+					this.base( blockHolder );
+
+					this.multiSelect = !!multiSelect;
+
+					this._ =
+					{
+						pendingHtml : [],
+						items : {}
+					};
+				},
+
+				_ :
+				{
+					close : function()
+					{
+						if ( this._.started )
+						{
+							this._.pendingHtml.push( '</ul>' );
+							delete this._.started;
+						}
+					},
+
+					getClick : function()
+					{
+						if ( !this._.click )
+						{
+							this._.click = CKEDITOR.tools.addFunction( function( value )
+								{
+									var marked = true;
+
+									if ( this.multiSelect )
+										marked = this.toggle( value );
+									else
+										this.mark( value );
+
+									if ( this.onClick )
+										this.onClick( value, marked );
+								},
+								this );
+						}
+						return this._.click;
+					}
+				},
+
+				proto :
+				{
+					add : function( value, html )
+					{
+						var pendingHtml = this._.pendingHtml,
+							id = CKEDITOR.tools.getNextNumber();
+
+						if ( !this._.started )
+						{
+							pendingHtml.push( '<ul class=cke_panel_list>' );
+							this._.started = 1;
+						}
+
+						this._.items[ value ] = id;
+
+						pendingHtml.push( '<li id=cke_', id, ' class=cke_panel_listItem><a hidefocus=true href="javascript:void(\'', value, '\')" onclick="CKEDITOR.tools.callFunction(', this._.getClick(), ',\'', value, '\');">', html || value, '</a></li>' );
+					},
+
+					startGroup : function( title )
+					{
+						this._.close();
+						this._.pendingHtml.push( '<h1 class=cke_panel_grouptitle>', title, '</h1>' );
+					},
+
+					commit : function()
+					{
+						this._.close();
+						this.element.appendHtml( this._.pendingHtml.join( '' ) );
+					},
+
+					toggle : function( value )
+					{
+						var isMarked = this.isMarked( value );
+
+						if ( isMarked )
+							this.unmark( value );
+						else
+							this.mark( value );
+
+						return !isMarked;
+					},
+
+					mark : function( value )
+					{
+						if ( !this.multiSelect )
+							this.unmarkAll();
+
+						this.element.getDocument().getById( 'cke_' + this._.items[ value ] ).addClass( 'cke_selected' );
+					},
+
+					unmark : function( value )
+					{
+						this.element.getDocument().getById( 'cke_' + this._.items[ value ] ).removeClass( 'cke_selected' );
+					},
+
+					unmarkAll : function()
+					{
+						var items = this._.items,
+							doc = this.element.getDocument();
+
+						for ( var value in items )
+						{
+							doc.getById( 'cke_' + items[ value ] ).removeClass( 'cke_selected' );
+						}
+					},
+
+					isMarked : function( value )
+					{
+						return this.element.getDocument().getById( 'cke_' + this._.items[ value ] ).hasClass( 'cke_selected' );
+					}
+				}
+			});
+	}
+});
+
+
Index: /CKEditor/trunk/_source/plugins/panel/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/panel/plugin.js	(revision 3113)
+++ /CKEditor/trunk/_source/plugins/panel/plugin.js	(revision 3113)
@@ -0,0 +1,193 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.plugins.add( 'panel',
+{
+	beforeInit : function( editor )
+	{
+		editor.ui.addHandler( CKEDITOR.UI_PANEL, CKEDITOR.ui.panel.handler );
+	}
+});
+
+/**
+ * Panel UI element.
+ * @constant
+ * @example
+ */
+CKEDITOR.UI_PANEL = 2;
+
+CKEDITOR.ui.panel = function( document, definition )
+{
+	// Copy all definition properties to this object.
+	if ( definition )
+		CKEDITOR.tools.extend( this, definition );
+
+	// Set defaults.
+	CKEDITOR.tools.extend( this,
+		{
+			className : '',
+			css : []
+		});
+
+	this.id = CKEDITOR.tools.getNextNumber();
+	this.document = document;
+
+	this._ =
+	{
+		blocks : {}
+	};
+};
+
+/**
+ * Transforms a rich combo definition in a {@link CKEDITOR.ui.richCombo}
+ * instance.
+ * @type Object
+ * @example
+ */
+CKEDITOR.ui.panel.handler =
+{
+	create : function( definition )
+	{
+		return new CKEDITOR.ui.panel( definition );
+	}
+};
+
+CKEDITOR.ui.panel.prototype =
+{
+	renderHtml : function()
+	{
+		var output = [];
+		this.render( output );
+		return output.join( '' );
+	},
+
+	/**
+	 * Renders the combo.
+	 * @param {CKEDITOR.editor} editor The editor instance which this button is
+	 *		to be used by.
+	 * @param {Array} output The output array to which append the HTML relative
+	 *		to this button.
+	 * @example
+	 */
+	render : function( output )
+	{
+		var id = 'cke_' + this.id;
+
+		output.push(
+			'<div id=', id,
+				' class="cke_panel' );
+
+		if ( this.className )
+			output.push( ' ', this.className);
+
+		output.push(
+			 '">');
+
+		if ( this.forceIFrame || this.css.length )
+		{
+			output.push(
+				'<iframe id="', id, '_frame"' +
+					' frameborder="0"' +
+					' src="javascript:void(0)"' +
+				'></iframe>' );
+		}
+
+		output.push(
+			'</div>' );
+
+		return id;
+	},
+
+	getHolderElement : function()
+	{
+		var holder = this._.holder;
+
+		if ( !holder )
+		{
+			if ( this.forceIFrame || this.css.length )
+			{
+				var iframe = this.document.getById( 'cke_' + this.id + '_frame' );
+				var doc = new CKEDITOR.dom.document( iframe.$.contentWindow.document );
+				
+				// Initialize the IFRAME document body.
+				doc.$.open();
+				doc.$.write(
+					'<!DOCTYPE html>' +
+					'<html>' +
+						'<head>' +
+							'<link type="text/css" rel=stylesheet href="' + this.css.join( '"><link type="text/css" rel="stylesheet" href="' ) + '">' +
+						'</head>' +
+						'<body class="cke_panel_frame" style="margin:0;padding:0">' +
+						'</body>' +
+					'<\/html>' );
+				doc.$.close();
+
+				// Register the CKEDITOR global.
+				doc.getWindow().$.CKEDITOR = CKEDITOR;
+
+				holder = doc.getBody();
+			}
+			else
+				holder = this.document.getById( 'cke_' + this.id );
+
+			this._.holder = holder;
+		}
+
+		return holder;
+	},
+
+	addBlock : function( name, block )
+	{
+		block = this._.blocks[ name ] = block || new CKEDITOR.ui.panel.block( this.getHolderElement() );
+
+		if ( !this._.currentBlock )
+			this.showBlock( name );
+
+		return block;
+	},
+
+	showBlock : function( name )
+	{
+		var blocks = this._.blocks,
+			block = blocks[ name ],
+			current = this._.currentBlock;
+
+		if ( current )
+			current.hide();
+
+		this._.currentBlock = block;
+
+		block.show();
+	}
+};
+
+CKEDITOR.ui.panel.block = function( blockHolder )
+{
+	this.element = blockHolder.append(
+		blockHolder.getDocument().createElement( 'div',
+			{
+				attributes :
+				{
+					'class' : 'cke_panel_block'
+				},
+				styles :
+				{
+					display : 'none'
+				}
+			}) );
+};
+
+CKEDITOR.ui.panel.block.prototype =
+{
+	show : function()
+	{
+		this.element.setStyle( 'display', '' );
+	},
+
+	hide : function()
+	{
+		this.element.setStyle( 'display', 'none' );
+	}
+};
Index: /CKEditor/trunk/_source/plugins/richcombo/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/richcombo/plugin.js	(revision 3113)
+++ /CKEditor/trunk/_source/plugins/richcombo/plugin.js	(revision 3113)
@@ -0,0 +1,253 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.plugins.add( 'richcombo',
+{
+	requires : [ 'floatpanel', 'listblock' ],
+
+	beforeInit : function( editor )
+	{
+		editor.ui.addHandler( CKEDITOR.UI_RICHCOMBO, CKEDITOR.ui.richCombo.handler );
+	}
+});
+
+/**
+ * Button UI element.
+ * @constant
+ * @example
+ */
+CKEDITOR.UI_RICHCOMBO = 3;
+
+CKEDITOR.ui.richCombo = CKEDITOR.tools.createClass(
+{
+	$ : function( definition )
+	{
+		// Copy all definition properties to this object.
+		CKEDITOR.tools.extend( this, definition,
+			// Set defaults.
+			{
+				title : definition.label
+			});
+
+		// We don't want the panel definition in this object.
+		delete this.panel;
+
+		this.id = CKEDITOR.tools.getNextNumber();
+
+		this.document = ( definition.panel
+							&& definition.panel.parent
+							&& definition.panel.parent.getDocument() )
+						|| CKEDITOR.document;
+
+		this._ =
+		{
+			panelDefinition : definition.panel,
+			items : {}
+		};
+	},
+
+	statics :
+	{
+		handler :
+		{
+			create : function( definition )
+			{
+				return new CKEDITOR.ui.richCombo( definition );
+			}
+		}
+	},
+
+	proto :
+	{
+		renderHtml : function( editor )
+		{
+			var output = [];
+			this.render( editor, output );
+			return output.join( '' );
+		},
+
+		/**
+		 * Renders the combo.
+		 * @param {CKEDITOR.editor} editor The editor instance which this button is
+		 *		to be used by.
+		 * @param {Array} output The output array to which append the HTML relative
+		 *		to this button.
+		 * @example
+		 */
+		render : function( editor, output )
+		{
+			var id = 'cke_' + this.id;
+
+			var clickFn = CKEDITOR.tools.addFunction( function( $element )
+				{
+					var _ = this._;
+
+					this.createPanel();
+
+					if ( _.on )
+					{
+						_.panel.hide();
+						return;
+					}
+
+					if ( !_.committed )
+					{
+						_.list.commit();
+						_.committed = 1;
+					}
+					
+					var value = this.getValue();
+					if ( value )
+						_.list.mark( value );
+					else
+						_.list.unmarkAll();
+					
+					_.panel.showBlock( this.id, new CKEDITOR.dom.element( $element ).getFirst(), 4 );
+				},
+				this );
+			
+			output.push(
+				'<span id=', id, ' class="cke_rcombo' );
+
+			if ( this.className )
+				output.push( ' ', this.className);
+
+			output.push(
+				 '">' +
+					'<span class=cke_label>', this.label, '</span>' +
+					'<a hidefocus=true title="', this.title, '" href="javascript:void(\'', this.label, '\')"' );
+
+			// Some browsers don't cancel key events in the keydown but in the
+			// keypress.
+			// TODO: Check if really needed for Gecko+Mac.
+			if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) )
+			{
+				output.push(
+					' onkeypress="return false;"' );
+			}
+
+			// With Firefox, we need to force it to redraw, otherwise it
+			// will remain in the focus state.
+			if ( CKEDITOR.env.gecko )
+			{
+				output.push(
+					' onblur="this.style.cssText = this.style.cssText;"' );
+			}
+
+			output.push(
+//					' onkeydown="return CKEDITOR.ui.button._.keydown(', id, ', event);"' +
+					' onmousedown="CKEDITOR.tools.callFunction(', clickFn, ', this);">' +
+						'<span id="', id, '_text" class=cke_text>&nbsp;</span>' +
+						'<span class=cke_openbutton></span>' +
+					'</a>' +
+				'</span>' );
+
+			if ( this.onRender )
+				this.onRender();
+
+			return {
+				id : id,
+				combo : this,
+				focus : function()
+				{
+					var element = CKEDITOR.document.getById( id ).getChild( 1 );
+					element.focus();
+				},
+				execute : clickFn
+			};
+		},
+
+		createPanel : function()
+		{
+			if ( this._.panel )
+				return;
+
+			var panelDefinition = this._.panelDefinition || {},
+				panelParentElement = panelDefinition.parent || CKEDITOR.document.getBody(),
+				panel = new CKEDITOR.ui.floatPanel( panelParentElement, panelDefinition ),
+				list = panel.addListBlock( this.id, this.multiSelect ),
+				me = this;
+
+			panel.onShow = function()
+				{
+					if ( me.className )
+						this.element.addClass( me.className );
+
+					me.document.getById( 'cke_' + me.id ).addClass( 'cke_on');
+
+					me._.on = 1;
+
+					if ( me.onOpen )
+						me.onOpen();
+				};
+
+			panel.onHide = function()
+				{
+					if ( me.className )
+						this.element.removeClass( me.className );
+
+					me.document.getById( 'cke_' + me.id ).removeClass( 'cke_on');
+
+					me._.on = 0;
+
+					if ( me.onClose )
+						me.onClose();
+				};
+
+			list.onClick = function( value, marked )
+				{
+					if ( marked )
+						me.setValue( value, me._.items[ value ] );
+					else
+						me.setValue( '' );
+
+					// Move the focus to the main windows, otherwise it will stay
+					// into the floating panel, even if invisible, and Safari and
+					// Opera will go a bit crazy.
+					me.document.getWindow().focus();
+
+					if ( me.onClick )
+						me.onClick.call( me, value, marked );
+
+					panel.hide();
+				};
+
+			this._.panel = panel;
+			this._.list = list;
+
+			if ( this.init )
+				this.init();
+		},
+
+		setValue : function( value, text )
+		{
+			this._.value = value;
+
+			var textElement = this.document.getById( 'cke_' + this.id + '_text' );
+			textElement.setHtml( typeof text != 'undefined' ? text : value );
+		},
+
+		getValue : function()
+		{
+			return this._.value || '';
+		},
+
+		add : function( value, html, text )
+		{
+			this._.items[ value ] = text || value;
+			this._.list.add( value, html );
+		},
+
+		startGroup : function( title )
+		{
+			this._.list.startGroup( title );
+		}
+	}
+});
+
+CKEDITOR.ui.prototype.addRichCombo = function( name, definition )
+{
+	this.add( name, CKEDITOR.UI_RICHCOMBO, definition );
+};
Index: /CKEditor/trunk/_source/plugins/styles/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/styles/plugin.js	(revision 3112)
+++ /CKEditor/trunk/_source/plugins/styles/plugin.js	(revision 3113)
@@ -178,5 +178,5 @@
 		{
 			if ( !element || element.getName() != this.element )
-				return false ;
+				return false;
 
 			var def = this._.definition;
@@ -186,5 +186,5 @@
 			// If no attributes are defined in the element.
 			if ( !fullMatch && !element.hasAttributes() )
-				return true ;
+				return true;
 
 			for ( var attName in attribs )
@@ -526,4 +526,50 @@
 	var applyBlockStyle = function( range )
 	{
+		// Bookmark the range so we can re-select it after processing.
+		var bookmark = range.createBookmark();
+
+		var iterator = range.createIterator();
+		iterator.enforceRealBlocks = true;
+
+		var block;
+		var doc = range.document;
+		var previousPreBlock;
+
+		while( ( block = iterator.getNextParagraph() ) )		// Only one =
+		{
+			// Create the new node right before the current one.
+			var newBlock = getElement( this, doc );
+
+			// Check if we are changing from/to <pre>.
+//			var newBlockIsPre	= newBlock.nodeName.IEquals( 'pre' );
+//			var blockIsPre		= block.nodeName.IEquals( 'pre' );
+
+//			var toPre	= newBlockIsPre && !blockIsPre;
+//			var fromPre	= !newBlockIsPre && blockIsPre;
+
+			// Move everything from the current node to the new one.
+//			if ( toPre )
+//				newBlock = this._ToPre( doc, block, newBlock );
+//			else if ( fromPre )
+//				newBlock = this._FromPre( doc, block, newBlock );
+//			else	// Convering from a regular block to another regular block.
+				block.moveChildren( newBlock );
+
+			// Replace the current block.
+			newBlock.insertBefore( block );
+			block.remove();
+
+			// Complete other tasks after inserting the node in the DOM.
+//			if ( newBlockIsPre )
+//			{
+//				if ( previousPreBlock )
+//					this._CheckAndMergePre( previousPreBlock, newBlock ) ;	// Merge successive <pre> blocks.
+//				previousPreBlock = newBlock;
+//			}
+//			else if ( fromPre )
+//				this._CheckAndSplitPre( newBlock ) ;	// Split <br><br> in successive <pre>s.
+		}
+
+		range.moveToBookmark( bookmark );
 	};
 
Index: /CKEditor/trunk/_source/plugins/toolbar/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/toolbar/plugin.js	(revision 3112)
+++ /CKEditor/trunk/_source/plugins/toolbar/plugin.js	(revision 3113)
@@ -135,5 +135,5 @@
 									item = CKEDITOR.ui.separator;
 								else
-									item = editor.ui.get( itemName );
+									item = editor.ui.create( itemName );
 
 								if ( item )
@@ -221,5 +221,6 @@
 		'Image', 'Flash', '-',
 		'Table', 'Smiley', 'HorizontalRule', 'SpecialChar', 'PageBreak', '-',
-		'ShowBlocks'
+		'ShowBlocks', '-',
+		'Format'
 	]
 ];
Index: /CKEditor/trunk/_source/skins/default/editor.css
===================================================================
--- /CKEditor/trunk/_source/skins/default/editor.css	(revision 3112)
+++ /CKEditor/trunk/_source/skins/default/editor.css	(revision 3113)
@@ -7,4 +7,6 @@
 @import url("mainui.css");
 @import url("toolbar.css");
+@import url("panel.css");
+@import url("richcombo.css");
 @import url("elementspath.css");
 
Index: /CKEditor/trunk/_source/skins/default/panel.css
===================================================================
--- /CKEditor/trunk/_source/skins/default/panel.css	(revision 3113)
+++ /CKEditor/trunk/_source/skins/default/panel.css	(revision 3113)
@@ -0,0 +1,262 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+.cke_skin_default.cke_panel
+{
+	border: 1px solid #316ac5;
+	background-color: #fff;
+
+	width: 120px;
+	height: 100px;
+
+	overflow:hidden;
+
+	-moz-border-radius-bottomright: 3px;
+	-webkit-border-bottom-right-radius: 3px;
+	border-bottom-left-radius: 3px;
+	-moz-border-radius-bottomleft: 3px;
+	-webkit-border-bottom-left-radius: 3px;
+	border-bottom-left-radius: 3px;
+	-moz-border-radius-topright: 3px;
+	-webkit-border-top-right-radius: 3px;
+	border-top-right-radius: 3px;
+}
+
+.cke_skin_default.cke_panel.cke_format
+{
+	width: 150px;
+	height: 170px;
+}
+
+/* Ideally we would use "inherit here"... but you know... IE :( */
+.cke_skin_default.cke_panel iframe
+{
+	width: 100%;
+	height: 100%;
+}
+
+/*
+ * All the following styles are to be used inside the iframe that holds panel
+ * contents. We don't use the cke_skin_default there to avoid the reset to be
+ * active.
+ * This is not an issue as we'll never have two skins running inside the same
+ * panel iframe.
+ */
+
+body.cke_panel_frame
+{
+	overflow: auto;
+	overflow-x: hidden;
+}
+
+ul.cke_panel_list
+{
+	list-style-type: none;
+	margin: 3px;
+	padding: 0px;
+    white-space: nowrap;
+}
+
+li.cke_panel_listItem
+{
+	margin: 0px;
+}
+
+.cke_panel_listItem a
+{
+	padding: 2px;
+	display: block;
+	border: 1px solid #fff;
+	color: inherit;
+	text-decoration: none;
+	overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+/* IE6 */
+* html .cke_panel_listItem a
+{
+	width : 100%;
+
+	/* IE is not able to inherit the color, so we must force it to black */
+	color: #000;
+}
+
+/* IE7 */
+*:first-child+html .cke_panel_listItem a
+{
+	/* IE is not able to inherit the color, so we must force it to black */
+	color: #000;
+}
+
+.cke_panel_listItem.cke_selected a
+{
+	border: 1px solid #ccc;
+	background-color: #e9f5ff;
+}
+
+.cke_panel_listItem a:hover,
+.cke_panel_listItem a:focus,
+.cke_panel_listItem a:active
+{
+	border-color: #316ac5;
+	background-color: #dff1ff;
+}
+
+.cke_panel_grouptitle
+{
+    font-size: 11px;
+    font-family: 'Microsoft Sans Serif' , Tahoma, Arial, Verdana, Sans-Serif;
+	font-weight: bold;
+    white-space: nowrap;
+	background-color: #dcdcdc;
+	color: #000;
+	margin:0px;
+	padding:3px;
+}
+
+.cke_panel_listItem p,
+.cke_panel_listItem h1,
+.cke_panel_listItem h2,
+.cke_panel_listItem h3,
+.cke_panel_listItem h4,
+.cke_panel_listItem h5,
+.cke_panel_listItem h6,
+.cke_panel_listItem pre
+{
+	margin-top: 3px;
+	margin-bottom: 3px;
+}
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+.cke_skin_default.cke_panel
+{
+	border: 1px solid #316ac5;
+	background-color: #fff;
+
+	width: 120px;
+	height: 100px;
+
+	overflow:hidden;
+
+	-moz-border-radius-bottomright: 3px;
+	-webkit-border-bottom-right-radius: 3px;
+	border-bottom-left-radius: 3px;
+	-moz-border-radius-bottomleft: 3px;
+	-webkit-border-bottom-left-radius: 3px;
+	border-bottom-left-radius: 3px;
+	-moz-border-radius-topright: 3px;
+	-webkit-border-top-right-radius: 3px;
+	border-top-right-radius: 3px;
+}
+
+.cke_skin_default.cke_panel.cke_format
+{
+	width: 150px;
+	height: 170px;
+}
+
+/* Ideally we would use "inherit here"... but you know... IE :( */
+.cke_skin_default.cke_panel iframe
+{
+	width: 100%;
+	height: 100%;
+}
+
+/*
+ * All the following styles are to be used inside the iframe that holds panel
+ * contents. We don't use the cke_skin_default there to avoid the reset to be
+ * active.
+ * This is not an issue as we'll never have two skins running inside the same
+ * panel iframe.
+ */
+
+body.cke_panel_frame
+{
+	overflow: auto;
+	overflow-x: hidden;
+}
+
+ul.cke_panel_list
+{
+	list-style-type: none;
+	margin: 3px;
+	padding: 0px;
+    white-space: nowrap;
+}
+
+li.cke_panel_listItem
+{
+	margin: 0px;
+}
+
+.cke_panel_listItem a
+{
+	padding: 2px;
+	display: block;
+	border: 1px solid #fff;
+	color: inherit;
+	text-decoration: none;
+	overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+/* IE6 */
+* html .cke_panel_listItem a
+{
+	width : 100%;
+
+	/* IE is not able to inherit the color, so we must force it to black */
+	color: #000;
+}
+
+/* IE7 */
+*:first-child+html .cke_panel_listItem a
+{
+	/* IE is not able to inherit the color, so we must force it to black */
+	color: #000;
+}
+
+.cke_panel_listItem.cke_selected a
+{
+	border: 1px solid #ccc;
+	background-color: #e9f5ff;
+}
+
+.cke_panel_listItem a:hover,
+.cke_panel_listItem a:focus,
+.cke_panel_listItem a:active
+{
+	border-color: #316ac5;
+	background-color: #dff1ff;
+}
+
+.cke_panel_grouptitle
+{
+    font-size: 11px;
+    font-family: 'Microsoft Sans Serif' , Tahoma, Arial, Verdana, Sans-Serif;
+	font-weight: bold;
+    white-space: nowrap;
+	background-color: #dcdcdc;
+	color: #000;
+	margin:0px;
+	padding:3px;
+}
+
+.cke_panel_listItem p,
+.cke_panel_listItem h1,
+.cke_panel_listItem h2,
+.cke_panel_listItem h3,
+.cke_panel_listItem h4,
+.cke_panel_listItem h5,
+.cke_panel_listItem h6,
+.cke_panel_listItem pre
+{
+	margin-top: 3px;
+	margin-bottom: 3px;
+}
Index: /CKEditor/trunk/_source/skins/default/richcombo.css
===================================================================
--- /CKEditor/trunk/_source/skins/default/richcombo.css	(revision 3113)
+++ /CKEditor/trunk/_source/skins/default/richcombo.css	(revision 3113)
@@ -0,0 +1,226 @@
+/* Special Combo */
+
+.cke_skin_default .cke_rcombo
+{
+	padding-right: 4px;
+	float: left;
+}
+
+/* IE6 only */
+/*\*/
+* html .cke_skin_default .cke_rcombo
+{
+	float: none;
+}
+/**/ 
+
+.cke_skin_default .cke_rcombo a
+{
+	filter: alpha(opacity=70); /* IE */
+	opacity: 0.70; /* Safari, Opera and Mozilla */
+}
+
+.cke_skin_default .cke_rcombo .cke_label
+{
+	padding-top: 6px;
+	padding-left: 4px;
+	padding-right: 5px;
+	float: left;
+	filter: alpha(opacity=70); /* IE */
+	opacity: 0.70; /* Safari, Opera and Mozilla */
+	background-color: #f1f1e3;	/* Because of IE6+ClearType */
+}
+
+.cke_skin_default .cke_rcombo .cke_text
+{
+	border: 1px solid #8f8f73;
+	background-color: #fff;
+	float: left;
+	height: 14px;
+	width:60px;
+	padding-top: 4px;
+	padding-bottom: 4px;
+	padding-left: 5px;
+	padding-right: 5px;
+    text-overflow: ellipsis;
+    overflow: hidden;
+	-moz-border-radius-topleft: 3px;
+	-webkit-border-top-left-radius: 3px;
+	border-top-left-radius: 3px;
+	-moz-border-radius-bottomleft: 3px;
+	-webkit-border-bottom-left-radius: 3px;
+	border-bottom-left-radius: 3px;
+}
+
+.cke_skin_default .cke_rcombo .cke_openbutton
+{
+    background-position: center center;
+    background-image: url(images/toolbar.buttonarrow.gif);
+    border-right: 1px solid #8f8f73;
+    border-top: 1px solid #8f8f73;
+    border-bottom: 1px solid #8f8f73;
+	display: block;
+	float: left;
+    width: 14px;
+	height: 22px;
+    background-repeat: no-repeat;
+	-moz-border-radius-topright: 3px;
+	-webkit-border-top-right-radius: 3px;
+	border-top-left-radius: 3px;
+	-moz-border-radius-bottomright: 3px;
+	-webkit-border-bottom-right-radius: 3px;
+	border-bottom-left-radius: 3px;
+}
+
+.cke_skin_default .cke_rcombo a:hover,
+.cke_skin_default .cke_rcombo a:focus,
+.cke_skin_default .cke_rcombo a:active,
+.cke_skin_default .cke_rcombo.cke_on a
+{
+	filter: alpha(opacity=100); /* IE */
+	opacity: 1; /* Safari, Opera and Mozilla */
+}
+
+.cke_skin_default .cke_rcombo a:hover .cke_text,
+.cke_skin_default .cke_rcombo a:focus .cke_text,
+.cke_skin_default .cke_rcombo a:active .cke_text,
+.cke_skin_default .cke_rcombo.cke_on .cke_text
+{
+	border-color: #316ac5;
+}
+
+.cke_skin_default .cke_rcombo a:hover .cke_openbutton,
+.cke_skin_default .cke_rcombo a:focus .cke_openbutton,
+.cke_skin_default .cke_rcombo a:active .cke_openbutton,
+.cke_skin_default .cke_rcombo.cke_on .cke_openbutton
+{
+	border-color: #316ac5;
+	background-color: #dff1ff;
+}
+
+.cke_skin_default .cke_rcombo.cke_on .cke_text
+{
+	-moz-border-radius-bottomleft: 0px;
+	-webkit-border-bottom-left-radius: 0px;
+	border-bottom-left-radius: 0px;
+}
+
+.cke_skin_default .cke_rcombo.cke_on .cke_openbutton
+{
+	-moz-border-radius-bottomright: 0px;
+	-webkit-border-bottom-right-radius: 0px;
+	border-bottom-right-radius: 0px;
+}
+/* Special Combo */
+
+.cke_skin_default .cke_rcombo
+{
+	padding-right: 4px;
+	float: left;
+}
+
+/* IE6 only */
+/*\*/
+* html .cke_skin_default .cke_rcombo
+{
+	float: none;
+}
+/**/ 
+
+.cke_skin_default .cke_rcombo a
+{
+	filter: alpha(opacity=70); /* IE */
+	opacity: 0.70; /* Safari, Opera and Mozilla */
+}
+
+.cke_skin_default .cke_rcombo .cke_label
+{
+	padding-top: 6px;
+	padding-left: 4px;
+	padding-right: 5px;
+	float: left;
+	filter: alpha(opacity=70); /* IE */
+	opacity: 0.70; /* Safari, Opera and Mozilla */
+	background-color: #f1f1e3;	/* Because of IE6+ClearType */
+}
+
+.cke_skin_default .cke_rcombo .cke_text
+{
+	border: 1px solid #8f8f73;
+	background-color: #fff;
+	float: left;
+	height: 14px;
+	width:60px;
+	padding-top: 4px;
+	padding-bottom: 4px;
+	padding-left: 5px;
+	padding-right: 5px;
+    text-overflow: ellipsis;
+    overflow: hidden;
+	-moz-border-radius-topleft: 3px;
+	-webkit-border-top-left-radius: 3px;
+	border-top-left-radius: 3px;
+	-moz-border-radius-bottomleft: 3px;
+	-webkit-border-bottom-left-radius: 3px;
+	border-bottom-left-radius: 3px;
+}
+
+.cke_skin_default .cke_rcombo .cke_openbutton
+{
+    background-position: center center;
+    background-image: url(images/toolbar.buttonarrow.gif);
+    border-right: 1px solid #8f8f73;
+    border-top: 1px solid #8f8f73;
+    border-bottom: 1px solid #8f8f73;
+	display: block;
+	float: left;
+    width: 14px;
+	height: 22px;
+    background-repeat: no-repeat;
+	-moz-border-radius-topright: 3px;
+	-webkit-border-top-right-radius: 3px;
+	border-top-left-radius: 3px;
+	-moz-border-radius-bottomright: 3px;
+	-webkit-border-bottom-right-radius: 3px;
+	border-bottom-left-radius: 3px;
+}
+
+.cke_skin_default .cke_rcombo a:hover,
+.cke_skin_default .cke_rcombo a:focus,
+.cke_skin_default .cke_rcombo a:active,
+.cke_skin_default .cke_rcombo.cke_on a
+{
+	filter: alpha(opacity=100); /* IE */
+	opacity: 1; /* Safari, Opera and Mozilla */
+}
+
+.cke_skin_default .cke_rcombo a:hover .cke_text,
+.cke_skin_default .cke_rcombo a:focus .cke_text,
+.cke_skin_default .cke_rcombo a:active .cke_text,
+.cke_skin_default .cke_rcombo.cke_on .cke_text
+{
+	border-color: #316ac5;
+}
+
+.cke_skin_default .cke_rcombo a:hover .cke_openbutton,
+.cke_skin_default .cke_rcombo a:focus .cke_openbutton,
+.cke_skin_default .cke_rcombo a:active .cke_openbutton,
+.cke_skin_default .cke_rcombo.cke_on .cke_openbutton
+{
+	border-color: #316ac5;
+	background-color: #dff1ff;
+}
+
+.cke_skin_default .cke_rcombo.cke_on .cke_text
+{
+	-moz-border-radius-bottomleft: 0px;
+	-webkit-border-bottom-left-radius: 0px;
+	border-bottom-left-radius: 0px;
+}
+
+.cke_skin_default .cke_rcombo.cke_on .cke_openbutton
+{
+	-moz-border-radius-bottomright: 0px;
+	-webkit-border-bottom-right-radius: 0px;
+	border-bottom-right-radius: 0px;
+}
Index: /CKEditor/trunk/_source/tests/core/event.html
===================================================================
--- /CKEditor/trunk/_source/tests/core/event.html	(revision 3112)
+++ /CKEditor/trunk/_source/tests/core/event.html	(revision 3113)
@@ -450,4 +450,32 @@
 		},
 
+		test_event_removeListener : function()
+		{
+			// Create a testObject and implement CKEDITOR.event on it.
+			var testObject = {};
+			CKEDITOR.event.implementOn( testObject );
+
+			var counter = 0;
+
+			// Add two listeners for the same event "A".
+
+			testObject.on( 'A', function( ev )
+				{
+					counter++;
+					ev.removeListener();
+				});
+
+			testObject.on( 'A', function( ev )
+				{
+					counter++;
+				});
+
+			// Fire the event twice.
+			testObject.fire( 'A' );
+			testObject.fire( 'A' );
+
+			assert.areSame( 3, counter );
+		},
+
 		name : document.title
 	};
Index: /CKEditor/trunk/_source/themes/default/theme.js
===================================================================
--- /CKEditor/trunk/_source/themes/default/theme.js	(revision 3112)
+++ /CKEditor/trunk/_source/themes/default/theme.js	(revision 3113)
@@ -58,5 +58,5 @@
 			var container = CKEDITOR.dom.element.createFromHtml( [
 				'<span id="cke_', name, '" onmousedown="return false;" class="cke_container cke_skin_', editor.config.skin, ' ', browserCssClass,
-					' cke_', editor.lang.dir, '" dir="', editor.lang.dir, '">' +
+					' cke_', editor.lang.dir, '" dir="', editor.lang.dir, '" title="', ( CKEDITOR.env.gecko ? ' ' : '' ), '">' +
 					'<table class="cke_editor" border="0" cellspacing="0" cellpadding="0" style="width:', width, ';height:', height, '"><tbody>' +
 						'<tr', topHtml		? '' : ' style="display:none"', '><td id="cke_top_'		, name, '" class="cke_top">'		, topHtml		, '</td></tr>' +
Index: /CKEditor/trunk/ckeditor.pack
===================================================================
--- /CKEditor/trunk/ckeditor.pack	(revision 3112)
+++ /CKEditor/trunk/ckeditor.pack	(revision 3113)
@@ -47,4 +47,5 @@
 		'CKEDITOR.SELECTION_TEXT' : 2,
 		'CKEDITOR.SELECTION_ELEMENT' : 3,
+		'CKEDITOR.UI_RICHCOMBO' : 3,
 		'CKEDITOR.DIALOG_RESIZE_NONE' : 0,
 		'CKEDITOR.DIALOG_RESIZE_WIDTH' : 1,
@@ -52,5 +53,6 @@
 		'CKEDITOR.DIALOG_RESIZE_BOTH' : 3,
 		'CKEDITOR.VALIDATE_OR' : 1,
-		'CKEDITOR.VALIDATE_AND' : 2
+		'CKEDITOR.VALIDATE_AND' : 2,
+		'CKEDITOR.UI_PANEL' : 2
 	},
 
@@ -121,4 +123,6 @@
 					'_source/plugins/elementspath/plugin.js',
 					'_source/plugins/find/plugin.js',
+					'_source/plugins/flash/plugin.js',
+					'_source/plugins/format/plugin.js',
 					'_source/plugins/horizontalrule/plugin.js',
 					'_source/plugins/htmldataprocessor/plugin.js',
@@ -137,4 +141,5 @@
 					'_source/plugins/removeformat/plugin.js',
 					'_source/plugins/smiley/plugin.js',
+					'_source/plugins/showblocks/plugin.js',
 					'_source/plugins/sourcearea/plugin.js',
 					'_source/plugins/table/plugin.js',
@@ -148,9 +153,13 @@
 					'_source/plugins/domiterator/plugin.js',
 					'_source/plugins/selection/plugin.js',
+					'_source/plugins/fakeobjects/plugin.js',
+					'_source/plugins/richcombo/plugin.js',
 					'_source/plugins/htmlwriter/plugin.js',
-					'_source/plugins/fakeobjects/plugin.js',
 					'_source/plugins/dialog/plugin.js',
 					'_source/plugins/editingblock/plugin.js',
+					'_source/plugins/floatpanel/plugin.js',
+					'_source/plugins/listblock/plugin.js',
 					'_source/plugins/dialogui/plugin.js',
+					'_source/plugins/panel/plugin.js',
 					'_source/skins/default/skin.js',
 					'_source/themes/default/theme.js'
Index: /CKEditor/trunk/contents.css
===================================================================
--- /CKEditor/trunk/contents.css	(revision 3112)
+++ /CKEditor/trunk/contents.css	(revision 3113)
@@ -10,4 +10,7 @@
 	font-size: 12px;
 
+	/* Text color */
+	color: #222;
+
 	/* Remove the background color to make it transparent */
 	background-color: #fff;
