Index: /FCKeditor/trunk/editor/_source/classes/fckspecialcombo.js
===================================================================
--- /FCKeditor/trunk/editor/_source/classes/fckspecialcombo.js	(revision 479)
+++ /FCKeditor/trunk/editor/_source/classes/fckspecialcombo.js	(revision 480)
@@ -139,4 +139,5 @@
 	for ( var i in this.Items )
 	{
+		if ( !this.Items[i] ) continue;
 		this.Items[i].className = this.Items[i].originalClass = 'SC_Item' ;
 		this.Items[i].Selected = false ;
Index: /FCKeditor/trunk/editor/_source/commandclasses/fck_othercommands.js
===================================================================
--- /FCKeditor/trunk/editor/_source/commandclasses/fck_othercommands.js	(revision 479)
+++ /FCKeditor/trunk/editor/_source/commandclasses/fck_othercommands.js	(revision 480)
@@ -99,8 +99,21 @@
 	if ( typeof( fontSize ) == 'string' ) fontSize = parseInt(fontSize, 10) ;
 
-	if ( fontSize == null || fontSize == '' )
-	{
-		// TODO: Remove font size attribute (Now it works with size 3. Will it work forever?)
-		FCK.ExecuteNamedCommand( 'FontSize', 3 ) ;
+	// If user wants the font size cleared, we have to find
+	// where the font size tag is and go clear it (if there's one)
+	if ( !fontSize || fontSize == null || fontSize == '' )
+	{
+		var oFont = FCK.Selection.MoveToAncestorNode('FONT');
+		if ( oFont && oFont.getAttribute("size") )
+		{
+			//if the only thing here is SIZE, collapse the whole tag
+			if (oFont.attributes.length == 1 ||
+				(oFont.outerHTML && oFont.outerHTML.search(/<FONT size=["]*\d["]*>/i)))
+			{
+				FCKTools.RemoveOuterTags(oFont);
+			}
+			else
+				oFont.removeAttribute("size");
+		}	
+
 	}
 	else
Index: /FCKeditor/trunk/editor/_source/internals/fck_gecko.js
===================================================================
--- /FCKeditor/trunk/editor/_source/internals/fck_gecko.js	(revision 479)
+++ /FCKeditor/trunk/editor/_source/internals/fck_gecko.js	(revision 480)
@@ -39,4 +39,19 @@
 	}
 
+	//allow the table handler to handle mouse messages for dynamic table sizing
+	this._ExecMouseDown = function(e)
+	{
+		FCK.Events.FireEvent( "OnMouseDown",e ) ;
+	}
+
+	this._ExecMouseMove = function(e)
+	{
+		FCK.Events.FireEvent( "OnMouseMove",e ) ;
+	}
+
+	this._ExecMouseUp = function(e)
+	{
+		FCK.Events.FireEvent( "OnMouseUp",e ) ;
+	}
 	this.ExecOnSelectionChangeTimer = function()
 	{
@@ -62,4 +77,10 @@
 	// Record changes for the undo system when there are key down events.
 	this.EditorDocument.addEventListener( 'keydown', this._KeyDownListener, false ) ;
+
+	
+	//Hooks for table sizing
+	this.EditorDocument.addEventListener( 'mousedown', this._ExecMouseDown, true ) ;
+	this.EditorDocument.addEventListener( 'mouseup', this._ExecMouseUp, true ) ;
+	this.EditorDocument.addEventListener( 'mousemove', this._ExecMouseMove, true ) ;
 
 	// Reset the context menu.
@@ -99,4 +120,5 @@
 	Print	: true,
 	Paste	: true,
+
 	Cut	: true,
 	Copy	: true
Index: /FCKeditor/trunk/editor/_source/internals/fck_ie.js
===================================================================
--- /FCKeditor/trunk/editor/_source/internals/fck_ie.js	(revision 479)
+++ /FCKeditor/trunk/editor/_source/internals/fck_ie.js	(revision 480)
@@ -70,4 +70,15 @@
 		FCK.EditorWindow.event.returnValue	= false ;
 	}
+	FCK.Events.FireEvent( "OnMouseUp",FCK.EditorWindow.event) ;
+}
+
+function Doc_OnMouseDown()
+{
+	FCK.Events.FireEvent( "OnMouseDown",FCK.EditorWindow.event ) ;
+}
+
+function Doc_OnMouseMove()
+{
+	FCK.Events.FireEvent( "OnMouseMove",FCK.EditorWindow.event) ;
 }
 
@@ -103,4 +114,8 @@
 
 	this.EditorDocument.attachEvent("ondblclick", Doc_OnDblClick ) ;
+	
+	//additions for table sizing
+	this.EditorDocument.attachEvent( 'onmousedown', Doc_OnMouseDown ) ;
+	this.EditorDocument.attachEvent( 'onmousemove', Doc_OnMouseMove ) ;
 
 	// Catch cursor selection changes.
Index: /FCKeditor/trunk/editor/_source/internals/fckcommands.js
===================================================================
--- /FCKeditor/trunk/editor/_source/internals/fckcommands.js	(revision 479)
+++ /FCKeditor/trunk/editor/_source/internals/fckcommands.js	(revision 480)
Index: /FCKeditor/trunk/editor/_source/internals/fckselection.js
===================================================================
--- /FCKeditor/trunk/editor/_source/internals/fckselection.js	(revision 479)
+++ /FCKeditor/trunk/editor/_source/internals/fckselection.js	(revision 480)
@@ -23,2 +23,3 @@
 
 var FCKSelection = FCK.Selection = new Object() ;
+
Index: /FCKeditor/trunk/editor/_source/internals/fckselection_gecko.js
===================================================================
--- /FCKeditor/trunk/editor/_source/internals/fckselection_gecko.js	(revision 479)
+++ /FCKeditor/trunk/editor/_source/internals/fckselection_gecko.js	(revision 480)
@@ -150,2 +150,48 @@
 	return oSel ;
 }
+
+// If FCKSelection is inside a table, return <td>'s so we can work on each
+// one as a separate element
+FCKSelection.TableNodes = function()
+{
+	var oSel = FCK.EditorWindow.getSelection();
+	var aNodes = new Array();
+	if (this.HasAncestorNode("TABLE"))
+	{
+		var oTable = this.MoveToAncestorNode("TABLE");
+		for (var r = 0; r < oTable.rows.length; r++)
+		{
+			for (var c = 0; c < oTable.rows[r].cells.length; c++)
+			{
+				if (oSel.containsNode(oTable.rows[r].cells[c],true))
+				{
+					aNodes[aNodes.length] = oTable.rows[r].cells[c];
+				}
+			}
+		}
+	}
+	return aNodes;
+}
+
+FCKSelection.SelectedHTML = function()
+{
+	var oSel = FCK.EditorWindow.getSelection();
+	var strHTML = "";
+	//convert to a text range and walk the elements
+	for ( var i = 0 ; i < oSel.rangeCount ; i++ )
+	{
+		var df = oSel.getRangeAt(i).cloneContents();
+		
+		for (var j = 0; j < df.childNodes.length; j++)
+		{
+			if (df.childNodes[j].nodeName == "#text")
+				{if (df.childNodes[j].textContent) strHTML += df.childNodes[j].textContent;}
+			else
+				strHTML += '<' + df.childNodes[j].nodeName + '>'
+						+ df.childNodes[j].innerHTML
+						+ '</' + df.childNodes[j].nodeName + '>';
+		}
+	}
+	return strHTML;
+}
+
Index: /FCKeditor/trunk/editor/_source/internals/fckselection_ie.js
===================================================================
--- /FCKeditor/trunk/editor/_source/internals/fckselection_ie.js	(revision 479)
+++ /FCKeditor/trunk/editor/_source/internals/fckselection_ie.js	(revision 480)
@@ -47,4 +47,5 @@
 	{
 		case 'Control' :
+			if (!FCKSelection.GetSelectedElement()) return;
 			return FCKSelection.GetSelectedElement().parentElement ;
 		case 'None' :
@@ -110,4 +111,25 @@
 	return false ;
 } ;
+// If FCKSelection is inside a table, return <td>'s so we can work on each
+// one as a separate element
+FCKSelection.TableNodes = function()
+{
+	var oRange = FCK.EditorDocument.selection.createRange() ;
+	if (!oRange.htmlText.search(/<TD /)) return;
+	var oCellRange = oRange.duplicate();
+	var oTable = this.MoveToAncestorNode("TABLE");
+	if (!oTable) return;
+	var aNodes = new Array();
+	for (var i = 0; i < oTable.cells.length; i++)
+	{
+		oCellRange.moveToElementText(oTable.cells[i]);
+		if (oRange.inRange(oCellRange))
+		{
+			aNodes[aNodes.length] = oTable.cells[i];
+		}
+	}
+	return aNodes;
+}
+
 
 // The "nodeTagName" parameter must be UPPER CASE.
@@ -157,3 +179,7 @@
 } ;
 
+FCKSelection.SelectedHTML = function()
+{
+	return FCK.EditorDocument.selection.createRange().htmlText;
+}
 
Index: /FCKeditor/trunk/editor/_source/internals/fcktablehandler.js
===================================================================
--- /FCKeditor/trunk/editor/_source/internals/fcktablehandler.js	(revision 479)
+++ /FCKeditor/trunk/editor/_source/internals/fcktablehandler.js	(revision 480)
@@ -1,24 +1,24 @@
 ﻿/*
- * FCKeditor - The text editor for Internet - http://www.fckeditor.net
- * Copyright (C) 2003-2007 Frederico Caldeira Knabben
- *
- * == BEGIN LICENSE ==
- *
- * Licensed under the terms of any of the following licenses at your
- * choice:
- *
- *  - GNU General Public License Version 2 or later (the "GPL")
- *    http://www.gnu.org/licenses/gpl.html
- *
- *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
- *    http://www.gnu.org/licenses/lgpl.html
- *
- *  - Mozilla Public License Version 1.1 or later (the "MPL")
- *    http://www.mozilla.org/MPL/MPL-1.1.html
- *
- * == END LICENSE ==
- *
- * Manage table operations.
- */
+       * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+       * Copyright (C) 2003-2007 Frederico Caldeira Knabben
+       *
+       * == BEGIN LICENSE ==
+       *
+       * Licensed under the terms of any of the following licenses at your
+       * choice:
+       *
+       *  - GNU General Public License Version 2 or later (the "GPL")
+       *    http://www.gnu.org/licenses/gpl.html
+       *
+       *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+       *    http://www.gnu.org/licenses/lgpl.html
+       *
+       *  - Mozilla Public License Version 1.1 or later (the "MPL")
+       *    http://www.mozilla.org/MPL/MPL-1.1.html
+       *
+       * == END LICENSE ==
+       *
+       * Manage table operations.
+       */
 
 var FCKTableHandler = new Object() ;
@@ -42,9 +42,25 @@
 FCKTableHandler.DeleteRows = function( row )
 {
-	// If no row has been passed as a parameter,
-	// then get the row where the selection is placed in.
-	if ( !row )
-		row = FCKSelection.MoveToAncestorNode( 'TR' ) ;
-	if ( !row ) return ;
+	// If no row has been passed as a parameer,
+	// then get the row( s ) containing the cells where the selection is placed in.	
+	// If user selected multiple rows ( by selecting multiple cells ), walk
+	// the selected cell list and delete the rows containing the selected cells
+	if ( ! row )
+	{
+		var aCells = FCKTableHandler.GetSelectedCells() ;
+		var aRowsToDelete = new Array() ;
+		//queue up the rows -- it's possible ( and likely ) that we may get duplicates
+		for ( var i = 0; i < aCells.length; i++ )
+		{
+			var oRow = FCKTools.GetElementAscensor( aCells[i],'TR' ) ;
+			aRowsToDelete[oRow.rowIndex] = oRow ;
+		}
+		for ( var i = aRowsToDelete.length; i >= 0; i-- )
+		{
+			if ( aRowsToDelete[i] )
+				FCKTableHandler.DeleteRows( aRowsToDelete[i] );
+		}
+		return ;
+	}
 
 	// Get the row's table.
@@ -77,5 +93,11 @@
 	FCKSelection.SelectNode( table ) ;
 	FCKSelection.Collapse();
-	table.parentNode.removeChild( table ) ;
+
+	// if the table is wrapped with a singleton <p> ( or something similar ), remove
+	// the surrounding tag -- which likely won't show after deletion anyway
+	if ( table.parentNode.childNodes.length == 1 )
+		table.parentNode.parentNode.removeChild( table.parentNode );
+	else
+		table.parentNode.removeChild( table  ) ;
 }
 
@@ -83,21 +105,10 @@
 {
 	// Get the cell where the selection is placed in.
-	var oCell = FCKSelection.MoveToAncestorNode('TD') || FCKSelection.MoveToAncestorNode('TH') ;
-
-	if ( !oCell ) 
-	{
-		// oCell not fouund could be due to multiple selection ranges on tables in Gecko.
-		// We have another function to find the table cell for this special case.
-		if ( ! FCKBrowserInfo.IsIE )
-		{
-			var node = this._GetSelectedCellFromGecko( true ) ;
-			if ( node )
-				oCell = node ;
-			else
-				return null ;
-		}
-		else
-			return null ;
-	}
+	var oCell = null ;
+	var nodes = this.GetSelectedCells() ;
+	if ( nodes && nodes.length )
+		oCell = nodes[ insertBefore ? 0 : ( nodes.length - 1 ) ] ;
+	if ( ! oCell )
+		return null ;
 
 	// Get the cell's table.
@@ -133,8 +144,18 @@
 }
 
-FCKTableHandler.DeleteColumns = function()
-{
-	// Get the cell where the selection is placed in.
-	var oCell = FCKSelection.MoveToAncestorNode('TD') || FCKSelection.MoveToAncestorNode('TH') ;
+FCKTableHandler.DeleteColumns = function( oCell )
+{
+	// if user selected multiple cols ( by selecting multiple cells ), walk
+	// the selected cell list and delete the rows containing the selected cells
+	if ( !oCell  )
+	{
+		var aColsToDelete = FCKTableHandler.GetSelectedCells();
+		for ( var i = aColsToDelete.length; i >= 0; i--  )
+		{
+			if ( aColsToDelete[i]  )
+				FCKTableHandler.DeleteColumns( aColsToDelete[i]  );
+		}
+		return;
+	}
 
 	if ( !oCell ) return ;
@@ -170,20 +191,10 @@
 {
 	// Get the cell where the selection is placed in.
-	var oCell = cell ? cell : FCKSelection.MoveToAncestorNode( 'TD' ) ;
-	if ( !oCell ) 
-	{
-		// oCell not fouund could be due to multiple selection ranges on tables in Gecko.
-		// We have another function to find the table cell for this special case.
-		if ( ! FCKBrowserInfo.IsIE )
-		{
-			var node = this._GetSelectedCellFromGecko( true ) ;
-			if ( node )
-				oCell = node ;
-			else
-				return null ;
-		}
-		else
-			return null ;
-	}
+	var oCell = null ;
+	var nodes = this.GetSelectedCells() ;
+	if ( nodes && nodes.length )
+		oCell = nodes[ insertBefore ? 0 : ( nodes.length - 1 ) ] ;
+	if ( ! oCell )
+		return null ;
 
 	// Create the new cell element to be added.
@@ -191,5 +202,5 @@
 	if ( FCKBrowserInfo.IsGecko )
 		oNewCell.innerHTML = GECKO_BOGUS ;
-//	oNewCell.innerHTML = "&nbsp;" ;
+	//	oNewCell.innerHTML = "&nbsp;" ;
 
 	if ( !insertBefore && oCell.cellIndex == oCell.parentNode.cells.length - 1 )
@@ -256,5 +267,5 @@
 				continue ;
 
-				oCellsContents.insertBefore( eChild, oCellsContents.firstChild ) ;
+			oCellsContents.insertBefore( eChild, oCellsContents.firstChild ) ;
 		}
 
@@ -288,5 +299,5 @@
 	var iCellIndex = FCKTableHandler._GetCellIndexSpan( aMap, aCells[0].parentNode.rowIndex , aCells[0] ) ;
 
-	var aCollCells = this._GetCollumnCells( aMap, iCellIndex ) ;
+	var aCollCells = this._GetColumnCells( aMap, iCellIndex ) ;
 
 	for ( var i = 0 ; i < aCollCells.length ; i++ )
@@ -325,6 +336,19 @@
 }
 
-// Get the cells available in a collumn of a TableMap.
-FCKTableHandler._GetCollumnCells = function( tableMap, collumnIndex )
+// Get the cell location from a TableMap. Returns an array with an [x,y] location
+FCKTableHandler._GetCellLocation = function( tableMap, cell  )
+{
+	for ( var i = 0 ; i < tableMap.length; i++ )
+	{
+		for ( var c = 0 ; c < tableMap[i].length ; c++  )
+		{
+			if ( tableMap[i][c] == cell  ) return [i,c];
+		}
+	}
+	return null ;
+}
+
+// Get the cells available in a column of a TableMap.
+FCKTableHandler._GetColumnCells = function( tableMap, columnIndex )
 {
 	var aCollCells = new Array() ;
@@ -332,5 +356,5 @@
 	for ( var r = 0 ; r < tableMap.length ; r++ )
 	{
-		var oCell = tableMap[r][collumnIndex] ;
+		var oCell = tableMap[r][columnIndex] ;
 		if ( oCell && ( aCollCells.length == 0 || aCollCells[ aCollCells.length - 1 ] != oCell ) )
 			aCollCells[ aCollCells.length ] = oCell ;
@@ -405,39 +429,2 @@
 	}
 }
-
-FCKTableHandler._GetSelectedCellFromGecko = function( getLastCell )
-{
-	var sel = FCK.EditorWindow.getSelection() ;
-	if ( sel.rangeCount < 1 )
-		return null ;
-	var range = getLastCell ? sel.getRangeAt( sel.rangeCount - 1 ) : sel.getRangeAt( 0 ) ;
-	var node = getLastCell ? range.endContainer : range.startContainer ;
-
-	// Gecko returns a <TR> as startContainer and endContainer when cells are selected.
-	// We need to find back the final <TD|TH> that's being selected.
-	if ( node.nodeType == 1 && node.tagName.toLowerCase() == 'tr' )
-	{
-		for ( var i = range.startOffset ; i <= range.endOffset ; i++ )
-		{
-			var candidate = node.childNodes[i] ;
-			var tag = candidate.tagName.toLowerCase() ;
-			if ( candidate.nodeType == 1 && ( tag == 'td' || tag == 'th' ) )
-			{
-				node = node.childNodes[i] ;
-				break ;
-			}
-		}
-	}
-	// For safety, we have to be ready for the 'usual' case as well.
-	else
-	{
-		while ( node && node.tagName.toLowerCase() != 'td' && node.tagName.toLowerCase() != 'th' )
-			node = node.parentNode ;
-	}
-
-	// Have we found the <TD|TH> node we wanted, finally? If yes, return the found node. If not, abort.
-	if ( node.tagName.toLowerCase() != 'td' && node.tagName.toLowerCase() != 'th' )
-		return null ;
-	else
-		return node ;
-}
Index: /FCKeditor/trunk/editor/_source/internals/fcktools.js
===================================================================
--- /FCKeditor/trunk/editor/_source/internals/fcktools.js	(revision 479)
+++ /FCKeditor/trunk/editor/_source/internals/fcktools.js	(revision 480)
@@ -94,9 +94,4 @@
 		return '' ;
 
-	text = text.replace( /&/g, '&amp;' ) ;
-	text = text.replace( /</g, '&lt;' ) ;
-	text = text.replace( />/g, '&gt;' ) ;
-
-	return text ;
 }
 
