Index: /CKEditor/trunk/_source/plugins/basicstyles/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/basicstyles/plugin.js	(revision 2985)
+++ /CKEditor/trunk/_source/plugins/basicstyles/plugin.js	(revision 2985)
@@ -0,0 +1,55 @@
+﻿/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.plugins.add( 'basicstyles',
+{
+	requires : [ 'styles', 'button' ],
+
+	init : function( editor, pluginPath )
+	{
+		// All buttons use the same code to register. So, to avoid
+		// duplications, let's use this tool function.
+		var addButtonCommand = function( buttonName, buttonLabel, commandName, styleDefiniton )
+		{
+			var style = new CKEDITOR.style( styleDefiniton );
+
+			editor.attachStyleStateChange( style, function( state )
+				{
+					var command = editor.getCommand( commandName );
+					command.state = state;
+					command.fire( 'state' );
+				});
+
+			editor.addCommand( commandName, new CKEDITOR.styleCommand( style ) );
+
+			editor.ui.addButton( buttonName,
+				{
+					label : buttonLabel,
+					command : commandName
+				});
+		};
+
+		var coreStyles = editor.config.coreStyles;
+		var lang = editor.lang;
+
+		addButtonCommand( 'Bold'		, lang.bold			, 'bold'		, coreStyles.bold );
+		addButtonCommand( 'Italic'		, lang.italic		, 'italic'		, coreStyles.italic );
+		addButtonCommand( 'Underline'	, lang.underline	, 'underline'	, coreStyles.underline );
+		addButtonCommand( 'Strike'		, lang.strike		, 'strike'		, coreStyles.strike );
+		addButtonCommand( 'Subscript'	, lang.subscript	, 'subscript'	, coreStyles.subscript );
+		addButtonCommand( 'Superscript'	, lang.superscript	, 'superscript'	, coreStyles.superscript );
+	}
+});
+
+CKEDITOR.config.coreStyles =
+{
+	// Basic Inline Styles.
+	bold			: { element : 'strong', overrides : 'b' },
+	italic			: { element : 'em', overrides : 'i' },
+	underline		: { element : 'u' },
+	strike			: { element : 'strike' },
+	subscript		: { element : 'sub' },
+	superscript		: { element : 'sup' }
+};
Index: /CKEditor/trunk/_source/plugins/button/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/button/plugin.js	(revision 2985)
+++ /CKEditor/trunk/_source/plugins/button/plugin.js	(revision 2985)
@@ -0,0 +1,237 @@
+﻿/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.plugins.add( 'button',
+{
+	beforeInit : function( editor )
+	{
+		editor.ui.addHandler( CKEDITOR.UI_BUTTON, CKEDITOR.ui.button.handler );
+	}
+});
+
+/**
+ * Button UI element.
+ * @constant
+ * @example
+ */
+CKEDITOR.UI_BUTTON = 1;
+
+/**
+ * Represents a button UI element. This class should not be called directly. To
+ * create new buttons use {@link CKEDITOR.ui.prototype.addButton} instead.
+ * @constructor
+ * @param {Object} definition The button definition.
+ * @example
+ */
+CKEDITOR.ui.button = function( definition )
+{
+	/**
+	 * The button label.
+	 * @name CKEDITOR.ui.button.prototype.label
+	 * @type String
+	 * @example
+	 */
+	this.label = definition.label;
+
+	/**
+	 * The button advisory title. It is usually displayed as the button tooltip.
+	 * If not defined, the label is used.
+	 * @name CKEDITOR.ui.button.prototype.title
+	 * @type String
+	 * @example
+	 */
+	this.title = definition.title || definition.label;
+
+	/**
+	 * The command name associated to the button. If no command is defined, the
+	 * "click" event is used.
+	 * @name CKEDITOR.ui.button.prototype.command
+	 * @type String
+	 * @example
+	 */
+	this.command = definition.command;
+
+	this.className = definition.className || ( definition.command && 'cke_button_' + definition.command ) || '';
+
+	/**
+	 * The function to be called when the user clicks the button. If not
+	 * defined, the "command" property is required, and the command gets
+	 * executed on click.
+	 * @function
+	 * @name CKEDITOR.ui.button.prototype.click
+	 * @example
+	 */
+	this.click = definition.click || function( editor )
+		{
+			editor.execCommand( definition.command );
+		};
+
+	this._ = {};
+};
+
+/**
+ * Transforms a button definition in a {@link CKEDITOR.ui.button} instance.
+ * @type Object
+ * @example
+ */
+CKEDITOR.ui.button.handler =
+{
+	create : function( definition )
+	{
+		return new CKEDITOR.ui.button( definition );
+	}
+};
+
+CKEDITOR.ui.button.prototype =
+{
+	/**
+	 * Renders the button.
+	 * @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 env = CKEDITOR.env;
+
+		var id = this._.id = 'cke_' + CKEDITOR.tools.getNextNumber();
+
+		var instance =
+		{
+			id : id,
+			button : this,
+			editor : editor,
+			focus : function()
+			{
+				var element = CKEDITOR.document.getById( id );
+				element.focus();
+			},
+			execute : function()
+			{
+				this.button.click( editor );
+			}
+		};
+
+		// Get the command name.
+		var command = this.command;
+
+		if ( command )
+		{
+			// Get the command instance.
+			command = editor.getCommand( command );
+
+			if ( command )
+			{
+				command.on( 'state', function()
+					{
+						this.setState( command.state );
+					}, this);
+			}
+		}
+
+		var index = CKEDITOR.ui.button._.instances.push( instance ) - 1;
+
+		output.push(
+			'<a id="', id, '"' +
+				' class="cke_button ', this.className, '" href="javascript:void(\'', ( this.label || '' ).replace( "'", '' ), '\')"' +
+				' title="', this.title, '"' +
+				' tabindex="-1"' +
+				' hidefocus="true"' );
+
+		// Some browsers don't cancel key events in the keydown but in the
+		// keypress.
+		// TODO: Check if really needed for Gecko+Mac.
+		if ( env.opera || ( env.gecko && env.mac ) )
+		{
+			output.push(
+				' onkeypress="return false;"' );
+		}
+
+		// With Firefox, we need to force the button to redraw, otherwise it
+		// will remain in the focus state.
+		if ( env.gecko )
+		{
+			output.push(
+				' onblur="this.style.cssText = this.style.cssText;"' );
+		}
+
+		output.push(
+				' onkeydown="return CKEDITOR.ui.button._.keydown(', index, ', event);"' +
+				' onclick="return CKEDITOR.ui.button._.click(', index, ', event);">' +
+					'<span class="cke_icon"></span>' +
+					'<span class="cke_label">', this.label, '</span>' +
+			'</a>' );
+
+		return instance;
+	},
+
+	setState : function( state )
+	{
+		var element = CKEDITOR.document.getById( this._.id );
+
+		switch ( state )
+		{
+			case CKEDITOR.TRISTATE_ON :
+				element.addClass( 'cke_on' );
+				element.removeClass( 'cke_off' );
+				element.removeClass( 'cke_disabled' );
+				break;
+			case CKEDITOR.TRISTATE_DISABLED :
+				element.addClass( 'cke_disabled' );
+				element.removeClass( 'cke_off' );
+				element.removeClass( 'cke_on' );
+				break;
+			default :
+				element.addClass( 'cke_off' );
+				element.removeClass( 'cke_on' );
+				element.removeClass( 'cke_disabled' );
+				break;
+		}
+	}
+};
+
+/**
+ * Handles a button click.
+ * @private
+ */
+CKEDITOR.ui.button._ =
+{
+	instances : [],
+
+	click : function( index )
+	{
+		CKEDITOR.ui.button._.instances[ index ].execute();
+		return false;
+	},
+
+	keydown : function( index, ev )
+	{
+		var instance = CKEDITOR.ui.button._.instances[ index ];
+
+		if ( instance.onkey )
+		{
+			ev = new CKEDITOR.dom.event( ev );
+			return ( instance.onkey( instance, ev.getKeystroke() ) !== false );
+		}
+	}
+};
+
+/**
+ * Adds a button definition to the UI elements list.
+ * @param {String} The button name.
+ * @param {Object} The button definition.
+ * @example
+ * editorInstance.ui.addButton( 'MyBold',
+ *     {
+ *         label : 'My Bold',
+ *         command : 'bold'
+ *     });
+ */
+CKEDITOR.ui.prototype.addButton = function( name, definition )
+{
+	this.add( name, CKEDITOR.UI_BUTTON, definition );
+};
Index: /CKEditor/trunk/_source/plugins/editingblock/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/editingblock/plugin.js	(revision 2985)
+++ /CKEditor/trunk/_source/plugins/editingblock/plugin.js	(revision 2985)
@@ -0,0 +1,157 @@
+﻿/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+/**
+ * @fileOverview The default editing block plugin, which holds the editing area
+ *		and source view.
+ */
+
+(function()
+{
+	var getMode = function( editor, mode )
+	{
+		return editor._.modes && editor._.modes[ mode || editor.mode ];
+	};
+
+	// This is a semaphore used to avoid recursive calls between
+	// the following data handling functions.
+	var isHandlingData;
+
+	CKEDITOR.plugins.add( 'editingblock',
+	{
+		init : function( editor, pluginPath )
+		{
+			if ( !editor.config.editingBlock )
+				return;
+
+			editor.on( 'themeSpace', function( event )
+				{
+					if ( event.data.space == 'contents' )
+						event.data.html += '<br>';
+				});
+
+			editor.on( 'themeLoaded', function()
+				{
+					editor.fireOnce( 'editingBlockReady' );
+				});
+
+			editor.on( 'uiReady', function()
+				{
+					editor.setMode( editor.config.startupMode );
+
+					if ( editor.config.startupFocus )
+						editor.focus();
+				});
+
+			editor.on( 'afterSetData', function()
+				{
+					if ( !isHandlingData && editor.mode )
+					{
+						isHandlingData = true;
+						getMode( editor ).loadData( editor.getData() );
+						isHandlingData = false;
+					}
+				});
+
+			editor.on( 'beforeGetData', function()
+				{
+					if ( !isHandlingData && editor.mode )
+					{
+						isHandlingData = true;
+						editor.setData( getMode( editor ).getData() );
+						isHandlingData = false;
+					}
+				});
+		}
+	});
+
+	/**
+	 * The current editing mode. An editing mode is basically a viewport for
+	 * editing or content viewing. By default the possible values for this
+	 * property are "wysiwyg" and "source".
+	 * @type String
+	 * @example
+	 * alert( CKEDITOR.instances.editor1.mode );  // "wysiwyg" (e.g.)
+	 */
+	CKEDITOR.editor.prototype.mode = '';
+
+	/**
+	 * Registers an editing mode. This function is to be used mainly by plugins.
+	 * @param {String} mode The mode name.
+	 * @param {Object} modeEditor The mode editor definition.
+	 * @example
+	 */
+	CKEDITOR.editor.prototype.addMode = function( mode, modeEditor )
+	{
+		modeEditor.name = mode;
+		( this._.modes || ( this._.modes = {} ) )[ mode ] = modeEditor;
+	};
+
+	/**
+	 * Sets the current editing mode in this editor instance.
+	 * @param {String} mode A registered mode name.
+	 * @example
+	 * // Switch to "source" view.
+	 * CKEDITOR.instances.editor1.setMode( 'source' );
+	 */
+	CKEDITOR.editor.prototype.setMode = function( mode )
+	{
+		var data,
+			holderElement = this.getThemeSpace( 'contents' );
+
+		// Unload the previous mode.
+		if ( this.mode )
+		{
+			if ( mode == this.mode )
+				return;
+
+			var currentMode = getMode( this );
+			data = currentMode.getData();
+			currentMode.unload( holderElement );
+			this.mode = '';
+		}
+
+		holderElement.setHtml( '' );
+
+		// Load required mode.
+		var modeEditor = getMode( this, mode );
+		if ( !modeEditor )
+			throw '[CKEDITOR.editor.setMode] Unknown mode "' + mode + '".';
+
+		modeEditor.load( holderElement, data || this.getData() );
+
+		this.mode = mode;
+		this.fire( 'mode' );
+	};
+
+	/**
+	 * Moves the selection focus to the editing are space in the editor.
+	 */
+	CKEDITOR.editor.prototype.focus = function()
+	{
+		var mode = getMode( this );
+		if ( mode )
+			mode.focus();
+	};
+})();
+
+/**
+ * The mode to load at the editor startup. It depends on the plugins
+ * loaded. By default, the "wysiwyg" and "source" modes are available.
+ * @type String
+ * @default 'wysiwyg'
+ * @example
+ * config.toolbarLocation = 'source';
+ */
+CKEDITOR.config.startupMode = 'wysiwyg';
+
+/**
+ * Sets whether the editor should have the focus when the page loads.
+ * @type Boolean
+ * @default false
+ */
+CKEDITOR.config.startupFocus = false;
+
+CKEDITOR.config.editingBlock = true;
Index: /CKEditor/trunk/_source/plugins/elementspath/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/elementspath/plugin.js	(revision 2985)
+++ /CKEditor/trunk/_source/plugins/elementspath/plugin.js	(revision 2985)
@@ -0,0 +1,177 @@
+﻿/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+/**
+ * @fileOverview The "elementspath" plugin. It shows all elements in the DOM
+ *		parent tree relative to the current selection in the editing area.
+ */
+
+(function()
+{
+	var commands =
+	{
+		toolbarFocus :
+		{
+			exec : function( editor )
+			{
+				var idBase = editor._.elementsPath.idBase;
+				var element = CKEDITOR.document.getById( idBase + '0' );
+
+				if ( element )
+					element.focus();
+			}
+		}
+	};
+
+	CKEDITOR.plugins.add( 'elementspath',
+	{
+		requires : [ 'selection' ],
+
+		init : function( editor, pluginPath )
+		{
+			var spaceId = 'cke_path_' + editor.name;
+			var spaceElement;
+			var getSpaceElement = function()
+			{
+				if ( !spaceElement )
+					spaceElement = CKEDITOR.document.getById( spaceId );
+				return spaceElement;
+			};
+
+			var idBase = 'cke_elementspath_' + CKEDITOR.tools.getNextNumber() + '_';
+
+			editor._.elementsPath = { idBase : idBase };
+
+			editor.on( 'themeSpace', function( event )
+				{
+					if ( event.data.space == 'bottom' )
+						event.data.html += '<div id="' + spaceId + '" class="cke_path"><br></div>';
+				});
+
+			editor.on( 'selectionChange', function( ev )
+				{
+					var env = CKEDITOR.env;
+
+					var selection = ev.data.selection;
+
+					var element = selection.getStartElement(),
+						html = [],
+						elementsList = this._.elementsPath.list = [];
+
+					while ( element )
+					{
+						var index = elementsList.push( element ) - 1;
+						var name;
+						if ( element.getAttribute( '_cke_real_element_type' ) )
+							name = element.getAttribute( '_cke_real_element_type' );
+						else
+							name = element.getName();
+
+						// Use this variable to add conditional stuff to the
+						// HTML (because we are doing it in reverse order... unshift).
+						var extra = '';
+
+						// Some browsers don't cancel key events in the keydown but in the
+						// keypress.
+						// TODO: Check if really needed for Gecko+Mac.
+						if ( env.opera || ( env.gecko && env.mac ) )
+							extra += ' onkeypress="return false;"';
+
+						// With Firefox, we need to force the button to redraw, otherwise it
+						// will remain in the focus state.
+						if ( env.gecko )
+							extra += ' onblur="this.style.cssText = this.style.cssText;"';
+
+						html.unshift(
+							'<a' +
+								' id="', idBase, index, '"' +
+								' href="javascript:void(\'', name, '\')"' +
+								' tabindex="-1"' +
+								' title="', editor.lang.elementsPath.eleTitle.replace( /%1/, name ), '"' +
+								' onkeydown="return CKEDITOR._.elementsPath.keydown(\'', this.name, '\',', index, ', event);"' +
+								extra ,
+								' onclick="return CKEDITOR._.elementsPath.click(\'', this.name, '\',', index, ');">',
+									name,
+							'</a>' );
+
+						if ( name == 'body' )
+							break;
+
+						element = element.getParent();
+					}
+
+					getSpaceElement().setHtml( html.join('') );
+				});
+
+			editor.on( 'contentDomUnload', function()
+				{
+					getSpaceElement().setHtml( '<br>' );
+				});
+
+			editor.addCommand( 'elementsPathFocus', commands.toolbarFocus );
+		}
+	});
+})();
+
+/**
+ * Handles the click on an element in the element path.
+ * @private
+ */
+CKEDITOR._.elementsPath =
+{
+	click : function( instanceName, elementIndex )
+	{
+		var editor = CKEDITOR.instances[ instanceName ];
+		editor.focus();
+
+		var element = editor._.elementsPath.list[ elementIndex ];
+		editor.getSelection().selectElement( element );
+
+		return false;
+	},
+
+	keydown : function( instanceName, elementIndex, ev )
+	{
+		var instance = CKEDITOR.ui.button._.instances[ elementIndex ];
+		var editor = CKEDITOR.instances[ instanceName ];
+		var idBase = editor._.elementsPath.idBase;
+
+		var element;
+
+		ev = new CKEDITOR.dom.event( ev );
+
+		switch ( ev.getKeystroke() )
+		{
+			case 37 :					// LEFT-ARROW
+			case 9 :					// TAB
+				element = CKEDITOR.document.getById( idBase + ( elementIndex + 1 ) );
+				if ( !element )
+					element = CKEDITOR.document.getById( idBase + '0' );
+				element.focus();
+				return false;
+
+			case 39 :					// RIGHT-ARROW
+			case CKEDITOR.SHIFT + 9 :	// SHIFT + TAB
+				element = CKEDITOR.document.getById( idBase + ( elementIndex - 1 ) );
+				if ( !element )
+					element = CKEDITOR.document.getById( idBase + ( editor._.elementsPath.list.length - 1 ) );
+				element.focus();
+				return false;
+
+			case 27 :					// ESC
+				editor.focus();
+				return false;
+
+			case 13 :					// ENTER	// Opera
+			case 32 :					// SPACE
+				this.click( instanceName, elementIndex );
+				return false;
+
+			//default :
+			//	alert( ev.getKeystroke() );
+		}
+		return true;
+	}
+};
Index: /CKEditor/trunk/_source/plugins/htmldataprocessor/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/htmldataprocessor/plugin.js	(revision 2985)
+++ /CKEditor/trunk/_source/plugins/htmldataprocessor/plugin.js	(revision 2985)
@@ -0,0 +1,40 @@
+﻿/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.plugins.add( 'htmldataprocessor',
+{
+	requires : [ 'htmlwriter' ],
+
+	init : function( editor, pluginPath )
+	{
+		editor.dataProcessor = new CKEDITOR.htmlDataProcessor();
+	}
+});
+
+CKEDITOR.htmlDataProcessor = function()
+{
+	this.writer = new CKEDITOR.htmlWriter();
+};
+
+CKEDITOR.htmlDataProcessor.prototype =
+{
+	toHtml : function( data )
+	{
+		// The source data is already HTML, so just return it as is.
+		return data;
+	},
+
+	toDataFormat : function( element )
+	{
+		var writer = this.writer,
+			fragment = CKEDITOR.htmlParser.fragment.fromHtml( element.getHtml() );
+
+		writer.reset();
+
+		fragment.writeHtml( writer );
+
+		return writer.getHtml( true );
+	}
+};
Index: /CKEditor/trunk/_source/plugins/htmlwriter/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/htmlwriter/plugin.js	(revision 2985)
+++ /CKEditor/trunk/_source/plugins/htmlwriter/plugin.js	(revision 2985)
@@ -0,0 +1,302 @@
+﻿/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+/**
+ * Class used to write HTML data.
+ * @constructor
+ * @example
+ * var writer = new CKEDITOR.htmlWriter();
+ * writer.openTag( 'p' );
+ * writer.attribute( 'class', 'MyClass' );
+ * writer.openTagClose( 'p' );
+ * writer.text( 'Hello' );
+ * writer.closeTag( 'p' );
+ * alert( writer.getHtml() );  "&lt;p class="MyClass"&gt;Hello&lt;/p&gt;"
+ */
+CKEDITOR.htmlWriter = function()
+{
+	/**
+	 * The characters to be used for each identation step.
+	 * @type String
+	 * @default "\t" (tab)
+	 * @example
+	 * // Use two spaces for indentation.
+	 * editorInstance.dataProcessor.writer.indentationChars = '  ';
+	 */
+	this.indentationChars	= '\t';
+
+	/**
+	 * The characters to be used to close "self-closing" elements, like "br" or
+	 * "img".
+	 * @type String
+	 * @default " /&gt;"
+	 * @example
+	 * // Use HTML4 notation for self-closing elements.
+	 * editorInstance.dataProcessor.writer.selfClosingEnd = '>';
+	 */
+	this.selfClosingEnd		= ' />';
+
+	/**
+	 * The characters to be used for line breaks.
+	 * @type String
+	 * @default "\n" (LF)
+	 * @example
+	 * // Use CRLF for line breaks.
+	 * editorInstance.dataProcessor.writer.lineBreakChars = '\r\n';
+	 */
+	this.lineBreakChars		= '\n';
+
+	this._ =
+	{
+		output : [],
+		indent : false,
+		indentation : '',
+		rules : {}
+	};
+
+	var dtd = CKEDITOR.dtd;
+
+	for ( var e in CKEDITOR.tools.extend( {}, dtd.$block, dtd.$listItem, dtd.$tableContent ) )
+	{
+		this.setRules( e,
+			{
+				indent : true,
+				breakBeforeOpen : true,
+				breakAfterOpen : true,
+				breakBeforeClose : !dtd[ e ][ '#' ],
+				breakAfterClose : true
+			});
+	}
+
+	this.setRules( 'br',
+		{
+			breakAfterOpen : true
+		});
+};
+
+CKEDITOR.htmlWriter.prototype =
+{
+	/**
+	 * Writes the tag opening part for a opener tag.
+	 * @param {String} tagName The element name for this tag.
+	 * @param {Object} attributes The attributes defined for this tag. The
+	 *		attributes could be used to inspect the tag.
+	 * @example
+	 * // Writes "&lt;p".
+	 * writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } );
+	 */
+	openTag : function( tagName, attributes )
+	{
+		var rules = this._.rules[ tagName ];
+
+		if ( this._.indent )
+			this.indentation();
+		// Do not break if indenting.
+		else if ( rules && rules.breakBeforeOpen )
+		{
+			this.lineBreak();
+			this.indentation();
+		}
+
+		this._.output.push( '<', tagName );
+	},
+
+	/**
+	 * Writes the tag closing part for a opener tag.
+	 * @param {String} tagName The element name for this tag.
+	 * @param {Boolean} isSelfClose Indicates that this is a self-closing tag,
+	 *		like "br" or "img".
+	 * @example
+	 * // Writes "&gt;".
+	 * writer.openTagClose( 'p', false );
+	 * @example
+	 * // Writes " /&gt;".
+	 * writer.openTagClose( 'br', true );
+	 */
+	openTagClose : function( tagName, isSelfClose )
+	{
+		var rules = this._.rules[ tagName ];
+
+		if ( isSelfClose )
+			this._.output.push( this.selfClosingEnd );
+		else
+		{
+			this._.output.push( '>' );
+
+			if ( rules && rules.indent )
+				this._.indentation += this.indentationChars;
+		}
+
+		if ( rules && rules.breakAfterOpen )
+			this.lineBreak();
+	},
+
+	/**
+	 * Writes an attribute. This function should be called after opening the
+	 * tag with {@link #openTagClose}.
+	 * @param {String} attName The attribute name.
+	 * @param {String} attValue The attribute value.
+	 * @example
+	 * // Writes ' class="MyClass"'.
+	 * writer.attribute( 'class', 'MyClass' );
+	 */
+	attribute : function( attName, attValue )
+	{
+		this._.output.push( ' ', attName, '="', attValue, '"' );
+	},
+
+	/**
+	 * Writes a closer tag.
+	 * @param {String} tagName The element name for this tag.
+	 * @example
+	 * // Writes "&lt;/p&gt;".
+	 * writer.closeTag( 'p' );
+	 */
+	closeTag : function( tagName )
+	{
+		var rules = this._.rules[ tagName ];
+
+		if ( rules && rules.indent )
+			this._.indentation = this._.indentation.substr( this.indentationChars.length );
+
+		if ( this._.indent )
+			this.indentation();
+		// Do not break if indenting.
+		else if ( rules && rules.breakBeforeClose )
+		{
+			this.lineBreak();
+			this.indentation();
+		}
+
+		this._.output.push( '</', tagName, '>' );
+
+		if ( rules && rules.breakAfterClose )
+			this.lineBreak();
+	},
+
+	/**
+	 * Writes text.
+	 * @param {String} text The text value
+	 * @example
+	 * // Writes "Hello Word".
+	 * writer.text( 'Hello Word' );
+	 */
+	text : function( text )
+	{
+		if ( this._.indent )
+		{
+			this.indentation();
+			text = CKEDITOR.tools.ltrim( text );
+		}
+
+		this._.output.push( text );
+	},
+
+	/**
+	 * Writes a comment.
+	 * @param {String} comment The comment text.
+	 * @example
+	 * // Writes "&lt;!-- My comment --&gt;".
+	 * writer.comment( ' My comment ' );
+	 */
+	comment : function( comment )
+	{
+		if ( this._.indent )
+			this.indentation();
+
+		this._.output.push( '<!--', comment, '-->' );
+	},
+
+	/**
+	 * Writes a line break. It uses the {@link #lineBreakChars} property for it.
+	 * @example
+	 * // Writes "\n" (e.g.).
+	 * writer.lineBreak();
+	 */
+	lineBreak : function()
+	{
+		if ( this._.output.length > 0 )
+			this._.output.push( this.lineBreakChars );
+		this._.indent = true;
+	},
+
+	/**
+	 * Writes the current indentation chars. It uses the
+	 * {@link #indentationChars} property, repeating it for the current
+	 * intentation steps.
+	 * @example
+	 * // Writes "\t" (e.g.).
+	 * writer.indentation();
+	 */
+	indentation : function()
+	{
+		this._.output.push( this._.indentation );
+		this._.indent = false;
+	},
+
+	/**
+	 * Empties the current output buffer.
+	 * @example
+	 * writer.reset();
+	 */
+	reset : function()
+	{
+		this._.output = [];
+	},
+
+	/**
+	 * Empties the current output buffer.
+	 * @param {Boolean} reset Indicates that the {@link reset} function is to
+	 *		be automatically called after retrieving the HTML.
+	 * @returns {String} The HTML written to the writer so far.
+	 * @example
+	 * var html = writer.getHtml();
+	 */
+	getHtml : function( reset )
+	{
+		var html = this._.output.join( '' );
+
+		if ( reset )
+			this.reset();
+
+		return html;
+	},
+
+	/**
+	 * Sets formatting rules for a give element. The possible rules are:
+	 * <ul>
+	 *	<li><b>indent</b>: indent the element contents.</li>
+	 *	<li><b>breakBeforeOpen</b>: break line before the opener tag for this element.</li>
+	 *	<li><b>breakAfterOpen</b>: break line after the opener tag for this element.</li>
+	 *	<li><b>breakBeforeClose</b>: break line before the closer tag for this element.</li>
+	 *	<li><b>breakAfterClose</b>: break line after the closer tag for this element.</li>
+	 * </ul>
+	 *
+	 * All rules default to "false".
+	 *
+	 * By default, all elements available in the {@link CKEDITOR.dtd.$block),
+	 * {@link CKEDITOR.dtd.$listItem} and {@link CKEDITOR.dtd.$tableContent}
+	 * lists have all the above rules set to "true". Additionaly, the "br"
+	 * element has the "breakAfterOpen" set to "true".
+	 * @param {String} tagName The element name to which set the rules.
+	 * @param {Object} rules An object containing the element rules.
+	 * @example
+	 * // Break line before and after "img" tags.
+	 * writer.setRules( 'img',
+	 *     {
+	 *         breakBeforeOpen : true
+	 *         breakAfterOpen : true
+	 *     });
+	 * @example
+	 * // Reset the rules for the "h1" tag.
+	 * writer.setRules( 'h1', {} );
+	 */
+	setRules : function( tagName, rules )
+	{
+		this._.rules[ tagName ] = rules;
+	}
+};
+
+CKEDITOR.plugins.add( 'htmlwriter' );
Index: /CKEditor/trunk/_source/plugins/keystrokes/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/keystrokes/plugin.js	(revision 2985)
+++ /CKEditor/trunk/_source/plugins/keystrokes/plugin.js	(revision 2985)
@@ -0,0 +1,158 @@
+﻿/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+// Register a plugin named "sample".
+CKEDITOR.plugins.add( 'keystrokes',
+{
+	beforeInit : function( editor )
+	{
+		/**
+		 * Controls keystrokes typing in this editor instance.
+		 * @name CKEDITOR.editor.prototype.keystrokeHandler
+		 * @type CKEDITOR.keystrokeHandler
+		 * @example
+		 */
+		editor.keystrokeHandler = new CKEDITOR.keystrokeHandler( editor );
+	},
+
+	init : function( editor )
+	{
+		var keystrokesConfig	= editor.config.keystrokes,
+			blockedConfig		= editor.config.blockedKeystrokes;
+
+		var keystrokes			= editor.keystrokeHandler.keystrokes,
+			blockedKeystrokes	= editor.keystrokeHandler.blockedKeystrokes;
+
+		for ( var i = 0 ; i < keystrokesConfig.length ; i++ )
+		{
+			keystrokes[ keystrokesConfig[i][0] ] = keystrokesConfig[i][1];
+		}
+
+		for ( i = 0 ; i < blockedConfig.length ; i++ )
+		{
+			blockedKeystrokes[ blockedConfig[i] ] = 1;
+		}
+	}
+});
+
+/**
+ * Controls keystrokes typing in an editor instance.
+ * @constructor
+ * @param {CKEDITOR.editor} editor The editor instance.
+ * @example
+ */
+CKEDITOR.keystrokeHandler = function( editor )
+{
+	if ( editor.keystrokeHandler )
+		return editor.keystrokeHandler;
+
+	/**
+	 * List of keystrokes associated to commands. Each entry points to the
+	 * command to be executed.
+	 * @type Object
+	 * @example
+	 */
+	this.keystrokes = {};
+
+	/**
+	 * List of keystrokes that should be blocked if not defined at
+	 * {@link keystrokes}. In this way it is possible to block the default
+	 * browser behavior for those keystrokes.
+	 * @type Object
+	 * @example
+	 */
+	this.blockedKeystrokes = {};
+
+	this._ =
+	{
+		editor : editor
+	};
+
+	return this;
+};
+
+(function()
+{
+	var onKeyDown = function( event )
+	{
+		// The DOM event object is passed by the "data" property.
+		event = event.data;
+
+		var keyCombination = event.getKeystroke();
+		var command = this.keystrokes[ keyCombination ];
+
+		var cancel = !this._.editor.fire( 'key', { keyCode : keyCombination } );
+
+		if ( !cancel )
+		{
+			if ( command )
+				cancel = ( this._.editor.execCommand( command ) !== false );
+
+			if ( !cancel )
+				cancel = !!this.blockedKeystrokes[ keyCombination ];
+		}
+
+		if ( cancel )
+			event.preventDefault( true );
+
+		return !cancel;
+	};
+
+	CKEDITOR.keystrokeHandler.prototype =
+	{
+		/**
+		 * Attaches this keystroke handle to a DOM object. Keystrokes typed
+		 ** over this object will get handled by this keystrokeHandler.
+		 * @param {CKEDITOR.dom.domObject} domObject The DOM object to attach
+		 *		to.
+		 * @example
+		 */
+		attach : function( domObject )
+		{
+			domObject.on( 'keydown', onKeyDown, this );
+		}
+	};
+})();
+
+/**
+ * A list of keystrokes to be blocked if not defined in the {@link #keystrokes}
+ * setting. In this way it is possible to block the default browser behavior
+ * for those keystrokes.
+ * @type Array
+ * @example
+ */
+CKEDITOR.config.blockedKeystrokes =
+[
+	CKEDITOR.CTRL + 66 /*B*/,
+	CKEDITOR.CTRL + 73 /*I*/,
+	CKEDITOR.CTRL + 85 /*U*/
+];
+
+/**
+ * A list associating keystrokes to editor commands. Each element in the list
+ * is an array where the first item is the keystroke, and the second is the
+ * command to be executed.
+ * @type Array
+ * @example
+ */
+CKEDITOR.config.keystrokes =
+[
+	[ CKEDITOR.ALT + 121 /*F10*/, 'toolbarFocus' ],
+	[ CKEDITOR.ALT + 122 /*F11*/, 'elementsPathFocus' ],
+
+	[ CKEDITOR.CTRL + 86 /*V*/, 'paste' ],
+	[ CKEDITOR.SHIFT + 45 /*INS*/, 'paste' ],
+	[ CKEDITOR.CTRL + 88 /*X*/, 'cut' ],
+	[ CKEDITOR.SHIFT + 46 /*DEL*/, 'cut' ],
+	[ CKEDITOR.CTRL + 90 /*Z*/, 'undo' ],
+	[ CKEDITOR.CTRL + 89 /*Y*/, 'redo' ],
+	[ CKEDITOR.CTRL + CKEDITOR.SHIFT + 90 /*Z*/, 'redo' ],
+	[ CKEDITOR.CTRL + 76 /*L*/, 'link' ],
+	[ CKEDITOR.CTRL + 66 /*B*/, 'bold' ],
+	[ CKEDITOR.CTRL + 73 /*I*/, 'italic' ],
+	[ CKEDITOR.CTRL + 85 /*U*/, 'underline' ],
+	[ CKEDITOR.CTRL + CKEDITOR.ALT + 13 /*ENTER*/, 'fitWindow' ],
+	[ CKEDITOR.SHIFT + 32 /*SPACE*/, 'nbsp' ]
+];
Index: /CKEditor/trunk/_source/plugins/removeformat/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/removeformat/plugin.js	(revision 2985)
+++ /CKEditor/trunk/_source/plugins/removeformat/plugin.js	(revision 2985)
@@ -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( 'removeformat',
+{
+	requires : [ 'selection' ],
+
+	init : function( editor, pluginPath )
+	{
+		editor.addCommand( 'removeFormat', CKEDITOR.plugins.removeformat.commands.removeformat );
+		editor.ui.addButton( 'RemoveFormat',
+			{
+				label : editor.lang.removeFormat,
+				command : 'removeFormat'
+			});
+	}
+});
+
+CKEDITOR.plugins.removeformat =
+{
+	commands :
+	{
+		removeformat :
+		{
+			exec : function( editor )
+			{
+				var tagsRegex = editor._.removeFormatRegex ||
+					( editor._.removeFormatRegex = new RegExp( '^(?:' + editor.config.removeFormatTags.replace( /,/g,'|' ) + ')$', 'i' ) );
+
+				var removeAttributes = editor._.removeAttributes ||
+					( editor._.removeAttributes = editor.config.removeFormatAttributes.split( ',' ) );
+
+				var ranges = editor.getSelection().getRanges();
+
+				for ( var i = 0, range ; range = ranges[ i ] ; i++ )
+				{
+					if ( range.collapsed )
+						continue;
+
+					range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+					// Bookmark the range so we can re-select it after processing.
+					var bookmark = range.createBookmark();
+
+					// The style will be applied within the bookmark boundaries.
+					var startNode	= bookmark.startNode;
+					var endNode		= bookmark.endNode;
+
+					// We need to check the selection boundaries (bookmark spans) to break
+					// the code in a way that we can properly remove partially selected nodes.
+					// For example, removing a <b> style from
+					//		<b>This is [some text</b> to show <b>the] problem</b>
+					// ... where [ and ] represent the selection, must result:
+					//		<b>This is </b>[some text to show the]<b> problem</b>
+					// The strategy is simple, we just break the partial nodes before the
+					// removal logic, having something that could be represented this way:
+					//		<b>This is </b>[<b>some text</b> to show <b>the</b>]<b> problem</b>
+
+					var breakParent = function( node )
+					{
+						// Let's start checking the start boundary.
+						var path = new CKEDITOR.dom.elementPath( node );
+						var pathElements = path.elements;
+
+						for ( var i = 1, pathElement ; pathElement = pathElements[ i ] ; i++ )
+						{
+							if ( pathElement.equals( path.block ) || pathElement.equals( path.blockLimit ) )
+								break;
+
+							// If this element can be removed (even partially).
+							if ( tagsRegex.test( pathElement.getName() ) )
+								node.breakParent( pathElement );
+						}
+					};
+
+					breakParent( startNode );
+					breakParent( endNode );
+
+					// Navigate through all nodes between the bookmarks.
+					var currentNode = startNode.getNextSourceNode( true, CKEDITOR.NODE_ELEMENT );
+
+					while ( currentNode )
+					{
+						// If we have reached the end of the selection, stop looping.
+						if ( currentNode.equals( endNode ) )
+							break;
+
+						// Cache the next node to be processed. Do it now, because
+						// currentNode may be removed.
+						var nextNode = currentNode.getNextSourceNode( false, CKEDITOR.NODE_ELEMENT );
+
+						// This node must not be a fake element.
+						if ( currentNode.getName() != 'img' || !currentNode.getAttribute( '_cke_protected_html' ) )
+						{
+							// Remove elements nodes that match with this style rules.
+							if ( tagsRegex.test( currentNode.getName() ) )
+								currentNode.remove( true );
+							else
+								currentNode.removeAttributes( removeAttributes );
+						}
+
+						currentNode = nextNode;
+					}
+
+					range.moveToBookmark( bookmark );
+				}
+
+				editor.getSelection().selectRanges( ranges );
+			}
+		}
+	}
+};
+
+// Only inline elements are valid.
+CKEDITOR.config.removeFormatTags = 'b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var';
+
+CKEDITOR.config.removeFormatAttributes = 'class,style,lang,width,height,align,hspace,valign';
Index: /CKEditor/trunk/_source/plugins/selection/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/selection/plugin.js	(revision 2985)
+++ /CKEditor/trunk/_source/plugins/selection/plugin.js	(revision 2985)
@@ -0,0 +1,765 @@
+﻿/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+(function()
+{
+	// #### checkSelectionChange : START
+
+	// The selection change check basically saves the element parent tree of
+	// the current node and check it on successive requests. If there is any
+	// change on the tree, then the selectionChange event gets fired.
+	var checkSelectionChange = function()
+	{
+		// In IE, the "selectionchange" event may still get thrown when
+		// releasing the WYSIWYG mode, so we need to check it first.
+		var sel = this.getSelection();
+		if ( !sel )
+			return;
+
+		var firstElement = sel.getStartElement();
+		var currentPath = new CKEDITOR.dom.elementPath( firstElement );
+
+		if ( !currentPath.compare( this._.selectionPreviousPath ) )
+		{
+			this._.selectionPreviousPath = currentPath;
+			this.fire( 'selectionChange', { selection : sel, path : currentPath, element : firstElement } );
+		}
+	};
+
+	var checkSelectionChangeTimer;
+	var checkSelectionChangeTimeoutPending;
+	var checkSelectionChangeTimeout = function()
+	{
+		// Firing the "OnSelectionChange" event on every key press started to
+		// be too slow. This function guarantees that there will be at least
+		// 200ms delay between selection checks.
+
+		checkSelectionChangeTimeoutPending = true;
+
+		if ( checkSelectionChangeTimer )
+			return;
+
+		checkSelectionChangeTimeoutExec.call( this );
+
+		checkSelectionChangeTimer = CKEDITOR.tools.setTimeout( checkSelectionChangeTimeoutExec, 200, this );
+	};
+
+	var checkSelectionChangeTimeoutExec = function()
+	{
+		checkSelectionChangeTimer = null;
+
+		if ( checkSelectionChangeTimeoutPending )
+		{
+			// Call this with a timeout so the browser properly moves the
+			// selection after the mouseup. It happened that the selection was
+			// being moved after the mouseup when clicking inside selected text
+			// with Firefox.
+			CKEDITOR.tools.setTimeout( checkSelectionChange, 0, this );
+
+			checkSelectionChangeTimeoutPending = false;
+		}
+	};
+
+	// #### checkSelectionChange : END
+
+	var selectAllCmd =
+	{
+		exec : function( editor )
+		{
+			switch ( editor.mode )
+			{
+				case 'wysiwyg' :
+					editor.document.$.execCommand( 'SelectAll', false, null );
+					break;
+				case 'source' :
+					// TODO
+			}
+		}
+	};
+
+	CKEDITOR.plugins.add( 'selection',
+	{
+		init : function( editor, pluginPath )
+		{
+			editor.on( 'contentDom', function()
+				{
+					if ( CKEDITOR.env.ie )
+					{
+						// IE is the only to provide the "selectionchange"
+						// event.
+						editor.document.on( 'selectionchange', checkSelectionChangeTimeout, editor );
+					}
+					else
+					{
+						// In other browsers, we make the selection change
+						// check based on other events, like clicks or keys
+						// press.
+
+						editor.document.on( 'mouseup', checkSelectionChangeTimeout, editor );
+						editor.document.on( 'keyup', checkSelectionChangeTimeout, editor );
+					}
+				});
+
+			editor.addCommand( 'selectAll', selectAllCmd );
+			editor.ui.addButton( 'SelectAll',
+				{
+					label : editor.lang.selectAll,
+					command : 'selectAll'
+				});
+		}
+	});
+})();
+
+/**
+ * Gets the current selection from the editing area when in WYSIWYG mode.
+ * @returns {CKEDITOR.dom.selection} A selection object or null if not on
+ *		WYSIWYG mode or no selection is available.
+ * @example
+ * var selection = CKEDITOR.instances.editor1.<b>getSelection()</b>;
+ * alert( selection.getType() );
+ */
+CKEDITOR.editor.prototype.getSelection = function()
+{
+	var retval = this.document ? this.document.getSelection() : null;
+
+	/**
+	 * IE BUG: The selection's document may be a different document than the
+	 * editor document. Return null if that's the case.
+	 */
+	if ( retval && CKEDITOR.env.ie )
+	{
+		var range = retval.getNative().createRange();
+		if ( !range )
+			return null;
+		else if ( range.item )
+			return range.item(0).ownerDocument == this.document.$ ? retval : null;
+		else
+			return range.parentElement().ownerDocument == this.document.$ ? retval : null;
+	}
+	return retval;
+};
+
+/**
+ * Gets the current selection from the document.
+ * @returns {CKEDITOR.dom.selection} A selection object.
+ * @example
+ * var selection = CKEDITOR.instances.editor1.document.<b>getSelection()</b>;
+ * alert( selection.getType() );
+ */
+CKEDITOR.dom.document.prototype.getSelection = function()
+{
+	return new CKEDITOR.dom.selection( this );
+};
+
+/**
+ * No selection.
+ * @constant
+ * @example
+ * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_NONE )
+ *     alert( 'Nothing is selected' );
+ */
+CKEDITOR.SELECTION_NONE		= 1;
+
+/**
+ * Text or collapsed selection.
+ * @constant
+ * @example
+ * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_TEXT )
+ *     alert( 'Text is selected' );
+ */
+CKEDITOR.SELECTION_TEXT		= 2;
+
+/**
+ * Element selection.
+ * @constant
+ * @example
+ * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_ELEMENT )
+ *     alert( 'An element is selected' );
+ */
+CKEDITOR.SELECTION_ELEMENT	= 3;
+
+/**
+ * Manipulates the selection in a DOM document.
+ * @constructor
+ * @example
+ */
+CKEDITOR.dom.selection = function( document )
+{
+	this.document = document;
+	this._ =
+	{
+		cache : {}
+	};
+};
+
+(function()
+{
+	var styleObjectElements = { img:1,hr:1,li:1,table:1,tr:1,td:1,embed:1,object:1,ol:1,ul:1 };
+
+	CKEDITOR.dom.selection.prototype =
+	{
+		/**
+		 * Gets the native selection object from the browser.
+		 * @function
+		 * @returns {Object} The native selection object.
+		 * @example
+		 * var selection = editor.getSelection().<b>getNative()</b>;
+		 */
+		getNative :
+			CKEDITOR.env.ie ?
+				function()
+				{
+					return this._.cache.nativeSel || ( this._.cache.nativeSel = this.document.$.selection );
+				}
+			:
+				function()
+				{
+					return this._.cache.nativeSel || ( this._.cache.nativeSel = this.document.getWindow().$.getSelection() );
+				},
+
+		/**
+		 * Gets the type of the current selection. The following values are
+		 * available:
+		 * <ul>
+		 *		<li>{@link CKEDITOR.SELECTION_NONE} (1): No selection.</li>
+		 *		<li>{@link CKEDITOR.SELECTION_TEXT} (2): Text is selected or
+		 *			collapsed selection.</li>
+		 *		<li>{@link CKEDITOR.SELECTION_ELEMENT} (3): A element
+		 *			selection.</li>
+		 * </ul>
+		 * @function
+		 * @returns {Number} One of the following constant values:
+		 *		{@link CKEDITOR.SELECTION_NONE}, {@link CKEDITOR.SELECTION_TEXT} or
+		 *		{@link CKEDITOR.SELECTION_ELEMENT}.
+		 * @example
+		 * if ( editor.getSelection().<b>getType()</b> == CKEDITOR.SELECTION_TEXT )
+		 *     alert( 'Text is selected' );
+		 */
+		getType :
+			CKEDITOR.env.ie ?
+				function()
+				{
+					if ( this._.cache.type )
+						return this._.cache.type;
+
+					var type = CKEDITOR.SELECTION_NONE;
+
+					try
+					{
+						var sel = this.getNative(),
+							ieType = sel.type;
+
+						if ( ieType == 'Text' )
+							type = CKEDITOR.SELECTION_TEXT;
+
+						if ( ieType == 'Control' )
+							type = CKEDITOR.SELECTION_ELEMENT;
+
+						// It is possible that we can still get a text range
+						// object even when type == 'None' is returned by IE.
+						// So we'd better check the object returned by
+						// createRange() rather than by looking at the type.
+						if ( sel.createRange().parentElement )
+							type = CKEDITOR.SELECTION_TEXT;
+					}
+					catch(e) {}
+
+					return ( this._.cache.type = type );
+				}
+			:
+				function()
+				{
+					if ( this._.cache.type )
+						return this._.cache.type;
+
+					var type = CKEDITOR.SELECTION_TEXT;
+
+					var sel = this.getNative();
+
+					if ( !sel )
+						type = CKEDITOR.SELECTION_NONE;
+					else if ( sel.rangeCount == 1 )
+					{
+						// Check if the actual selection is a control (IMG,
+						// TABLE, HR, etc...).
+
+						var range = sel.getRangeAt(0),
+							startContainer = range.startContainer;
+
+						if ( startContainer == range.endContainer
+							&& startContainer.nodeType == 1
+							&& ( range.endOffset - range.startOffset ) == 1
+							&& styleObjectElements[ startContainer.childNodes[ range.startOffset ].nodeName.toLowerCase() ] )
+						{
+							type = CKEDITOR.SELECTION_ELEMENT;
+						}
+					}
+
+					return ( this._.cache.type = type );
+				},
+
+		getRanges :
+			CKEDITOR.env.ie ?
+				( function()
+				{
+					// Finds the container and offset for a specific boundary
+					// of an IE range.
+					var getBoundaryInformation = function( range, start )
+					{
+						// Creates a collapsed range at the requested boundary.
+						range = range.duplicate();
+						range.collapse( start );
+
+						// Gets the element that encloses the range entirely.
+						var parent = range.parentElement();
+						var siblings = parent.childNodes;
+
+						var testRange;
+
+						for ( var i = 0 ; i < siblings.length ; i++ )
+						{
+							var child = siblings[ i ];
+							if ( child.nodeType == 1 )
+							{
+								testRange = range.duplicate();
+
+								testRange.moveToElementText( child );
+								testRange.collapse();
+
+								var comparison = testRange.compareEndPoints( 'StartToStart', range );
+
+								if ( comparison > 0 )
+									break;
+								else if ( comparison === 0 )
+									return {
+										container : parent,
+										offset : i
+									};
+
+								testRange = null;
+							}
+						}
+
+						if ( !testRange )
+						{
+							testRange = range.duplicate();
+							testRange.moveToElementText( parent );
+							testRange.collapse( false );
+						}
+
+						testRange.setEndPoint( 'StartToStart', range );
+						var distance = testRange.text.length;
+
+						while ( distance > 0 )
+							distance -= siblings[ --i ].nodeValue.length;
+
+						if ( distance === 0 )
+						{
+							return {
+								container : parent,
+								offset : i
+							};
+						}
+						else
+						{
+							return {
+								container : siblings[ i ],
+								offset : -distance
+							};
+						}
+					};
+
+					return function()
+					{
+						if ( this._.cache.ranges )
+							return this._.cache.ranges;
+
+						// IE doesn't have range support (in the W3C way), so we
+						// need to do some magic to transform selections into
+						// CKEDITOR.dom.range instances.
+
+						var sel = this.getNative(),
+							nativeRange = sel.createRange(),
+							type = this.getType();
+
+						if ( type == CKEDITOR.SELECTION_TEXT )
+						{
+							var range = new CKEDITOR.dom.range( this.document );
+
+							var boundaryInfo = getBoundaryInformation( nativeRange, true );
+							range.setStart( new CKEDITOR.dom.node( boundaryInfo.container ), boundaryInfo.offset );
+
+							boundaryInfo = getBoundaryInformation( nativeRange );
+							range.setEnd( new CKEDITOR.dom.node( boundaryInfo.container ), boundaryInfo.offset );
+
+							return ( this._.cache.ranges = [ range ] );
+						}
+						else if ( type == CKEDITOR.SELECTION_ELEMENT )
+						{
+							var retval = this._.cache.ranges = [];
+
+							for ( var i = 0 ; i < nativeRange.length ; i++ )
+							{
+								var element = nativeRange.item( i ),
+									parentElement = element.parentNode,
+									j = 0,
+									range = new CKEDITOR.dom.range( this.document );
+								for (; j < parentElement.childNodes.length && parentElement.childNodes[j] != element ; j++ );
+
+								range.setStart( new CKEDITOR.dom.node( parentElement ), j );
+								range.setEnd( new CKEDITOR.dom.node( parentElement ), j + 1 );
+								retval.push( range );
+							}
+
+							return retval;
+						}
+
+						return ( this._.cache.ranges = [] );
+					};
+				})()
+			:
+				function()
+				{
+					if ( this._.cache.ranges )
+						return this._.cache.ranges;
+
+					// On browsers implementing the W3C range, we simply
+					// tranform the native ranges in CKEDITOR.dom.range
+					// instances.
+
+					var ranges = [];
+					var sel = this.getNative();
+
+					for ( var i = 0 ; i < sel.rangeCount ; i++ )
+					{
+						var nativeRange = sel.getRangeAt( i );
+						var range = new CKEDITOR.dom.range( this.document );
+
+						range.setStart( new CKEDITOR.dom.node( nativeRange.startContainer ), nativeRange.startOffset );
+						range.setEnd( new CKEDITOR.dom.node( nativeRange.endContainer ), nativeRange.endOffset );
+						ranges.push( range );
+					}
+
+					return ( this._.cache.ranges = ranges );
+				},
+
+		/**
+		 * Gets the DOM element in which the selection starts.
+		 * @returns {CKEDITOR.dom.element} The element at the beginning of the
+		 *		selection.
+		 * @example
+		 * var element = editor.getSelection().<b>getStartElement()</b>;
+		 * alert( element.getName() );
+		 */
+		getStartElement : function()
+		{
+			var node,
+				sel = this.getNative();
+
+			switch ( this.getType() )
+			{
+				case CKEDITOR.SELECTION_ELEMENT :
+					return this.getSelectedElement();
+
+				case CKEDITOR.SELECTION_TEXT :
+
+					var range = this.getRanges()[0];
+
+					if ( range )
+					{
+						if ( !range.collapsed )
+						{
+							range.optimize();
+
+							node = range.startContainer;
+
+							if ( node.type != CKEDITOR.NODE_ELEMENT )
+								return node.getParent();
+
+							node = node.getChild( range.startOffset );
+
+							if ( !node || node.type != CKEDITOR.NODE_ELEMENT )
+								return range.startContainer;
+
+							var child = node.getFirst();
+							while (  child && child.type == CKEDITOR.NODE_ELEMENT )
+							{
+								node = child;
+								child = child.getFirst();
+							}
+
+							return node;
+						}
+					}
+
+					if ( CKEDITOR.env.ie )
+					{
+						var range = sel.createRange();
+						range.collapse( true );
+
+						node = range.parentElement();
+					}
+					else
+					{
+						node = sel.anchorNode;
+
+						if ( node.nodeType != 1 )
+							node = node.parentNode;
+					}
+			}
+
+			return ( node ? new CKEDITOR.dom.element( node ) : null );
+		},
+
+		/**
+		 * Gets the current selected element.
+		 * @returns {CKEDITOR.dom.element} The selected element. Null if no
+		 *		selection is available or the selection type is not
+		 *		{@link CKEDITOR.SELECTION_ELEMENT}.
+		 * @example
+		 * var element = editor.getSelection().<b>getSelectedElement()</b>;
+		 * alert( element.getName() );
+		 */
+		getSelectedElement : function()
+		{
+			var node;
+
+			if ( this.getType() == CKEDITOR.SELECTION_ELEMENT )
+			{
+				var sel = this.getNative();
+
+				if ( CKEDITOR.env.ie )
+				{
+					try
+					{
+						node = sel.createRange().item(0);
+					}
+					catch(e) {}
+				}
+				else
+				{
+					var range = sel.getRangeAt( 0 );
+					node = range.startContainer.childNodes[ range.startOffset ];
+				}
+			}
+
+			return ( node ? new CKEDITOR.dom.element( node ) : null );
+		},
+
+		reset : function()
+		{
+			this._.cache = {};
+		},
+
+		selectElement :
+			CKEDITOR.env.ie ?
+				function( element )
+				{
+					this.getNative().empty();
+
+					var range;
+					try
+					{
+						// Try to select the node as a control.
+						range = this.document.$.body.createControlRange();
+						range.addElement( element.$ );
+					}
+					catch(e)
+					{
+						// If failed, select it as a text range.
+						range = this.document.$.body.createTextRange();
+						range.moveToElementText( element.$ );
+					}
+
+					range.select();
+				}
+			:
+				function( element )
+				{
+					// Create the range for the element.
+					var range = this.document.$.createRange();
+					range.selectNode( element.$ );
+
+					// Select the range.
+					var sel = this.getNative();
+					sel.removeAllRanges();
+					sel.addRange( range );
+				},
+
+		selectRanges :
+			CKEDITOR.env.ie ?
+				function( ranges )
+				{
+					// IE doesn't accept multiple ranges selection, so we just
+					// select the first one.
+					if ( ranges[ 0 ] )
+						ranges[ 0 ].select();
+				}
+			:
+				function( ranges )
+				{
+					var sel = this.getNative();
+					sel.removeAllRanges();
+
+					for ( var i = 0 ; i < ranges.length ; i++ )
+					{
+						var range = ranges[ i ];
+						var nativeRange = this.document.$.createRange();
+						nativeRange.setStart( range.startContainer.$, range.startOffset );
+						nativeRange.setEnd( range.endContainer.$, range.endOffset );
+
+						// Select the range.
+						sel.addRange( nativeRange );
+					}
+				},
+
+		createBookmarks : function()
+		{
+			var retval = [],
+				ranges = this.getRanges();
+			for ( var i = 0 ; i < ranges.length ; i++ )
+				retval.push( ranges[i].createBookmark() );
+			return retval;
+		},
+
+		selectBookmarks : function( bookmarks )
+		{
+			var ranges = [];
+			for ( var i = 0 ; i < bookmarks.length ; i++ )
+			{
+				var range = new CKEDITOR.dom.range( this.document );
+				range.moveToBookmark( bookmarks[i] );
+				ranges.push( range );
+			}
+			this.selectRanges( ranges );
+			return this;
+		}
+	};
+})();
+
+CKEDITOR.dom.range.prototype.select =
+	CKEDITOR.env.ie ?
+		// V2
+		function()
+		{
+			var collapsed = this.collapsed;
+			var isStartMakerAlone;
+			var dummySpan;
+
+			var bookmark = this.createBookmark();
+
+			// Create marker tags for the start and end boundaries.
+			var startNode = bookmark.startNode;
+
+			var endNode;
+			if ( !collapsed )
+				endNode = bookmark.endNode;
+
+			// Create the main range which will be used for the selection.
+			var ieRange = this.document.$.body.createTextRange();
+
+			// Position the range at the start boundary.
+			ieRange.moveToElementText( startNode.$ );
+			ieRange.moveStart( 'character', 1 );
+
+			if ( endNode )
+			{
+				// Create a tool range for the end.
+				var ieRangeEnd = this.document.$.body.createTextRange();
+
+				// Position the tool range at the end.
+				ieRangeEnd.moveToElementText( endNode.$ );
+
+				// Move the end boundary of the main range to match the tool range.
+				ieRange.setEndPoint( 'EndToEnd', ieRangeEnd );
+				ieRange.moveEnd( 'character', -1 );
+			}
+			else
+			{
+				isStartMakerAlone = ( !startNode.hasPrevious() || ( startNode.getPrevious().is && startNode.getPrevious().is( 'br' ) ) )
+					&& !startNode.hasNext();
+
+				// Append a temporary <span>&#65279;</span> before the selection.
+				// This is needed to avoid IE destroying selections inside empty
+				// inline elements, like <b></b> (#253).
+				// It is also needed when placing the selection right after an inline
+				// element to avoid the selection moving inside of it.
+				dummySpan = this.document.createElement( 'span' );
+				dummySpan.setHtml( '&#65279;' );	// Zero Width No-Break Space (U+FEFF). See #1359.
+				dummySpan.insertBefore( startNode );
+
+				if ( isStartMakerAlone )
+				{
+					// To expand empty blocks or line spaces after <br>, we need
+					// instead to have any char, which will be later deleted using the
+					// selection.
+					// \ufeff = Zero Width No-Break Space (U+FEFF). See #1359.
+					this.document.createText( '\ufeff' ).insertBefore( startNode );
+				}
+			}
+
+			// Remove the markers (reset the position, because of the changes in the DOM tree).
+			this.setStartBefore( startNode );
+			startNode.remove();
+
+			if ( collapsed )
+			{
+				if ( isStartMakerAlone )
+				{
+					// Move the selection start to include the temporary &#65279;.
+					//ieRange.moveStart( 'character', -1 );
+
+					ieRange.select();
+
+					// Remove our temporary stuff.
+//					this.document.$.selection.clear();
+				}
+				else
+					ieRange.select();
+
+				dummySpan.remove();
+			}
+			else
+			{
+				this.setEndBefore( endNode );
+				endNode.remove();
+				ieRange.select();
+			}
+		}
+	:
+		function()
+		{
+			var startContainer = this.startContainer;
+
+			// If we have a collapsed range, inside an empty element, we must add
+			// something to it, otherwise the caret will not be visible.
+			if ( this.collapsed && startContainer.type == CKEDITOR.NODE_ELEMENT && !startContainer.getChildCount() )
+				startContainer.append( new CKEDITOR.dom.text( '' ) );
+
+			var nativeRange = this.document.$.createRange();
+			nativeRange.setStart( startContainer.$, this.startOffset );
+
+			try
+			{
+				nativeRange.setEnd( this.endContainer.$, this.endOffset );
+			}
+			catch ( e )
+			{
+				// There is a bug in Firefox implementation (it would be too easy
+				// otherwise). The new start can't be after the end (W3C says it can).
+				// So, let's create a new range and collapse it to the desired point.
+				if ( e.toString().indexOf( 'NS_ERROR_ILLEGAL_VALUE' ) >= 0 )
+				{
+					this.collapse( true );
+					nativeRange.setEnd( this.endContainer.$, this.endOffset );
+				}
+				else
+					throw( e );
+			}
+
+			var selection = this.document.getSelection().getNative();
+			selection.removeAllRanges();
+			selection.addRange( nativeRange );
+		};
Index: /CKEditor/trunk/_source/plugins/sourcearea/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/sourcearea/plugin.js	(revision 2985)
+++ /CKEditor/trunk/_source/plugins/sourcearea/plugin.js	(revision 2985)
@@ -0,0 +1,134 @@
+﻿/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+/**
+ * @fileOverview The "sourcearea" plugin. It registers the "source" editing
+ *		mode, which displays the raw data being edited in the editor.
+ */
+
+CKEDITOR.plugins.add( 'sourcearea',
+{
+	requires : [ 'editingblock' ],
+
+	init : function( editor, pluginPath )
+	{
+		var sourcearea = CKEDITOR.plugins.sourcearea;
+
+		editor.on( 'editingBlockReady', function()
+			{
+				var textarea;
+
+				editor.addMode( 'source',
+					{
+						load : function( holderElement, data )
+						{
+							// Create the source area <textarea>.
+							textarea = new CKEDITOR.dom.element( 'textarea' );
+							textarea.setAttribute( 'dir', 'ltr' );
+							textarea.addClass( 'cke_source' );
+							textarea.setStyles({
+								width	: '100%',
+								height	: '100%',
+								resize	: 'none',
+								outline	: 'none',
+								'text-align' : 'left' });
+
+							// The textarea height/width='100%' doesn't
+							// constraint to the 'td' in IE strick mode
+							if ( CKEDITOR.env.ie )
+							{
+								textarea.setStyles({
+									height : holderElement.$.clientHeight + 'px',
+									width : holderElement.$.clientWidth + 'px' });
+							}
+
+							// By some yet unknown reason, we must stop the
+							// mousedown propagation for the textarea,
+							// otherwise it's not possible to place the caret
+							// inside of it (non IE).
+							if ( !CKEDITOR.env.ie )
+							{
+								textarea.on( 'mousedown', function( evt )
+									{
+										evt = evt.data.$;
+										if ( evt.stopPropagation )
+											evt.stopPropagation();
+									} );
+							}
+
+							// Reset the holder element and append the
+							// <textarea> to it.
+							holderElement.setHtml( '' );
+							holderElement.append( textarea );
+
+							// Set the <textarea> value.
+							this.loadData( data );
+						},
+
+						loadData : function( data )
+						{
+							textarea.setValue( data );
+						},
+
+						getData : function()
+						{
+							return textarea.getValue();
+						},
+
+						getSnapshotData : function()
+						{
+							return textarea.getValue();
+						},
+
+						unload : function( holderElement )
+						{
+							textarea = null;
+						},
+
+						focus : function()
+						{
+							textarea.focus();
+						}
+					});
+			});
+
+		editor.addCommand( 'source', sourcearea.commands.source );
+		
+		if ( editor.ui.addButton )
+		{
+			editor.ui.addButton( 'Source',
+				{
+					label : editor.lang.source,
+					command : 'source'
+				});
+		}
+
+		editor.on( 'mode', function()
+			{
+				var command = editor.getCommand( 'source' );
+				command.state = ( editor.mode == 'source' ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );
+				command.fire( 'state' );
+			});
+	}
+});
+
+/**
+ * Holds the definition of commands an UI elements included with the sourcearea
+ * plugin.
+ * @example
+ */
+CKEDITOR.plugins.sourcearea =
+{
+	commands :
+	{
+		source :
+		{
+			exec : function( editor )
+			{
+				editor.setMode( editor.mode == 'source' ? 'wysiwyg' : 'source' );
+			}
+		}
+	}
+};
Index: /CKEditor/trunk/_source/plugins/styles/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/styles/plugin.js	(revision 2985)
+++ /CKEditor/trunk/_source/plugins/styles/plugin.js	(revision 2985)
@@ -0,0 +1,606 @@
+﻿/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.plugins.add( 'styles',
+{
+	requires : [ 'selection' ]
+});
+
+/**
+ * Registers a function to be called whenever a style changes its state in the
+ * editing area. The current state is passed to the function. The possible
+ * states are {@link CKEDITOR.TRISTATE_ON} and {@link CKEDITOR.TRISTATE_OFF}.
+ * @param {CKEDITOR.style} The style to be watched.
+ * @param {Function} The function to be called when the style state changes.
+ * @example
+ * // Create a style object for the <b> element.
+ * var style = new CKEDITOR.style( { element : 'b' } );
+ * var editor = CKEDITOR.instances.editor1;
+ * editor.attachStyleStateChange( style, function( state )
+ *     {
+ *         if ( state == CKEDITOR.TRISTATE_ON )
+ *             alert( 'The current state for the B element is ON' );
+ *         else
+ *             alert( 'The current state for the B element is OFF' );
+ *     });
+ */
+CKEDITOR.editor.prototype.attachStyleStateChange = function( style, callback )
+{
+	// Try to get the list of attached callbacks.
+	var styleStateChangeCallbacks = this._.styleStateChangeCallbacks;
+
+	// If it doesn't exist, it means this is the first call. So, let's create
+	// all the structure to manage the style checks and the callback calls.
+	if ( !styleStateChangeCallbacks )
+	{
+		// Create the callbacks array.
+		styleStateChangeCallbacks = this._.styleStateChangeCallbacks = [];
+
+		// Attach to the selectionChange event, so we can check the styles at
+		// that point.
+		this.on( 'selectionChange', function( ev )
+			{
+				// Loop throw all registered callbacks.
+				for ( var i = 0 ; i < styleStateChangeCallbacks.length ; i++ )
+				{
+					var callback = styleStateChangeCallbacks[ i ];
+
+					// Check the current state for the style defined for that
+					// callback.
+					var currentState = callback.style.checkActive( ev.data.path ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF;
+
+					// If the state changed since the last check.
+					if ( callback.state !== currentState )
+					{
+						// Call the callback function, passing the current
+						// state to it.
+						callback.fn.call( this, currentState );
+
+						// Save the current state, so it can be compared next
+						// time.
+						callback.state !== currentState;
+					}
+				}
+			});
+	}
+
+	// Save the callback info, so it can be checked on the next occurence of
+	// selectionChange.
+	styleStateChangeCallbacks.push( { style : style, fn : callback } );
+};
+
+CKEDITOR.STYLE_BLOCK = 1;
+CKEDITOR.STYLE_INLINE = 2;
+CKEDITOR.STYLE_OBJECT = 3;
+
+(function()
+{
+	var blockElements	= { address:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1 };
+	var objectElements	= { a:1,embed:1,hr:1,img:1,li:1,object:1,ol:1,table:1,td:1,tr:1,ul:1 };
+
+	CKEDITOR.style = function( styleDefinition )
+	{
+		var element = this.element = ( styleDefinition.element || '*' ).toLowerCase();
+
+		this.type =
+			( element == '#' || blockElements[ element ] ) ?
+				CKEDITOR.STYLE_BLOCK
+			: objectElements[ element ] ?
+				CKEDITOR.STYLE_OBJECT
+			:
+				CKEDITOR.STYLE_INLINE;
+
+		this._ =
+		{
+			definition : styleDefinition
+		};
+	};
+
+	CKEDITOR.style.prototype =
+	{
+		apply : function( document )
+		{
+			// Get all ranges from the selection.
+			var selection = document.getSelection();
+			var ranges = selection.getRanges();
+
+			// Apply the style to the ranges.
+			for ( var i = 0 ; i < ranges.length ; i++ )
+				this.applyToRange( ranges[ i ] );
+
+			// Select the ranges again.
+			selection.selectRanges( ranges );
+		},
+
+		applyToRange : function( range )
+		{
+			return ( this.applyToRange =
+						this.type == CKEDITOR.STYLE_INLINE ?
+							applyInlineStyle
+						: this.type == CKEDITOR.STYLE_BLOCK ?
+							applyBlockStyle
+						: null ).call( this, range );
+		},
+
+		/**
+		 * Get the style state inside an element path. Returns "true" if the
+		 * element is active in the path.
+		 */
+		checkActive : function( elementPath )
+		{
+			switch ( this.type )
+			{
+				case CKEDITOR.STYLE_BLOCK :
+					return this.checkElementRemovable( elementPath.block || elementPath.blockLimit, true );
+
+				case CKEDITOR.STYLE_INLINE :
+
+					var elements = elementPath.elements;
+
+					for ( var i = 0, element ; i < elements.length ; i++ )
+					{
+						element = elements[i];
+
+						if ( element == elementPath.block || element == elementPath.blockLimit )
+							continue;
+
+						if ( this.checkElementRemovable( element, true ) )
+							return true;
+					}
+			}
+			return false;
+		},
+
+		// Checks if an element, or any of its attributes, is removable by the
+		// current style definition.
+		checkElementRemovable : function( element, fullMatch )
+		{
+			if ( !element || element.getName() != this.element )
+				return false ;
+
+			var def = this._.definition;
+			var attribs = def.attributes;
+			var styles = def.styles;
+
+			// If no attributes are defined in the element.
+			if ( !fullMatch && !element.hasAttributes() )
+				return true ;
+
+			for ( var attName in attribs )
+			{
+				if ( element.getAttribute( attName ) == attribs[ attName ] )
+				{
+					if ( !fullMatch )
+						return true;
+				}
+				else if ( fullMatch )
+					return false;
+			}
+
+			return true;
+		},
+
+		/**
+		 * Sets the value of a variable attribute or style, to be used when
+		 * appliying the style. This function must be called before using any
+		 * other function in this object.
+		 */
+		setVariable : function( name, value )
+		{
+			var variables = this._.variables || ( this._variables = {} );
+			variables[ name ] = value;
+		}
+	};
+
+	var applyInlineStyle = function( range )
+	{
+		var document = range.document;
+
+		if ( range.collapsed )
+		{
+			// Create the element to be inserted in the DOM.
+			var collapsedElement = getElement( this, document );
+
+			// Insert the empty element into the DOM at the range position.
+			range.insertNode( collapsedElement );
+
+			// Place the selection right inside the empty element.
+			range.moveToPosition( collapsedElement, CKEDITOR.POSITION_BEFORE_END );
+
+			return;
+		}
+
+		var elementName = this.element;
+		var def = this._.definition;
+		var isUnknownElement;
+
+		// Get the DTD definition for the element. Defaults to "span".
+		var dtd = CKEDITOR.dtd[ elementName ] || ( isUnknownElement = true, CKEDITOR.dtd.span );
+
+		// Bookmark the range so we can re-select it after processing.
+		var bookmark = range.createBookmark();
+
+		// Expand the range.
+		range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+		range.trim();
+
+		// Get the first node to be processed and the last, which concludes the
+		// processing.
+		var firstNode = range.startContainer.getChild( range.startOffset ) || range.startContainer.getNextSourceNode();
+		var lastNode = range.endContainer.getChild( range.endOffset ) || ( range.endOffset ? range.endContainer.getNextSourceNode() : range.endContainer );
+
+		var currentNode = firstNode;
+
+		var styleRange;
+
+		// Indicates that that some useful inline content has been found, so
+		// the style should be applied.
+		var hasContents;
+
+		while ( currentNode )
+		{
+			var applyStyle = false;
+
+			if ( currentNode.equals( lastNode ) )
+			{
+				currentNode = null;
+				applyStyle = true;
+			}
+			else
+			{
+				var nodeType = currentNode.type;
+				var nodeName = nodeType == CKEDITOR.NODE_ELEMENT ? currentNode.getName() : null;
+
+				if ( nodeName && currentNode.getAttribute( '_fck_bookmark' ) )
+				{
+					currentNode = currentNode.getNextSourceNode( true );
+					continue;
+				}
+
+				// Check if the current node can be a child of the style element.
+				if ( !nodeName || ( dtd[ nodeName ] && ( currentNode.getPosition( lastNode ) | CKEDITOR.POSITION_PRECEDING | CKEDITOR.POSITION_IDENTICAL | CKEDITOR.POSITION_IS_CONTAINED ) == ( CKEDITOR.POSITION_PRECEDING + CKEDITOR.POSITION_IDENTICAL + CKEDITOR.POSITION_IS_CONTAINED ) ) )
+				{
+					var currentParent = currentNode.getParent();
+
+					// Check if the style element can be a child of the current
+					// node parent or if the element is not defined in the DTD.
+					if ( currentParent && ( ( currentParent.getDtd() || CKEDITOR.dtd.span )[ elementName ] || isUnknownElement ) )
+					{
+						// This node will be part of our range, so if it has not
+						// been started, place its start right before the node.
+						// In the case of an element node, it will be included
+						// only if it is entirely inside the range.
+						if ( !styleRange && ( !nodeName || !CKEDITOR.dtd.$removeEmpty[ nodeName ] || ( currentNode.getPosition( lastNode ) | CKEDITOR.POSITION_PRECEDING | CKEDITOR.POSITION_IDENTICAL | CKEDITOR.POSITION_IS_CONTAINED ) == ( CKEDITOR.POSITION_PRECEDING + CKEDITOR.POSITION_IDENTICAL + CKEDITOR.POSITION_IS_CONTAINED ) ) )
+						{
+							styleRange = new CKEDITOR.dom.range( document );
+							styleRange.setStartBefore( currentNode );
+						}
+
+						// Non element nodes, or empty elements can be added
+						// completely to the range.
+						if ( nodeType == CKEDITOR.NODE_TEXT || ( nodeType == CKEDITOR.NODE_ELEMENT && !currentNode.getChildCount() && currentNode.$.offsetWidth ) )
+						{
+							var includedNode = currentNode;
+							var parentNode;
+
+							// This node is about to be included completelly, but,
+							// if this is the last node in its parent, we must also
+							// check if the parent itself can be added completelly
+							// to the range.
+							while ( !includedNode.$.nextSibling
+								&& ( parentNode = includedNode.getParent(), dtd[ parentNode.getName() ] )
+								&& ( parentNode.getPosition( firstNode ) | CKEDITOR.POSITION_FOLLOWING | CKEDITOR.POSITION_IDENTICAL | CKEDITOR.POSITION_IS_CONTAINED ) == ( CKEDITOR.POSITION_FOLLOWING + CKEDITOR.POSITION_IDENTICAL + CKEDITOR.POSITION_IS_CONTAINED ) )
+							{
+								includedNode = parentNode;
+							}
+
+							styleRange.setEndAfter( includedNode );
+
+							// If the included node still is the last node in its
+							// parent, it means that the parent can't be included
+							// in this style DTD, so apply the style immediately.
+							if ( !includedNode.$.nextSibling )
+								applyStyle = true;
+
+							if ( !hasContents )
+								hasContents = ( nodeType != CKEDITOR.NODE_TEXT || (/[^\s\ufeff]/).test( currentNode.getText() ) );
+						}
+					}
+					else
+						applyStyle = true;
+				}
+				else
+					applyStyle = true;
+
+				// Get the next node to be processed.
+				currentNode = currentNode.getNextSourceNode();
+			}
+
+			// Apply the style if we have something to which apply it.
+			if ( applyStyle && hasContents && styleRange && !styleRange.collapsed )
+			{
+				// Build the style element, based on the style object definition.
+				var styleNode = getElement( this, document );
+
+				var parent = styleRange.getCommonAncestor();
+
+				while ( styleNode && parent )
+				{
+					if ( parent.getName() == elementName )
+					{
+						for ( var attName in def.attribs )
+						{
+							if ( styleNode.getAttribute( attName ) == parent.getAttribute( attName ) )
+								styleNode.removeAttribute( attName );
+						}
+
+						for ( var styleName in def.styles )
+						{
+							if ( styleNode.getStyle( styleName ) == parent.getStyle( styleName ) )
+								styleNode.removeStyle( styleName );
+						}
+
+						if ( !styleNode.hasAttributes() )
+						{
+							styleNode = null;
+							break;
+						}
+					}
+
+					parent = parent.getParent();
+				}
+
+				if ( styleNode )
+				{
+					// Move the contents of the range to the style element.
+					styleRange.extractContents().appendTo( styleNode );
+
+					// Here we do some cleanup, removing all duplicated
+					// elements from the style element.
+					removeFromElement( this, styleNode );
+
+					// Insert it into the range position (it is collapsed after
+					// extractContents.
+					styleRange.insertNode( styleNode );
+
+					// Let's merge our new style with its neighbors, if possible.
+					mergeSiblings( styleNode );
+
+					// As the style system breaks text nodes constantly, let's normalize
+					// things for performance.
+					// With IE, some paragraphs get broken when calling normalize()
+					// repeatedly. Also, for IE, we must normalize body, not documentElement.
+					// IE is also known for having a "crash effect" with normalize().
+					// We should try to normalize with IE too in some way, somewhere.
+					if ( !CKEDITOR.env.ie )
+						styleNode.$.normalize();
+				}
+
+				// Style applied, let's release the range, so it gets
+				// re-initialization in the next loop.
+				styleRange = null;
+			}
+		}
+
+//		this._FixBookmarkStart( startNode );
+
+		range.moveToBookmark( bookmark );
+	};
+
+	var applyBlockStyle = function( range )
+	{
+	};
+
+	// Removes a style from inside an element.
+	var removeFromElement = function( style, element )
+	{
+		var def = style._.definition;
+		var attribs = def.attributes;
+		var styles = def.styles;
+
+		var innerElements = element.getElementsByTag( style.element );
+
+		for ( var i = innerElements.count() ; --i >= 0 ; )
+		{
+			var innerElement = innerElements.getItem( i );
+
+			for ( var attName in attribs )
+			{
+				// The 'class' element value must match (#1318).
+				if ( attName == 'class' && innerElement.getAttribute( 'class' ) != attribs[ attName ] )
+					continue;
+
+				innerElement.removeAttribute( attName );
+			}
+
+			for ( var styleName in styles )
+			{
+				innerElement.removeStyle( styleName );
+			}
+
+			removeNoAttribsElement( innerElement );
+		}
+	};
+
+	// If the element has no more attributes, remove it.
+	var removeNoAttribsElement = function( element )
+	{
+		// If no more attributes remained in the element, remove it,
+		// leaving its children.
+		if ( !element.hasAttributes() )
+		{
+			// Removing elements may open points where merging is possible,
+			// so let's cache the first and last nodes for later checking.
+			var firstChild	= element.getFirst();
+			var lastChild	= element.getLast();
+
+			element.remove( true );
+
+			if ( firstChild )
+			{
+				// Check the cached nodes for merging.
+				mergeSiblings( firstChild );
+
+				if ( lastChild && !firstChild.equals( lastChild ) )
+					mergeSiblings( lastChild );
+			}
+		}
+	};
+
+	// Get the the collection used to compare the attributes defined in this
+	// style with attributes in an element. All information in it is lowercased.
+	// V2
+//	var getAttribsForComparison = function( style )
+//	{
+//		// If we have already computed it, just return it.
+//		var attribs = style._.attribsForComparison;
+//		if ( attribs )
+//			return attribs;
+
+//		attribs = {};
+
+//		var def = style._.definition;
+
+//		// Loop through all defined attributes.
+//		var styleAttribs = def.attributes;
+//		if ( styleAttribs )
+//		{
+//			for ( var styleAtt in styleAttribs )
+//			{
+//				attribs[ styleAtt.toLowerCase() ] = styleAttribs[ styleAtt ].toLowerCase();
+//			}
+//		}
+
+//		// Includes the style definitions.
+//		if ( this._GetStyleText().length > 0 )
+//		{
+//			attribs['style'] = this._GetStyleText().toLowerCase();
+//		}
+
+//		// Appends the "length" information to the object.
+//		FCKTools.AppendLengthProperty( attribs, '_length' );
+
+//		// Return it, saving it to the next request.
+//		return ( this._GetAttribsForComparison_$ = attribs );
+//	},
+
+	var mergeSiblings = function( element )
+	{
+		if ( !element || element.type != CKEDITOR.NODE_ELEMENT || !CKEDITOR.dtd.$removeEmpty[ element.getName() ] )
+			return;
+
+		mergeElements( element, element.getNext(), true );
+		mergeElements( element, element.getPrevious() );
+	};
+
+	var mergeElements = function( element, sibling, isNext )
+	{
+		if ( sibling && sibling.type == CKEDITOR.NODE_ELEMENT )
+		{
+			var hasBookmark = sibling.getAttribute( '_fck_bookmark' );
+
+			if ( hasBookmark )
+				sibling = isNext ? sibling.getNext() : sibling.getPrevious();
+
+			if ( sibling && sibling.type == CKEDITOR.NODE_ELEMENT && sibling.getName() == element.getName() )
+			{
+				// Save the last child to be checked too, to merge things like
+				// <b><i></i></b><b><i></i></b> => <b><i></i></b>
+				var innerSibling = isNext ? element.getLast() : element.getFirst();
+
+				if ( hasBookmark )
+					( isNext ? sibling.getPrevious() : sibling.getNext() ).move( element, !isNext );
+
+				sibling.moveChildren( element, !isNext );
+				sibling.remove();
+
+				// Now check the last inner child (see two comments above).
+				if ( innerSibling )
+					mergeSiblings( innerSibling );
+			}
+		}
+	};
+
+	// Regex used to match all variables defined in an attribute or style
+	// value. The variable name is returned with $2.
+	var styleVariableAttNameRegex = /#\(\s*("|')(.+?)\1[^\)]*\s*\)/g;
+
+	var getElement = function( style, targetDocument )
+	{
+		var el = style._.element;
+
+		if ( el )
+			return el.clone();
+
+		var def = style._.definition;
+		var variables = style._.variables;
+
+		var elementName = style.element;
+		var attributes = def.attributes;
+		var styles = def.styles;
+
+		// The "*" element name will always be a span for this function.
+		if ( elementName == '*' )
+			elementName = 'span';
+
+		// Create the element.
+		el = new CKEDITOR.dom.element( elementName, targetDocument );
+
+		// Assign all defined attributes.
+		if ( attributes )
+		{
+			for ( var att in attributes )
+			{
+				var attValue = attributes[ att ];
+				if ( attValue && variables )
+				{
+					attValue = attValue.replace( styleVariableAttNameRegex, function()
+						{
+							// The second group in the regex is the variable name.
+							return variables[ arguments[2] ] || arguments[0];
+						});
+				}
+				el.setAttribute( att, attValue );
+			}
+		}
+
+		// Assign all defined styles.
+		if ( styles )
+		{
+			for ( var styleName in styles )
+				el.setStyle( styleName, styles[ styleName ] );
+
+			if ( variables )
+			{
+				attValue = el.getAttribute( 'style' ).replace( styleVariableAttNameRegex, function()
+					{
+						// The second group in the regex is the variable name.
+						return variables[ arguments[2] ] || arguments[0];
+					});
+				el.setAttribute( 'style', attValue );
+			}
+		}
+
+		// Save the created element. It will be reused on future calls.
+		return ( style._.element = el );
+	};
+})();
+
+CKEDITOR.styleCommand = function( style )
+{
+	this.style = style;
+};
+
+CKEDITOR.styleCommand.prototype.exec = function( editor )
+{
+	editor.focus();
+
+	var doc = editor.document;
+
+	if ( doc )
+		this.style.apply( doc );
+
+	return !!doc;
+};
Index: /CKEditor/trunk/_source/plugins/tab/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/tab/plugin.js	(revision 2985)
+++ /CKEditor/trunk/_source/plugins/tab/plugin.js	(revision 2985)
@@ -0,0 +1,283 @@
+﻿/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+(function()
+{
+	var blurInternal = function( editor, previous )
+	{
+		var hasContainer = editor.container;
+
+		if ( hasContainer )
+		{
+			// We need an empty element after the container, so the focus don't go to a container child.
+			var tempSpan = new CKEDITOR.dom.element( 'span' );
+			tempSpan.setAttribute( 'tabindex', editor.container.getTabIndex() );
+			tempSpan.hide();
+
+			// Insert the temp element and set the focus.
+			if ( previous )
+			{
+				tempSpan.insertBefore( editor.container );
+				tempSpan.focusPrevious();
+			}
+			else
+			{
+				tempSpan.insertAfter( editor.container );
+				tempSpan.focusNext();
+			}
+
+			// Remove the temporary node.
+			tempSpan.remove();
+		}
+
+		return hasContainer;
+	};
+
+	var blurCommand =
+		{
+			exec : function( editor )
+			{
+				return blurInternal( editor );
+			}
+		};
+
+	var blurBackCommand =
+		{
+			exec : function( editor )
+			{
+				return blurInternal( editor, true );
+			}
+		};
+
+	CKEDITOR.plugins.add( 'tab',
+	{
+		requires : [ 'keystrokes' ],
+
+		init : function( editor, pluginPath )
+		{
+			// Register the keystrokes.
+			var keystrokes = editor.keystrokeHandler.keystrokes;
+			keystrokes[ 9 /* TAB */ ] = 'tab';
+			keystrokes[ CKEDITOR.SHIFT + 9 /* TAB */ ] = 'shiftTab';
+
+			var tabSpaces = editor.config.tabSpaces,
+				tabText = '';
+
+			while ( tabSpaces-- )
+				tabText += '\xa0';
+
+			// Register the "tab" and "shiftTab" commands.
+			editor.addCommand( 'tab',
+				{
+					exec : function( editor )
+					{
+						// Fire the "tab" event, making it possible to
+						// customize the TAB key behavior on specific cases.
+						if ( !editor.fire( 'tab' ) )
+						{
+							if ( tabText.length > 0 )
+							{
+								// TODO
+								/*jsl:pass*/
+							}
+							else
+							{
+								// All browsers jump to the next field on TAB,
+								// except Safari, so we have to do that manually
+								// here.
+								/// https://bugs.webkit.org/show_bug.cgi?id=20597
+								return editor.execCommand( 'blur' );
+							}
+						}
+
+						return true;
+					}
+				});
+
+			editor.addCommand( 'shiftTab',
+				{
+					exec : function( editor )
+					{
+						// Fire the "tab" event, making it possible to
+						// customize the TAB key behavior on specific cases.
+						if ( !editor.fire( 'shiftTab' ) )
+							return editor.execCommand( 'blurBack' );
+
+						return true;
+					}
+				});
+
+			editor.addCommand( 'blur', blurCommand );
+			editor.addCommand( 'blurBack', blurBackCommand );
+		}
+	});
+})();
+
+/**
+ * Moves the UI focus to the element following this element in the tabindex
+ * order.
+ * @example
+ * var element = CKEDITOR.document.getById( 'example' );
+ * element.focusNext();
+ */
+CKEDITOR.dom.element.prototype.focusNext = function()
+{
+	var $ = this.$,
+		curTabIndex = this.getTabIndex(),
+		passedCurrent = false,
+		elected,
+		electedTabIndex;
+
+	var all = document.body.all || document.body.getElementsByTagName( '*' );
+
+	if ( curTabIndex <= 0 )
+	{
+		for ( var i = 0, element ; element = all[ i ] ; i++ )
+		{
+			if ( !passedCurrent )
+			{
+				if ( element == $ )
+					passedCurrent = true;
+				continue;
+			}
+
+			element = new CKEDITOR.dom.element( element );
+
+			if ( element.getComputedStyle( 'display' ) == 'none' || element.getComputedStyle( 'visibility' ) == 'hidden' )
+				continue;
+
+			if ( element.getTabIndex() === 0 )
+			{
+				elected = element;
+				break;
+			}
+		}
+	}
+	else
+	{
+		for ( i = 0, element ; element = all[ i ] ; i++ )
+		{
+			if ( !passedCurrent && element == $ )
+			{
+				passedCurrent = true;
+				continue;
+			}
+
+			element = new CKEDITOR.dom.element( element );
+
+			if ( element.getComputedStyle( 'display' ) == 'none' || element.getComputedStyle( 'visibility' ) == 'hidden' )
+				continue;
+
+			var elementTabIndex = element.getTabIndex();
+
+			if ( passedCurrent && elementTabIndex == curTabIndex )
+			{
+				elected = element;
+				break;
+			}
+			else if ( elementTabIndex > curTabIndex && ( !elected || electedTabIndex > elementTabIndex || electedTabIndex === 0 ) )
+			{
+				elected = element;
+				electedTabIndex = elementTabIndex;
+			}
+			else if ( !elected && elementTabIndex === 0 )
+			{
+				elected = element;
+				electedTabIndex = elementTabIndex;
+			}
+		}
+	}
+
+	if ( elected )
+		elected.focus();
+};
+
+/**
+ * Moves the UI focus to the element before this element in the tabindex order.
+ * @example
+ * var element = CKEDITOR.document.getById( 'example' );
+ * element.focusPrevious();
+ */
+CKEDITOR.dom.element.prototype.focusPrevious = function()
+{
+	var $ = this.$,
+		curTabIndex = this.getTabIndex(),
+		passedCurrent = false,
+		elected,
+		electedTabIndex;
+
+	var all = document.body.all || document.body.getElementsByTagName( '*' );
+
+	if ( curTabIndex <= 0 )
+	{
+		for ( var i = 0, element ; element = all[ i ] ; i++ )
+		{
+			if ( !passedCurrent && element == $ )
+			{
+				if ( elected && electedTabIndex === 0 )
+					break;
+
+				passedCurrent = true;
+				continue;
+			}
+
+			element = new CKEDITOR.dom.element( element );
+
+			if ( element.getComputedStyle( 'display' ) == 'none' || element.getComputedStyle( 'visibility' ) == 'hidden' )
+				continue;
+
+			var elementTabIndex = element.getTabIndex();
+
+			if ( ( !passedCurrent && elementTabIndex === 0 )
+				|| ( elementTabIndex > 0 && ( !elected || ( electedTabIndex > 0 && electedTabIndex <= elementTabIndex ) ) ) )
+			{
+				elected = element;
+				electedTabIndex = elementTabIndex;
+			}
+		}
+	}
+	else
+	{
+		for ( i = 0, element ; element = all[ i ] ; i++ )
+		{
+			if ( !passedCurrent && element == $ )
+			{
+				if ( elected && electedTabIndex == curTabIndex )
+					break;
+
+				passedCurrent = true;
+				continue;
+			}
+
+			element = new CKEDITOR.dom.element( element );
+
+			elementTabIndex = element.getTabIndex();
+
+			if ( elementTabIndex > 0 )
+			{
+				if ( ( !passedCurrent && elementTabIndex == curTabIndex )
+					|| ( elementTabIndex < curTabIndex && ( !elected || electedTabIndex <= elementTabIndex ) ) )
+				{
+					elected = element;
+					electedTabIndex = elementTabIndex;
+				}
+			}
+		}
+	}
+
+	if ( elected )
+		elected.focus();
+};
+
+/**
+ * Intructs the editor to add a number of spaces (&amp;nbsp;) to the text when
+ * hitting the TAB key. If set to zero, the TAB key will have its default
+ * behavior instead (like moving out of the editor).
+ * @type {Number}
+ * @default 0
+ * @example
+ * config.tabSpaces = 4;
+ */
+CKEDITOR.config.tabSpaces = 0 ;
Index: /CKEditor/trunk/_source/plugins/toolbar/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/toolbar/plugin.js	(revision 2985)
+++ /CKEditor/trunk/_source/plugins/toolbar/plugin.js	(revision 2985)
@@ -0,0 +1,212 @@
+﻿/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+/**
+ * @fileOverview The "toolbar" plugin. Renders the default toolbar interface in
+ * the editor.
+ */
+
+(function()
+{
+	var toolbox = function()
+	{
+		this.toolbars = [];
+	};
+
+	toolbox.prototype.focus = function()
+	{
+		for ( var t = 0, toolbar ; toolbar = this.toolbars[ t++ ] ; )
+		{
+			for ( var i = 0, item ; item = toolbar.items[ i++ ] ; )
+			{
+				if ( item.focus )
+				{
+					item.focus();
+					return;
+				}
+			}
+		}
+	};
+
+	var commands =
+	{
+		toolbarFocus :
+		{
+			exec : function( editor )
+			{
+				if ( editor.toolbox )
+					editor.toolbox.focus();
+			}
+		}
+	};
+
+	CKEDITOR.plugins.add( 'toolbar',
+	{
+		init : function( editor, pluginPath )
+		{
+			var itemKeystroke = function( item, keystroke )
+			{
+				switch ( keystroke )
+				{
+					case 39 :					// RIGHT-ARROW
+					case 9 :					// TAB
+						// Look for the next item in the toolbar.
+						while ( ( item = item.next || ( item.toolbar.next && item.toolbar.next.items[ 0 ] ) ) && !item.focus )
+						{ /*jsl:pass*/ }
+
+						// If available, just focus it, otherwise focus the
+						// first one.
+						if ( item )
+							item.focus();
+						else
+							editor.toolbox.focus();
+
+						return false;
+
+					case 37 :					// LEFT-ARROW
+					case CKEDITOR.SHIFT + 9 :	// SHIFT + TAB
+						// Look for the previous item in the toolbar.
+						while ( ( item = item.previous || ( item.toolbar.previous && item.toolbar.previous.items[ item.toolbar.previous.items.length - 1 ] ) ) && !item.focus )
+						{ /*jsl:pass*/ }
+
+						// If available, just focus it, otherwise focus the
+						// last one.
+						if ( item )
+							item.focus();
+						else
+						{
+							var lastToolbarItems = editor.toolbox.toolbars[ editor.toolbox.toolbars.length - 1 ].items;
+							lastToolbarItems[ lastToolbarItems.length - 1 ].focus();
+						}
+
+						return false;
+
+					case 27 :					// ESC
+						editor.focus();
+						return false;
+
+					case 13 :					// ENTER
+					case 32 :					// SPACE
+						item.execute();
+						return false;
+				}
+				return true;
+			};
+
+			editor.on( 'themeSpace', function( event )
+				{
+					if ( event.data.space == editor.config.toolbarLocation )
+					{
+						editor.toolbox = new toolbox();
+
+						var output = [ '<div class="cke_toolbox">' ];
+
+						var toolbars = editor.toolbox.toolbars,
+							toolbar = editor.config.toolbar;
+
+						for ( var r = 0 ; r < toolbar.length ; r++ )
+						{
+							var row = toolbar[ r ],
+								toolbarId = 'cke_' + CKEDITOR.tools.getNextNumber(),
+								toolbarObj = { id : toolbarId, items : [] };
+
+							output.push( '<div id="', toolbarId, '" class="cke_toolbar">' );
+
+							// Add the toolbar to the "editor.toolbox.toolbars"
+							// array.
+							var index = toolbars.push( toolbarObj ) - 1;
+
+							// Create the next/previous reference.
+							if ( index > 0 )
+							{
+								toolbarObj.previous = toolbars[ index - 1 ];
+								toolbarObj.previous.next = toolbarObj;
+							}
+
+							// Create all items defined for this toolbar.
+							for ( var i = 0 ; i < row.length ; i++ )
+							{
+								var item,
+									itemName = row[ i ];
+
+								if ( itemName == '-' )
+									item = CKEDITOR.ui.separator;
+								else
+									item = editor.ui.get( itemName );
+
+								if ( item )
+								{
+									var itemObj = item.render( editor, output );
+									index = toolbarObj.items.push( itemObj ) - 1;
+
+									if ( index > 0 )
+									{
+										itemObj.previous = toolbarObj.items[ index - 1 ];
+										itemObj.previous.next = itemObj;
+									}
+
+									itemObj.toolbar = toolbarObj;
+									itemObj.onkey = itemKeystroke;
+								}
+							}
+
+							output.push( '</div>' );
+						}
+
+						output.push( '</div>' );
+
+						event.data.html += output.join( '' );
+					}
+				});
+
+			editor.addCommand( 'toolbarFocus', commands.toolbarFocus );
+		}
+	});
+})();
+
+/**
+ * The UI element that renders a toolbar separator.
+ * @type Object
+ * @example
+ */
+CKEDITOR.ui.separator =
+{
+	render : function( editor, output )
+	{
+		output.push( '<span class="cke_separator"></span>' );
+		return {};
+	}
+};
+
+/**
+ * The "theme space" to which rendering the toolbar. For the default theme,
+ * the recommended options are "top" and "bottom".
+ * @type String
+ * @default 'top'
+ * @see CKEDITOR.config.theme
+ * @example
+ * config.toolbarLocation = 'bottom';
+ */
+CKEDITOR.config.toolbarLocation = 'top';
+
+/**
+ * The toolbox (alias toolbar) definition. It is an array of toolbars (strips),
+ * each one being also an array, containing a list of UI items.
+ * @type Array
+ * @example
+ * // Defines a toolbar with only one strip containing the "Source" button, a
+ * // separator and the "Bold" and "Italic" buttons.
+ * <b>CKEDITOR.config.toolbar =
+ * [
+ *     [ 'Source', '-', 'Bold', 'Italic' ]
+ * ]</b>;
+ */
+CKEDITOR.config.toolbar =
+[
+	[ 'Source', '-', 'NewPage', '-', 'Bold', 'Italic', 'Underline', 'Strike', '-', 'Subscript', 'Superscript', '-', 'Print', 'Find', 'Replace', '-',
+	'SelectAll', 'RemoveFormat', '-',
+	'Link', 'Unlink', 'Anchor', 'Image', 'Flash', 'Table', 'Smiley', 'HorizontalRule', 'SpecialChar', 'PageBreak', '-',
+	'Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField' ]
+];
Index: /CKEditor/trunk/_source/plugins/wysiwygarea/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/wysiwygarea/plugin.js	(revision 2985)
+++ /CKEditor/trunk/_source/plugins/wysiwygarea/plugin.js	(revision 2985)
@@ -0,0 +1,423 @@
+﻿/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+/**
+ * @fileOverview The "wysiwygarea" plugin. It registers the "wysiwyg" editing
+ *		mode, which handles the main editing area space.
+ */
+
+(function()
+{
+	// Matches all self-closing tags that are not defined as empty elements in
+	// the DTD (like &lt;span/&gt;).
+	var invalidSelfCloseTagsRegex = /(<(?!br|hr|base|meta|link|param|img|area|input|col)([a-zA-Z0-9:]+)[^>]*)\/>/gi;
+
+	// #### protectEvents - START
+
+	// Matches all tags that have event attributes (onXYZ).
+	var tagsWithEventRegex = /<[^\>]+ on\w+\s*=[\s\S]+?\>/g;
+
+	// Matches all event attributes.
+	var eventAttributesRegex = /\s(on\w+)(?=\s*=\s*?('|")[\s\S]*?\2)/g;
+
+	// Matches the protected attribute prefix.
+	var protectedEventsRegex = /_cke_pa_/g;
+
+	var protectEvents = function( html )
+	{
+		return html.replace( tagsWithEventRegex, protectEvents_ReplaceTags );
+	};
+
+	var protectEvents_ReplaceTags = function( tagMatch )
+	{
+		// Appends the "_cke_pa_" prefix to the event name.
+		return tagMatch.replace( eventAttributesRegex, ' _cke_pa_$1' );
+	};
+
+	var protectEventsRestore = function( html )
+	{
+		return html.replace( protectedEventsRegex, '' ) ;
+	};
+
+	// #### protectEvents - END
+
+	// #### protectAttributes - START
+	var protectUrlTagRegex = /<(?:a|area|img)(?=\s).*?\s(?:href|src)=((?:(?:\s*)("|').*?\2)|(?:[^"'][^ >]+))/gi,
+		protectUrlAttributeRegex = /\s(href|src)(\s*=\s*?('|")[\s\S]*?\3)/gi,
+		protectedUrlTagRegex = /<(?:a|area|img)(?=\s)(?:"[^"]*"|'[^']*'|[^<])*>/gi,
+		protectedAttributeRegex = /_cke_saved_/gi,
+		protectUrls = function( html )
+		{
+			return html.replace( protectUrlTagRegex, protectUrls_ReplaceTags );
+		},
+		protectUrls_ReplaceTags = function( tagMatch )
+		{
+			return tagMatch.replace( protectUrlAttributeRegex, '$& _cke_saved_$1$2');
+		},
+		protectUrlsRestore = function( html )
+		{
+			return html.replace( protectedUrlTagRegex, protectUrlsRestore_ReplaceTags );
+		},
+		protectUrlsRestore_ReplaceTags = function( tagMatch )
+		{
+			return tagMatch.replace( protectUrlAttributeRegex, '' ).replace( protectedAttributeRegex, '' );
+		};
+	// #### protectAttributes - END
+
+	var onInsertHtml = function( evt )
+	{
+		if ( this.mode == 'wysiwyg' )
+		{
+			var $doc = this.document.$;
+
+			if ( CKEDITOR.env.ie )
+				$doc.selection.createRange().pasteHtml( evt.data );
+			else
+				$doc.execCommand( 'inserthtml', false, evt.data );
+		}
+	};
+
+	var onInsertElement = function( evt )
+	{
+		if ( this.mode == 'wysiwyg' )
+		{
+			var element = evt.data;
+				isBlock = CKEDITOR.dtd.$block[ element.getName() ];
+
+			var selection = this.getSelection(),
+				ranges = selection.getRanges();
+
+			var range, clone, lastElement, bookmark;
+
+			for ( var i = ranges.length - 1 ; i >= 0 ; i-- )
+			{
+				range = ranges[ i ];
+
+				// Remove the original contents.
+				range.deleteContents();
+
+				clone = element.clone( true );
+
+				// If the new node is a block element, split the current block.
+				if ( this.config.enterMode != 'br' && isBlock )
+					range.splitBlock();
+
+				// Insert the new node.
+				range.insertNode( clone );
+
+				// Save the last element reference so we can make the
+				// selection later.
+				if ( !lastElement )
+					lastElement = clone;
+			}
+
+			range.moveToPosition( lastElement, CKEDITOR.POSITION_AFTER_END );
+			selection.selectRanges( [ range ] );
+		}
+	};
+
+	CKEDITOR.plugins.add( 'wysiwygarea',
+	{
+		requires : [ 'editingblock' ],
+
+		init : function( editor, pluginPath )
+		{
+			editor.on( 'editingBlockReady', function()
+				{
+					var mainElement,
+						iframe,
+						isLoadingData,
+						isPendingFocus;
+
+					// The following information is needed for IE only.
+					var isCustomDomain = CKEDITOR.env.ie && document.domain != window.location.hostname;
+
+					// Creates the iframe that holds the editable document.
+					var createIFrame = function()
+					{
+						if ( iframe )
+							iframe.remove();
+
+						iframe = new CKEDITOR.dom.element( 'iframe' )
+							.setAttributes({
+								frameBorder : 0,
+								allowTransparency : true })
+							.setStyles({
+								width : '100%',
+								height : '100%' });
+
+						if ( CKEDITOR.env.ie )
+						{
+							if ( isCustomDomain )
+							{
+								// The document domain must be set within the src
+								// attribute.
+								iframe.setAttribute( 'src',
+									'javascript:void( (function(){' +
+										'document.open();' +
+										'document.domain="' + document.domain + '";' +
+										'document.write( window.parent._cke_htmlToLoad_' + editor.name + ' );' +
+										'document.close();' +
+										'window.parent._cke_htmlToLoad_' + editor.name + ' = null;' +
+									'})() )' );
+							}
+							else
+								// To avoid HTTPS warnings.
+								iframe.setAttribute( 'src', 'javascript:void(0)' );
+						}
+
+						// Append the new IFRAME to the main element. For IE, it
+						// must be done after setting the "src", to avoid the
+						// "secure/unsecure" message under HTTPS.
+						mainElement.append( iframe );
+					};
+
+					// The script that is appended to the data being loaded. It
+					// enables editing, and makes some
+					var activationScript =
+						'<script id="cke_actscrpt" type="text/javascript">' +
+							'window.onload = function()' +
+							'{' +
+								// Remove this script from the DOM.
+								'var s = document.getElementById( "cke_actscrpt" );' +
+								's.parentNode.removeChild( s );' +
+
+								// Call the temporary function for the editing
+								// boostrap.
+								'window.parent.CKEDITOR._.contentDomReady' + editor.name + '( window );' +
+							'}' +
+						'</script>';
+
+					// Editing area bootstrap code.
+					var contentDomReady = function( domWindow )
+					{
+						delete CKEDITOR._[ 'contentDomReady' + editor.name ];
+
+						var domDocument = domWindow.document,
+							body = domDocument.body;
+
+						body.spellcheck = !editor.config.disableNativeSpellChecker;
+
+						if ( CKEDITOR.env.ie )
+						{
+							// Don't display the focus border.
+							body.hideFocus = true;
+
+							// Disable and re-enable the body to avoid IE from
+							// taking the editing focus at startup. (#141 / #523)
+							body.disabled = true;
+							body.contentEditable = true;
+							body.removeAttribute( 'disabled' );
+						}
+						else
+							domDocument.designMode = 'on';
+
+						// IE, Opera and Safari may not support it and throw
+						// errors.
+						try { domDocument.execCommand( 'enableObjectResizing', false, !editor.config.disableObjectResizing ) ; } catch(e) {}
+						try { domDocument.execCommand( 'enableInlineTableEditing', false, !editor.config.disableNativeTableHandles ) ; } catch(e) {}
+
+						domWindow	= editor.window		= new CKEDITOR.dom.window( domWindow );
+						domDocument	= editor.document	= new CKEDITOR.dom.document( domDocument );
+
+						var focusTarget = ( CKEDITOR.env.ie || CKEDITOR.env.safari ) ?
+								domWindow : domDocument;
+
+						focusTarget.on( 'blur', function()
+							{
+								editor.focusManager.blur();
+							});
+
+						focusTarget.on( 'focus', function()
+							{
+								editor.focusManager.focus();
+							});
+
+						var keystrokeHandler = editor.keystrokeHandler;
+						if ( keystrokeHandler )
+							keystrokeHandler.attach( domDocument );
+
+						editor.fire( 'contentDom' );
+
+						isLoadingData = false;
+
+						if ( isPendingFocus )
+							editor.focus();
+					};
+
+					editor.addMode( 'wysiwyg',
+						{
+							load : function( holderElement, data, isSnapshot )
+							{
+								mainElement = holderElement;
+
+								// Create the iframe at load for all browsers
+								// except FF and IE with custom domain.
+								if ( !isCustomDomain || !CKEDITOR.env.gecko )
+									createIFrame();
+
+								if ( isSnapshot )
+									this.loadSnapshotData( data );
+								else
+									this.loadData( data );
+							},
+
+							loadData : function( data )
+							{
+								isLoadingData = true;
+								
+								// Get the HTML version of the data.
+								if ( editor.dataProcessor )
+									data = editor.dataProcessor.toHtml( data );
+
+								// Fix for invalid self-closing tags (see #152).
+								// TODO: Check if this fix is really needed as
+								// soon as we have the XHTML generator.
+								if ( CKEDITOR.env.ie )
+									data = data.replace( invalidSelfCloseTagsRegex, '$1></$2>' );
+
+								// Prevent event attributes (like "onclick") to
+								// execute while editing.
+								if ( CKEDITOR.env.ie || CKEDITOR.env.webkit )
+									data = protectEvents( data );
+
+								// Protect src or href attributes.
+								data = protectUrls( data );
+
+								// Replace tags with fake elements.
+								if ( editor.fakeobjects )
+									data = editor.fakeobjects.protectHtml( data );
+
+								data =
+									editor.config.docType +
+									'<html dir="' + editor.config.contentsLangDirection + '">' +
+									'<head>' +
+										'<link href="' + editor.config.contentsCss + '" type="text/css" rel="stylesheet" _fcktemp="true"/>' +
+									'</head>' +
+									'<body>' +
+										data +
+									'</body>' +
+									'</html>' +
+									activationScript;
+
+								// For custom domain in IE, set the global variable
+								// that will temporarily hold the editor data. This
+								// reference will be used in the ifram src.
+								if ( isCustomDomain )
+									window[ '_cke_htmlToLoad_' + editor.name ] = data;
+
+								CKEDITOR._[ 'contentDomReady' + editor.name ] = contentDomReady;
+
+								// We need to recreate the iframe in FF for every
+								// data load, otherwise the following spellcheck
+								// and execCommand features will be active only for
+								// the first time.
+								// The same is valid for IE with custom domain,
+								// because the iframe src must be reset every time.
+								if ( isCustomDomain || CKEDITOR.env.gecko )
+									createIFrame();
+
+								// For custom domain in IE, the data loading is
+								// done through the src attribute of the iframe.
+								if ( !isCustomDomain )
+								{
+									var doc = iframe.$.contentWindow.document;
+									doc.open();
+									doc.write( data );
+									doc.close();
+								}
+							},
+
+							getData : function()
+							{
+								var data = iframe.$.contentWindow.document.body;
+								
+								if ( editor.dataProcessor )
+									data = editor.dataProcessor.toDataFormat( new CKEDITOR.dom.element( data ) );
+								else
+									data = data.innerHTML;
+
+								// Restore protected attributes.
+								data = protectEventsRestore( data );
+
+								// Restore protected URLs.
+								data = protectUrlsRestore( data );
+
+								// Restore fake elements.
+								if ( editor.fakeobjects )
+									data = editor.fakeobjects.restoreHtml( data );
+
+								return data;
+							},
+
+							getSnapshotData : function()
+							{
+								return iframe.$.contentWindow.document.body.innerHTML;
+							},
+
+							loadSnapshotData : function( data )
+							{
+								iframe.$.contentWindow.document.body.innerHTML = data;
+							},
+
+							unload : function( holderElement )
+							{
+								editor.window = editor.document = iframe = mainElement = isPendingFocus = null;
+
+								editor.fire( 'contentDomUnload' );
+							},
+
+							focus : function()
+							{
+								if ( isLoadingData )
+									isPendingFocus = true;
+								else if ( editor.window )
+									editor.window.focus();
+							}
+						});
+
+					editor.on( 'insertHtml', onInsertHtml, null, null, 20 );
+					editor.on( 'insertElement', onInsertElement, null, null, 20 );
+				});
+		}
+	});
+})();
+
+/**
+ * Disables the ability of resize objects (image and tables) in the editing
+ * area
+ * @type Boolean
+ * @default false
+ * @example
+ * config.disableObjectResizing = true;
+ */
+CKEDITOR.config.disableObjectResizing = false;
+
+/**
+ * Disables the "table tools" offered natively by the browser (currently
+ * Firefox only) to make quick table editing operations, like adding or
+ * deleting rows and columns.
+ * @type Boolean
+ * @default true
+ * @example
+ * config.disableNativeTableHandles = false;
+ */
+CKEDITOR.config.disableNativeTableHandles = true;
+
+/**
+ * Disables the built-in spell checker while typing natively available in the
+ * browser (currently Firefox and Safari only).<br /><br />
+ *
+ * Even if word suggestions will not appear in the FCKeditor context menu, this
+ * feature is useful to help quickly identifying misspelled words.<br /><br />
+ *
+ * This setting is currently compatible with Firefox only due to limitations in
+ * other browsers.
+ * @type Boolean
+ * @default true
+ * @example
+ * config.disableNativeSpellChecker = false;
+ */
+CKEDITOR.config.disableNativeSpellChecker = true;
Index: /CKEditor/trunk/ckeditor.pack
===================================================================
--- /CKEditor/trunk/ckeditor.pack	(revision 2984)
+++ /CKEditor/trunk/ckeditor.pack	(revision 2985)
@@ -39,5 +39,12 @@
 		'CKEDITOR.ENLARGE_ELEMENT' : 1,
 		'CKEDITOR.ENLARGE_BLOCK_CONTENTS' : 2,
-		'CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS' : 3
+		'CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS' : 3,
+		'CKEDITOR.UI_BUTTON' : 1,
+		'CKEDITOR.STYLE_BLOCK' : 1,
+		'CKEDITOR.STYLE_INLINE' : 2,
+		'CKEDITOR.STYLE_OBJECT' : 3,
+		'CKEDITOR.SELECTION_NONE' : 1,
+		'CKEDITOR.SELECTION_TEXT' : 2,
+		'CKEDITOR.SELECTION_ELEMENT' : 3
 	},
 
@@ -102,4 +109,18 @@
 					'_source/core/_bootstrap.js',
 //					'_source/lang/en.js',
+					'_source/plugins/basicstyles/plugin.js',
+					'_source/plugins/button/plugin.js',
+					'_source/plugins/editingblock/plugin.js',
+					'_source/plugins/elementspath/plugin.js',
+					'_source/plugins/htmldataprocessor/plugin.js',
+					'_source/plugins/keystrokes/plugin.js',
+					'_source/plugins/removeformat/plugin.js',
+					'_source/plugins/sourcearea/plugin.js',
+					'_source/plugins/tab/plugin.js',
+					'_source/plugins/toolbar/plugin.js',
+					'_source/plugins/wysiwygarea/plugin.js',
+					'_source/plugins/styles/plugin.js',
+					'_source/plugins/selection/plugin.js',
+					'_source/plugins/htmlwriter/plugin.js',
 					'_source/skins/default/skin.js',
 					'_source/themes/default/theme.js'
Index: /CKEditor/trunk/config.js
===================================================================
--- /CKEditor/trunk/config.js	(revision 2984)
+++ /CKEditor/trunk/config.js	(revision 2985)
@@ -8,5 +8,5 @@
 	// This is a temporary setting we'll have while moving plugins from the
 	// prototype to trunk.
-	config.plugins = '';
+	config.plugins = 'basicstyles,button,editingblock,elementspath,htmldataprocessor,keystrokes,removeformat,sourcearea,tab,toolbar,wysiwygarea';
 
 	// Define changes to default configuration here. For example:
