Index: CKEditor/trunk/CHANGES.html
===================================================================
--- CKEditor/trunk/CHANGES.html	(revision 5802)
+++ CKEditor/trunk/CHANGES.html	(revision 5812)
@@ -35,4 +35,25 @@
 		CKEditor Changelog
 	</h1>
+	<h3>
+			CKEditor 3.4 Beta</h3>
+	<p>
+			New features:</p>
+	<ul>
+		<li><a href="http://dev.fckeditor.net/ticket/5909">#5909</a> : New BiDi feature, making it possible to switch the base language direction of block elements.</li>
+		<li><a href="http://dev.fckeditor.net/ticket/5268">#5268</a> : Introducing the "tableresize" plugin, which makes it possible to resize tables columns by mouse drag. It's not enabled by default, so it must be enabled in the configurations file.</li>
+		<li><a href="http://dev.fckeditor.net/ticket/979">#979</a> : New <a href="http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html#.enableTabKeyTools">enableTabKeyTools</a> configuration to allow using the TAB key to navigate through table cells.</li>
+		<li><a href="http://dev.fckeditor.net/ticket/4606">#4606</a> : Introduce the "autogrow" plugin, which makes the editor resize automatically, based on the contents size.</li>
+		<li><a href="http://dev.fckeditor.net/ticket/5737">#5737</a> : Added support for the <a href="http://www.w3.org/TR/html5/editing.html#contenteditable">HTML5 contenteditable attribute</a>, making it possible to define read only regions into the editor contents.</li>
+		<li><a href="http://dev.fckeditor.net/ticket/5418">#5418</a> : New "Advanced" tab introduced on the Table Properties dialog. It's based on the new dialogadvtab plugin.</li>
+		<li><a href="http://dev.fckeditor.net/ticket/6082">#6082</a> : Introduced the <a href="http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html#.useComputedState">useComputedState</a> setting, making it possible to control whether toolbar features, like alignment and direction, should reflect the "computed" selection states, even when the effective feature value is not applied.</li>
+	</ul>
+	<p>
+			Fixed issues:</p>
+	<ul>
+		<li><a href="http://dev.fckeditor.net/ticket/5911">#5911</a> : BiDi: List items should support and retain correct base language direction
+		<li><a href="http://dev.fckeditor.net/ticket/5689">#5689</a> : Make it possible to run CKEditor inside of Firefox chrome.</li>
+		<li><a href="http://dev.fckeditor.net/ticket/6042">#6042</a> : It wasn't possible to align a paragraph with the dir attribute to the opposite direction.</li>
+		<li><a href="http://dev.fckeditor.net/ticket/6058">#6058</a> : Fixed a small style glitch with file upload fields in IE+Quirks.</li>
+	</ul>
 	<h3>
 			CKEditor 3.3.2</h3>
Index: CKEditor/trunk/_dev/releaser/release.bat
===================================================================
--- CKEditor/trunk/_dev/releaser/release.bat	(revision 5802)
+++ CKEditor/trunk/_dev/releaser/release.bat	(revision 5812)
@@ -11,3 +11,3 @@
 :: rmdir /S /Q release
 
-java -jar ckreleaser/ckreleaser.jar ckreleaser.release ../.. release "3.3.2 SVN" ckeditor_3.3.2_svn --run-before-release=langtool.bat
+java -jar ckreleaser/ckreleaser.jar ckreleaser.release ../.. release "3.4 Beta" ckeditor_3.4b --run-before-release=langtool.bat
Index: CKEditor/trunk/_dev/releaser/release.sh
===================================================================
--- CKEditor/trunk/_dev/releaser/release.sh	(revision 5802)
+++ CKEditor/trunk/_dev/releaser/release.sh	(revision 5812)
@@ -13,4 +13,4 @@
 
 pushd $DIR
-java -jar ckreleaser/ckreleaser.jar ckreleaser.release ../.. release "3.3.2 SVN" ckeditor_3.3.2_svn --run-before-release=$LANGTOOL
+java -jar ckreleaser/ckreleaser.jar ckreleaser.release ../.. release "3.4 Beta" ckeditor_3.4b --run-before-release=$LANGTOOL
 popd
Index: CKEditor/trunk/_samples/autogrow.html
===================================================================
--- CKEditor/trunk/_samples/autogrow.html	(revision 5812)
+++ CKEditor/trunk/_samples/autogrow.html	(revision 5812)
@@ -0,0 +1,79 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!--
+Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+-->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>AutoGrow Plugin - CKEditor Sample</title>
+	<meta content="text/html; charset=utf-8" http-equiv="content-type" />
+	<!-- CKReleaser %REMOVE_LINE%
+	<script type="text/javascript" src="../ckeditor.js"></script>
+	CKReleaser %REMOVE_START% -->
+	<script type="text/javascript" src="../ckeditor_source.js"></script>
+	<!-- CKReleaser %REMOVE_END% -->
+	<script src="sample.js" type="text/javascript"></script>
+	<link href="sample.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+	<h1>
+		CKEditor Sample
+	</h1>
+	<!-- This <div> holds alert messages to be display in the sample page. -->
+	<div id="alerts">
+		<noscript>
+			<p>
+				<strong>CKEditor requires JavaScript to run</strong>. In a browser with no JavaScript
+				support, like yours, you should still see the contents (HTML data) and you should
+				be able to edit it normally, without a rich editor interface.
+			</p>
+		</noscript>
+	</div>
+	<form action="sample_posteddata.php" method="post">
+		<p>
+			In this sample the AutoGrow plugin is available. It makes the editor grow to fit the size of the content.</p>
+		<p>
+			<label for="editor1">
+				With default configuration:</label><br />
+			<textarea cols="80" id="editor1" name="editor1" rows="10">&lt;p&gt;This is some &lt;strong&gt;sample text&lt;/strong&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.&lt;/p&gt;</textarea>
+			<script type="text/javascript">
+			//<![CDATA[
+
+				CKEDITOR.replace( 'editor1', {
+					extraPlugins : 'autogrow'
+				});
+
+			//]]>
+			</script>
+		</p>
+		<p>
+			<label for="editor2">
+				With maximum height set to 400:</label><br />
+			<textarea cols="80" id="editor2" name="editor2" rows="10">&lt;p&gt;This is some &lt;strong&gt;sample text&lt;/strong&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.&lt;/p&gt;</textarea>
+			<script type="text/javascript">
+			//<![CDATA[
+
+				CKEDITOR.replace( 'editor2', {
+					extraPlugins : 'autogrow',
+					autoGrow_maxHeight : 400
+				});
+
+			//]]>
+			</script>
+		</p>
+		<p>
+			<input type="submit" value="Submit" />
+		</p>
+	</form>
+	<div id="footer">
+		<hr />
+		<p>
+			CKEditor - The text editor for Internet - <a href="http://ckeditor.com/">http://ckeditor.com</a>
+		</p>
+		<p id="copy">
+			Copyright &copy; 2003-2010, <a href="http://cksource.com/">CKSource</a> - Frederico
+			Knabben. All rights reserved.
+		</p>
+	</div>
+</body>
+</html>
Index: CKEditor/trunk/_samples/index.html
===================================================================
--- CKEditor/trunk/_samples/index.html	(revision 5802)
+++ CKEditor/trunk/_samples/index.html	(revision 5812)
@@ -42,4 +42,5 @@
 		<li><a href="output_xhtml.html">Output XHTML</a></li>
 		<li><a href="output_html.html">Output HTML</a></li>
+		<li><a href="autogrow.html">AutoGrow plugin</a></li>
 	</ul>
 	<div id="footer">
Index: CKEditor/trunk/_source/core/config.js
===================================================================
--- CKEditor/trunk/_source/core/config.js	(revision 5802)
+++ CKEditor/trunk/_source/core/config.js	(revision 5812)
@@ -244,5 +244,5 @@
 	 * @example
 	 */
-	plugins : 'about,a11yhelp,basicstyles,blockquote,button,clipboard,colorbutton,colordialog,contextmenu,div,elementspath,enterkey,entities,filebrowser,find,flash,font,format,forms,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,liststyle,maximize,newpage,pagebreak,pastefromword,pastetext,popup,preview,print,removeformat,resize,save,scayt,smiley,showblocks,showborders,sourcearea,stylescombo,table,tabletools,specialchar,tab,templates,toolbar,undo,wysiwygarea,wsc',
+	plugins : 'about,a11yhelp,basicstyles,bidi,blockquote,button,clipboard,colorbutton,colordialog,contextmenu,dialogadvtab,div,elementspath,enterkey,entities,filebrowser,find,flash,font,format,forms,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,liststyle,maximize,newpage,pagebreak,pastefromword,pastetext,popup,preview,print,removeformat,resize,save,scayt,smiley,showblocks,showborders,sourcearea,stylescombo,table,tabletools,specialchar,tab,templates,toolbar,undo,wysiwygarea,wsc',
 
 	/**
@@ -331,3 +331,19 @@
 };
 
+/**
+ * Indicates that some of the editor features, like alignement and text
+ * direction, should used the "computed value" of the feature to indicate it's
+ * on/off state, instead of using the "real value".
+ *
+ * If enabled, in a left to right written document, the "Left Justify"
+ * alignment button will show as active, even if the aligment style is not
+ * explicitly applied to the current paragraph in the editor.
+ * @name CKEDITOR.config.useComputedState
+ * @type Boolean
+ * @default true
+ * @since 3.4
+ * @example
+ * config.useComputedState = false;
+ */
+
 // PACKAGER_RENAME( CKEDITOR.config )
Index: CKEditor/trunk/_source/core/dom/node.js
===================================================================
--- CKEditor/trunk/_source/core/dom/node.js	(revision 5802)
+++ CKEditor/trunk/_source/core/dom/node.js	(revision 5812)
@@ -658,4 +658,25 @@
 				}
 			}
+		},
+
+		isReadOnly : function()
+		{
+			var current = this;
+			while( current )
+			{
+				if ( current.type == CKEDITOR.NODE_ELEMENT )
+				{
+					if ( current.is( 'body' ) || current.getCustomData( '_cke_notReadOnly' ) )
+						break;
+
+					if ( current.getAttribute( 'contentEditable' ) == 'false' )
+						return current;
+					else if ( current.getAttribute( 'contentEditable' ) == 'true' )
+						break;
+				}
+				current = current.getParent();
+			}
+
+			return false;
 		}
 	}
Index: CKEditor/trunk/_source/core/dom/range.js
===================================================================
--- CKEditor/trunk/_source/core/dom/range.js	(revision 5802)
+++ CKEditor/trunk/_source/core/dom/range.js	(revision 5812)
@@ -398,4 +398,5 @@
 			var baseId;
 			var clone;
+			var collapsed = this.collapsed;
 
 			startNode = this.document.createElement( 'span' );
@@ -414,5 +415,5 @@
 
 			// If collapsed, the endNode will not be created.
-			if ( !this.collapsed )
+			if ( !collapsed )
 			{
 				endNode = startNode.clone();
@@ -443,5 +444,6 @@
 				startNode : serializable ? baseId + 'S' : startNode,
 				endNode : serializable ? baseId + 'E' : endNode,
-				serializable : serializable
+				serializable : serializable,
+				collapsed : collapsed
 			};
 		},
@@ -466,4 +468,6 @@
 				endOffset	= this.endOffset;
 
+			var collapsed = this.collapsed;
+
 			var child, previous;
 
@@ -502,5 +506,5 @@
 
 				// Process the end only if not normalized.
-				if ( !this.isCollapsed )
+				if ( !collapsed )
 				{
 					// Find out if the start is pointing to a text node that
@@ -533,8 +537,9 @@
 			return {
 				start		: startContainer.getAddress( normalized ),
-				end			: this.isCollapsed ? null : endContainer.getAddress( normalized ),
+				end			: collapsed ? null : endContainer.getAddress( normalized ),
 				startOffset	: startOffset,
 				endOffset	: endOffset,
 				normalized	: normalized,
+				collapsed	: collapsed,
 				is2			: true		// It's a createBookmark2 bookmark.
 			};
@@ -1633,22 +1638,32 @@
 
 		/**
-		 * Check whether current range is on the inner edge of the specified element.
-		 * @param {Number} checkType ( CKEDITOR.START | CKEDITOR.END ) The checking side.
+		 * Check whether a range boundary is at the inner boundary of a given
+		 * element.
 		 * @param {CKEDITOR.dom.element} element The target element to check.
+		 * @param {Number} checkType The boundary to check for both the range
+		 *		and the element. It can be CKEDITOR.START or CKEDITOR.END.
+		 * @returns {Boolean} "true" if the range boundary is at the inner
+		 *		boundary of the element.
 		 */
 		checkBoundaryOfElement : function( element, checkType )
 		{
+			var checkStart = ( checkType == CKEDITOR.START );
+
+			// Create a copy of this range, so we can manipulate it for our checks.
 			var walkerRange = this.clone();
+
+			// Collapse the range at the proper size.
+			walkerRange.collapse( checkStart );
+
 			// Expand the range to element boundary.
-			walkerRange[ checkType == CKEDITOR.START ?
-			 'setStartAt' : 'setEndAt' ]
-			 ( element, checkType == CKEDITOR.START ?
-			   CKEDITOR.POSITION_AFTER_START
-			   : CKEDITOR.POSITION_BEFORE_END );
-
+			walkerRange[ checkStart ? 'setStartAt' : 'setEndAt' ]
+			 ( element, checkStart ? CKEDITOR.POSITION_AFTER_START : CKEDITOR.POSITION_BEFORE_END );
+
+			// Create the walker, which will check if we have anything useful
+			// in the range.
 			var walker = new CKEDITOR.dom.walker( walkerRange );
 			walker.evaluator = elementBoundaryEval;
-			return walker[ checkType == CKEDITOR.START ?
-				'checkBackward' : 'checkForward' ]();
+
+			return walker[ checkStart ? 'checkBackward' : 'checkForward' ]();
 		},
 
Index: CKEditor/trunk/_source/core/dom/rangelist.js
===================================================================
--- CKEditor/trunk/_source/core/dom/rangelist.js	(revision 5812)
+++ CKEditor/trunk/_source/core/dom/rangelist.js	(revision 5812)
@@ -0,0 +1,163 @@
+﻿/*
+Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+(function()
+{
+	/**
+	 * Represents a list os CKEDITOR.dom.range objects, which can be easily
+	 * iterated sequentially.
+	 * @constructor
+	 * @param {CKEDITOR.dom.range|Array} [ranges] The ranges contained on this list.
+	 *		Note that, if an array of ranges is specified, the range sequence
+	 *		should match its DOM order. This class will not help to sort them.
+	 */
+	CKEDITOR.dom.rangeList = function( ranges )
+	{
+		if ( ranges instanceof CKEDITOR.dom.rangeList )
+			return ranges;
+
+		if ( !ranges )
+			ranges = [];
+		else if ( ranges instanceof CKEDITOR.dom.range )
+			ranges = [ ranges ];
+
+		return CKEDITOR.tools.extend( ranges, mixins );
+	};
+
+	var mixins =
+	/** @lends CKEDITOR.dom.rangeList.prototype */
+	{
+			/**
+			 * Creates an instance of the rangeList iterator, it should be used
+			 * only when the ranges processing could be DOM intrusive, which
+			 * means it may pollute and break other ranges in this list.
+			 * Otherwise, it's enough to just iterate over this array in a for loop.
+			 * @returns {CKEDITOR.dom.rangeListIterator}
+			 */
+			createIterator : function()
+			{
+				var rangeList = this,
+					bookmarks = [],
+					current;
+
+				/**
+				 * @lends CKEDITOR.dom.rangeListIterator.prototype
+				 */
+				return {
+
+					/**
+					 * Retrieves the next range in the list.
+					 */
+					getNextRange : function()
+					{
+						current = current == undefined ? 0 : current + 1;
+
+						var range = rangeList[ current ];
+
+						// Multiple ranges might be mangled by each other.
+						if ( range && rangeList.length > 1 )
+						{
+							// Bookmarking all other ranges on the first iteration,
+							// the range correctness after it doesn't matter since we'll
+							// restore them before the next iteration.
+							if ( !current )
+							{
+								// Make sure bookmark correctness by reverse processing.
+								for ( var i = rangeList.length - 1; i > 0; i-- )
+									bookmarks.unshift( rangeList[ i ].createBookmark( true ) );
+							}
+							else
+								range.moveToBookmark( bookmarks.shift() );
+						}
+
+						return range;
+					}
+				};
+			},
+
+			createBookmarks : function( serializable )
+			{
+				var retval = [], bookmark;
+				for ( var i = 0; i < this.length ; i++ )
+				{
+					retval.push( bookmark = this[ i ].createBookmark( serializable, true) );
+
+					// Updating the container & offset values for ranges
+					// that have been touched.
+					for ( var j = i + 1; j < this.length; j++ )
+					{
+						this[ j ] = updateDirtyRange( bookmark, this[ j ] );
+						this[ j ] = updateDirtyRange( bookmark, this[ j ], true );
+					}
+				}
+				return retval;
+			},
+
+			createBookmarks2 : function( normalized )
+			{
+				var bookmarks = [];
+
+				for ( var i = 0 ; i < this.length ; i++ )
+					bookmarks.push( this[ i ].createBookmark2( normalized ) );
+
+				return bookmarks;
+			},
+
+			/**
+			 * Move each range in the list to the position specified by a list of bookmarks.
+			 * @param {Array} bookmarks The list of bookmarks, each one matching a range in the list.
+			 */
+			moveToBookmarks :  function( bookmarks )
+			{
+				for ( var i = 0 ; i < this.length ; i++ )
+					this[ i ].moveToBookmark( bookmarks[ i ] );
+			}
+	};
+
+	// Update the specified range which has been mangled by previous insertion of
+	// range bookmark nodes.(#3256)
+	function updateDirtyRange( bookmark, dirtyRange, checkEnd )
+	{
+		var serializable = bookmark.serializable,
+			container = dirtyRange[ checkEnd ? 'endContainer' : 'startContainer' ],
+			offset = checkEnd ? 'endOffset' : 'startOffset';
+
+		var bookmarkStart = serializable ?
+				dirtyRange.document.getById( bookmark.startNode )
+				: bookmark.startNode;
+
+		var bookmarkEnd = serializable ?
+				dirtyRange.document.getById( bookmark.endNode )
+				: bookmark.endNode;
+
+		if ( container.equals( bookmarkStart.getPrevious() ) )
+		{
+			dirtyRange.startOffset = dirtyRange.startOffset
+					- container.getLength()
+					- bookmarkEnd.getPrevious().getLength();
+			container = bookmarkEnd.getNext();
+		}
+		else if ( container.equals( bookmarkEnd.getPrevious() ) )
+		{
+			dirtyRange.startOffset = dirtyRange.startOffset - container.getLength();
+			container = bookmarkEnd.getNext();
+		}
+
+		container.equals( bookmarkStart.getParent() ) && dirtyRange[ offset ]++;
+		container.equals( bookmarkEnd.getParent() ) && dirtyRange[ offset ]++;
+
+		// Update and return this range.
+		dirtyRange[ checkEnd ? 'endContainer' : 'startContainer' ] = container;
+		return dirtyRange;
+	}
+})();
+
+/**
+ * (Virtual Class) Do not call this constructor. This class is not really part
+ *	of the API. It just describes the return type of {@link CKEDITOR.dom.rangeList#createIterator}.
+ * @name CKEDITOR.dom.rangeListIterator
+ * @constructor
+ * @example
+ */
Index: CKEditor/trunk/_source/core/env.js
===================================================================
--- CKEditor/trunk/_source/core/env.js	(revision 5802)
+++ CKEditor/trunk/_source/core/env.js	(revision 5812)
@@ -76,9 +76,11 @@
 			isCustomDomain : function()
 			{
+				if ( !this.ie )
+					return false;
+
 				var domain = document.domain,
 					hostname = window.location.hostname;
 
-				return this.ie &&
-					domain != hostname &&
+				return domain != hostname &&
 					domain != ( '[' + hostname + ']' );	// IPv6 IP support (#5434)
 			}
Index: CKEditor/trunk/_source/core/loader.js
===================================================================
--- CKEditor/trunk/_source/core/loader.js	(revision 5802)
+++ CKEditor/trunk/_source/core/loader.js	(revision 5812)
@@ -24,5 +24,5 @@
 		var scripts =
 		{
-			'core/_bootstrap'		: [ 'core/config', 'core/ckeditor', 'core/plugins', 'core/scriptloader', 'core/tools', /* The following are entries that we want to force loading at the end to avoid dependence recursion */ 'core/dom/comment', 'core/dom/elementpath', 'core/dom/text', 'core/dom/range' ],
+			'core/_bootstrap'		: [ 'core/config', 'core/ckeditor', 'core/plugins', 'core/scriptloader', 'core/tools', /* The following are entries that we want to force loading at the end to avoid dependence recursion */ 'core/dom/comment', 'core/dom/elementpath', 'core/dom/text', 'core/dom/rangelist' ],
 			'core/ajax'				: [ 'core/xml' ],
 			'core/ckeditor'			: [ 'core/ckeditor_basic', 'core/dom', 'core/dtd', 'core/dom/document', 'core/dom/element', 'core/editor', 'core/event', 'core/htmlparser', 'core/htmlparser/element', 'core/htmlparser/fragment', 'core/htmlparser/filter', 'core/htmlparser/basicwriter', 'core/tools' ],
@@ -42,4 +42,5 @@
 			'core/dom/domobject'	: [ 'core/dom/event' ],
 			'core/dom/range'		: [ 'core/dom/document', 'core/dom/documentfragment', 'core/dom/element', 'core/dom/walker' ],
+			'core/dom/rangelist'    : [ 'core/dom/range' ],
 			'core/dom/text'			: [ 'core/dom/node', 'core/dom/domobject' ],
 			'core/dom/walker'		: [ 'core/dom/node' ],
Index: CKEditor/trunk/_source/core/tools.js
===================================================================
--- CKEditor/trunk/_source/core/tools.js	(revision 5802)
+++ CKEditor/trunk/_source/core/tools.js	(revision 5812)
@@ -378,4 +378,18 @@
 
 		/**
+		 * Gets a unique ID for CKEditor's interface elements. It returns a
+		 * string with the "cke_" prefix and a progressive number.
+		 * @function
+		 * @returns {String} A unique ID.
+		 * @example
+		 * alert( CKEDITOR.tools.<b>getNextId()</b> );  // "cke_1" (e.g.)
+		 * alert( CKEDITOR.tools.<b>getNextId()</b> );  // "cke_2"
+		 */
+		getNextId : function()
+		{
+			return 'cke_' + this.getNextNumber();
+		},
+
+		/**
 		 * Creates a function override.
 		 * @param {Function} originalFunction The function to be overridden.
Index: CKEditor/trunk/_source/lang/_translationstatus.txt
===================================================================
--- CKEditor/trunk/_source/lang/_translationstatus.txt	(revision 5802)
+++ CKEditor/trunk/_source/lang/_translationstatus.txt	(revision 5812)
@@ -2,59 +2,59 @@
 For licensing, see LICENSE.html or http://ckeditor.com/license
 
-af.js      Found: 287 Missing: 238
-ar.js      Found: 451 Missing: 74
-bg.js      Found: 280 Missing: 245
-bn.js      Found: 281 Missing: 244
-bs.js      Found: 187 Missing: 338
-ca.js      Found: 490 Missing: 35
-cs.js      Found: 411 Missing: 114
-cy.js      Found: 452 Missing: 73
-da.js      Found: 404 Missing: 121
-de.js      Found: 522 Missing: 3
-el.js      Found: 286 Missing: 239
-en-au.js   Found: 369 Missing: 156
-en-ca.js   Found: 369 Missing: 156
-en-gb.js   Found: 370 Missing: 155
-eo.js      Found: 259 Missing: 266
-es.js      Found: 524 Missing: 1
-et.js      Found: 301 Missing: 224
-eu.js      Found: 403 Missing: 122
-fa.js      Found: 302 Missing: 223
-fi.js      Found: 518 Missing: 7
-fo.js      Found: 420 Missing: 105
-fr-ca.js   Found: 301 Missing: 224
-fr.js      Found: 403 Missing: 122
-gl.js      Found: 283 Missing: 242
-gu.js      Found: 300 Missing: 225
-he.js      Found: 525 Missing: 0
-hi.js      Found: 302 Missing: 223
-hr.js      Found: 404 Missing: 121
-hu.js      Found: 445 Missing: 80
-is.js      Found: 307 Missing: 218
-it.js      Found: 404 Missing: 121
-ja.js      Found: 413 Missing: 112
-km.js      Found: 275 Missing: 250
-ko.js      Found: 293 Missing: 232
-lt.js      Found: 306 Missing: 219
-lv.js      Found: 283 Missing: 242
-mn.js      Found: 300 Missing: 225
-ms.js      Found: 265 Missing: 260
-nb.js      Found: 470 Missing: 55
-nl.js      Found: 494 Missing: 31
-no.js      Found: 470 Missing: 55
-pl.js      Found: 411 Missing: 114
-pt-br.js   Found: 524 Missing: 1
-pt.js      Found: 282 Missing: 243
-ro.js      Found: 301 Missing: 224
-ru.js      Found: 467 Missing: 58
-sk.js      Found: 302 Missing: 223
-sl.js      Found: 410 Missing: 115
-sr-latn.js Found: 276 Missing: 249
-sr.js      Found: 275 Missing: 250
-sv.js      Found: 299 Missing: 226
-th.js      Found: 287 Missing: 238
-tr.js      Found: 524 Missing: 1
-uk.js      Found: 404 Missing: 121
-vi.js      Found: 481 Missing: 44
-zh-cn.js   Found: 523 Missing: 2
-zh.js      Found: 404 Missing: 121
+af.js      Found: 287 Missing: 245
+ar.js      Found: 451 Missing: 81
+bg.js      Found: 280 Missing: 252
+bn.js      Found: 281 Missing: 251
+bs.js      Found: 187 Missing: 345
+ca.js      Found: 490 Missing: 42
+cs.js      Found: 411 Missing: 121
+cy.js      Found: 452 Missing: 80
+da.js      Found: 404 Missing: 128
+de.js      Found: 522 Missing: 10
+el.js      Found: 286 Missing: 246
+en-au.js   Found: 369 Missing: 163
+en-ca.js   Found: 369 Missing: 163
+en-gb.js   Found: 370 Missing: 162
+eo.js      Found: 259 Missing: 273
+es.js      Found: 524 Missing: 8
+et.js      Found: 301 Missing: 231
+eu.js      Found: 403 Missing: 129
+fa.js      Found: 302 Missing: 230
+fi.js      Found: 518 Missing: 14
+fo.js      Found: 420 Missing: 112
+fr-ca.js   Found: 301 Missing: 231
+fr.js      Found: 403 Missing: 129
+gl.js      Found: 283 Missing: 249
+gu.js      Found: 300 Missing: 232
+he.js      Found: 532 Missing: 0
+hi.js      Found: 302 Missing: 230
+hr.js      Found: 404 Missing: 128
+hu.js      Found: 445 Missing: 87
+is.js      Found: 307 Missing: 225
+it.js      Found: 404 Missing: 128
+ja.js      Found: 413 Missing: 119
+km.js      Found: 275 Missing: 257
+ko.js      Found: 293 Missing: 239
+lt.js      Found: 306 Missing: 226
+lv.js      Found: 283 Missing: 249
+mn.js      Found: 300 Missing: 232
+ms.js      Found: 265 Missing: 267
+nb.js      Found: 470 Missing: 62
+nl.js      Found: 494 Missing: 38
+no.js      Found: 470 Missing: 62
+pl.js      Found: 411 Missing: 121
+pt-br.js   Found: 524 Missing: 8
+pt.js      Found: 282 Missing: 250
+ro.js      Found: 301 Missing: 231
+ru.js      Found: 467 Missing: 65
+sk.js      Found: 302 Missing: 230
+sl.js      Found: 410 Missing: 122
+sr-latn.js Found: 276 Missing: 256
+sr.js      Found: 275 Missing: 257
+sv.js      Found: 299 Missing: 233
+th.js      Found: 287 Missing: 245
+tr.js      Found: 524 Missing: 8
+uk.js      Found: 404 Missing: 128
+vi.js      Found: 481 Missing: 51
+zh-cn.js   Found: 523 Missing: 9
+zh.js      Found: 404 Missing: 128
Index: CKEditor/trunk/_source/lang/af.js
===================================================================
--- CKEditor/trunk/_source/lang/af.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/af.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/ar.js
===================================================================
--- CKEditor/trunk/_source/lang/ar.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/ar.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/bg.js
===================================================================
--- CKEditor/trunk/_source/lang/bg.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/bg.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/bn.js
===================================================================
--- CKEditor/trunk/_source/lang/bn.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/bn.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/bs.js
===================================================================
--- CKEditor/trunk/_source/lang/bs.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/bs.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/ca.js
===================================================================
--- CKEditor/trunk/_source/lang/ca.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/ca.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Mateixa finestra (_self)',
 		targetParent	: 'Finestra pare (_parent)',
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Redueix la barra d\'eines',
-	toolbarExpand	: 'Amplia la barra d\'eines'
+	toolbarExpand	: 'Amplia la barra d\'eines',
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/cs.js
===================================================================
--- CKEditor/trunk/_source/lang/cs.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/cs.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/cy.js
===================================================================
--- CKEditor/trunk/_source/lang/cy.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/cy.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Cyfangu\'r Bar Offer',
-	toolbarExpand	: 'Ehangu\'r Bar Offer'
+	toolbarExpand	: 'Ehangu\'r Bar Offer',
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/da.js
===================================================================
--- CKEditor/trunk/_source/lang/da.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/da.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/de.js
===================================================================
--- CKEditor/trunk/_source/lang/de.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/de.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Gleiches Fenster (_self)',
 		targetParent	: 'Oberes Fenster (_parent)',
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Symbolleiste einklappen',
-	toolbarExpand	: 'Symbolleiste ausklappen'
+	toolbarExpand	: 'Symbolleiste ausklappen',
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/el.js
===================================================================
--- CKEditor/trunk/_source/lang/el.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/el.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/en-au.js
===================================================================
--- CKEditor/trunk/_source/lang/en-au.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/en-au.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/en-ca.js
===================================================================
--- CKEditor/trunk/_source/lang/en-ca.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/en-ca.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/en-gb.js
===================================================================
--- CKEditor/trunk/_source/lang/en-gb.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/en-gb.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/en.js
===================================================================
--- CKEditor/trunk/_source/lang/en.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/en.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)',
 		targetParent	: 'Parent Window (_parent)',
+		advanced		: 'Advanced',
+		langDirLTR		: 'Left to Right (LTR)',
+		langDirRTL		: 'Right to Left (RTL)',
+		styles			: 'Style',
+		cssClasses		: 'Stylesheet Classes',
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar',
-	toolbarExpand	: 'Expand Toolbar'
+	toolbarExpand	: 'Expand Toolbar',
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right',
+		rtl : 'Text direction from right to left'
+	}
 };
Index: CKEditor/trunk/_source/lang/eo.js
===================================================================
--- CKEditor/trunk/_source/lang/eo.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/eo.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/es.js
===================================================================
--- CKEditor/trunk/_source/lang/es.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/es.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Misma ventana (_self)',
 		targetParent	: 'Ventana padre (_parent)',
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Contraer barra de herramientas',
-	toolbarExpand	: 'Expandir barra de herramientas'
+	toolbarExpand	: 'Expandir barra de herramientas',
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/et.js
===================================================================
--- CKEditor/trunk/_source/lang/et.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/et.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/eu.js
===================================================================
--- CKEditor/trunk/_source/lang/eu.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/eu.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/fa.js
===================================================================
--- CKEditor/trunk/_source/lang/fa.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/fa.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/fi.js
===================================================================
--- CKEditor/trunk/_source/lang/fi.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/fi.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Sama ikkuna (_self)',
 		targetParent	: 'Ylemmän tason ikkuna (_parent)',
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Kutista työkalupalkki',
-	toolbarExpand	: 'Laajenna työkalupalkki'
+	toolbarExpand	: 'Laajenna työkalupalkki',
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/fo.js
===================================================================
--- CKEditor/trunk/_source/lang/fo.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/fo.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Sama vindeyga (_self)',
 		targetParent	: 'Upphavligt vindeyga (_parent)',
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/fr-ca.js
===================================================================
--- CKEditor/trunk/_source/lang/fr-ca.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/fr-ca.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/fr.js
===================================================================
--- CKEditor/trunk/_source/lang/fr.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/fr.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/gl.js
===================================================================
--- CKEditor/trunk/_source/lang/gl.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/gl.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/gu.js
===================================================================
--- CKEditor/trunk/_source/lang/gu.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/gu.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/he.js
===================================================================
--- CKEditor/trunk/_source/lang/he.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/he.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'אותו חלון (_self)',
 		targetParent	: 'חלון האב (_parent)',
+		advanced		: 'מתקדם',
+		langDirLTR		: 'שמאל לימין (LTR)',
+		langDirRTL		: 'ימין לשמאל (RTL)',
+		styles			: 'סגנון',
+		cssClasses		: 'מחלקות גליונות סגנון',
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'מזעור סרגל כלים',
-	toolbarExpand	: 'הרחבת סרגל כלים'
+	toolbarExpand	: 'הרחבת סרגל כלים',
+
+	bidi :
+	{
+		ltr : 'כיוון טקסט משמאל לימין (LTR)',
+		rtl : 'כיוון טקסט מימין לשמאל (RTL)'
+	}
 };
Index: CKEditor/trunk/_source/lang/hi.js
===================================================================
--- CKEditor/trunk/_source/lang/hi.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/hi.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/hr.js
===================================================================
--- CKEditor/trunk/_source/lang/hr.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/hr.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/hu.js
===================================================================
--- CKEditor/trunk/_source/lang/hu.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/hu.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/is.js
===================================================================
--- CKEditor/trunk/_source/lang/is.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/is.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/it.js
===================================================================
--- CKEditor/trunk/_source/lang/it.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/it.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/ja.js
===================================================================
--- CKEditor/trunk/_source/lang/ja.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/ja.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'ツールバーを閉じる',
-	toolbarExpand	: 'ツールバーを開く'
+	toolbarExpand	: 'ツールバーを開く',
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/km.js
===================================================================
--- CKEditor/trunk/_source/lang/km.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/km.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/ko.js
===================================================================
--- CKEditor/trunk/_source/lang/ko.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/ko.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/lt.js
===================================================================
--- CKEditor/trunk/_source/lang/lt.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/lt.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/lv.js
===================================================================
--- CKEditor/trunk/_source/lang/lv.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/lv.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/mn.js
===================================================================
--- CKEditor/trunk/_source/lang/mn.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/mn.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/ms.js
===================================================================
--- CKEditor/trunk/_source/lang/ms.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/ms.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/nb.js
===================================================================
--- CKEditor/trunk/_source/lang/nb.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/nb.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Samme vindu (_self)',
 		targetParent	: 'Foreldrevindu (_parent)',
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Slå sammen verktøylinje',
-	toolbarExpand	: 'Vis verktøylinje'
+	toolbarExpand	: 'Vis verktøylinje',
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/nl.js
===================================================================
--- CKEditor/trunk/_source/lang/nl.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/nl.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Zelfde venster (_self)',
 		targetParent	: 'Origineel venster (_parent)',
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Werkbalk inklappen',
-	toolbarExpand	: 'Werkbalk uitklappen'
+	toolbarExpand	: 'Werkbalk uitklappen',
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/no.js
===================================================================
--- CKEditor/trunk/_source/lang/no.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/no.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Samme vindu (_self)',
 		targetParent	: 'Foreldrevindu (_parent)',
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Slå sammen verktøylinje',
-	toolbarExpand	: 'Vis verktøylinje'
+	toolbarExpand	: 'Vis verktøylinje',
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/pl.js
===================================================================
--- CKEditor/trunk/_source/lang/pl.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/pl.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/pt-br.js
===================================================================
--- CKEditor/trunk/_source/lang/pt-br.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/pt-br.js	(revision 5812)
@@ -105,4 +105,9 @@
 		targetSelf		: 'Mesma Janela (_self)',
 		targetParent	: 'Janela Pai (_parent)',
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -744,4 +749,10 @@
 
 	toolbarCollapse	: 'Diminuir Barra de Ferramentas',
-	toolbarExpand	: 'Aumentar Barra de Ferramentas'
+	toolbarExpand	: 'Aumentar Barra de Ferramentas',
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/pt.js
===================================================================
--- CKEditor/trunk/_source/lang/pt.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/pt.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/ro.js
===================================================================
--- CKEditor/trunk/_source/lang/ro.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/ro.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/ru.js
===================================================================
--- CKEditor/trunk/_source/lang/ru.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/ru.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Свернуть панель инструментов',
-	toolbarExpand	: 'Развернуть панель инструментов'
+	toolbarExpand	: 'Развернуть панель инструментов',
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/sk.js
===================================================================
--- CKEditor/trunk/_source/lang/sk.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/sk.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/sl.js
===================================================================
--- CKEditor/trunk/_source/lang/sl.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/sl.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/sr-latn.js
===================================================================
--- CKEditor/trunk/_source/lang/sr-latn.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/sr-latn.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/sr.js
===================================================================
--- CKEditor/trunk/_source/lang/sr.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/sr.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/sv.js
===================================================================
--- CKEditor/trunk/_source/lang/sv.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/sv.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/th.js
===================================================================
--- CKEditor/trunk/_source/lang/th.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/th.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/tr.js
===================================================================
--- CKEditor/trunk/_source/lang/tr.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/tr.js	(revision 5812)
@@ -105,4 +105,9 @@
 		targetSelf		: 'Aynı Pencere (_self)',
 		targetParent	: 'Ana Pencere (_parent)',
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -744,4 +749,10 @@
 
 	toolbarCollapse	: 'Toolbar\'ı topla',
-	toolbarExpand	: 'Toolbar\'ı aç'
+	toolbarExpand	: 'Toolbar\'ı aç',
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/uk.js
===================================================================
--- CKEditor/trunk/_source/lang/uk.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/uk.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/vi.js
===================================================================
--- CKEditor/trunk/_source/lang/vi.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/vi.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Tại trang (_self)',
 		targetParent	: 'Cửa sổ cha (_parent)',
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Thu gọn thanh công cụ',
-	toolbarExpand	: 'Mở rộng thnah công cụ'
+	toolbarExpand	: 'Mở rộng thnah công cụ',
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/zh-cn.js
===================================================================
--- CKEditor/trunk/_source/lang/zh-cn.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/zh-cn.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: '本窗口 (_self)',
 		targetParent	: '父窗口 (_parent)',
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: '折叠工具栏',
-	toolbarExpand	: '展开工具栏'
+	toolbarExpand	: '展开工具栏',
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/lang/zh.js
===================================================================
--- CKEditor/trunk/_source/lang/zh.js	(revision 5802)
+++ CKEditor/trunk/_source/lang/zh.js	(revision 5812)
@@ -106,4 +106,9 @@
 		targetSelf		: 'Same Window (_self)', // MISSING
 		targetParent	: 'Parent Window (_parent)', // MISSING
+		advanced		: 'Advanced', // MISSING
+		langDirLTR		: 'Left to Right (LTR)', // MISSING
+		langDirRTL		: 'Right to Left (RTL)', // MISSING
+		styles			: 'Style', // MISSING
+		cssClasses		: 'Stylesheet Classes', // MISSING
 
 		// Put the voice-only part of the label in the span.
@@ -745,4 +750,10 @@
 
 	toolbarCollapse	: 'Collapse Toolbar', // MISSING
-	toolbarExpand	: 'Expand Toolbar' // MISSING
+	toolbarExpand	: 'Expand Toolbar', // MISSING
+
+	bidi :
+	{
+		ltr : 'Text direction from left to right', // MISSING
+		rtl : 'Text direction from right to left' // MISSING
+	}
 };
Index: CKEditor/trunk/_source/plugins/autogrow/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/autogrow/plugin.js	(revision 5812)
+++ CKEditor/trunk/_source/plugins/autogrow/plugin.js	(revision 5812)
@@ -0,0 +1,79 @@
+﻿/*
+Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+/**
+ * @file AutoGrow plugin
+ */
+(function(){
+	var resizeEditor = function( editor )
+	{
+		var doc = editor.document,
+			currentHeight = editor.window.getViewPaneSize().height,
+			newHeight;
+
+		// We can not use documentElement to calculate the height for IE (#6061).
+		if ( CKEDITOR.env.ie )
+			newHeight = doc.getBody().$.scrollHeight + 24;
+		else
+			newHeight = doc.getDocumentElement().$.offsetHeight;
+
+		var min = editor.config.autoGrow_minHeight,
+			max = editor.config.autoGrow_maxHeight;
+		( min == undefined ) && ( editor.config.autoGrow_minHeight = min = 200 );
+		if ( min )
+			newHeight = Math.max( newHeight, min );
+		if ( max )
+			newHeight = Math.min( newHeight, max );
+
+		if ( newHeight != currentHeight )
+		{
+			newHeight = editor.fire( 'autoGrow', { currentHeight : currentHeight, newHeight : newHeight } ).newHeight;
+			editor.resize( editor.container.getStyle( 'width' ), newHeight, true );
+		}
+	};
+	CKEDITOR.plugins.add( 'autogrow',
+	{
+		init : function( editor )
+		{
+			for ( var eventName in { contentDom:1, key:1, selectionChange:1, insertElement:1 } )
+			{
+				editor.on( eventName, function( evt )
+				{
+					// Some time is required for insertHtml, and it gives other events better performance as well.
+					if ( evt.editor.mode == 'wysiwyg' )
+						setTimeout( function(){ resizeEditor( evt.editor ); }, 100 );
+				});
+			}
+		}
+	});
+})();
+/**
+ * The minimum height to which the editor can reach using AutoGrow.
+ * @name CKEDITOR.config.autoGrow_minHeight
+ * @type Number
+ * @default 200
+ * @since 3.4
+ * @example
+ * config.autoGrow_minHeight = 300;
+ */
+
+/**
+ * The maximum height to which the editor can reach using AutoGrow. Zero means unlimited.
+ * @name CKEDITOR.config.autoGrow_maxHeight
+ * @type Number
+ * @default 0
+ * @since 3.4
+ * @example
+ * config.autoGrow_maxHeight = 400;
+ */
+
+/**
+ * Fired when the AutoGrow plugin is about to change the size of the editor.
+ * @name CKEDITOR#autogrow
+ * @event
+ * @param {Number} data.currentHeight The current height of the editor (before the resizing).
+ * @param {Number} data.newHeight The new height of the editor (after the resizing). It can be changed
+ *				to determine another height to be used instead.
+ */
Index: CKEditor/trunk/_source/plugins/bidi/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/bidi/plugin.js	(revision 5812)
+++ CKEditor/trunk/_source/plugins/bidi/plugin.js	(revision 5812)
@@ -0,0 +1,244 @@
+﻿/*
+Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+(function()
+{
+	var guardElements = { table:1, ul:1, ol:1, blockquote:1, div:1 };
+	var directSelectionGuardElements = {};
+	CKEDITOR.tools.extend( directSelectionGuardElements, guardElements, { tr:1, p:1, div:1, li:1 } );
+
+	function onSelectionChange( evt )
+	{
+		evt.editor.getCommand( 'bidirtl' ).setState( getState( evt.editor, evt.data.path, 'rtl' ) );
+		evt.editor.getCommand( 'bidiltr' ).setState( getState( evt.editor, evt.data.path, 'ltr' ) );
+	}
+
+	function getState( editor, path, dir )
+	{
+		var useComputedState = editor.config.useComputedState,
+			selectedElement;
+
+		useComputedState = useComputedState === undefined || useComputedState;
+
+		if ( useComputedState )
+		{
+			var selection = editor.getSelection(),
+				ranges = selection.getRanges();
+
+			selectedElement = ranges && ranges[ 0 ].getEnclosedNode();
+
+			// If this is not our element of interest, apply to fully selected elements from guardElements.
+			if ( !selectedElement || selectedElement
+					&& !( selectedElement.type == CKEDITOR.NODE_ELEMENT && selectedElement.getName() in directSelectionGuardElements )
+				)
+				selectedElement = getFullySelected( selection, guardElements );
+		}
+
+		selectedElement = selectedElement || path.block || path.blockLimit;
+
+		if ( !selectedElement || selectedElement.getName() == 'body' )
+			return CKEDITOR.TRISTATE_OFF;
+
+		selectedElement = useComputedState ?
+			selectedElement.getComputedStyle( 'direction' ) :
+			selectedElement.getStyle( 'direction' ) || selectedElement.getAttribute( 'dir' );
+
+		return ( selectedElement == dir ) ?
+			CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF;
+	}
+
+	function switchDir( element, dir, editor )
+	{
+		var dirBefore = element.getComputedStyle( 'direction' ),
+			currentDir = element.getStyle( 'direction' ) || element.getAttribute( 'dir' ) || '';
+
+		element.removeStyle( 'direction' );
+
+		if ( currentDir.toLowerCase() == dir )
+			element.removeAttribute( 'dir' );
+		else
+			element.setAttribute( 'dir', dir );
+
+		// If the element direction changed, we need to switch the margins of
+		// the element and all its children, so it will get really reflected
+		// like a mirror. (#5910)
+		var dirAfter = element.getComputedStyle( 'direction' );
+		if ( dirAfter != dirBefore )
+		{
+			var range = new CKEDITOR.dom.range( element.getDocument() );
+			range.setStartBefore( element );
+			range.setEndAfter( element );
+
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var node;
+			while ( ( node = walker.next() ) )
+			{
+				if ( node.type == CKEDITOR.NODE_ELEMENT )
+				{
+					// A child with dir defined is to be ignored.
+					if ( !node.equals( element ) && node.hasAttribute( 'dir' ) )
+					{
+						range.setStartAfter( node );
+						walker = new CKEDITOR.dom.walker( range );
+						continue;
+					}
+
+					// Switch the margins.
+					var marginLeft = node.getStyle( 'margin-right' ),
+						marginRight = node.getStyle( 'margin-left' );
+
+					marginLeft ? node.setStyle( 'margin-left', marginLeft ) : node.removeStyle( 'margin-left' );
+					marginRight ? node.setStyle( 'margin-right', marginRight ) : node.removeStyle( 'margin-right' );
+				}
+			}
+		}
+
+		editor.forceNextSelectionCheck();
+	}
+
+	function getFullySelected( selection, elements )
+	{
+		var selectedElement = selection.getCommonAncestor();
+		while( selectedElement.type == CKEDITOR.NODE_ELEMENT
+				&& !( selectedElement.getName() in elements )
+				&& selectedElement.getParent().getChildCount() == 1
+			)
+			selectedElement = selectedElement.getParent();
+
+		return selectedElement.type == CKEDITOR.NODE_ELEMENT
+			&& ( selectedElement.getName() in elements )
+			&& selectedElement;
+	}
+
+	function bidiCommand( dir )
+	{
+		return function( editor )
+		{
+			var selection = editor.getSelection(),
+				enterMode = editor.config.enterMode,
+				ranges = selection.getRanges();
+
+			if ( ranges && ranges.length )
+			{
+				// Apply do directly selected elements from guardElements.
+				var selectedElement = ranges[ 0 ].getEnclosedNode();
+
+				// If this is not our element of interest, apply to fully selected elements from guardElements.
+				if ( !selectedElement || selectedElement
+						&& !( selectedElement.type == CKEDITOR.NODE_ELEMENT && selectedElement.getName() in directSelectionGuardElements )
+					)
+					selectedElement = getFullySelected( selection, guardElements );
+
+				if ( selectedElement )
+				{
+					if ( !selectedElement.isReadOnly() )
+						switchDir( selectedElement, dir, editor );
+				}
+				else
+				{
+					// Creates bookmarks for selection, as we may split some blocks.
+					var bookmarks = selection.createBookmarks();
+
+					var iterator,
+						block;
+
+					for ( var i = ranges.length - 1 ; i >= 0 ; i-- )
+					{
+						// Array of elements processed as guardElements.
+						var processedElements = [];
+						// Walker searching for guardElements.
+						var walker = new CKEDITOR.dom.walker( ranges[ i ] );
+						walker.evaluator = function( node ){
+							return node.type == CKEDITOR.NODE_ELEMENT
+								&& node.getName() in guardElements
+								&& !( node.getName() == ( enterMode == CKEDITOR.ENTER_P ) ? 'p' : 'div'
+									&& node.getParent().type == CKEDITOR.NODE_ELEMENT
+									&& node.getParent().getName() == 'blockquote'
+								);
+						};
+
+						while ( ( block = walker.next() ) )
+						{
+							switchDir( block, dir, editor );
+							processedElements.push( block );
+						}
+
+						iterator = ranges[ i ].createIterator();
+						iterator.enlargeBr = enterMode != CKEDITOR.ENTER_BR;
+
+						while ( ( block = iterator.getNextParagraph( enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ) ) )
+						{
+							if ( block.isReadOnly() )
+								continue;
+
+							var _break = 0;
+
+							// Check if block have been already processed by the walker above.
+							for ( var ii = 0; ii < processedElements.length; ii++ )
+							{
+								var parent = block.getParent();
+
+								while( parent && parent.getName() != 'body' )
+								{
+									if ( ( parent.$.isSameNode && parent.$.isSameNode( processedElements[ ii ].$ ) )
+											|| parent.$ == processedElements[ ii ].$ )
+									{
+										_break = 1;
+										break;
+									}
+									parent = parent.getParent();
+								}
+
+								if ( _break )
+									break;
+							}
+
+							if ( !_break )
+							{
+								switchDir( block, dir, editor );
+							}
+						}
+					}
+
+					editor.forceNextSelectionCheck();
+					// Restore selection position.
+					selection.selectBookmarks( bookmarks );
+				}
+
+				editor.focus();
+			}
+		};
+	}
+
+	CKEDITOR.plugins.add( 'bidi',
+	{
+		requires : [ 'styles', 'button' ],
+
+		init : function( editor )
+		{
+			// All buttons use the same code to register. So, to avoid
+			// duplications, let's use this tool function.
+			var addButtonCommand = function( buttonName, buttonLabel, commandName, commandExec )
+			{
+				editor.addCommand( commandName, new CKEDITOR.command( editor, { exec : commandExec }) );
+
+				editor.ui.addButton( buttonName,
+					{
+						label : buttonLabel,
+						command : commandName
+					});
+			};
+
+			var lang = editor.lang.bidi;
+
+			addButtonCommand( 'BidiLtr', lang.ltr, 'bidiltr', bidiCommand( 'ltr' ) );
+			addButtonCommand( 'BidiRtl', lang.rtl, 'bidirtl', bidiCommand( 'rtl' ) );
+
+			editor.on( 'selectionChange', onSelectionChange );
+		}
+	});
+
+})();
Index: CKEditor/trunk/_source/plugins/blockquote/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/blockquote/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/blockquote/plugin.js	(revision 5812)
@@ -48,5 +48,5 @@
 			var state = editor.getCommand( 'blockquote' ).state,
 				selection = editor.getSelection(),
-				range = selection && selection.getRanges()[0];
+				range = selection && selection.getRanges( true )[0];
 
 			if ( !range )
Index: CKEditor/trunk/_source/plugins/clipboard/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/clipboard/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/clipboard/plugin.js	(revision 5812)
@@ -387,12 +387,11 @@
 					}
 
-					editor.contextMenu.addListener( function()
+					editor.contextMenu.addListener( function( element, selection )
 						{
+							var readOnly = selection.getCommonAncestor().isReadOnly();
 							return {
-								cut : stateFromNamedCommand( 'Cut' ),
-
-								// Browser bug: 'Cut' has the correct states for both Copy and Cut.
-								copy : stateFromNamedCommand( 'Cut' ),
-								paste : CKEDITOR.env.webkit ? CKEDITOR.TRISTATE_OFF : stateFromNamedCommand( 'Paste' )
+								cut : !readOnly && stateFromNamedCommand( 'Cut' ),
+								copy : stateFromNamedCommand( 'Copy' ),
+								paste : !readOnly && ( CKEDITOR.env.webkit ? CKEDITOR.TRISTATE_OFF : stateFromNamedCommand( 'Paste' ) )
 							};
 						});
Index: CKEditor/trunk/_source/plugins/colordialog/dialogs/colordialog.js
===================================================================
--- CKEditor/trunk/_source/plugins/colordialog/dialogs/colordialog.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/colordialog/dialogs/colordialog.js	(revision 5812)
@@ -244,9 +244,10 @@
 		var numbering = function( id )
 			{
-				return id + CKEDITOR.tools.getNextNumber();
+				return CKEDITOR.tools.getNextId() + '_' + id;
 			},
 			hicolorId = numbering( 'hicolor' ),
 			hicolorTextId = numbering( 'hicolortext' ),
-			selHiColorId = numbering( 'selhicolor' );
+			selHiColorId = numbering( 'selhicolor' ),
+			tableLabelId = numbering( 'color_table_label' );
 
 		return {
@@ -274,6 +275,6 @@
 								{
 									type : 'html',
-									html : '<table role="listbox" aria-labelledby="color_table_label" onmouseout="CKEDITOR.tools.callFunction( ' + onMouseout + ' );">' + table.getHtml() + '</table>' +
-												'<span id="color_table_label" class="cke_voice_label">' + lang.options +'</span>',
+									html : '<table role="listbox" aria-labelledby="' + tableLabelId + '" onmouseout="CKEDITOR.tools.callFunction( ' + onMouseout + ' );">' + table.getHtml() + '</table>' +
+												'<span id="' + tableLabelId + '" class="cke_voice_label">' + lang.options +'</span>',
 									onLoad : function()
 									{
Index: CKEditor/trunk/_source/plugins/dialog/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/dialog/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/dialog/plugin.js	(revision 5812)
@@ -473,5 +473,8 @@
 		// Insert the tabs and contents.
 		for ( var i = 0 ; i < definition.contents.length ; i++ )
-			this.addPage( definition.contents[i] );
+		{
+			var page = definition.contents[i];
+			page && this.addPage( page );
+		}
 
 		this.parts['tabs'].on( 'click', function( evt )
@@ -481,6 +484,8 @@
 					if ( target.hasClass( 'cke_dialog_tab' ) )
 					{
+						// Get the ID of the tab, without the 'cke_' prefix and the unique number suffix.
 						var id = target.$.id;
-						this.selectPage( id.substr( 0, id.lastIndexOf( '_' ) ) );
+						this.selectPage( id.substring( 4, id.lastIndexOf( '_' ) ) );
+
 						if ( this._.tabBarMode )
 						{
@@ -882,5 +887,5 @@
 
 			var env = CKEDITOR.env;
-			var tabId = contents.id + '_' + CKEDITOR.tools.getNextNumber(),
+			var tabId = 'cke_' + contents.id + '_' + CKEDITOR.tools.getNextNumber(),
 				 tab = CKEDITOR.dom.element.createFromHtml( [
 					'<a class="cke_dialog_tab"',
@@ -1387,5 +1392,5 @@
 		var contents = dialogDefinition.contents;
 		for ( var i = 0, content ; ( content = contents[i] ) ; i++ )
-			contents[ i ] = new contentObject( dialog, content );
+			contents[ i ] = content && new contentObject( dialog, content );
 
 		CKEDITOR.tools.extend( this, dialogDefinition );
@@ -2052,5 +2057,5 @@
 					attributes = ( attributesArg && attributesArg.call ? attributesArg( elementDefinition ) : attributesArg ) || {},
 					innerHTML = ( contentsArg && contentsArg.call ? contentsArg.call( this, dialog, elementDefinition ) : contentsArg ) || '',
-					domId = this.domId = attributes.id || CKEDITOR.tools.getNextNumber() + '_uiElement',
+					domId = this.domId = attributes.id || CKEDITOR.tools.getNextId() + '_uiElement',
 					id = this.id = elementDefinition.id,
 					i;
Index: CKEditor/trunk/_source/plugins/dialogadvtab/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/dialogadvtab/plugin.js	(revision 5812)
+++ CKEditor/trunk/_source/plugins/dialogadvtab/plugin.js	(revision 5812)
@@ -0,0 +1,216 @@
+﻿/*
+Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+(function()
+{
+
+function setupAdvParams( element )
+{
+	var attrName = this.att;
+
+	var value = element && element.hasAttribute( attrName ) && element.getAttribute( attrName ) || '';
+
+	if ( value !== undefined )
+		this.setValue( value );
+}
+
+function commitAdvParams()
+{
+	// Dialogs may use different parameters in the commit list, so, by
+	// definition, we take the first CKEDITOR.dom.element available.
+	var element;
+
+	for ( var i = 0 ; i < arguments.length ; i++ )
+	{
+		if ( arguments[ i ] instanceof CKEDITOR.dom.element )
+		{
+			element = arguments[ i ];
+			break;
+		}
+	}
+
+	if ( element )
+	{
+		var attrName = this.att,
+			value = this.getValue();
+
+		if ( value )
+			element.setAttribute( attrName, value );
+		else
+			element.removeAttribute( attrName, value );
+	}
+}
+
+var isUpdating;
+
+CKEDITOR.plugins.add( 'dialogadvtab',
+{
+	/**
+	 *
+	 * @param tabConfig
+	 * id, dir, classes, styles
+	 */
+	createAdvancedTab : function( editor, tabConfig )
+	{
+		if ( !tabConfig )
+			tabConfig = { id:1, dir:1, classes:1, styles:1 };
+
+		var lang = editor.lang.common;
+
+		var result =
+		{
+			id : 'advanced',
+			label : lang.advanced,
+			title : lang.advanced,
+			elements :
+				[
+					{
+						type : 'vbox',
+						padding : 1,
+						children : []
+					}
+				]
+		};
+
+		var contents = [];
+
+		if ( tabConfig.id || tabConfig.dir )
+		{
+			if ( tabConfig.id )
+			{
+				contents.push(
+					{
+						id : 'advId',
+						att : 'id',
+						type : 'text',
+						label : lang.id,
+						setup : setupAdvParams,
+						commit : commitAdvParams
+					});
+			}
+
+			if ( tabConfig.dir )
+			{
+				contents.push(
+					{
+						id : 'advLangDir',
+						att : 'dir',
+						type : 'select',
+						label : lang.langDir,
+						'default' : '',
+						style : 'width:110px',
+						items :
+						[
+							[ lang.notSet, '' ],
+							[ lang.langDirLTR, 'ltr' ],
+							[ lang.langDirRTL, 'rtl' ]
+						],
+						setup : setupAdvParams,
+						commit : commitAdvParams
+					});
+			}
+
+			result.elements[ 0 ].children.push(
+				{
+					type : 'hbox',
+					widths : [ '50%', '50%' ],
+					children : [].concat( contents )
+				});
+		}
+
+		if ( tabConfig.styles || tabConfig.classes )
+		{
+			contents = [];
+
+			if ( tabConfig.id )
+			{
+				contents.push(
+					{
+						id : 'advStyles',
+						att : 'style',
+						type : 'text',
+						label : lang.styles,
+						'default' : '',
+
+						onChange : function(){},
+
+						getStyle : function( name, defaultValue )
+						{
+							var match = this.getValue().match( new RegExp( name + '\\s*:\s*([^;]*)', 'i') );
+							return match ? match[ 1 ] : defaultValue;
+						},
+
+						updateStyle : function( name, value )
+						{
+							if ( isUpdating )
+								return;
+
+							// Flag to avoid recursion.
+							isUpdating = 1;
+
+							var styles = this.getValue();
+
+							// Remove the current value.
+							if ( styles )
+							{
+								styles = styles
+									.replace( new RegExp( '\\s*' + name + '\s*:[^;]*(?:$|;\s*)', 'i' ), '' )
+									.replace( /^[;\s]+/, '' )
+									.replace( /\s+$/, '' );
+							}
+
+							if ( value )
+							{
+								styles && !(/;\s*$/).test( styles ) && ( styles += '; ' );
+								styles += name + ': ' + value;
+							}
+
+							this.setValue( styles );
+
+							isUpdating = 0;
+						},
+
+						setup : setupAdvParams,
+
+						commit : commitAdvParams
+
+					});
+			}
+
+			if ( tabConfig.classes )
+			{
+				contents.push(
+					{
+						type : 'hbox',
+						widths : [ '45%', '55%' ],
+						children :
+						[
+							{
+								id : 'advCSSClasses',
+								att : 'class',
+								type : 'text',
+								label : lang.cssClasses,
+								'default' : '',
+								setup : setupAdvParams,
+								commit : commitAdvParams
+
+							}
+						]
+					});
+			}
+
+			result.elements[ 0 ].children.push(
+				{
+					type : 'hbox',
+					widths : [ '50%', '50%' ],
+					children : [].concat( contents )
+				});
+		}
+
+		return result;
+	}
+});
+
+})();
Index: CKEditor/trunk/_source/plugins/dialogui/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/dialogui/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/dialogui/plugin.js	(revision 5812)
@@ -148,5 +148,5 @@
 
 				var _ = initPrivateObject.call( this, elementDefinition );