Index: /FCKeditor/trunk/editor/plugins/dragresizetable/fckplugin.js
===================================================================
--- /FCKeditor/trunk/editor/plugins/dragresizetable/fckplugin.js	(revision 480)
+++ /FCKeditor/trunk/editor/plugins/dragresizetable/fckplugin.js	(revision 480)
@@ -0,0 +1,542 @@
+var FCKDragTableHandler = 
+{
+	"_DragState" : 0,
+	"_LeftCell" : null,
+	"_RightCell" : null,
+	"_MouseMoveMode" : 0,	// 0 - find candidate cells for resizing, 1 - drag to resize
+	"_ResizeBar" : null,
+	"_OriginalX" : null,
+	"_MinimumX" : null,
+	"_MaximumX" : null,
+	"_LastX" : null,
+	"_GetWindowScrollX" : function( w )
+	{
+		var scrollX = 0 ;
+		if ( w.document.documentElement && w.document.documentElement.scrollLeft ) 
+			scrollX = w.document.documentElement.scrollLeft ;
+		else if ( w.document.body && w.document.body.scrollLeft )
+			scrollX = w.document.body.scrollLeft ;
+		else if ( w.scrollX )
+			scrollX = w.scrollX ;
+		return scrollX ;
+	},
+	"_GetWindowScrollY" : function( w )
+	{
+		var scrollY = 0 ;
+		if ( w.document.documentElement && w.document.documentElement.scrollTop )
+			scrollY = w.document.documentElement.scrollTop ;
+		else if ( w.document.body && w.document.body.scrollTop )
+			scrollY = w.document.body.scrollTop ;
+		else if ( w.scrollY )
+			scrollY = w.scrollY ;
+		return scrollY ;
+	},
+	"_GetDocumentPosition" : function( w, node )
+	{
+		var x = 0 ;
+		var y = 0 ;
+		var curNode = node ;
+		while ( curNode && curNode != w.document.body )
+		{
+			x += curNode.offsetLeft - curNode.scrollLeft ;
+			y += curNode.offsetTop - curNode.scrollTop ;
+			curNode = curNode.offsetParent ;
+		}
+		return { "x" : x, "y" : y } ;
+	},
+	"_GetWindowPosition" : function( w, node )
+	{
+		var pos = this._GetDocumentPosition( w, node ) ;
+		pos.x -= this._GetWindowScrollX( w ) ;
+		pos.y -= this._GetWindowScrollY( w ) ;
+		return pos ;
+	},
+	"_IsInsideNode" : function( w, domNode, pos )
+	{
+		var myCoords = this._GetWindowPosition( w, domNode ) ; 
+		var xMin = myCoords.x ;
+		var yMin = myCoords.y ;
+		var xMax = parseInt( xMin ) + parseInt( domNode.offsetWidth ) ;
+		var yMax = parseInt( yMin ) + parseInt( domNode.offsetHeight ) ;
+		if ( pos.x >= xMin && pos.x <= xMax && pos.y >= yMin && pos.y <= yMax )
+			return true;
+		return false;
+	},
+	"_GetBorderCells" : function( w, tableNode, mouse )
+	{
+		// Enumerate all the cells in the table.
+		var cells = [] ;
+		for ( var i = 0 ; i < tableNode.rows.length ; i++ )
+		{
+			var r = tableNode.rows[i] ;
+			for ( var j = 0 ; j < r.cells.length ; j++ )
+				cells.push( r.cells[j] ) ;
+		}
+
+		if ( cells.length < 1 )
+			return null ;
+
+		// Get the cells whose right or left border is nearest to the mouse cursor's x coordinate.
+		var minRxDist = null ;
+		var lxDist = null ;
+		var minYDist = null ;
+		var rbCell = null ;
+		var lbCell = null ;
+		for ( var i = 0 ; i < cells.length ; i++ )
+		{
+			var pos = this._GetWindowPosition( w, cells[i] ) ;
+			var rightX = pos.x + parseInt( cells[i].clientWidth ) ;
+			var rxDist = mouse.x - rightX ;
+			var yDist = mouse.y - ( pos.y + ( cells[i].clientHeight / 2 ) ) ;
+			if ( minRxDist == null || 
+					( Math.abs( rxDist ) <= Math.abs( minRxDist ) &&
+					  ( minYDist == null || Math.abs( yDist ) <= Math.abs( minYDist ) ) ) )
+			{
+				minRxDist = rxDist ;
+				minYDist = yDist ;
+				rbCell = cells[i] ;
+			}
+		}
+		var rowNode = FCKTools.GetElementAscensor( rbCell, "tr" ) ;
+		var cellIndex = rbCell.cellIndex + 1 ;
+		if ( cellIndex >= rowNode.cells.length )
+			return null ;
+		lbCell = rowNode.cells.item( cellIndex ) ;
+
+		// Abort if too far from the border.
+		lxDist = mouse.x - this._GetWindowPosition( w, lbCell ).x ;
+		if ( lxDist < 0 && minRxDist < 0 && minRxDist < -2 )
+			return null ; 
+		if ( lxDist > 0 && minRxDist > 0 && lxDist > 3 )
+			return null ;
+
+		return { "leftCell" : rbCell, "rightCell" : lbCell } ;
+	},
+	"_GetResizeBarPosition" : function()
+	{
+		var row = FCKTools.GetElementAscensor( this._LeftCell, "tr" ) ;
+		var colIndex = 0 ;
+		for ( var i = 0 ; i <= this._LeftCell.cellIndex ; i++ )
+		{
+			var colSpan = parseInt( row.cells.item( i ).colSpan ) ;
+			if ( colSpan != colSpan )
+				colSpan = 1 ;
+			colIndex += colSpan ;
+		}
+		return colIndex ;
+	},
+	"_ResizeBarMouseDownListener" : function( evt )
+	{
+		if ( ! evt )
+			evt = window.event ;
+		if ( FCKDragTableHandler._LeftCell )
+			FCKDragTableHandler._MouseMoveMode = 1 ;
+		if ( FCKBrowserInfo.IsIE )
+			FCKDragTableHandler._ResizeBar.filters.item("DXImageTransform.Microsoft.Alpha").opacity = 50 ;
+		else
+			FCKDragTableHandler._ResizeBar.style.opacity = 0.5 ;
+		FCKDragTableHandler._OriginalX = evt.clientX ;
+
+		// Calculate maximum and minimum x-coordinate delta.
+		var borderIndex = FCKDragTableHandler._GetResizeBarPosition() ;
+		var offset = FCKDragTableHandler._GetDocumentPosition( window, FCK.EditingArea.IFrame ) ;
+		var table = FCKTools.GetElementAscensor( FCKDragTableHandler._LeftCell, "table" );
+		var minX = null ;
+		var maxX = null ;
+		for ( var r = 0 ; r < table.rows.length ; r++ )
+		{
+			var row = table.rows.item( r ) ;
+			var colIndex = 0 ;
+			for ( var c = 0 ; c < row.cells.length ; c++ )
+			{
+				var cell = row.cells.item( c ) ;
+				var cellPosition = FCKDragTableHandler._GetWindowPosition( FCK.EditorWindow, cell ) ;
+				var cellPadding = FCKDragTableHandler._GetCellPadding( table, cell ) ;
+				var cellMinX = cellPosition.x + cellPadding ;
+				var cellMaxX = cellPosition.x + cell.clientWidth - cellPadding ;
+				if ( colIndex < borderIndex )
+				{
+					if ( minX == null || cellMinX > minX )
+						minX = cellMinX ;
+				}
+				else
+				{
+					if ( maxX == null || cellMaxX < maxX )
+						maxX = cellMaxX ;
+				}
+				colIndex += cell.colSpan ;
+			}
+		}
+		FCKDragTableHandler._MinimumX = minX + offset.x ;
+		FCKDragTableHandler._MaximumX = maxX + offset.x ;
+		FCKDragTableHandler._LastX = null ;
+	},
+	"_ResizeBarMouseUpListener" : function( evt )
+	{
+		if ( ! evt )
+			evt = window.event ;
+		FCKDragTableHandler._MouseMoveMode = 0 ;
+		FCKDragTableHandler._HideResizeBar() ;
+		
+		if ( FCKDragTableHandler._LastX == null )
+			return ;
+		
+		// Calculate the delta value.
+		var deltaX = FCKDragTableHandler._LastX - FCKDragTableHandler._OriginalX ;
+
+		// Then, build an array of current column width values.
+		// This algorithm can be very slow if the cells have insane colSpan values. (e.g. colSpan=1000).
+		var table = FCKTools.GetElementAscensor( FCKDragTableHandler._LeftCell, "table" ) ;
+		var colArray = [] ;
+		for ( var r = 0 ; r < table.rows.length ; r++ )
+		{
+			var colIndex = 0 ;
+			var row = table.rows.item( r ) ;
+			for ( var c = 0 ; c < row.cells.length ; c++ )
+			{
+				var cell = row.cells.item( c ) ;
+				var width = FCKDragTableHandler._GetCellWidth( table, cell ) ;
+				var colSpan = parseInt( cell.colSpan ) ;
+				if ( colSpan != colSpan )
+					colSpan = 1 ;
+				if ( colArray.length < colIndex + colSpan )
+				{
+					for ( var i = 0 ; i < colSpan ; i++ )
+						colArray.push( { "width" : width / colSpan, "colSpan" : colSpan } ) ;
+				}
+				else
+				{
+					for ( var i = colIndex ; i < colIndex + colSpan ; i++ )
+					{
+						var guessItem = colArray[i] ;
+						if ( guessItem.colSpan > colSpan )
+						{
+							guessItem.width = width / colSpan ;
+							guessItem.colSpan = colSpan ;
+						}
+					}
+				}
+				colIndex += colSpan ;
+			}
+		}
+
+		// Find out the equivalent column index of the two cells selected for resizing.
+		colIndex = FCKDragTableHandler._GetResizeBarPosition() ;
+
+		// Note that colIndex must be at least 1 here, so it's safe to subtract 1 from it.
+		colIndex-- ;
+
+		// Modify the widths in the colArray according to the mouse coordinate delta value.
+		colArray[colIndex].width += deltaX ;
+		colArray[colIndex + 1].width -= deltaX ;
+
+		// Clear all cell widths, delete all <col> elements from the table.
+		for ( var r = 0 ; r < table.rows.length ; r++ )
+		{
+			var row = table.rows.item( r ) ;
+			for ( var c = 0 ; c < row.cells.length ; c++ )
+			{
+				var cell = row.cells.item( c ) ;
+				cell.width = "" ;
+				cell.style.width = "" ;
+			}
+		}
+		var colElements = table.getElementsByTagName( "col" ) ;
+		for ( var i = colElements.length - 1 ; i >= 0 ; i-- )
+			colElements[i].parentNode.removeChild( colElements[i] ) ;
+
+		// Set new cell widths.
+		for ( var r = 0 ; r < table.rows.length ; r++ )
+		{
+			var row = table.rows.item( r ) ;
+			var colIndex = 0 ;
+			for ( var c = 0 ; c < row.cells.length ; c++ )
+			{
+				var cell = row.cells.item( c ) ;
+				var colSpan = parseInt( cell.colSpan ) ;
+				if ( colSpan != colSpan )
+					colSpan = 1 ;
+				var cellWidth = 0 ;
+				for ( var i = colIndex ; i < colIndex + colSpan ; i++ )
+					cellWidth += colArray[i].width ;
+				try
+				{
+					cell.width = cellWidth ;
+				}
+				catch(e)	
+				{				
+				}
+				colIndex += colSpan ;
+			}
+		}
+
+		FCKDragTableHandler._LastX = null ;
+	},
+	"_ResizeBarMouseMoveListener" : function( evt )
+	{
+		if ( ! evt )
+			evt = window.event ;		
+		if ( FCKDragTableHandler._MouseMoveMode == 0 )
+			return FCKDragTableHandler._MouseFindHandler( FCK, evt ) ;
+		else
+			return FCKDragTableHandler._MouseDragHandler( FCK, evt ) ;
+	},
+	// Calculate the padding of a table cell.
+	// It returns the value of paddingLeft + paddingRight of a table cell.
+	// This function is used, in part, to calculate the width parameter that should be used for setting cell widths.
+	// The equation in question is clientWidth = paddingLeft + paddingRight + width.
+	// So that width = clientWidth - paddingLeft - paddingRight.
+	// The return value of this function must be pixel accurate acorss all supported browsers, so be careful if you need to modify it.
+	"_GetCellPadding" : function( table, cell )
+	{
+		var attrGuess = parseInt( table.cellPadding ) * 2 ;
+		var cssGuess = null ;
+		if ( typeof( window.getComputedStyle ) == "function" )
+		{
+			var styleObj = window.getComputedStyle( cell, null ) ;
+			cssGuess = parseInt( styleObj.getPropertyValue( "padding-left" ) ) + 
+				parseInt( styleObj.getPropertyValue( "padding-right" ) ) ;
+		}
+		else
+			cssGuess = parseInt( cell.currentStyle.paddingLeft ) + parseInt (cell.currentStyle.paddingRight ) ;
+
+		var cssRuntime = cell.style.padding ;
+		if ( parseInt( cssRuntime ) == parseInt( cssRuntime ) )
+			cssGuess = parseInt( cssRuntime ) * 2 ;
+		else
+		{
+			cssRuntime = cell.style.paddingLeft ;
+			if ( parseInt( cssRuntime ) == parseInt( cssRuntime ) )
+				cssGuess = parseInt( cssRuntime ) ;
+			cssRuntime = cell.style.paddingRight ;
+			if ( parseInt( cssRuntime ) == parseInt( cssRuntime ) )
+				cssGuess += parseInt( cssRuntime ) ;
+		}
+
+		attrGuess = parseInt( attrGuess ) ;
+		cssGuess = parseInt( cssGuess ) ;
+		if ( attrGuess != attrGuess )
+			attrGuess = 0 ;
+		if ( cssGuess != cssGuess )
+			cssGuess = 0 ;
+		return Math.max( attrGuess, cssGuess ) ;
+	},
+	// Calculate the real width of the table cell.
+	// The real width of the table cell is the pixel width that you can set to the width attribute of the table cell and after
+	// that, the table cell should be of exactly the same width as before.
+	// The real width of a table cell can be calculated as:
+	// width = clientWidth - paddingLeft - paddingRight.
+	"_GetCellWidth" : function( table, cell )
+	{
+		var clientWidth = parseInt( cell.clientWidth ) ;
+		if ( clientWidth != clientWidth )		// NaN possible? lets just be safe...
+			clientWidth = 0 ;
+		return clientWidth - this._GetCellPadding( table, cell ) ;
+	},
+	"MouseMoveListener" : function( FCK, evt )
+	{
+		if ( FCKDragTableHandler._MouseMoveMode == 0 )
+			return FCKDragTableHandler._MouseFindHandler( FCK, evt ) ;
+		else
+			return FCKDragTableHandler._MouseDragHandler( FCK, evt ) ;
+	},
+	"_MouseFindHandler" : function( FCK, evt )
+	{
+		var node = evt.srcElement || evt.originalTarget ;
+		try
+		{
+			if ( ! node || node.nodeType != 1 )
+			{
+				this._HideResizeBar() ;
+				return ;
+			}
+		}
+		catch ( e )
+		{
+			this._HideResizeBar() ;
+			return ;
+		}
+		
+		// Since this function might be called from the editing area iframe or the outer fckeditor iframe,
+		// the mouse point coordinates from evt.clientX/Y can have different reference points.
+		// We need to resolve the mouse pointer position relative to the editing area iframe.
+		var mouseX = evt.clientX ;
+		var mouseY = evt.clientY ;
+		if ( node.ownerDocument == document )
+		{
+			var offset = this._GetDocumentPosition( window, FCK.EditingArea.IFrame ) ;
+			mouseX -= offset.x ;
+			mouseY -= offset.y ;
+		}
+
+
+		if ( this._ResizeBar && this._LeftCell )
+		{
+			var leftPos = this._GetWindowPosition( FCK.EditorWindow, this._LeftCell ) ;
+			var rightPos = this._GetWindowPosition( FCK.EditorWindow, this._RightCell ) ; 
+			var rxDist = mouseX - ( leftPos.x + this._LeftCell.clientWidth ) ;
+			var lxDist = mouseX - rightPos.x ;
+			var inRangeFlag = false ;
+			if ( lxDist >= 0 && rxDist <= 0 )
+				inRangeFlag = true ;
+			else if ( rxDist > 0 && lxDist <= 3 )
+				inRangeFlag = true ;
+			else if ( lxDist < 0 && rxDist >= -2 )
+				inRangeFlag = true ;
+			if ( inRangeFlag )
+			{
+				this._ShowResizeBar( FCK.EditorWindow, 
+					FCKTools.GetElementAscensor( this._LeftCell, "table" ),
+					{ "x" : mouseX, "y" : mouseY } ) ;
+				return ;
+			}
+		}
+
+		var tagName = node.tagName.toLowerCase() ;
+		if ( tagName != "table" && tagName != "td" && tagName != "th" )
+		{
+			if ( this._LeftCell )
+				this._LeftCell = this._RightCell = null ;
+			this._HideResizeBar() ;
+			return ;
+		}
+		node = FCKTools.GetElementAscensor( node, "table" ) ;
+		var cellTuple = this._GetBorderCells( FCK.EditorWindow, node, { "x" : mouseX, "y" : mouseY } ) ;
+
+		if ( cellTuple == null )
+		{
+			if ( this._LeftCell )
+				this._LeftCell = this._RightCell = null ;
+			this._HideResizeBar() ;
+		}
+		else
+		{
+			this._LeftCell = cellTuple["leftCell"] ;
+			this._RightCell = cellTuple["rightCell"] ;
+			this._ShowResizeBar( FCK.EditorWindow, 
+					FCKTools.GetElementAscensor( this._LeftCell, "table" ),
+					{ "x" : mouseX, "y" : mouseY } ) ;
+		}
+	},
+	"_MouseDragHandler" : function( FCK, evt )
+	{
+		var mouse = { "x" : evt.clientX, "y" : evt.clientY } ;
+		
+		// Convert mouse coordinates in reference to the outer iframe.
+		var node = evt.srcElement || evt.originalTarget ;
+		if ( node.ownerDocument == FCK.EditorDocument )
+		{
+			var offset = this._GetDocumentPosition( window, FCK.EditingArea.IFrame ) ;
+			mouse.x += offset.x ;
+			mouse.y += offset.y ;
+		}
+
+		// Calculate the mouse position delta and see if we've gone out of range.
+		if ( mouse.x >= this._MaximumX - 5 )
+			mouse.x = this._MaximumX - 5 ;
+		if ( mouse.x <= this._MinimumX + 5 ) 
+			mouse.x = this._MinimumX + 5 ;
+
+		var docX = mouse.x + this._GetWindowScrollX( window ) ;
+		this._ResizeBar.style.left = ( docX - this._ResizeBar.offsetWidth / 2 ) + "px" ;
+		this._LastX = mouse.x ;
+	},
+	"_ShowResizeBar" : function( w, table, mouse )
+	{
+		if ( this._ResizeBar == null )
+		{
+			this._ResizeBar = document.createElement( "div" ) ;
+			var paddingBar = this._ResizeBar ;
+			paddingBar.style.position = "absolute" ;
+			paddingBar.style.cursor = "e-resize" ;
+			if ( FCKBrowserInfo.IsIE )
+				paddingBar.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=10,enabled=true)" ;
+			else
+				paddingBar.style.opacity = 0.10 ;
+			document.body.appendChild( paddingBar ) ;
+			FCKTools.AddEventListener( paddingBar, "mousemove", this._ResizeBarMouseMoveListener ) ;
+			FCKTools.AddEventListener( paddingBar, "mousedown", this._ResizeBarMouseDownListener ) ;
+			FCKTools.AddEventListener( document, "mouseup", this._ResizeBarMouseUpListener ) ;
+			FCKTools.AddEventListener( FCK.EditorDocument, "mouseup", this._ResizeBarMouseUpListener ) ;
+
+			// IE doesn't let the tranparent part of the padding block to receive mouse events unless there's something inside.
+			// So we need to create a spacer image to fill the block up.
+			var filler = document.createElement( "img" ) ;
+			filler.border = 0 ;
+			filler.src = FCKConfig.BasePath + "images/spacer.gif" ;
+			filler.style.position = "absolute" ;
+			paddingBar.appendChild( filler ) ;
+
+			// Disable drag and drop, and selection for the filler image.
+			var disabledListener = function( evt )
+			{
+				if ( ! evt )
+					evt = window.event ;
+				if ( evt.preventDefault )
+					evt.preventDefault() ;
+				else
+					evt.returnValue = false ;
+			}
+			FCKTools.AddEventListener( filler, "dragstart", disabledListener ) ;
+			FCKTools.AddEventListener( filler, "selectstart", disabledListener ) ;
+		}
+
+		var paddingBar = this._ResizeBar ;
+		if ( FCKBrowserInfo.IsIE )
+			paddingBar.filters.item("DXImageTransform.Microsoft.Alpha").opacity = 10 ;
+		else
+			paddingBar.style.opacity = 0.1 ;
+		var offset = this._GetDocumentPosition( window, FCK.EditingArea.IFrame ) ;
+		var tablePos = this._GetWindowPosition( w, table ) ;
+		var barHeight = table.offsetHeight ;
+		var barTop = offset.y + tablePos.y ;
+		// Do not let the resize bar intrude into the toolbar area.
+		if ( tablePos.y < 0 )
+		{
+			barHeight += tablePos.y ;
+			barTop -= tablePos.y ;
+		}
+		paddingBar.style.top = barTop + "px" ;
+		paddingBar.style.height = barHeight + "px" ;
+		var bw = parseInt( table.border ) ;
+		if ( bw != bw )
+			bw = 0 ;
+		var cs = parseInt( table.cellSpacing ) ;
+		if ( cs != cs )
+			cs = 0 ;
+		var barWidth = Math.max( bw+100, cs+100 ) ;
+		paddingBar.style.width = barWidth + "px" ;
+		paddingBar.style.left = ( offset.x + mouse.x + this._GetWindowScrollX( w ) - barWidth / 2 ) +  "px" ;
+		var filler = paddingBar.getElementsByTagName( "img" )[0] ;
+		filler.style.width = paddingBar.offsetWidth + "px" ;
+		filler.style.height = barHeight + "px" ;
+
+		barWidth = Math.max( bw, cs, 3 ) ;
+		var visibleBar = null ;
+		if ( paddingBar.getElementsByTagName( "div" ).length < 1 )
+		{
+			visibleBar = document.createElement( "div" ) ;
+			paddingBar.appendChild( visibleBar ) ;
+		}
+		else
+			visibleBar = paddingBar.getElementsByTagName( "div" )[0] ;
+		visibleBar.style.position = "absolute" ;
+		visibleBar.style.backgroundColor = "blue" ;
+		visibleBar.style.width = barWidth + "px" ;
+		visibleBar.style.height = barHeight + "px" ;
+		visibleBar.style.left = "50px" ;
+		visibleBar.style.top = "0px" ;
+	},
+	"_HideResizeBar" : function()
+	{
+		if ( this._ResizeBar )
+		{
+			// IE bug: display : none does not hide the resize bar for some reason.
+			// so set the position to somewhere invisible.
+			this._ResizeBar.style.top = "-100000px" ;
+			this._ResizeBar.style.left = "-100000px" ;
+		}
+	}
+};
+
+FCK.Events.AttachEvent( "OnMouseMove", FCKDragTableHandler.MouseMoveListener ) ;
Index: /FCKeditor/trunk/fckconfig.js
===================================================================
--- /FCKeditor/trunk/fckconfig.js	(revision 479)
+++ /FCKeditor/trunk/fckconfig.js	(revision 480)
@@ -49,4 +49,5 @@
 
 // FCKConfig.Plugins.Add( 'autogrow' ) ;
+// FCKConfig.Plugins.Add( 'dragresizetable' );
 FCKConfig.AutoGrowMax = 400 ;
 
