Index: _source/plugins/tableresize/plugin.js
===================================================================
--- _source/plugins/tableresize/plugin.js	(revision 5730)
+++ _source/plugins/tableresize/plugin.js	(working copy)
@@ -3,255 +3,377 @@
 For licensing, see LICENSE.html or http://ckeditor.com/license
 */
 
-( function()
+(function()
 {
-	var pxUnit = CKEDITOR.tools.cssLength;
+	var pxUnit = CKEDITOR.tools.cssLength,
+		needsIEHacks = CKEDITOR.env.ie && ( CKEDITOR.env.ie7Compat || CKEDITOR.env.quirks || CKEDITOR.env.version < 7 );
 
-	function getCellWidth( cell )
+	function getWidth( el )
 	{
-		return CKEDITOR.env.ie ? cell.$.clientWidth : parseInt( cell.getComputedStyle( 'width' ), 10 );
+		return CKEDITOR.env.ie ? el.$.clientWidth : parseInt( el.getComputedStyle( 'width' ), 10 );
 	}
 
-	function getCellBorderWidth( cell, side )
+	function getBorderWidth( element, side )
 	{
-		var computed = cell.getComputedStyle( 'border-' + side + '-width' ),
+		var computed = element.getComputedStyle( 'border-' + side + '-width' ),
 			borderMap =
 			{
-				thin: '2px',
-				medium: '4px',
-				thick: '6px'
+				thin: '0px',
+				medium: '1px',
+				thick: '2px'
 			};
 
 		if ( computed.indexOf( 'px' ) < 0 )
 		{
 			// look up keywords
-			if ( computed in borderMap && cell.getComputedStyle( 'border-style' ) != 'none' )
+			if ( computed in borderMap && element.getComputedStyle( 'border-style' ) != 'none' )
 				computed = borderMap[ computed ];
 			else
 				computed = 0;
 		}
 
-		return computed;
+		return parseInt( computed, 10 );
 	}
-
-	function buildTableColumnPillars( tableElement )
+	
+	// Gets the table row that contains the most columns.
+	function getMasterPillarRow( table )
 	{
-		var table = tableElement.$;
+		var $rows = table.$.rows,
+			maxCells = 0, cellsCount,
+			$elected, $tr;
 
-		// Elect the table row that contains the most columns.
-		var maxCells = 0, elected;
-		for ( var i = 0, rowCount = table.rows.length ; i < rowCount; i++ )
+		for ( var i = 0, len = $rows.length ; i < len; i++ )
 		{
-			var tr = table.rows[ i ], cellsCount = tr.cells.length;
+			$tr = $rows[ i ];
+			cellsCount = $tr.cells.length;
 
 			if ( cellsCount > maxCells )
 			{
 				maxCells = cellsCount;
-				elected = tr;
+				$elected = $tr;
 			}
 		}
+		
+		return $elected;
+	}
 
-		tr = elected;
-		var columnIndex = -1, pillars = [];
-		var tbody = new CKEDITOR.dom.element( table.tBodies[ 0 ] ),
-				tbodyPosition = tbody.getDocumentPosition();
-		for ( var j = 0, colCount = tr.cells.length ; j < colCount ; j++ )
+	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++ )
 		{
-			var td = new CKEDITOR.dom.element( tr.cells[ j ] ),
-					nextTd = tr.cells[ j + 1 ] && new CKEDITOR.dom.element( tr.cells[ j + 1 ] );
+			// 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 ] );
 
-			columnIndex += td.$.colSpan || 1;
-			var cellPosition =  td.getDocumentPosition(),
-					rangeLeft = cellPosition.x + td.$.offsetWidth - parseInt( getCellBorderWidth ( td, 'right' ), 10 );
+			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 )
 			{
-				cellPosition =  nextTd.getDocumentPosition();
-				var rangeRight = cellPosition.x + parseInt( getCellBorderWidth( nextTd, 'left' ), 10 );
+				x =  nextTd.getDocumentPosition().x;
 
-				// Compsensate for too "slim" line between columns, make the pillar shown easier.
-				if ( rangeRight - rangeLeft < 8 )
-				{
-					rangeLeft-= 4;
-					rangeRight += 4;
-				}
+				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;
 
-				var columnWidth = rangeRight - rangeLeft;
+				rtl ?
+					pillarLeft	= x :
+					pillarRight	= x + table.$.offsetWidth;
+			}
 
-				// The pillar should reflects exactly the shape of the hovered column border line.
-				pillars.push({ table : tableElement, index : columnIndex, x : rangeLeft, y : tbodyPosition.y , width : columnWidth, height: tbody.$.offsetHeight });
-			}
+			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, position )
+	function getPillarAtPosition( pillars, positionX )
 	{
-		for ( var i = 0, length = pillars.length; i < length; i++ )
+		for ( var i = 0, len = pillars.length ; i < len ; i++ )
 		{
-			if ( position.x > pillars[ i ].x && position.x - pillars[ i ].x < pillars[ i ].width )
-				return pillars[ 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.preventDefault();
+		( evt.data || evt ).preventDefault();
 	}
 
 	function columnResizer( editor )
 	{
-		var pillar, document, resizer, startOffset, currentShift;
+		var pillar, 
+			document, 
+			resizer, 
+			isResizing,
+			startOffset, 
+			currentShift;
 
 		var leftSideCells, rightSideCells, leftShiftBoundary, rightShiftBoundary;
 
 		function detach()
 		{
 			pillar = null;
-			currentShift = null;
-			document.removeListener( 'mousemove', onMouseMove );
+			currentShift = 0;
+			isResizing = 0;
+
 			document.removeListener( 'mouseup', onMouseUp );
 			resizer.removeListener( 'mousedown', onMouseDown );
-			resizer.removeListener( 'mouseout', onMouseOut );
-			resizer.hide();
+			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;
+				map = CKEDITOR.tools.buildTableMap( pillar.table ),
+				leftColumnCells = [],
+				rightColumnCells = [],
+				leftMinSize = Number.MAX_VALUE,
+				rightMinSize = leftMinSize,
+				rtl = pillar.rtl;
 
-			for ( var i = 0, rowCount = map.length; i < rowCount; i++ )
+			for ( var i = 0, len = map.length ; i < len ; i++ )
 			{
-				var row = map[ i ],
-						leftCell = new CKEDITOR.dom.element( row[ columnIndex ] ),
-						rightCell = new CKEDITOR.dom.element( row[ columnIndex + 1 ] );
+				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.equals( rightCell ) )
+				if ( !leftCell || !rightCell || !leftCell.equals( rightCell ) )
 				{
-					leftMinSize = Math.min( leftMinSize, getCellWidth( leftCell ) );
-					rightMinSize = Math.min( rightMinSize, getCellWidth( 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;
-			document.on( 'mousemove', onMouseMove, this );
-			// Prevent the native drag behavior otherwise the above 'mousemove' won't fired.
-			document.on( 'dragstart', cancel, this );
+			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 );
 
-			detach();
+			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, count = leftSideCells.length; i < count; i++ )
+			for ( var i = 0 ; i < cellsCount ; i++ )
 			{
 				var leftCell = leftSideCells[ i ],
-						rightCell = rightSideCells[ i ];
-
+					rightCell = rightSideCells[ i ],
+					table = pillar.table;
+				
 				// Defer the resizing to avoid any interference among cells.
-				( function( leftCell, leftOldWidth, rightCell, rightOldWidth, sizeShift )
-				{
-					CKEDITOR.tools.setTimeout( function()
+				CKEDITOR.tools.setTimeout(
+					function( leftCell, leftOldWidth, rightCell, rightOldWidth, tableWidth, sizeShift )
 					{
-						leftCell.setStyle( 'width', pxUnit(  leftOldWidth + sizeShift ) );
-						rightCell.setStyle( 'width', pxUnit(  rightOldWidth - sizeShift ) );
-
-					}, 0, this );
-
-				}).call( this, leftCell, getCellWidth( leftCell ),
-						rightCell, getCellWidth( rightCell ), currentShift );
+						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 onMouseMove( evt )
+		function onMouseDown( evt )
 		{
-			var mouseOffset = evt.data.$.clientX,
-					resizerNewPosition = mouseOffset - Math.round( parseInt( resizer.getComputedStyle( 'width' ), 10 ) / 2 );
-
-			// Boundaries checking.
-			if ( resizerNewPosition > leftShiftBoundary && resizerNewPosition < rightShiftBoundary )
-			{
-				resizer.setStyle( 'left', pxUnit( resizerNewPosition ) );
-				currentShift = resizerNewPosition - startOffset;
-			}
-
 			cancel( evt );
-		}
 
-		function onMouseDown( evt )
-		{
-			cancel( evt );
 			resizeStart();
+
 			document.on( 'mouseup', onMouseUp, this );
 		}
 
-		function onMouseUp()
+		function onMouseUp( evt )
 		{
+			evt.removeListener();
+
 			resizeEnd();
 		}
-
-		function onMouseOut()
+		
+		function onMouseMove( evt )
 		{
-			// Don't detach during resizing.
-			!currentShift && detach();
+			move( evt.data.$.clientX );
 		}
 
 		document = editor.document;
-		resizer = CKEDITOR.dom.element.createFromHtml( '<div style="position: absolute; cursor: col-resize; ' +
-			'filter:alpha(opacity=0);opacity:0;padding:0;background-color:#004;background-image:none;border: 0px none;"></div>' );
 
-		// Place the resizer after body to prevent it from being editable.
-		document.getDocumentElement().append( resizer );
+		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 ( currentShift )
+			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 )
-			});
+				{
+					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 );
-			resizer.on( 'mouseout', onMouseOut, 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 )
@@ -265,14 +387,14 @@
 				return;
 
 			var dest = new CKEDITOR.dom.element( evt.data.$.relatedTarget || evt.data.$.toElement );
-			while( dest && !dest.equals( target ) && !dest.is( 'body' ) )
+			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 && evt.removeListener();
+		evt.removeListener();
 	}
 
 	CKEDITOR.plugins.add( 'tableresize',
@@ -280,38 +402,49 @@
 		requires : [ 'tabletools' ],
 		init : function( editor )
 		{
-			editor.on( 'contentDom', function ()
+			editor.on( 'contentDom', function()
 			{
 				var resizer;
+
 				editor.document.getBody().on( 'mousemove', function( evt )
-				{
-					evt = evt.data;
+					{
+						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();
-					if ( !( target.is( 'table' ) || target.getAscendant( 'tbody', true ) ) )
-						return;
-
-					var table = target.getAscendant( 'table', true ),
+						// Considering table, tr, td, tbody but nothing else.
+						var target = evt.getTarget(),
+							table,
 							pillars;
 
-					if ( !( pillars = table.getCustomData( '_cke_table_pillars' ) ) )
-					{
-						// Cache table pillars caculation result.
-						table.setCustomData( '_cke_table_pillars', ( pillars = buildTableColumnPillars( table ) ) );
-						table.on( 'mouseout', clearPillarsCache );
-						table.on( 'mousedown', clearPillarsCache );
-					}
+						if ( !target.is( 'table' ) && !target.getAscendant( 'tbody', true ) )
+							return;
 
-					var pillar = getPillarAtPosition( pillars, { x : evt.$.clientX, y : evt.$.clientY } );
-					if ( pillar )
-					{
-						!resizer && ( resizer = new columnResizer( editor ) );
-						resizer.attachTo( pillar );
-					}
-				});
+						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 );
+						}
+					});
 			});
 		}
 	});
 
-} )( );
+})();