-				_.labelId = CKEDITOR.tools.getNextNumber() + '_label';
+				_.labelId = CKEDITOR.tools.getNextId() + '_label';
 				var children = this._.children = [];
 				/** @ignore */
@@ -224,5 +224,5 @@
 
 				initPrivateObject.call( this, elementDefinition );
-				var domId = this._.inputId = CKEDITOR.tools.getNextNumber() + '_textInput',
+				var domId = this._.inputId = CKEDITOR.tools.getNextId() + '_textInput',
 					attributes = { 'class' : 'cke_dialog_ui_input_' + elementDefinition.type, id : domId, type : 'text' },
 					i;
@@ -314,5 +314,5 @@
 				initPrivateObject.call( this, elementDefinition );
 				var me = this,
-					domId = this._.inputId = CKEDITOR.tools.getNextNumber() + '_textarea',
+					domId = this._.inputId = CKEDITOR.tools.getNextId() + '_textarea',
 					attributes = {};
 
@@ -371,9 +371,9 @@
 					var myDefinition = CKEDITOR.tools.extend( {}, elementDefinition,
 							{
-								id : elementDefinition.id ? elementDefinition.id + '_checkbox' : CKEDITOR.tools.getNextNumber() + '_checkbox'
+								id : elementDefinition.id ? elementDefinition.id + '_checkbox' : CKEDITOR.tools.getNextId() + '_checkbox'
 							}, true ),
 						html = [];
 
-					var labelId = CKEDITOR.tools.getNextNumber() + '_label';
+					var labelId = CKEDITOR.tools.getNextId() + '_label';
 					var attributes = { 'class' : 'cke_dialog_ui_checkbox_input', type : 'checkbox', 'aria-labelledby' : labelId };
 					cleanInnerDefinition( myDefinition );
@@ -431,5 +431,5 @@
 					var inputHtmlList = [], html = [],
 						commonAttributes = { 'class' : 'cke_dialog_ui_radio_item', 'aria-labelledby' : this._.labelId },
-						commonName = elementDefinition.id ? elementDefinition.id + '_radio' : CKEDITOR.tools.getNextNumber() + '_radio';
+						commonName = elementDefinition.id ? elementDefinition.id + '_radio' : CKEDITOR.tools.getNextId() + '_radio';
 					for ( var i = 0 ; i < elementDefinition.items.length ; i++ )
 					{
@@ -437,5 +437,5 @@
 							title = item[2] !== undefined ? item[2] : item[0],
 							value = item[1] !== undefined ? item[1] : item[0],
-							inputId = CKEDITOR.tools.getNextNumber() + '_radio_input',
+							inputId = CKEDITOR.tools.getNextId() + '_radio_input',
 							labelId = inputId + '_label',
 							inputDefinition = CKEDITOR.tools.extend( {}, elementDefinition,
@@ -541,5 +541,5 @@
 				delete outerDefinition.style;
 
-				var labelId = CKEDITOR.tools.getNextNumber() + '_label';
+				var labelId = CKEDITOR.tools.getNextId() + '_label';
 				CKEDITOR.ui.dialog.uiElement.call(
 					this,
@@ -597,5 +597,5 @@
 					this.validate = elementDefinition.validate;
 
-				_.inputId = CKEDITOR.tools.getNextNumber() + '_select';
+				_.inputId = CKEDITOR.tools.getNextId() + '_select';
 				/** @ignore */
 				var innerHTML = function()
@@ -603,5 +603,5 @@
 					var myDefinition = CKEDITOR.tools.extend( {}, elementDefinition,
 							{
-								id : elementDefinition.id ? elementDefinition.id + '_select' : CKEDITOR.tools.getNextNumber() + '_select'
+								id : elementDefinition.id ? elementDefinition.id + '_select' : CKEDITOR.tools.getNextId() + '_select'
 							}, true ),
 						html = [],
@@ -664,5 +664,5 @@
 				var innerHTML = function()
 				{
-					_.frameId = CKEDITOR.tools.getNextNumber() + '_fileInput';
+					_.frameId = CKEDITOR.tools.getNextId() + '_fileInput';
 
 					// Support for custom document.domain in IE.
Index: CKEditor/trunk/_source/plugins/div/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/div/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/div/plugin.js	(revision 5812)
@@ -96,5 +96,5 @@
 					editor.contextMenu.addListener( function( element, selection )
 						{
-							if ( !element )
+							if ( !element || element.isReadOnly())
 								return null;
 
Index: CKEditor/trunk/_source/plugins/enterkey/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/enterkey/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/enterkey/plugin.js	(revision 5812)
@@ -24,4 +24,9 @@
 			// Get the range for the current selection.
 			range = range || getRange( editor );
+
+			// We may not have valid ranges to work on, like when inside a
+			// contenteditable=false element.
+			if ( !range )
+				return;
 
 			var doc = range.document;
@@ -189,4 +194,9 @@
 			// Get the range for the current selection.
 			range = range || getRange( editor );
+
+			// We may not have valid ranges to work on, like when inside a
+			// contenteditable=false element.
+			if ( !range )
+				return;
 
 			var doc = range.document;
@@ -340,5 +350,5 @@
 	{
 		// Get the selection ranges.
-		var ranges = editor.getSelection().getRanges();
+		var ranges = editor.getSelection().getRanges( true );
 
 		// Delete the contents of all ranges except the first one.
Index: CKEditor/trunk/_source/plugins/filebrowser/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/filebrowser/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/filebrowser/plugin.js	(revision 5812)
@@ -389,9 +389,11 @@
 		for ( var i in definition.contents )
 		{
-			element = definition.contents[ i ] ;
-			attachFileBrowser( evt.editor, evt.data.name, definition, element.elements );
-			if ( element.hidden && element.filebrowser )
-			{
-				element.hidden = !isConfigured( definition, element[ 'id' ], element.filebrowser );
+			if ( ( element = definition.contents[ i ] ) )
+			{
+				attachFileBrowser( evt.editor, evt.data.name, definition, element.elements );
+				if ( element.hidden && element.filebrowser )
+				{
+					element.hidden = !isConfigured( definition, element[ 'id' ], element.filebrowser );
+				}
 			}
 		}
Index: CKEditor/trunk/_source/plugins/find/dialogs/find.js
===================================================================
--- CKEditor/trunk/_source/plugins/find/dialogs/find.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/find/dialogs/find.js	(revision 5812)
@@ -6,7 +6,9 @@
 (function()
 {
-	function nonEmptyText( node )
+	var isReplace;
+
+	function findEvaluator( node )
 	{
-		return ( node.type == CKEDITOR.NODE_TEXT && node.getLength() > 0 );
+		return node.type == CKEDITOR.NODE_TEXT && node.getLength() > 0 && ( !isReplace || !node.isReadOnly() );
 	}
 
@@ -14,5 +16,5 @@
 	 * Elements which break characters been considered as sequence.
 	*/
-	function nonCharactersBoundary ( node )
+	function nonCharactersBoundary( node )
 	{
 		return !( node.type == CKEDITOR.NODE_ELEMENT && node.isBlockBoundary(
@@ -85,5 +87,5 @@
 				new CKEDITOR.dom.walker( range );
 			walker.guard = matchWord ? nonCharactersBoundary : null;
-			walker[ 'evaluator' ] = nonEmptyText;
+			walker[ 'evaluator' ] = findEvaluator;
 			walker.breakOnFalse = true;
 
@@ -252,6 +254,8 @@
 
 				// Apply the highlight.
-				var range = this.toDomRange();
+				var range = this.toDomRange(),
+					bookmark = range.createBookmark();
 				highlightStyle.applyToRange( range );
+				range.moveToBookmark( bookmark );
 				this._.highlightRange = range;
 
@@ -274,7 +278,17 @@
 					return;
 
+				var bookmark = this._.highlightRange.createBookmark();
 				highlightStyle.removeFromRange( this._.highlightRange );
+				this._.highlightRange.moveToBookmark( bookmark );
 				this.updateFromDomRange( this._.highlightRange );
 				this._.highlightRange = null;
+			},
+
+			isReadOnly : function()
+			{
+				if ( !this._.highlightRange )
+					return 0;
+
+				return this._.highlightRange.startContainer.isReadOnly();
 			},
 
@@ -515,4 +529,6 @@
 				matchCyclic , isReplaceAll )
 			{
+				isReplace = 1;
+
 				// Successiveness of current replace/find.
 				var result = false;
@@ -521,5 +537,5 @@
 				// 2. Otherwise perform the find but don't replace it immediately.
 				if ( this.matchRange && this.matchRange.isMatched()
-						&& !this.matchRange._.isReplaced )
+						&& !this.matchRange._.isReplaced && !this.matchRange.isReadOnly() )
 				{
 					// Turn off highlight for a while when saving snapshots.
@@ -551,4 +567,6 @@
 					result = this.find( pattern, matchCase, matchWord, matchCyclic, !isReplaceAll );
 
+				isReplace = 0;
+
 				return result;
 			}
Index: CKEditor/trunk/_source/plugins/flash/dialogs/flash.js
===================================================================
--- CKEditor/trunk/_source/plugins/flash/dialogs/flash.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/flash/dialogs/flash.js	(revision 5812)
@@ -176,6 +176,6 @@
 		var previewPreloader,
 			previewAreaHtml = '<div>' + CKEDITOR.tools.htmlEncode( editor.lang.common.preview ) +'<br>' +
-			'<div id="FlashPreviewLoader' + CKEDITOR.tools.getNextNumber() + '" style="display:none"><div class="loading">&nbsp;</div></div>' +
-			'<div id="FlashPreviewBox' + CKEDITOR.tools.getNextNumber() + '" class="FlashPreviewBox"></div></div>';
+			'<div id="cke_FlashPreviewLoader' + CKEDITOR.tools.getNextNumber() + '" style="display:none"><div class="loading">&nbsp;</div></div>' +
+			'<div id="cke_FlashPreviewBox' + CKEDITOR.tools.getNextNumber() + '" class="FlashPreviewBox"></div></div>';
 
 		return {
Index: CKEditor/trunk/_source/plugins/flash/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/flash/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/flash/plugin.js	(revision 5812)
@@ -91,5 +91,6 @@
 				editor.contextMenu.addListener( function( element, selection )
 					{
-						if ( element && element.is( 'img' ) && element.getAttribute( '_cke_real_element_type' ) == 'flash' )
+						if ( element && element.is( 'img' ) && !element.isReadOnly()
+								&& element.getAttribute( '_cke_real_element_type' ) == 'flash' )
 							return { flash : CKEDITOR.TRISTATE_OFF };
 					});
Index: CKEditor/trunk/_source/plugins/forms/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/forms/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/forms/plugin.js	(revision 5812)
@@ -132,5 +132,5 @@
 			editor.contextMenu.addListener( function( element )
 				{
-					if ( element && element.hasAscendant( 'form', true ) )
+					if ( element && element.hasAscendant( 'form', true ) && !element.isReadOnly() )
 						return { form : CKEDITOR.TRISTATE_OFF };
 				});
@@ -138,5 +138,5 @@
 			editor.contextMenu.addListener( function( element )
 				{
-					if ( element )
+					if ( element && !element.isReadOnly() )
 					{
 						var name = element.getName();
Index: CKEditor/trunk/_source/plugins/image/dialogs/image.js
===================================================================
--- CKEditor/trunk/_source/plugins/image/dialogs/image.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/image/dialogs/image.js	(revision 5812)
@@ -251,5 +251,8 @@
 		};
 
-		var numbering = function( id ){ return id + CKEDITOR.tools.getNextNumber(); },
+		var numbering = function( id )
+			{
+				return CKEDITOR.tools.getNextId() + '_' + id;
+			},
 			btnLockSizesId = numbering( 'btnLockSizes' ),
 			btnResetSizeId = numbering( 'btnResetSize' ),
Index: CKEditor/trunk/_source/plugins/image/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/image/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/image/plugin.js	(revision 5812)
@@ -54,5 +54,5 @@
 			editor.contextMenu.addListener( function( element, selection )
 				{
-					if ( !element || !element.is( 'img' ) || element.getAttribute( '_cke_realelement' ) )
+					if ( !element || !element.is( 'img' ) || element.getAttribute( '_cke_realelement' ) || element.isReadOnly() )
 						return null;
 
Index: CKEditor/trunk/_source/plugins/indent/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/indent/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/indent/plugin.js	(revision 5812)
@@ -54,5 +54,5 @@
 		else
 		{
-			var indent = parseInt( firstBlock.getStyle( this.indentCssProperty ), 10 );
+			var indent = parseInt( firstBlock.getStyle( getIndentCssProperty( firstBlock ) ), 10 );
 			if ( isNaN( indent ) )
 				indent = 0;
@@ -62,185 +62,4 @@
 		}
 	}
-
-	function indentList( editor, range, listNode )
-	{
-		// Our starting and ending points of the range might be inside some blocks under a list item...
-		// So before playing with the iterator, we need to expand the block to include the list items.
-		var startContainer = range.startContainer,
-			endContainer = range.endContainer;
-		while ( startContainer && !startContainer.getParent().equals( listNode ) )
-			startContainer = startContainer.getParent();
-		while ( endContainer && !endContainer.getParent().equals( listNode ) )
-			endContainer = endContainer.getParent();
-
-		if ( !startContainer || !endContainer )
-			return;
-
-		// Now we can iterate over the individual items on the same tree depth.
-		var block = startContainer,
-			itemsToMove = [],
-			stopFlag = false;
-		while ( !stopFlag )
-		{
-			if ( block.equals( endContainer ) )
-				stopFlag = true;
-			itemsToMove.push( block );
-			block = block.getNext();
-		}
-		if ( itemsToMove.length < 1 )
-			return;
-
-		// Do indent or outdent operations on the array model of the list, not the
-		// list's DOM tree itself. The array model demands that it knows as much as
-		// possible about the surrounding lists, we need to feed it the further
-		// ancestor node that is still a list.
-		var listParents = listNode.getParents( true );
-		for ( var i = 0 ; i < listParents.length ; i++ )
-		{
-			if ( listParents[i].getName && listNodeNames[ listParents[i].getName() ] )
-			{
-				listNode = listParents[i];
-				break;
-			}
-		}
-		var indentOffset = this.name == 'indent' ? 1 : -1,
-			startItem = itemsToMove[0],
-			lastItem = itemsToMove[ itemsToMove.length - 1 ],
-			database = {};
-
-		// Convert the list DOM tree into a one dimensional array.
-		var listArray = CKEDITOR.plugins.list.listToArray( listNode, database );
-
-		// Apply indenting or outdenting on the array.
-		var baseIndent = listArray[ lastItem.getCustomData( 'listarray_index' ) ].indent;
-		for ( i = startItem.getCustomData( 'listarray_index' ); i <= lastItem.getCustomData( 'listarray_index' ); i++ )
-		{
-			listArray[ i ].indent += indentOffset;
-			// Make sure the newly created sublist get a brand-new element of the same type. (#5372)
-			var listRoot = listArray[ i ].parent;
-			listArray[ i ].parent = new CKEDITOR.dom.element( listRoot.getName(), listRoot.getDocument() );
-		}
-
-		for ( i = lastItem.getCustomData( 'listarray_index' ) + 1 ;
-				i < listArray.length && listArray[i].indent > baseIndent ; i++ )
-			listArray[i].indent += indentOffset;
-
-		// Convert the array back to a DOM forest (yes we might have a few subtrees now).
-		// And replace the old list with the new forest.
-		var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode, 0 );
-
-		// Avoid nested <li> after outdent even they're visually same,
-		// recording them for later refactoring.(#3982)
-		if ( this.name == 'outdent' )
-		{
-			var parentLiElement;
-			if ( ( parentLiElement = listNode.getParent() ) && parentLiElement.is( 'li' ) )
-			{
-				var children = newList.listNode.getChildren(),
-					pendingLis = [],
-					count = children.count(),
-					child;
-
-				for ( i = count - 1 ; i >= 0 ; i-- )
-				{
-					if ( ( child = children.getItem( i ) ) && child.is && child.is( 'li' )  )
-						pendingLis.push( child );
-				}
-			}
-		}
-
-		if ( newList )
-			newList.listNode.replace( listNode );
-
-		// Move the nested <li> to be appeared after the parent.
-		if ( pendingLis && pendingLis.length )
-		{
-			for (  i = 0; i < pendingLis.length ; i++ )
-			{
-				var li = pendingLis[ i ],
-					followingList = li;
-
-				// Nest preceding <ul>/<ol> inside current <li> if any.
-				while ( ( followingList = followingList.getNext() ) &&
-					   followingList.is &&
-					   followingList.getName() in listNodeNames )
-				{
-					// IE requires a filler NBSP for nested list inside empty list item,
-					// otherwise the list item will be inaccessiable. (#4476)
-					if ( CKEDITOR.env.ie && !li.getFirst( function( node ){ return isNotWhitespaces( node ) && isNotBookmark( node ); } ) )
-						li.append( range.document.createText( '\u00a0' ) );
-
-					li.append( followingList );
-				}
-
-				li.insertAfter( parentLiElement );
-			}
-		}
-
-		// Clean up the markers.
-		CKEDITOR.dom.element.clearAllMarkers( database );
-	}
-
-	function indentBlock( editor, range )
-	{
-		var iterator = range.createIterator(),
-			enterMode = editor.config.enterMode;
-		iterator.enforceRealBlocks = true;
-		iterator.enlargeBr = enterMode != CKEDITOR.ENTER_BR;
-		var block;
-		while ( ( block = iterator.getNextParagraph() ) )
-			indentElement.call( this, editor, block );
-	}
-
-	function indentElement( editor, element )
-		{
-			if ( this.useIndentClasses )
-			{
-				// Transform current class name to indent step index.
-			var indentClass = element.$.className.match( this.classNameRegex ),
-					indentStep = 0;
-				if ( indentClass )
-				{
-					indentClass = indentClass[1];
-					indentStep = this.indentClassMap[ indentClass ];
-				}
-
-				// Operate on indent step index, transform indent step index back to class
-				// name.
-				if ( this.name == 'outdent' )
-					indentStep--;
-				else
-					indentStep++;
-
-			if ( indentStep < 0 )
-				return false;
-
-				indentStep = Math.min( indentStep, editor.config.indentClasses.length );
-				indentStep = Math.max( indentStep, 0 );
-			var className = CKEDITOR.tools.ltrim( element.$.className.replace( this.classNameRegex, '' ) );
-				if ( indentStep < 1 )
-				element.$.className = className;
-				else
-				element.addClass( editor.config.indentClasses[ indentStep - 1 ] );
-			}
-			else
-			{
-			var currentOffset = parseInt( element.getStyle( this.indentCssProperty ), 10 );
-				if ( isNaN( currentOffset ) )
-					currentOffset = 0;
-				currentOffset += ( this.name == 'indent' ? 1 : -1 ) * editor.config.indentOffset;
-
-			if ( currentOffset < 0 )
-				return false;
-
-				currentOffset = Math.max( currentOffset, 0 );
-				currentOffset = Math.ceil( currentOffset / editor.config.indentOffset ) * editor.config.indentOffset;
-			element.setStyle( this.indentCssProperty, currentOffset ? currentOffset + editor.config.indentUnit : '' );
-			if ( element.getAttribute( 'style' ) === '' )
-				element.removeAttribute( 'style' );
-			}
-
-		return true;
-		}
 
 	function indentCommand( editor, name )
@@ -255,7 +74,12 @@
 				this.indentClassMap[ editor.config.indentClasses[i] ] = i + 1;
 		}
-		else
-			this.indentCssProperty = editor.config.contentsLangDirection == 'ltr' ? 'margin-left' : 'margin-right';
+
 		this.startDisabled = name == 'outdent';
+	}
+
+	// Returns the CSS property to be used for identing a given element.
+	function getIndentCssProperty( element )
+	{
+		return element.getComputedStyle( 'direction' ) == 'ltr' ? 'margin-left' : 'margin-right';
 	}
 
@@ -268,53 +92,243 @@
 		exec : function( editor )
 		{
+			var self = this, database = {};
+
+			function indentList( listNode )
+			{
+				// Our starting and ending points of the range might be inside some blocks under a list item...
+				// So before playing with the iterator, we need to expand the block to include the list items.
+				var startContainer = range.startContainer,
+					endContainer = range.endContainer;
+				while ( startContainer && !startContainer.getParent().equals( listNode ) )
+					startContainer = startContainer.getParent();
+				while ( endContainer && !endContainer.getParent().equals( listNode ) )
+					endContainer = endContainer.getParent();
+
+				if ( !startContainer || !endContainer )
+					return;
+
+				// Now we can iterate over the individual items on the same tree depth.
+				var block = startContainer,
+					itemsToMove = [],
+					stopFlag = false;
+				while ( !stopFlag )
+				{
+					if ( block.equals( endContainer ) )
+						stopFlag = true;
+					itemsToMove.push( block );
+					block = block.getNext();
+				}
+				if ( itemsToMove.length < 1 )
+					return;
+
+				// Do indent or outdent operations on the array model of the list, not the
+				// list's DOM tree itself. The array model demands that it knows as much as
+				// possible about the surrounding lists, we need to feed it the further
+				// ancestor node that is still a list.
+				var listParents = listNode.getParents( true );
+				for ( var i = 0 ; i < listParents.length ; i++ )
+				{
+					if ( listParents[i].getName && listNodeNames[ listParents[i].getName() ] )
+					{
+						listNode = listParents[i];
+						break;
+					}
+				}
+				var indentOffset = self.name == 'indent' ? 1 : -1,
+					startItem = itemsToMove[0],
+					lastItem = itemsToMove[ itemsToMove.length - 1 ];
+
+				// Convert the list DOM tree into a one dimensional array.
+				var listArray = CKEDITOR.plugins.list.listToArray( listNode, database );
+
+				// Apply indenting or outdenting on the array.
+				var baseIndent = listArray[ lastItem.getCustomData( 'listarray_index' ) ].indent;
+				for ( i = startItem.getCustomData( 'listarray_index' ); i <= lastItem.getCustomData( 'listarray_index' ); i++ )
+				{
+					listArray[ i ].indent += indentOffset;
+					// Make sure the newly created sublist get a brand-new element of the same type. (#5372)
+					var listRoot = listArray[ i ].parent;
+					listArray[ i ].parent = new CKEDITOR.dom.element( listRoot.getName(), listRoot.getDocument() );
+				}
+
+				for ( i = lastItem.getCustomData( 'listarray_index' ) + 1 ;
+						i < listArray.length && listArray[i].indent > baseIndent ; i++ )
+					listArray[i].indent += indentOffset;
+
+				// Convert the array back to a DOM forest (yes we might have a few subtrees now).
+				// And replace the old list with the new forest.
+				var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode, 0 );
+
+				// Avoid nested <li> after outdent even they're visually same,
+				// recording them for later refactoring.(#3982)
+				if ( self.name == 'outdent' )
+				{
+					var parentLiElement;
+					if ( ( parentLiElement = listNode.getParent() ) && parentLiElement.is( 'li' ) )
+					{
+						var children = newList.listNode.getChildren(),
+							pendingLis = [],
+							count = children.count(),
+							child;
+
+						for ( i = count - 1 ; i >= 0 ; i-- )
+						{
+							if ( ( child = children.getItem( i ) ) && child.is && child.is( 'li' )  )
+								pendingLis.push( child );
+						}
+					}
+				}
+
+				if ( newList )
+					newList.listNode.replace( listNode );
+
+				// Move the nested <li> to be appeared after the parent.
+				if ( pendingLis && pendingLis.length )
+				{
+					for (  i = 0; i < pendingLis.length ; i++ )
+					{
+						var li = pendingLis[ i ],
+							followingList = li;
+
+						// Nest preceding <ul>/<ol> inside current <li> if any.
+						while ( ( followingList = followingList.getNext() ) &&
+							   followingList.is &&
+							   followingList.getName() in listNodeNames )
+						{
+							// IE requires a filler NBSP for nested list inside empty list item,
+							// otherwise the list item will be inaccessiable. (#4476)
+							if ( CKEDITOR.env.ie && !li.getFirst( function( node ){ return isNotWhitespaces( node ) && isNotBookmark( node ); } ) )
+								li.append( range.document.createText( '\u00a0' ) );
+
+							li.append( followingList );
+						}
+
+						li.insertAfter( parentLiElement );
+					}
+				}
+			}
+
+			function indentBlock()
+			{
+				var iterator = range.createIterator(),
+					enterMode = editor.config.enterMode;
+				iterator.enforceRealBlocks = true;
+				iterator.enlargeBr = enterMode != CKEDITOR.ENTER_BR;
+				var block;
+				while ( ( block = iterator.getNextParagraph() ) )
+					indentElement( block );
+			}
+
+			function indentElement( element )
+			{
+				if ( element.getCustomData( 'indent_processed' ) )
+					return false;
+
+				if ( self.useIndentClasses )
+				{
+					// Transform current class name to indent step index.
+					var indentClass = element.$.className.match( self.classNameRegex ),
+							indentStep = 0;
+					if ( indentClass )
+					{
+						indentClass = indentClass[1];
+						indentStep = self.indentClassMap[ indentClass ];
+					}
+
+					// Operate on indent step index, transform indent step index back to class
+					// name.
+					if ( self.name == 'outdent' )
+						indentStep--;
+					else
+						indentStep++;
+
+					if ( indentStep < 0 )
+						return false;
+
+					indentStep = Math.min( indentStep, editor.config.indentClasses.length );
+					indentStep = Math.max( indentStep, 0 );
+					var className = CKEDITOR.tools.ltrim( element.$.className.replace( self.classNameRegex, '' ) );
+					if ( indentStep < 1 )
+						element.$.className = className;
+					else
+						element.addClass( editor.config.indentClasses[ indentStep - 1 ] );
+				}
+				else
+				{
+					var indentCssProperty = getIndentCssProperty( element );
+					var currentOffset = parseInt( element.getStyle( indentCssProperty ), 10 );
+					if ( isNaN( currentOffset ) )
+						currentOffset = 0;
+					currentOffset += ( self.name == 'indent' ? 1 : -1 ) * editor.config.indentOffset;
+
+					if ( currentOffset < 0 )
+						return false;
+
+					currentOffset = Math.max( currentOffset, 0 );
+					currentOffset = Math.ceil( currentOffset / editor.config.indentOffset ) * editor.config.indentOffset;
+					element.setStyle( indentCssProperty, currentOffset ? currentOffset + editor.config.indentUnit : '' );
+					if ( element.getAttribute( 'style' ) === '' )
+						element.removeAttribute( 'style' );
+				}
+
+				CKEDITOR.dom.element.setMarker( database, element, 'indent_processed', true );
+				return true;
+			}
+
 			var selection = editor.getSelection(),
-				range = selection && selection.getRanges()[0];
-
-			var startContainer = range.startContainer,
-				endContainer = range.endContainer,
-				rangeRoot = range.getCommonAncestor(),
-				nearestListBlock = rangeRoot;
-
-			while ( nearestListBlock && !( nearestListBlock.type == CKEDITOR.NODE_ELEMENT &&
-				listNodeNames[ nearestListBlock.getName() ] ) )
-				nearestListBlock = nearestListBlock.getParent();
-
-			// Avoid selection anchors under list root.
-			// <ul>[<li>...</li>]</ul> =>	<ul><li>[...]</li></ul>
-			if ( nearestListBlock && startContainer.type == CKEDITOR.NODE_ELEMENT
-				&& startContainer.getName() in listNodeNames )
-			{
-				var walker = new CKEDITOR.dom.walker( range );
-				walker.evaluator = isListItem;
-				range.startContainer = walker.next();
-			}
-
-			if ( nearestListBlock && endContainer.type == CKEDITOR.NODE_ELEMENT
-				&& endContainer.getName() in listNodeNames )
-			{
-				walker = new CKEDITOR.dom.walker( range );
-				walker.evaluator = isListItem;
-				range.endContainer = walker.previous();
-			}
-
-			var bookmarks = selection.createBookmarks( true );
-
-			if ( nearestListBlock  )
-			{
-				var firstListItem = nearestListBlock.getFirst( function( node )
-					{
-						return node.type == CKEDITOR.NODE_ELEMENT && node.is( 'li' );
-					}),
-					rangeStart = range.startContainer,
-					indentWholeList = firstListItem.equals( rangeStart ) || firstListItem.contains( rangeStart );
-
-				// Indent the entire list if  cursor is inside the first list item. (#3893)
-				if ( !( indentWholeList && indentElement.call( this, editor, nearestListBlock ) ) )
-				indentList.call( this, editor, range, nearestListBlock );
-			}
-			else
-				indentBlock.call( this, editor, range );
-
-			editor.focus();
+				bookmarks = selection.createBookmarks( true ),
+				ranges = selection && selection.getRanges( true ),
+				range;
+
+			var iterator = ranges.createIterator();
+			while ( ( range = iterator.getNextRange() ) )
+			{
+				var startContainer = range.startContainer,
+					endContainer = range.endContainer,
+					rangeRoot = range.getCommonAncestor(),
+					nearestListBlock = rangeRoot;
+
+				while ( nearestListBlock && !( nearestListBlock.type == CKEDITOR.NODE_ELEMENT &&
+					listNodeNames[ nearestListBlock.getName() ] ) )
+					nearestListBlock = nearestListBlock.getParent();
+
+				// Avoid selection anchors under list root.
+				// <ul>[<li>...</li>]</ul> =>	<ul><li>[...]</li></ul>
+				if ( nearestListBlock && startContainer.type == CKEDITOR.NODE_ELEMENT
+					&& startContainer.getName() in listNodeNames )
+				{
+					var walker = new CKEDITOR.dom.walker( range );
+					walker.evaluator = isListItem;
+					range.startContainer = walker.next();
+				}
+
+				if ( nearestListBlock && endContainer.type == CKEDITOR.NODE_ELEMENT
+					&& endContainer.getName() in listNodeNames )
+				{
+					walker = new CKEDITOR.dom.walker( range );
+					walker.evaluator = isListItem;
+					range.endContainer = walker.previous();
+				}
+
+				if ( nearestListBlock  )
+				{
+					var firstListItem = nearestListBlock.getFirst( function( node )
+						{
+							return node.type == CKEDITOR.NODE_ELEMENT && node.is( 'li' );
+						}),
+						rangeStart = range.startContainer,
+						indentWholeList = firstListItem.equals( rangeStart ) || firstListItem.contains( rangeStart );
+
+					// Indent the entire list if  cursor is inside the first list item. (#3893)
+					if ( !( indentWholeList && indentElement( nearestListBlock ) ) )
+						indentList( nearestListBlock );
+				}
+				else
+					indentBlock();
+			}
+
+			// Clean up the markers.
+			CKEDITOR.dom.element.clearAllMarkers( database );
+
 			editor.forceNextSelectionCheck();
 			selection.selectBookmarks( bookmarks );
Index: CKEditor/trunk/_source/plugins/justify/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/justify/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/justify/plugin.js	(revision 5812)
@@ -10,6 +10,4 @@
 (function()
 {
-	var alignRemoveRegex = /(-moz-|-webkit-|start|auto)/i;
-
 	function getState( editor, path )
 	{
@@ -19,8 +17,22 @@
 			return CKEDITOR.TRISTATE_OFF;
 
-		var currentAlign = firstBlock.getComputedStyle( 'text-align' ).replace( alignRemoveRegex, '' );
-		if ( ( !currentAlign && this.isDefaultAlign ) || currentAlign == this.value )
-			return CKEDITOR.TRISTATE_ON;
-		return CKEDITOR.TRISTATE_OFF;
+		return ( getAlignment( firstBlock, editor.config.useComputedState ) == this.value ) ?
+			CKEDITOR.TRISTATE_ON :
+			CKEDITOR.TRISTATE_OFF;
+	}
+
+	function getAlignment( element, useComputedState )
+	{
+		useComputedState = useComputedState === undefined || useComputedState;
+
+		var align = useComputedState ?
+			element.getComputedStyle( 'text-align' ) :
+			element.getStyle( 'text-align' ) || element.getAttribute( 'align' ) || '';
+
+		align && ( align = align.replace( /-moz-|-webkit-|start|auto/i, '' ) );
+
+		!align && useComputedState && ( align = element.getComputedStyle( 'direction' ) == 'rtl' ? 'right' : 'left' );
+
+		return align;
 	}
 
@@ -36,8 +48,4 @@
 		this.name = name;
 		this.value = value;
-
-		var contentDir = editor.config.contentsLangDirection;
-		this.isDefaultAlign = ( value == 'left' && contentDir == 'ltr' ) ||
-			( value == 'right' && contentDir == 'rtl' );
 
 		var classes = editor.config.justifyClasses;
@@ -74,10 +82,13 @@
 
 			var bookmarks = selection.createBookmarks(),
-				ranges = selection.getRanges();
-
+				ranges = selection.getRanges( true );
 
 			var cssClassName = this.cssClassName,
 				iterator,
 				block;
+
+			var useComputedState = editor.config.useComputedState;
+			useComputedState = useComputedState === undefined || useComputedState;
+
 			for ( var i = ranges.length - 1 ; i >= 0 ; i-- )
 			{
@@ -88,24 +99,24 @@
 				{
 					block.removeAttribute( 'align' );
+					block.removeStyle( 'text-align' );
+
+					// Remove any of the alignment classes from the className.
+					var className = cssClassName && ( block.$.className =
+						CKEDITOR.tools.ltrim( block.$.className.replace( this.cssClassRegex, '' ) ) );
+
+					var apply =
+						( this.state == CKEDITOR.TRISTATE_OFF ) &&
+						( !useComputedState || ( getAlignment( block, true ) != this.value ) );
 
 					if ( cssClassName )
 					{
-						// Remove any of the alignment classes from the className.
-						var className = block.$.className =
-							CKEDITOR.tools.ltrim( block.$.className.replace( this.cssClassRegex, '' ) );
-
 						// Append the desired class name.
-						if ( this.state == CKEDITOR.TRISTATE_OFF && !this.isDefaultAlign )
+						if ( apply )
 							block.addClass( cssClassName );
 						else if ( !className )
 							block.removeAttribute( 'class' );
 					}
-					else
-					{
-						if ( this.state == CKEDITOR.TRISTATE_OFF && !this.isDefaultAlign )
-							block.setStyle( 'text-align', this.value );
-						else
-							block.removeStyle( 'text-align' );
-					}
+					else if ( apply )
+						block.setStyle( 'text-align', this.value );
 				}
 
Index: CKEditor/trunk/_source/plugins/link/dialogs/link.js
===================================================================
--- CKEditor/trunk/_source/plugins/link/dialogs/link.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/link/dialogs/link.js	(revision 5812)
@@ -1295,5 +1295,5 @@
 				// Create element if current selection is collapsed.
 				var selection = editor.getSelection(),
-					ranges = selection.getRanges();
+					ranges = selection.getRanges( true );
 				if ( ranges.length == 1 && ranges[0].collapsed )
 				{
Index: CKEditor/trunk/_source/plugins/link/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/link/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/link/plugin.js	(revision 5812)
@@ -59,5 +59,5 @@
 				 */
 				var command = editor.getCommand( 'unlink' ),
-					element = evt.data.path.lastElement.getAscendant( 'a', true );
+					element = evt.data.path.lastElement && evt.data.path.lastElement.getAscendant( 'a', true );
 				if ( element && element.getName() == 'a' && element.getAttribute( 'href' ) )
 					command.setState( CKEDITOR.TRISTATE_OFF );
@@ -111,5 +111,5 @@
 			editor.contextMenu.addListener( function( element, selection )
 				{
-					if ( !element )
+					if ( !element || element.isReadOnly() )
 						return null;
 
@@ -178,10 +178,12 @@
 	{
 		var range;
-		try { range  = editor.getSelection().getRanges()[ 0 ]; }
+		try
+		{
+			range  = editor.getSelection().getRanges( true )[ 0 ];
+			range.shrink( CKEDITOR.SHRINK_TEXT );
+			var root = range.getCommonAncestor();
+			return root.getAscendant( 'a', true );
+		}
 		catch( e ) { return null; }
-
-		range.shrink( CKEDITOR.SHRINK_TEXT );
-		var root = range.getCommonAncestor();
-		return root.getAscendant( 'a', true );
 	}
 };
Index: CKEditor/trunk/_source/plugins/list/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/list/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/list/plugin.js	(revision 5812)
@@ -68,5 +68,5 @@
 
 		// Convert our internal representation of a list back to a DOM forest.
-		arrayToList : function( listArray, database, baseIndex, paragraphMode )
+		arrayToList : function( listArray, database, baseIndex, paragraphMode, dir )
 		{
 			if ( !baseIndex )
@@ -110,6 +110,10 @@
 					{
 						// Create completely new blocks here, attributes are dropped.
-						if ( paragraphMode != CKEDITOR.ENTER_BR && item.grandparent.getName() != 'td' )
+						if ( dir || ( paragraphMode != CKEDITOR.ENTER_BR && item.grandparent.getName() != 'td' ) )
+						{
 							currentListItem = doc.createElement( paragraphName );
+							if ( dir )
+								currentListItem.setAttribute( 'dir', dir );
+						}
 						else
 							currentListItem = new CKEDITOR.dom.documentFragment( doc );
@@ -287,5 +291,6 @@
 		// Insert the list to the DOM tree.
 		var insertAnchor = listContents[ listContents.length - 1 ].getNext(),
-			listNode = doc.createElement( this.type );
+			listNode = doc.createElement( this.type ),
+			dir;
 
 		listsCreated.push( listNode );
@@ -300,4 +305,9 @@
 			else
 			{
+				if ( contentBlock.hasAttribute( 'dir' ) )
+				{
+					dir = dir || contentBlock.getAttribute( 'dir' );
+					contentBlock.removeAttribute( 'dir' );
+				}
 				contentBlock.copyAttributes( listItem );
 				contentBlock.moveChildren( listItem );
@@ -311,4 +321,8 @@
 				listItem.appendBogus();
 		}
+
+		if ( dir )
+			listNode.setAttribute( 'dir', dir );
+
 		if ( insertAnchor )
 			listNode.insertBefore( insertAnchor );
@@ -360,5 +374,6 @@
 		}
 
-		var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode );
+		var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode,
+			groupObj.root.getAttribute( 'dir' ) );
 
 		// Compensate <br> before/after the list node if the surrounds are non-blocks.(#3836)
@@ -392,5 +407,5 @@
 			var doc = editor.document,
 				selection = editor.getSelection(),
-				ranges = selection && selection.getRanges();
+				ranges = selection && selection.getRanges( true );
 
 			// There should be at least one selected range.
@@ -440,9 +455,20 @@
 			// or multiple lists have to be cancelled.
 			var listGroups = [],
-				database = {};
-
-			while ( ranges.length > 0 )
-			{
-				range = ranges.shift();
+				database = {},
+				rangeIterator = ranges.createIterator(),
+				index = 0;
+
+			while ( ( range = rangeIterator.getNextRange() ) && ++index )
+			{
+				var boundaryNodes = range.getBoundaryNodes(),
+					startNode = boundaryNodes.startNode,
+					endNode = boundaryNodes.endNode;
+
+				if ( startNode.type == CKEDITOR.NODE_ELEMENT && startNode.getName() == 'td' )
+					range.setStartAt( boundaryNodes.startNode, CKEDITOR.POSITION_AFTER_START );
+
+				if ( endNode.type == CKEDITOR.NODE_ELEMENT && endNode.getName() == 'td' )
+					range.setEndAt( boundaryNodes.endNode, CKEDITOR.POSITION_BEFORE_END );
+
 				var iterator = range.createIterator(),
 					block;
@@ -452,4 +478,10 @@
 				while ( ( block = iterator.getNextParagraph() ) )
 				{
+					// Avoid duplicate blocks get processed across ranges.
+					if( block.getCustomData( 'list_block' ) )
+						continue;
+					else
+						CKEDITOR.dom.element.setMarker( database, block, 'list_block', 1 );
+
 					var path = new CKEDITOR.dom.elementPath( block ),
 						pathElements = path.elements,
@@ -471,5 +503,5 @@
 							// should belong to a different group of paragraphs before
 							// the list. (Bug #1309)
-							blockLimit.removeCustomData( 'list_group_object' );
+							blockLimit.removeCustomData( 'list_group_object_' + index );
 
 							var groupObj = element.getCustomData( 'list_group_object' );
@@ -490,12 +522,12 @@
 						continue;
 
-					// No list ancestor? Group by block limit.
+					// No list ancestor? Group by block limit, but don't mix contents from different ranges.
 					var root = blockLimit;
-					if ( root.getCustomData( 'list_group_object' ) )
-						root.getCustomData( 'list_group_object' ).contents.push( block );
+					if ( root.getCustomData( 'list_group_object_' + index ) )
+						root.getCustomData( 'list_group_object_' + index ).contents.push( block );
 					else
 					{
 						groupObj = { root : root, contents : [ block ] };
-						CKEDITOR.dom.element.setMarker( database, root, 'list_group_object', groupObj );
+						CKEDITOR.dom.element.setMarker( database, root, 'list_group_object_' + index, groupObj );
 						listGroups.push( groupObj );
 					}
@@ -531,5 +563,5 @@
 						'getPrevious' : 'getNext' ]( CKEDITOR.dom.walker.whitespaces( true ) );
 					if ( sibling && sibling.getName &&
-					     sibling.getName() == listCommand.type )
+						 sibling.getName() == listCommand.type )
 					{
 						sibling.remove();
Index: CKEditor/trunk/_source/plugins/liststyle/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/liststyle/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/liststyle/plugin.js	(revision 5812)
@@ -44,4 +44,7 @@
 				editor.contextMenu.addListener( function( element, selection )
 					{
+						if ( !element || element.isReadOnly() )
+							return null;
+
 						while ( element )
 						{
Index: CKEditor/trunk/_source/plugins/pagebreak/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/pagebreak/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/pagebreak/plugin.js	(revision 5812)
@@ -83,13 +83,13 @@
 		breakObject = editor.createFakeElement( breakObject, 'cke_pagebreak', 'div' );
 
-		var ranges = editor.getSelection().getRanges();
+		var ranges = editor.getSelection().getRanges( true );
 
 		editor.fire( 'saveSnapshot' );
 
-		for ( var range, i = 0 ; i < ranges.length ; i++ )
+		for ( var range, i = ranges.length - 1 ; i >= 0; i-- )
 		{
 			range = ranges[ i ];
 
-			if ( i > 0 )
+			if ( i < ranges.length -1 )
 				breakObject = breakObject.clone( true );
 
Index: CKEditor/trunk/_source/plugins/removeformat/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/removeformat/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/removeformat/plugin.js	(revision 5812)
@@ -36,7 +36,9 @@
 
 				var filter = CKEDITOR.plugins.removeformat.filter;
-				var ranges = editor.getSelection().getRanges();
+				var ranges = editor.getSelection().getRanges( true ),
+					iterator = ranges.createIterator(),
+					range;
 
-				for ( var i = 0, range ; range = ranges[ i ] ; i++ )
+				while ( ( range = iterator.getNextRange() ) )
 				{
 					if ( range.collapsed )
Index: CKEditor/trunk/_source/plugins/scayt/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/scayt/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/scayt/plugin.js	(revision 5812)
@@ -625,7 +625,8 @@
 			if ( editor.contextMenu && editor.addMenuItems )
 			{
-				editor.contextMenu.addListener( function(  )
-					{
-						if ( !plugin.isScaytEnabled( editor ) )
+				editor.contextMenu.addListener( function( element, selection )
+					{
+						if ( !plugin.isScaytEnabled( editor )
+								|| selection.getCommonAncestor().isReadOnly() )
 							return null;
 
Index: CKEditor/trunk/_source/plugins/selection/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/selection/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/selection/plugin.js	(revision 5812)
@@ -526,6 +526,7 @@
 		 * alert(ranges.length);
 		 */
-		getRanges :
-			CKEDITOR.env.ie ?
+		getRanges : (function ()
+		{
+			var func = CKEDITOR.env.ie ?
 				( function()
 				{
@@ -615,8 +616,4 @@
 					return function()
 					{
-						var cache = this._.cache;
-						if ( cache.ranges )
-							return cache.ranges;
-
 						// IE doesn't have range support (in the W3C way), so we
 						// need to do some magic to transform selections into
@@ -641,9 +638,9 @@
 							range.setEnd( new CKEDITOR.dom.node( boundaryInfo.container ), boundaryInfo.offset );
 
-							return ( cache.ranges = [ range ] );
+							return [ range ];
 						}
 						else if ( type == CKEDITOR.SELECTION_ELEMENT )
 						{
-							var retval = this._.cache.ranges = [];
+							var retval = [];
 
 							for ( var i = 0 ; i < nativeRange.length ; i++ )
@@ -666,5 +663,5 @@
 						}
 
-						return ( cache.ranges = [] );
+						return [];
 					};
 				})()
@@ -672,7 +669,4 @@
 				function()
 				{
-					var cache = this._.cache;
-					if ( cache.ranges )
-						return cache.ranges;
 
 					// On browsers implementing the W3C range, we simply
@@ -695,7 +689,99 @@
 						ranges.push( range );
 					}
-
-					return ( cache.ranges = ranges );
-				},
+					return ranges;
+				};
+
+			return function( onlyEditables )
+			{
+				var cache = this._.cache;
+				if ( cache.ranges && !onlyEditables )
+					return cache.ranges;
+				else if ( !cache.ranges )
+					cache.ranges = new CKEDITOR.dom.rangeList( func.call( this ) );
+
+				// Split range into multiple by read-only nodes.
+				if ( onlyEditables )
+				{
+					var ranges = cache.ranges;
+					for ( var i = 0; i < ranges.length; i++ )
+					{
+						var range = ranges[ i ];
+
+						// Drop range spans inside one ready-only node.
+						var parent = range.getCommonAncestor();
+						if ( parent.isReadOnly())
+							ranges.splice( i, 1 );
+
+						if ( range.collapsed )
+							continue;
+
+						var startContainer = range.startContainer,
+							endContainer = range.endContainer,
+							startOffset = range.startOffset,
+							endOffset = range.endOffset,
+							walkerRange = range.clone();
+
+						// Range may start inside a non-editable element, restart range
+						// by the end of it.
+						var readOnly;
+						if ( ( readOnly = startContainer.isReadOnly() ) )
+							range.setStartAfter( readOnly );
+
+						// Enlarge range start/end with text node to avoid walker
+						// being DOM destructive, it doesn't interfere our checking
+						// of elements below as well.
+						if ( startContainer && startContainer.type == CKEDITOR.NODE_TEXT )
+						{
+							if ( startOffset >= startContainer.getLength() )
+								walkerRange.setStartAfter( startContainer );
+							else
+								walkerRange.setStartBefore( startContainer );
+						}
+
+						if ( endContainer && endContainer.type == CKEDITOR.NODE_TEXT )
+						{
+							if ( !endOffset )
+								walkerRange.setEndBefore( endContainer );
+							else
+								walkerRange.setEndAfter( endContainer );
+						}
+
+						// Looking for non-editable element inside the range.
+						var walker = new CKEDITOR.dom.walker( walkerRange );
+						walker.evaluator = function( node )
+						{
+							if ( node.type == CKEDITOR.NODE_ELEMENT
+								&& node.getAttribute( 'contenteditable' ) == 'false' )
+							{
+								var newRange = range.clone();
+								range.setEndBefore( node );
+
+								// Drop collapsed range around read-only elements,
+								// it make sure the range list empty when selecting
+								// only non-editable elements.
+								if ( range.collapsed )
+									ranges.splice( i--, 1 );
+
+								// Avoid creating invalid range.
+								if ( !( node.getPosition( walkerRange.endContainer ) & CKEDITOR.POSITION_CONTAINS ) )
+								{
+									newRange.setStartAfter( node );
+									if ( !newRange.collapsed )
+										ranges.splice( i + 1, 0, newRange );
+								}
+
+								return true;
+							}
+
+							return false;
+						};
+
+						walker.next();
+					}
+				}
+
+				return cache.ranges;
+			};
+		})(),
 
 		/**
@@ -901,5 +987,5 @@
 				this._.cache.selectedElement = element;
 				this._.cache.startElement = element;
-				this._.cache.ranges = [ range ];
+				this._.cache.ranges = new CKEDITOR.dom.rangeList( range );
 				this._.cache.type = CKEDITOR.SELECTION_ELEMENT;
 
@@ -957,6 +1043,6 @@
 			{
 				this._.cache.selectedElement = null;
-				this._.cache.startElement = ranges[ 0 ].getTouchedStartNode();
-				this._.cache.ranges = ranges;
+				this._.cache.startElement = ranges[ 0 ] && ranges[ 0 ].getTouchedStartNode();
+				this._.cache.ranges = new CKEDITOR.dom.rangeList( ranges );
 				this._.cache.type = CKEDITOR.SELECTION_TEXT;
 
@@ -966,6 +1052,12 @@
 			if ( CKEDITOR.env.ie )
 			{
-				// IE doesn't accept multiple ranges selection, so we just
-				// select the first one.
+				if ( ranges.length > 1 )
+				{
+					// IE doesn't accept multiple ranges selection, so we join all into one.
+					var last = ranges[ ranges.length -1 ] ;
+					ranges[ 0 ].setEnd( last.endContainer, last.endOffset );
+					ranges.length = 1;
+				}
+
 				if ( ranges[ 0 ] )
 					ranges[ 0 ].select();
@@ -976,8 +1068,33 @@
 			{
 				var sel = this.getNative();
-				sel.removeAllRanges();
+
+				if ( ranges.length )
+					sel.removeAllRanges();
 
 				for ( var i = 0 ; i < ranges.length ; i++ )
 				{
+					// Joining sequential ranges introduced by
+					// readonly elements protection.
+					if ( i < ranges.length -1 )
+					{
+						var left = ranges[ i ], right = ranges[ i +1 ],
+								between = left.clone();
+						between.setStart( left.endContainer, left.endOffset );
+						between.setEnd( right.startContainer, right.startOffset );
+
+						// Don't confused by Firefox adjancent multi-ranges
+						// introduced by table cells selection.
+						if ( !between.collapsed )
+						{
+							between.shrink( CKEDITOR.NODE_ELEMENT, true );
+							if ( between.getCommonAncestor().isReadOnly())
+							{
+								right.setStart( left.startContainer, left.startOffset );
+								ranges.splice( i--, 1 );
+								continue;
+							}
+						}
+					}
+
 					var range = ranges[ i ];
 					var nativeRange = this.document.$.createRange();
@@ -1014,32 +1131,5 @@
 		createBookmarks : function( serializable )
 		{
-			var retval = [],
-				ranges = this.getRanges(),
-				length = ranges.length,
-				bookmark;
-			for ( var i = 0; i < length ; i++ )
-			{
-			    retval.push( bookmark = ranges[ i ].createBookmark( serializable, true ) );
-
-				serializable = bookmark.serializable;
-
-				var bookmarkStart = serializable ? this.document.getById( bookmark.startNode ) : bookmark.startNode,
-					bookmarkEnd = serializable ? this.document.getById( bookmark.endNode ) : bookmark.endNode;
-
-			    // Updating the offset values for rest of ranges which have been mangled(#3256).
-			    for ( var j = i + 1 ; j < length ; j++ )
-			    {
-			        var dirtyRange = ranges[ j ],
-			               rangeStart = dirtyRange.startContainer,
-			               rangeEnd = dirtyRange.endContainer;
-
-			       rangeStart.equals( bookmarkStart.getParent() ) && dirtyRange.startOffset++;
-			       rangeStart.equals( bookmarkEnd.getParent() ) && dirtyRange.startOffset++;
-			       rangeEnd.equals( bookmarkStart.getParent() ) && dirtyRange.endOffset++;
-			       rangeEnd.equals( bookmarkEnd.getParent() ) && dirtyRange.endOffset++;
-			    }
-			}
-
-			return retval;
+			return this.getRanges().createBookmarks( serializable );
 		},
 
@@ -1052,11 +1142,5 @@
 		createBookmarks2 : function( normalized )
 		{
-			var bookmarks = [],
-				ranges = this.getRanges();
-
-			for ( var i = 0 ; i < ranges.length ; i++ )
-				bookmarks.push( ranges[i].createBookmark2( normalized ) );
-
-			return bookmarks;
+			return this.getRanges().createBookmarks2( normalized );
 		},
 
Index: CKEditor/trunk/_source/plugins/showborders/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/showborders/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/showborders/plugin.js	(revision 5812)
@@ -162,4 +162,30 @@
 					};
 			} );
+
+			var advTab = dialogDefinition.getContents( 'advanced' ),
+				classField = advTab && advTab.get( 'advCSSClasses' );
+
+			if ( classField )
+			{
+				classField.setup = CKEDITOR.tools.override( classField.setup, function( originalSetup )
+					{
+						return function()
+							{
+								originalSetup.apply( this, arguments );
+								this.setValue( this.getValue().replace( /cke_show_border/, '' ) );
+							};
+					});
+
+				classField.commit = CKEDITOR.tools.override( classField.commit, function( originalCommit )
+					{
+						return function( data, element )
+							{
+								originalCommit.apply( this, arguments );
+
+								if ( !parseInt( element.getAttribute( 'border' ), 10 ) )
+									element.addClass( 'cke_show_border' );
+							};
+					});
+			}
 		}
 	});
Index: CKEditor/trunk/_source/plugins/smiley/dialogs/smiley.js
===================================================================
--- CKEditor/trunk/_source/plugins/smiley/dialogs/smiley.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/smiley/dialogs/smiley.js	(revision 5812)
@@ -132,5 +132,5 @@
 
 	// Build the HTML for the smiley images table.
-	var labelId = 'smiley_emtions_label' + CKEDITOR.tools.getNextNumber();
+	var labelId = CKEDITOR.tools.getNextId() + '_smiley_emtions_label';
 	var html =
 	[
Index: CKEditor/trunk/_source/plugins/specialchar/dialogs/specialchar.js
===================================================================
--- CKEditor/trunk/_source/plugins/specialchar/dialogs/specialchar.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/specialchar/dialogs/specialchar.js	(revision 5812)
@@ -16,20 +16,23 @@
 	{
 		var selection = editor.getSelection(),
-			ranges	  = selection.getRanges(),
+			ranges = selection.getRanges( true ),
 			range, textNode;
 
 		editor.fire( 'saveSnapshot' );
 
-		for ( var i = 0, len = ranges.length ; i < len ; i++ )
+		for ( var i = ranges.length - 1; i >= 0 ; i-- )
 		{
 			range = ranges[ i ];
 			range.deleteContents();
 
-			textNode =  CKEDITOR.dom.element.createFromHtml( specialChar );
+			textNode = CKEDITOR.dom.element.createFromHtml( specialChar );
 			range.insertNode( textNode );
 		}
 
-		range.moveToPosition( textNode, CKEDITOR.POSITION_AFTER_END );
-		range.select();
+		if ( range )
+		{
+			range.moveToPosition( textNode, CKEDITOR.POSITION_AFTER_END );
+			range.select();
+		}
 
 		editor.fire( 'saveSnapshot' );
@@ -263,5 +266,5 @@
 				chars = this.definition.chars;
 
-			var charsTableLabel =  'specialchar_table_label' + CKEDITOR.tools.getNextNumber();
+			var charsTableLabel =  CKEDITOR.tools.getNextId() + '_specialchar_table_label';
 			var html = [ '<table role="listbox" aria-labelledby="' + charsTableLabel + '"' +
 						 			' style="width: 320px; height: 100%; border-collapse: separate;"' +
Index: CKEditor/trunk/_source/plugins/styles/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/styles/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/styles/plugin.js	(revision 5812)
@@ -377,7 +377,4 @@
 		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 );
@@ -545,7 +542,7 @@
 		}
 
-		firstNode.remove();
-		lastNode.remove();
-		range.moveToBookmark( bookmark );
+		// Remove the bookmark nodes.
+		range.moveToBookmark( boundaryNodes );
+
 		// Minimize the result range to exclude empty text nodes. (#5374)
 		range.shrink( CKEDITOR.SHRINK_TEXT );
@@ -586,10 +583,12 @@
 				if ( this.checkElementRemovable( element ) )
 				{
-					var endOfElement = range.checkBoundaryOfElement( element, CKEDITOR.END ),
-							startOfElement = !endOfElement && range.checkBoundaryOfElement( element, CKEDITOR.START );
-					if ( startOfElement || endOfElement )
+					var isStart;
+
+					if ( range.collapsed && (
+						 range.checkBoundaryOfElement( element, CKEDITOR.END ) ||
+						 ( isStart = range.checkBoundaryOfElement( element, CKEDITOR.START ) ) ) )
 					{
 						boundaryElement = element;
-						boundaryElement.match = startOfElement ? 'start' : 'end';
+						boundaryElement.match = isStart ? 'start' : 'end';
 					}
 					else
@@ -1275,15 +1274,22 @@
 	function applyStyle( document, remove )
 	{
-		// Get all ranges from the selection.
-		var selection = document.getSelection();
-		var ranges = selection.getRanges();
-		var func = remove ? this.removeFromRange : this.applyToRange;
-
-		// Apply the style to the ranges.
-		for ( var i = 0 ; i < ranges.length ; i++ )
-			func.call( this, ranges[ i ] );
-
-		// Select the ranges again.
-		selection.selectRanges( ranges );
+		var selection = document.getSelection(),
+			// Bookmark the range so we can re-select it after processing.
+			bookmarks = selection.createBookmarks(),
+			ranges = selection.getRanges( true ),
+			func = remove ? this.removeFromRange : this.applyToRange,
+			range;
+
+		var iterator = ranges.createIterator();
+		while ( ( range = iterator.getNextRange() ) )
+			func.call( this, range );
+
+		if ( bookmarks.length == 1 && bookmarks[0].collapsed )
+		{
+			selection.selectRanges( ranges );
+			bookmarks[0].startNode.remove();
+		}
+		else
+			selection.selectBookmarks( bookmarks );
 	}
 })();
Index: CKEditor/trunk/_source/plugins/tab/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/tab/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/tab/plugin.js	(revision 5812)
@@ -28,4 +28,76 @@
 		};
 
+	function selectNextCellCommand( backward )
+	{
+		return {
+			editorFocus : false,
+			canUndo : false,
+			modes : { wysiwyg : 1 },
+			exec : function( editor )
+			{
+				if ( editor.focusManager.hasFocus )
+				{
+					var sel = editor.getSelection(),
+							ancestor = sel.getCommonAncestor(),
+							cell;
+
+					if ( ( cell = ( ancestor.getAscendant( 'td', true ) || ancestor.getAscendant( 'th', true ) ) ) )
+					{
+						var resultRange = new CKEDITOR.dom.range( editor.document ),
+								next = CKEDITOR.tools.tryThese( function()
+								{
+									var row = cell.getParent(),
+											next = row.$.cells[ cell.$.cellIndex + ( backward ? - 1 : 1 ) ];
+
+									// Invalid any empty value.
+									next.parentNode.parentNode;
+									return next;
+								},
+								function()
+								{
+									var row = cell.getParent(),
+											table = row.getAscendant( 'table' ),
+											nextRow = table.$.rows[ row.$.rowIndex + ( backward ? - 1 : 1 ) ];
+
+									return nextRow.cells[ backward? nextRow.cells.length -1 : 0 ];
+								});
+
+						// Clone one more row at the end of table and select the first newly established cell.
+						if ( ! ( next || backward ) )
+						{
+							var table = cell.getAscendant( 'table' ).$,
+									cells = cell.getParent().$.cells;
+
+							var newRow = new CKEDITOR.dom.element( table.insertRow( -1 ), editor.document );
+
+							for ( var i = 0, count = cells.length ; i < count; i++ )
+							{
+								var newCell = newRow.append( new CKEDITOR.dom.element(
+										cells[ i ], editor.document ).clone( false, false ) );
+								!CKEDITOR.env.ie && newCell.appendBogus();
+							}
+
+							resultRange.moveToElementEditStart( newRow );
+						}
+						else if ( next )
+						{
+							next = new CKEDITOR.dom.element( next );
+							resultRange.moveToElementEditStart( next );
+							// Avoid selecting empty block makes the cursor blind.
+							if ( !( resultRange.checkStartOfBlock() && resultRange.checkEndOfBlock() ) )
+								resultRange.selectNodeContents( next );
+						}
+						else
+							return true;
+
+						resultRange.select( true );
+						return true;
+					}
+				}
+				return false;
+			}
+		};
+	}
+
 	CKEDITOR.plugins.add( 'tab',
 	{
@@ -34,5 +106,6 @@
 		init : function( editor )
 		{
-			var tabSpaces = editor.config.tabSpaces || 0,
+			var tabTools = editor.config.enableTabKeyTools !== false,
+				tabSpaces = editor.config.tabSpaces || 0,
 				tabText = '';
 
@@ -52,4 +125,14 @@
 			}
 
+			if ( tabTools )
+			{
+				editor.on( 'key', function( ev )
+				{
+					if ( ev.data.keyCode == 9 && editor.execCommand( 'selectNextCell' ) ||	// TAB
+							ev.data.keyCode == ( CKEDITOR.SHIFT + 9 ) && editor.execCommand( 'selectPreviousCell' ) )	// SHIFT+TAB
+						ev.cancel();
+				});
+			}
+
 			if ( CKEDITOR.env.webkit || CKEDITOR.env.gecko )
 			{
@@ -74,4 +157,6 @@
 			editor.addCommand( 'blur', CKEDITOR.tools.extend( blurCommand, meta ) );
 			editor.addCommand( 'blurBack', CKEDITOR.tools.extend( blurBackCommand, meta ) );
+			editor.addCommand( 'selectNextCell', selectNextCellCommand() );
+			editor.addCommand( 'selectPreviousCell', selectNextCellCommand( true ) );
 		}
 	});
@@ -260,2 +345,23 @@
  * config.tabSpaces = 4;
  */
+
+/**
+ * Allow context-sensitive tab key behaviors, including the following scenarios:
+ * <h5>When selection is anchored inside <b>table cells</b>:</h5>
+ * <ul>
+ * 		<li>If TAB is pressed, select the contents of the "next" cell. If in the last cell in the table, add a new row to it and focus its first cell.</li>
+ * 		<li>If SHIFT+TAB is pressed, select the contents of the "previous" cell. Do nothing when it's in the first cell.</li>
+ * </ul>
+ * @name CKEDITOR.config.enableTabKeyTools
+ * @type Boolean
+ * @default true
+ * @example
+ * config.enableTabKeyTools = false;
+ */
+
+// If the TAB key is not supposed to be enabled for navigation, the following
+// settings could be used alternatively:
+// config.keystrokes.push(
+//	[ CKEDITOR.ALT + 38 /*Arrow Up*/, 'selectPreviousCell' ],
+//	[ CKEDITOR.ALT + 40 /*Arrow Down*/, 'selectNextCell' ]
+// );
Index: CKEditor/trunk/_source/plugins/table/dialogs/table.js
===================================================================
--- CKEditor/trunk/_source/plugins/table/dialogs/table.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/table/dialogs/table.js	(revision 5812)
@@ -19,5 +19,10 @@
 	function tableDialog( editor, command )
 	{
-		var makeElement = function( name ){ return new CKEDITOR.dom.element( name, editor.document ); };
+		var makeElement = function( name )
+			{
+				return new CKEDITOR.dom.element( name, editor.document );
+			};
+
+		var dialogadvtab = editor.plugins.dialogadvtab;
 
 		return {
@@ -25,4 +30,49 @@
 			minWidth : 310,
 			minHeight : CKEDITOR.env.ie ? 310 : 280,
+
+			onLoad : function()
+			{
+				var dialog = this,
+					isUpdating;
+
+				var styles = dialog.getContentElement( 'advanced', 'advStyles' );
+
+				if ( styles )
+				{
+					styles.on( 'change', function( evt )
+						{
+							if ( isUpdating )
+								return;
+
+							// Flag to avoid recursion.
+							isUpdating = 1;
+
+							// Synchronize width value.
+							var width = this.getStyle( 'width', '' ),
+								txtWidth = dialog.getContentElement( 'info', 'txtWidth' ),
+								cmbWidthType = dialog.getContentElement( 'info', 'cmbWidthType' ),
+								isPx = 1;
+
+							if ( width )
+							{
+								isPx = ( width.length < 3 || width.substr( width.length - 1 ) != '%' );
+								width = parseInt( width, 10 );
+							}
+
+							txtWidth && txtWidth.setValue( width );
+							cmbWidthType && cmbWidthType.setValue( isPx ? 'pixels' : 'percents' );
+
+							// Synchronize height value.
+							var height = this.getStyle( 'height', '' ),
+								txtHeight = dialog.getContentElement( 'info', 'txtHeight' );
+
+							height && ( height = parseInt( height, 10 ) );
+							txtHeight && txtHeight.setValue( height );
+
+							isUpdating = 0;
+						});
+				}
+			},
+
 			onShow : function()
 			{
@@ -34,5 +84,7 @@
 				var rowsInput = this.getContentElement( 'info', 'txtRows' ),
 					colsInput = this.getContentElement( 'info', 'txtCols' ),
-					widthInput = this.getContentElement( 'info', 'txtWidth' );
+					widthInput = this.getContentElement( 'info', 'txtWidth' ),
+					heightInput = this.getContentElement( 'info', 'txtHeight' );
+
 				if ( command == 'tableProperties' )
 				{
@@ -71,4 +123,9 @@
 					rowsInput && rowsInput.select();
 				}
+
+				// Call the onChange method for the widht and height fields so
+				// they get reflected into the Advanced tab.
+				widthInput && widthInput.onChange();
+				heightInput && heightInput.onChange();
 			},
 			onOk : function()
@@ -381,5 +438,5 @@
 													style : 'width:5em',
 													label : editor.lang.table.width,
-													'default' : 200,
+													'default' : 500,
 													validate : CKEDITOR.dialog.validate['number']( editor.lang.table.invalidWidth ),
 
@@ -393,4 +450,19 @@
 
 														inputElement.setAttribute( 'aria-labelledby', [ ariaLabelledByAttr, labelElement.$.id ].join( ' ' ) );
+													},
+
+													onChange : function()
+													{
+														var styles = this.getDialog().getContentElement( 'advanced', 'advStyles' );
+
+														if ( styles )
+														{
+															var value = this.getValue();
+
+															if ( value )
+																value += this.getDialog().getContentElement( 'info', 'cmbWidthType' ).getValue() == 'percents' ? '%' : 'px';
+
+															styles.updateStyle( 'width', value );
+														}
 													},
 
@@ -422,4 +494,8 @@
 															this.setValue( widthMatch[2] == 'px' ? 'pixels' : 'percents' );
 													},
+													onChange : function()
+													{
+														this.getDialog().getContentElement( 'info', 'txtWidth' ).onChange();
+													},
 													commit : commitValue
 												}
@@ -448,4 +524,15 @@
 
 														inputElement.setAttribute( 'aria-labelledby', [ ariaLabelledByAttr, labelElement.$.id ].join( ' ' ) );
+													},
+
+													onChange : function()
+													{
+														var styles = this.getDialog().getContentElement( 'advanced', 'advStyles' );
+
+														if ( styles )
+														{
+															var value = this.getValue();
+															styles.updateStyle( 'height', value && ( value + 'px' ) );
+														}
 													},
 
@@ -583,5 +670,6 @@
 						}
 					]
-				}
+				},
+				dialogadvtab && dialogadvtab.createAdvancedTab( editor )
 			]
 		};
Index: CKEditor/trunk/_source/plugins/table/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/table/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/table/plugin.js	(revision 5812)
@@ -59,5 +59,5 @@
 			editor.contextMenu.addListener( function( element, selection )
 				{
-					if ( !element )
+					if ( !element || element.isReadOnly())
 						return null;
 
Index: CKEditor/trunk/_source/plugins/tableresize/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/tableresize/plugin.js	(revision 5812)
+++ CKEditor/trunk/_source/plugins/tableresize/plugin.js	(revision 5812)
@@ -0,0 +1,450 @@
+﻿/*
+Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+(function()
+{
+	var pxUnit = CKEDITOR.tools.cssLength,
+		needsIEHacks = CKEDITOR.env.ie && ( CKEDITOR.env.ie7Compat || CKEDITOR.env.quirks || CKEDITOR.env.version < 7 );
+
+	function getWidth( el )
+	{
+		return CKEDITOR.env.ie ? el.$.clientWidth : parseInt( el.getComputedStyle( 'width' ), 10 );
+	}
+
+	function getBorderWidth( element, side )
+	{
+		var computed = element.getComputedStyle( 'border-' + side + '-width' ),
+			borderMap =
+			{
+				thin: '0px',
+				medium: '1px',
+				thick: '2px'
+			};
+
+		if ( computed.indexOf( 'px' ) < 0 )
+		{
+			// look up keywords
+			if ( computed in borderMap && element.getComputedStyle( 'border-style' ) != 'none' )
+				computed = borderMap[ computed ];
+			else
+				computed = 0;
+		}
+
+		return parseInt( computed, 10 );
+	}
+
+	// Gets the table row that contains the most columns.
+	function getMasterPillarRow( table )
+	{
+		var $rows = table.$.rows,
+			maxCells = 0, cellsCount,
+			$elected, $tr;
+
+		for ( var i = 0, len = $rows.length ; i < len; i++ )
+		{
+			$tr = $rows[ i ];
+			cellsCount = $tr.cells.length;
+
+			if ( cellsCount > maxCells )
+			{
+				maxCells = cellsCount;
+				$elected = $tr;
+			}
+		}
+
+		return $elected;
+	}
+
+	function buildTableColumnPillars( table )
+	{
+		var pillars = [],
+			pillarIndex = -1,
+			rtl = ( table.getComputedStyle( 'direction' ) == 'rtl' );
+
+		// Get the raw row element that cointains the most columns.
+		var $tr = getMasterPillarRow( table );
+
+		// Get the tbody element and position, which will be used to set the
+		// top and bottom boundaries.
+		var tbody = new CKEDITOR.dom.element( table.$.tBodies[ 0 ] ),
+			tbodyPosition = tbody.getDocumentPosition();
+
+		// Loop thorugh all cells, building pillars after each one of them.
+		for ( var i = 0, len = $tr.cells.length ; i < len ; i++ )
+		{
+			// Both the current cell and the successive one will be used in the
+			// pillar size calculation.
+			var td = new CKEDITOR.dom.element( $tr.cells[ i ] ),
+				nextTd = $tr.cells[ i + 1 ] && new CKEDITOR.dom.element( $tr.cells[ i + 1 ] );
+
+			pillarIndex += td.$.colSpan || 1;
+
+			// Calculate the pillar boundary positions.
+			var pillarLeft, pillarRight, pillarWidth, pillarPadding;
+
+			var x = td.getDocumentPosition().x;
+
+			// Calculate positions based on the current cell.
+			rtl ?
+				pillarRight = x + getBorderWidth( td, 'left' ) :
+				pillarLeft  = x + td.$.offsetWidth - getBorderWidth( td, 'right' );
+
+			// Calculate positions based on the next cell, if available.
+			if ( nextTd )
+			{
+				x =  nextTd.getDocumentPosition().x;
+
+				rtl ?
+					pillarLeft	= x + nextTd.$.offsetWidth - getBorderWidth( nextTd, 'right' ) :
+					pillarRight	= x + getBorderWidth( nextTd, 'left' );
+			}
+			// Otherwise calculate positions based on the table (for last cell).
+			else
+			{
+				x =  table.getDocumentPosition().x;
+
+				rtl ?
+					pillarLeft	= x :
+					pillarRight	= x + table.$.offsetWidth;
+			}
+
+			pillarWidth = Math.max( pillarRight - pillarLeft, 3 );
+
+			// Make the pillar touch area at least 14 pixels wide, for easy to use.
+			pillarPadding = Math.max( Math.round( 7 - ( pillarWidth / 2 ) ), 0 );
+
+			// The pillar should reflects exactly the shape of the hovered
+			// column border line.
+			pillars.push( {
+				table : table,
+				index : pillarIndex,
+				x : pillarLeft,
+				y : tbodyPosition.y,
+				width : pillarWidth,
+				height: tbody.$.offsetHeight,
+				padding : pillarPadding,
+				rtl : rtl } );
+		}
+
+		return pillars;
+	}
+
+	function getPillarAtPosition( pillars, positionX )
+	{
+		for ( var i = 0, len = pillars.length ; i < len ; i++ )
+		{
+			var pillar = pillars[ i ],
+				pad = pillar.padding;
+
+			if ( positionX >= pillar.x - pad && positionX <= ( pillar.x + pillar.width + pad ) )
+				return pillar;
+		}
+
+		return null;
+	}
+
+	function cancel( evt )
+	{
+		( evt.data || evt ).preventDefault();
+	}
+
+	function columnResizer( editor )
+	{
+		var pillar,
+			document,
+			resizer,
+			isResizing,
+			startOffset,
+			currentShift;
+
+		var leftSideCells, rightSideCells, leftShiftBoundary, rightShiftBoundary;
+
+		function detach()
+		{
+			pillar = null;
+			currentShift = 0;
+			isResizing = 0;
+
+			document.removeListener( 'mouseup', onMouseUp );
+			resizer.removeListener( 'mousedown', onMouseDown );
+			resizer.removeListener( 'mousemove', onMouseMove );
+
+			document.getBody().setStyle( 'cursor', 'auto' );
+
+			// Hide the resizer (remove it on IE7 - #5890).
+			needsIEHacks ? resizer.remove() : resizer.hide();
+		}
+
+		function resizeStart()
+		{
+			// Before starting to resize, figure out which cells to change
+			// and the boundaries of this resizing shift.
+
+			var columnIndex = pillar.index,
+				map = CKEDITOR.tools.buildTableMap( pillar.table ),
+				leftColumnCells = [],
+				rightColumnCells = [],
+				leftMinSize = Number.MAX_VALUE,
+				rightMinSize = leftMinSize,
+				rtl = pillar.rtl;
+
+			for ( var i = 0, len = map.length ; i < len ; i++ )
+			{
+				var row			= map[ i ],
+					leftCell	= row[ columnIndex + ( rtl ? 1 : 0 ) ],
+					rightCell	= row[ columnIndex + ( rtl ? 0 : 1 ) ];
+
+				leftCell	= leftCell && new CKEDITOR.dom.element( leftCell );
+				rightCell	= rightCell && new CKEDITOR.dom.element( rightCell );
+
+				if ( !leftCell || !rightCell || !leftCell.equals( rightCell ) )
+				{
+					leftCell && ( leftMinSize = Math.min( leftMinSize, getWidth( leftCell ) ) );
+					rightCell && ( rightMinSize = Math.min( rightMinSize, getWidth( rightCell ) ) );
+
+					leftColumnCells.push( leftCell );
+					rightColumnCells.push( rightCell );
+				}
+			}
+
+			// Cache the list of cells to be resized.
+			leftSideCells = leftColumnCells;
+			rightSideCells = rightColumnCells;
+
+			// Cache the resize limit boundaries.
+			leftShiftBoundary =  pillar.x - leftMinSize;
+			rightShiftBoundary = pillar.x + rightMinSize;
+
+			resizer.setOpacity( 0.5 );
+			startOffset = parseInt( resizer.getStyle( 'left' ), 10 );
+			currentShift = 0;
+			isResizing = 1;
+
+			resizer.on( 'mousemove', onMouseMove );
+
+			// Prevent the native drag behavior otherwise 'mousemove' won't fire.
+			document.on( 'dragstart', cancel );
+		}
+
+		function resizeEnd()
+		{
+			isResizing = 0;
+
+			resizer.setOpacity( 0 );
+
+			currentShift && resizeColumn();
+
+			var table = pillar.table;
+			setTimeout( function () { table.removeCustomData( '_cke_table_pillars' ); }, 0 );
+
+			document.removeListener( 'dragstart', cancel );
+		}
+
+		function resizeColumn()
+		{
+			var rtl = pillar.rtl,
+				cellsCount = rtl ? rightSideCells.length : leftSideCells.length;
+
+			// Perform the actual resize to table cells, only for those by side of the pillar.
+			for ( var i = 0 ; i < cellsCount ; i++ )
+			{
+				var leftCell = leftSideCells[ i ],
+					rightCell = rightSideCells[ i ],
+					table = pillar.table;
+
+				// Defer the resizing to avoid any interference among cells.
+				CKEDITOR.tools.setTimeout(
+					function( leftCell, leftOldWidth, rightCell, rightOldWidth, tableWidth, sizeShift )
+					{
+						leftCell && leftCell.setStyle( 'width', pxUnit( Math.max( leftOldWidth + sizeShift, 0 ) ) );
+						rightCell && rightCell.setStyle( 'width', pxUnit( Math.max( rightOldWidth - sizeShift, 0 ) ) );
+
+						// If we're in the last cell, we need to resize the table as well
+						if ( tableWidth )
+							table.setStyle( 'width', pxUnit( tableWidth + sizeShift * ( rtl ? -1 : 1 ) ) );
+					}
+					, 0,
+					this, [
+						leftCell, leftCell && getWidth( leftCell ),
+						rightCell, rightCell && getWidth( rightCell ),
+						( !leftCell || !rightCell ) && ( getWidth( table ) + getBorderWidth( table, 'left' ) + getBorderWidth( table, 'right' ) ),
+						currentShift ] );
+			}
+		}
+
+		function onMouseDown( evt )
+		{
+			cancel( evt );
+
+			resizeStart();
+
+			document.on( 'mouseup', onMouseUp, this );
+		}
+
+		function onMouseUp( evt )
+		{
+			evt.removeListener();
+
+			resizeEnd();
+		}
+
+		function onMouseMove( evt )
+		{
+			move( evt.data.$.clientX );
+		}
+
+		document = editor.document;
+
+		resizer = CKEDITOR.dom.element.createFromHtml(
+			'<div cke_temp=1 contenteditable=false unselectable=on '+
+			'style="position:absolute;cursor:col-resize;filter:alpha(opacity=0);opacity:0;' +
+				'padding:0;background-color:#004;background-image:none;border:0px none;z-index:10"></div>', document );
+
+		// Except on IE6/7 (#5890), place the resizer after body to prevent it
+		// from being editable.
+		if ( !needsIEHacks )
+			document.getDocumentElement().append( resizer );
+
+		this.attachTo = function( targetPillar )
+		{
+			// Accept only one pillar at a time.
+			if ( isResizing )
+				return;
+
+			// On IE6/7, we append the resizer everytime we need it. (#5890)
+			if ( needsIEHacks )
+			{
+				document.getBody().append( resizer );
+				currentShift = 0;
+			}
+
+			pillar = targetPillar;
+
+			resizer.setStyles(
+				{
+					width: pxUnit( targetPillar.width ),
+					height : pxUnit( targetPillar.height ),
+					left : pxUnit( targetPillar.x ),
+					top : pxUnit( targetPillar.y )
+				});
+
+			// In IE6/7, it's not possible to have custom cursors for floating
+			// elements in an editable document. Show the resizer in that case,
+			// to give the user a visual clue.
+			needsIEHacks && resizer.setOpacity( 0.25 );
+
+			resizer.on( 'mousedown', onMouseDown, this );
+
+			document.getBody().setStyle( 'cursor', 'col-resize' );
+
+			// Display the resizer to receive events but don't show it,
+			// only change the cursor to resizable shape.
+			resizer.show();
+		};
+
+		var move = this.move = function( posX )
+		{
+			if ( !pillar )
+				return 0;
+
+			var pad = pillar.padding;
+
+			if ( !isResizing && ( posX < pillar.x - pad || posX > ( pillar.x + pillar.width + pad ) ) )
+			{
+				detach();
+				return 0;
+			}
+
+			var resizerNewPosition = posX - Math.round( resizer.$.offsetWidth / 2 );
+
+			if ( isResizing )
+			{
+				if ( resizerNewPosition == leftShiftBoundary || resizerNewPosition == rightShiftBoundary )
+					return 1;
+
+				resizerNewPosition = Math.max( resizerNewPosition, leftShiftBoundary );
+				resizerNewPosition = Math.min( resizerNewPosition, rightShiftBoundary );
+
+				currentShift = resizerNewPosition - startOffset;
+			}
+
+			resizer.setStyle( 'left', pxUnit( resizerNewPosition ) );
+
+			return 1;
+		};
+	}
+
+	function clearPillarsCache( evt )
+	{
+		var target = evt.data.getTarget();
+
+		if ( evt.name == 'mouseout' )
+		{
+			// Bypass interal mouse move.
+			if ( !target.is ( 'table' ) )
+				return;
+
+			var dest = new CKEDITOR.dom.element( evt.data.$.relatedTarget || evt.data.$.toElement );
+			while( dest && dest.$ && !dest.equals( target ) && !dest.is( 'body' ) )
+				dest = dest.getParent();
+			if ( !dest || dest.equals( target ) )
+				return;
+		}
+
+		target.getAscendant( 'table', true ).removeCustomData( '_cke_table_pillars' );
+		evt.removeListener();
+	}
+
+	CKEDITOR.plugins.add( 'tableresize',
+	{
+		requires : [ 'tabletools' ],
+		init : function( editor )
+		{
+			editor.on( 'contentDom', function()
+			{
+				var resizer;
+
+				editor.document.getBody().on( 'mousemove', function( evt )
+					{
+						evt = evt.data;
+
+						// If we're already attached to a pillar, simply move the
+						// resizer.
+						if ( resizer && resizer.move( evt.$.clientX ) )
+						{
+							cancel( evt );
+							return;
+						}
+
+						// Considering table, tr, td, tbody but nothing else.
+						var target = evt.getTarget(),
+							table,
+							pillars;
+
+						if ( !target.is( 'table' ) && !target.getAscendant( 'tbody', true ) )
+							return;
+
+						table = target.getAscendant( 'table', true );
+
+						if ( !( pillars = table.getCustomData( '_cke_table_pillars' ) ) )
+						{
+							// Cache table pillars calculation result.
+							table.setCustomData( '_cke_table_pillars', ( pillars = buildTableColumnPillars( table ) ) );
+							table.on( 'mouseout', clearPillarsCache );
+							table.on( 'mousedown', clearPillarsCache );
+						}
+
+						var pillar = getPillarAtPosition( pillars, evt.$.clientX );
+						if ( pillar )
+						{
+							!resizer && ( resizer = new columnResizer( editor ) );
+							resizer.attachTo( pillar );
+						}
+					});
+			});
+		}
+	});
+
+})();
Index: CKEditor/trunk/_source/plugins/tabletools/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/tabletools/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/tabletools/plugin.js	(revision 5812)
@@ -399,49 +399,4 @@
 		}
 		range.select( true );
-	}
-
-	function buildTableMap( table )
-	{
-
-		var aRows = table.$.rows ;
-
-		// Row and Column counters.
-		var r = -1 ;
-
-		var aMap = [];
-
-		for ( var i = 0 ; i < aRows.length ; i++ )
-		{
-			r++ ;
-			!aMap[r] && ( aMap[r] = [] );
-
-			var c = -1 ;
-
-			for ( var j = 0 ; j < aRows[i].cells.length ; j++ )
-			{
-				var oCell = aRows[i].cells[j] ;
-
-				c++ ;
-				while ( aMap[r][c] )
-					c++ ;
-
-				var iColSpan = isNaN( oCell.colSpan ) ? 1 : oCell.colSpan ;
-				var iRowSpan = isNaN( oCell.rowSpan ) ? 1 : oCell.rowSpan ;
-
-				for ( var rs = 0 ; rs < iRowSpan ; rs++ )
-				{
-					if ( !aMap[r + rs] )
-						aMap[r + rs] = new Array() ;
-
-					for ( var cs = 0 ; cs < iColSpan ; cs++ )
-					{
-						aMap[r + rs][c + cs] = aRows[i].cells[j] ;
-					}
-				}
-
-				c += iColSpan - 1 ;
-			}
-		}
-		return aMap ;
 	}
 
@@ -499,5 +454,5 @@
 			firstCell = cells[ 0 ],
 			table = firstCell.getAscendant( 'table' ),
-			map = buildTableMap( table ),
+			map = CKEDITOR.tools.buildTableMap( table ),
 			mapHeight = map.length,
 			mapWidth = map[ 0 ].length,
@@ -634,5 +589,5 @@
 			tr = cell.getParent(),
 			table = tr.getAscendant( 'table' ),
-			map = buildTableMap( table ),
+			map = CKEDITOR.tools.buildTableMap( table ),
 			rowIndex = tr.$.rowIndex,
 			colIndex = cellInRow( map, rowIndex, cell ),
@@ -710,5 +665,5 @@
 			tr = cell.getParent(),
 			table = tr.getAscendant( 'table' ),
-			map = buildTableMap( table ),
+			map = CKEDITOR.tools.buildTableMap( table ),
 			rowIndex = tr.$.rowIndex,
 			colIndex = cellInRow( map, rowIndex, cell ),
@@ -1089,5 +1044,5 @@
 				editor.contextMenu.addListener( function( element, selection )
 					{
-						if ( !element )
+						if ( !element || element.isReadOnly() )
 							return null;
 
@@ -1115,2 +1070,51 @@
 	CKEDITOR.plugins.add( 'tabletools', CKEDITOR.plugins.tabletools );
 })();
+
+/**
+ * Create a two-dimension array that reflects the actual layout of table cells,
+ * with cell spans, with mappings to the original td elements.
+ * @param table {CKEDITOR.dom.element}
+ */
+CKEDITOR.tools.buildTableMap = function ( table )
+{
+	var aRows = table.$.rows ;
+
+	// Row and Column counters.
+	var r = -1 ;
+
+	var aMap = [];
+
+	for ( var i = 0 ; i < aRows.length ; i++ )
+	{
+		r++ ;
+		!aMap[r] && ( aMap[r] = [] );
+
+		var c = -1 ;
+
+		for ( var j = 0 ; j < aRows[i].cells.length ; j++ )
+		{
+			var oCell = aRows[i].cells[j] ;
+
+			c++ ;
+			while ( aMap[r][c] )
+				c++ ;
+
+			var iColSpan = isNaN( oCell.colSpan ) ? 1 : oCell.colSpan ;
+			var iRowSpan = isNaN( oCell.rowSpan ) ? 1 : oCell.rowSpan ;
+
+			for ( var rs = 0 ; rs < iRowSpan ; rs++ )
+			{
+				if ( !aMap[r + rs] )
+					aMap[r + rs] = [];
+
+				for ( var cs = 0 ; cs < iColSpan ; cs++ )
+				{
+					aMap[r + rs][c + cs] = aRows[i].cells[j] ;
+				}
+			}
+
+			c += iColSpan - 1 ;
+		}
+	}
+	return aMap ;
+};
Index: CKEditor/trunk/_source/plugins/toolbar/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/toolbar/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/toolbar/plugin.js	(revision 5812)
@@ -434,4 +434,5 @@
 	['NumberedList','BulletedList','-','Outdent','Indent','Blockquote','CreateDiv'],
 	['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],
+	['BidiLtr', 'BidiRtl'],
 	['Link','Unlink','Anchor'],
 	['Image','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak'],
Index: CKEditor/trunk/_source/plugins/wysiwygarea/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/wysiwygarea/plugin.js	(revision 5802)
+++ CKEditor/trunk/_source/plugins/wysiwygarea/plugin.js	(revision 5812)
@@ -19,4 +19,12 @@
 	var notWhitespaceEval = CKEDITOR.dom.walker.whitespaces( true );
 
+	function checkReadOnly( selection )
+	{
+		if ( selection.getType() == CKEDITOR.SELECTION_ELEMENT )
+			return selection.getSelectedElement().isReadOnly();
+		else
+			return selection.getCommonAncestor().isReadOnly();
+	}
+
 	function onInsertHtml( evt )
 	{
@@ -24,8 +32,11 @@
 		{
 			this.focus();
+
+			var selection = this.getSelection();
+			if ( checkReadOnly( selection ) )
+				return;
+
+			var data = evt.data;
 			this.fire( 'saveSnapshot' );
-
-			var selection = this.getSelection(),
-				data = evt.data;
 
 			if ( this.dataProcessor )
@@ -40,6 +51,27 @@
 
 				var $sel = selection.getNative();
+
+				// Delete control selections to avoid IE bugs on pasteHTML.
 				if ( $sel.type == 'Control' )
 					$sel.clear();
+				else if  ( selection.getType() == CKEDITOR.SELECTION_TEXT )
+				{
+					// Due to IE bugs on handling contenteditable=false blocks
+					// (#6005), we need to make some checks and eventually
+					// delete the selection first.
+
+					var range = selection.getRanges()[0],
+						endContainer = range && range.endContainer;
+
+					if ( endContainer &&
+ 						 endContainer.type == CKEDITOR.NODE_ELEMENT &&
+ 						 endContainer.getAttribute( 'contenteditable' ) == 'false' &&
+						 range.checkBoundaryOfElement( endContainer, CKEDITOR.END ) )
+					{
+						range.setEndAfter( range.endContainer );
+						range.deleteContents();
+					}
+				}
+
 				$sel.createRange().pasteHTML( data );
 
@@ -71,12 +103,15 @@
 		{
 			this.focus();
+
+			var selection = this.getSelection();
+			if ( checkReadOnly( selection ) )
+				return;
+
 			this.fire( 'saveSnapshot' );
 
-			var element = evt.data,
+			var ranges = selection.getRanges(),
+				element = evt.data,
 				elementName = element.getName(),
 				isBlock = CKEDITOR.dtd.$block[ elementName ];
-
-			var selection = this.getSelection(),
-				ranges = selection.getRanges();
 
 			var selIsLocked = selection.isLocked;
@@ -378,4 +413,8 @@
   							'></iframe>' );
 
+						// #5689 Running inside of Firefox chrome the load event doesn't bubble like in a normal page
+						if (document.location.protocol == 'chrome:')
+							CKEDITOR.event.useCapture = true;
+
 						// With FF, it's better to load the data on iframe.load. (#3894,#4058)
 						iframe.on( 'load', function( ev )
@@ -391,4 +430,8 @@
 								doc.close();
 							});
+
+						// #5689 Reset adjustment back to default
+						if (document.location.protocol == 'chrome:')
+							CKEDITOR.event.useCapture = false;
 
 						mainElement.append( iframe );
@@ -493,4 +536,12 @@
 							} );
 						}
+
+						// Prevent the browser opening links in read-only blocks. (#6032)
+						domDocument.on( 'click', function( ev )
+							{
+								ev = ev.data;
+								if ( ev.getTarget().is( 'a' ) && ev.$.button != 2 )
+									ev.preventDefault();
+							});
 
 						// Webkit: avoid from editing form control elements content.
@@ -934,5 +985,11 @@
 						&& ( element.is( 'input' ) || element.is( 'textarea' ) ) )
 				{
-					element.setAttribute( 'contentEditable', false );
+					if ( !element.isReadOnly() )
+					{
+						element.setAttribute( 'contentEditable', false );
+						// We should flag that the element was locked by our code so
+						// it'll be editable by the editor functions (#6046).
+						element.setCustomData( '_cke_notReadOnly', 1 );
+					}
 				}
 			});
Index: CKEditor/trunk/_source/skins/kama/dialog.css
===================================================================
--- CKEditor/trunk/_source/skins/kama/dialog.css	(revision 5802)
+++ CKEditor/trunk/_source/skins/kama/dialog.css	(revision 5812)
@@ -611,5 +611,5 @@
 }
 
-.cke_skin_kama iframe.cke_dialog_ui_input_file
+.cke_skin_kama .cke_dialog_ui_input_file
 {
 	width: 100%;
Index: CKEditor/trunk/_source/skins/kama/icons.css
===================================================================
--- CKEditor/trunk/_source/skins/kama/icons.css	(revision 5802)
+++ CKEditor/trunk/_source/skins/kama/icons.css	(revision 5812)
@@ -321,6 +321,17 @@
 	background-position: 0 -1040px;
 }
-.cke_skin_office2003 .cke_button_editdiv .cke_icon
+
+.cke_skin_kama .cke_button_editdiv .cke_icon
 {
 	background-position: 0 -1184px;
 }
+
+.cke_skin_kama .cke_button_bidirtl .cke_icon
+{
+	background-position: 0 -1072px;
+}
+
+.cke_skin_kama .cke_button_bidiltr .cke_icon
+{
+	background-position: 0 -1056px;
+}
Index: CKEditor/trunk/_source/skins/office2003/dialog.css
===================================================================
--- CKEditor/trunk/_source/skins/office2003/dialog.css	(revision 5802)
+++ CKEditor/trunk/_source/skins/office2003/dialog.css	(revision 5812)
@@ -542,5 +542,5 @@
 }
 
-.cke_skin_office2003 iframe.cke_dialog_ui_input_file
+.cke_skin_office2003 .cke_dialog_ui_input_file
 {
 	width: 100%;
Index: CKEditor/trunk/_source/skins/office2003/icons.css
===================================================================
--- CKEditor/trunk/_source/skins/office2003/icons.css	(revision 5802)
+++ CKEditor/trunk/_source/skins/office2003/icons.css	(revision 5812)
@@ -323,2 +323,12 @@
 	background-position: 0 -1200px;
 }
+
+.cke_skin_office2003 .cke_button_bidirtl .cke_icon
+{
+	background-position: 0 -1072px;
+}
+
+.cke_skin_office2003 .cke_button_bidiltr .cke_icon
+{
+	background-position: 0 -1056px;
+}
Index: CKEditor/trunk/_source/skins/v2/dialog.css
===================================================================
--- CKEditor/trunk/_source/skins/v2/dialog.css	(revision 5802)
+++ CKEditor/trunk/_source/skins/v2/dialog.css	(revision 5812)
@@ -544,5 +544,5 @@
 }
 
-.cke_skin_v2 iframe.cke_dialog_ui_input_file
+.cke_skin_v2 .cke_dialog_ui_input_file
 {
 	width: 100%;
Index: CKEditor/trunk/_source/skins/v2/icons.css
===================================================================
--- CKEditor/trunk/_source/skins/v2/icons.css	(revision 5802)
+++ CKEditor/trunk/_source/skins/v2/icons.css	(revision 5812)
@@ -323,2 +323,12 @@
 	background-position: 0 -1200px;
 }
+
+.cke_skin_v2 .cke_button_bidirtl .cke_icon
+{
+	background-position: 0 -1072px;
+}
+
+.cke_skin_v2 .cke_button_bidiltr .cke_icon
+{
+	background-position: 0 -1056px;
+}
Index: CKEditor/trunk/ckeditor.pack
===================================================================
--- CKEditor/trunk/ckeditor.pack	(revision 5802)
+++ CKEditor/trunk/ckeditor.pack	(revision 5812)
@@ -130,4 +130,5 @@
 					'_source/core/dom/walker.js',
 					'_source/core/dom/range.js',
+					'_source/core/dom/rangelist.js',
 					'_source/core/_bootstrap.js',
 					'_source/skins/kama/skin.js',
@@ -136,4 +137,5 @@
 					'_source/plugins/a11yhelp/plugin.js',
 					'_source/plugins/basicstyles/plugin.js',
+					'_source/plugins/bidi/plugin.js',
 					'_source/plugins/blockquote/plugin.js',
 					'_source/plugins/button/plugin.js',
@@ -142,4 +144,5 @@
 					'_source/plugins/colordialog/plugin.js',
 					'_source/plugins/contextmenu/plugin.js',
+					'_source/plugins/dialogadvtab/plugin.js',
 					'_source/plugins/div/plugin.js',
 					'_source/plugins/elementspath/plugin.js',
