Index: /FCKeditor/branches/developers/mjk/editor/_source/classes/fckspecialcombo.js
===================================================================
--- /FCKeditor/branches/developers/mjk/editor/_source/classes/fckspecialcombo.js	(revision 242)
+++ /FCKeditor/branches/developers/mjk/editor/_source/classes/fckspecialcombo.js	(revision 243)
@@ -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 ;
@@ -176,4 +177,15 @@
 
 	this._OuterTable.className = isEnabled ? '' : 'SC_FieldDisabled' ;
+}
+
+FCKSpecialCombo.prototype.ClearItems = function ()
+{
+	if ( this.Items )
+	{
+		for ( var key in this.Items )
+			this.Items[key] = null ;
+	}
+	while (this._ItemsHolderEl.firstChild)
+		this._ItemsHolderEl.removeChild(this._ItemsHolderEl.firstChild);
 }
 
Index: /FCKeditor/branches/developers/mjk/editor/_source/commandclasses/fck_othercommands.js
===================================================================
--- /FCKeditor/branches/developers/mjk/editor/_source/commandclasses/fck_othercommands.js	(revision 242)
+++ /FCKeditor/branches/developers/mjk/editor/_source/commandclasses/fck_othercommands.js	(revision 243)
@@ -99,12 +99,25 @@
 	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
 		FCK.ExecuteNamedCommand( 'FontSize', fontSize ) ;
 }
+
 
 FCKFontSizeCommand.prototype.GetState = function()
@@ -380,2 +393,68 @@
 	}
 } ;
+
+var FCKAnchorDeleteCommand = function()
+{
+	this.Name = 'AnchorDelete' ;
+}
+
+FCKAnchorDeleteCommand.prototype.Execute = function()
+{
+	if (FCK.Selection.GetType() == 'Control')
+	{
+		FCK.Selection.Delete();
+	}
+	else
+	{
+		var oFakeImage = FCK.Selection.GetSelectedElement() ;
+		if ( oFakeImage )
+		{
+			if ( oFakeImage.tagName == 'IMG' && oFakeImage.getAttribute('_fckanchor') )
+				oAnchor = FCK.GetRealElement( oFakeImage ) ;
+			else
+				oFakeImage = null ;
+		}
+		
+		//Search for a real anchor
+		if ( !oFakeImage )
+		{
+			oAnchor = FCK.Selection.MoveToAncestorNode( 'A' ) ;
+			if ( oAnchor )
+				FCK.Selection.SelectNode( oAnchor ) ;
+		}
+
+		// If it's also a link, then just remove the name and exit
+		if ( oAnchor.href.length != 0 )
+		{
+			oAnchor.removeAttribute( 'name' ) ;
+			// Remove temporary class for IE
+			if ( FCKBrowserInfo.IsIE )
+				oAnchor.className = oAnchor.className.replace( FCKRegexLib.FCK_Class, '' ) ;
+			return ;
+		}
+	
+		// We need to remove the anchor
+		// If we got a fake image, then just remove it and we're done
+		if ( oFakeImage )
+		{
+			oFakeImage.parentNode.removeChild( oFakeImage ) ;
+			return ;
+		}
+		// Empty anchor, so just remove it
+		if ( oAnchor.innerHTML.length == 0 )
+		{
+			oAnchor.parentNode.removeChild( oAnchor ) ;
+			return ;
+		}
+		// Anchor with content, leave the content
+		FCKTools.RemoveOuterTags( oAnchor ) ;
+	}
+	if ( FCKBrowserInfo.IsGecko )
+		FCK.Selection.Collapse( true ) ;
+}
+
+FCKAnchorDeleteCommand.prototype.GetState = function()
+{
+	return FCK.GetNamedCommandState( 'Unlink') ;
+}
+
Index: /FCKeditor/branches/developers/mjk/editor/_source/internals/fck_contextmenu.js
===================================================================
--- /FCKeditor/branches/developers/mjk/editor/_source/internals/fck_contextmenu.js	(revision 242)
+++ /FCKeditor/branches/developers/mjk/editor/_source/internals/fck_contextmenu.js	(revision 243)
@@ -141,4 +141,5 @@
 					menu.AddSeparator() ;
 					menu.AddItem( 'Anchor', FCKLang.AnchorProp, 36 ) ;
+					menu.AddItem( 'AnchorDelete', FCKLang.AnchorDelete) ;
 				}
 			}} ;
Index: /FCKeditor/branches/developers/mjk/editor/_source/internals/fck_gecko.js
===================================================================
--- /FCKeditor/branches/developers/mjk/editor/_source/internals/fck_gecko.js	(revision 242)
+++ /FCKeditor/branches/developers/mjk/editor/_source/internals/fck_gecko.js	(revision 243)
@@ -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()
 	{
@@ -63,4 +78,10 @@
 	FCK.ContextMenu._InnerContextMenu.SetMouseClickWindow( FCK.EditorWindow ) ;
 	FCK.ContextMenu._InnerContextMenu.AttachToElement( FCK.EditorDocument ) ;
+	
+	//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 ) ;
+
 }
 
@@ -99,4 +120,5 @@
 	Copy	: true
 } ;
+
 
 // ExecuteNamedCommand overload for Gecko.
Index: /FCKeditor/branches/developers/mjk/editor/_source/internals/fck_ie.js
===================================================================
--- /FCKeditor/branches/developers/mjk/editor/_source/internals/fck_ie.js	(revision 242)
+++ /FCKeditor/branches/developers/mjk/editor/_source/internals/fck_ie.js	(revision 243)
@@ -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) ;
 }
 
@@ -140,4 +151,9 @@
 
 	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/branches/developers/mjk/editor/_source/internals/fckcommands.js
===================================================================
--- /FCKeditor/branches/developers/mjk/editor/_source/internals/fckcommands.js	(revision 242)
+++ /FCKeditor/branches/developers/mjk/editor/_source/internals/fckcommands.js	(revision 243)
@@ -44,4 +44,5 @@
 		case 'Unlink'		: oCommand = new FCKUnlinkCommand() ; break ;
 		case 'Anchor'		: oCommand = new FCKDialogCommand( 'Anchor'		, FCKLang.DlgAnchorTitle		, 'dialog/fck_anchor.html'		, 370, 170 ) ; break ;
+		case 'AnchorDelete'	: oCommand = new FCKAnchorDeleteCommand() ; break ;
 		case 'BulletedList'	: oCommand = new FCKDialogCommand( 'BulletedList', FCKLang.BulletedListProp		, 'dialog/fck_listprop.html?UL'	, 370, 170 ) ; break ;
 		case 'NumberedList'	: oCommand = new FCKDialogCommand( 'NumberedList', FCKLang.NumberedListProp		, 'dialog/fck_listprop.html?OL'	, 370, 170 ) ; break ;
Index: /FCKeditor/branches/developers/mjk/editor/_source/internals/fckselection.js
===================================================================
--- /FCKeditor/branches/developers/mjk/editor/_source/internals/fckselection.js	(revision 242)
+++ /FCKeditor/branches/developers/mjk/editor/_source/internals/fckselection.js	(revision 243)
@@ -23,2 +23,16 @@
 
 var FCKSelection = FCK.Selection = new Object() ;
+
+//Return the nearest ancestor to the current position of the caret.
+FCKSelection.GetCaretAncestor = function(strTag)
+{
+	var e = FCKSelection.GetParentElement();
+	var tn = e ?	FCKTools.GetElementAscensor(e,strTag) :
+					FCKSelection.MoveToAncestorNode(strTag);
+	return tn;
+}
+
+FCKSelection.SelectedText = function()
+{
+	return FCKTools.HTMLToText( this.SelectedHTML() );
+}
Index: /FCKeditor/branches/developers/mjk/editor/_source/internals/fckselection_gecko.js
===================================================================
--- /FCKeditor/branches/developers/mjk/editor/_source/internals/fckselection_gecko.js	(revision 242)
+++ /FCKeditor/branches/developers/mjk/editor/_source/internals/fckselection_gecko.js	(revision 243)
@@ -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/branches/developers/mjk/editor/_source/internals/fckselection_ie.js
===================================================================
--- /FCKeditor/branches/developers/mjk/editor/_source/internals/fckselection_ie.js	(revision 242)
+++ /FCKeditor/branches/developers/mjk/editor/_source/internals/fckselection_ie.js	(revision 243)
@@ -46,4 +46,5 @@
 	{
 		case 'Control' :
+			if (!FCKSelection.GetSelectedElement()) return;
 			return FCKSelection.GetSelectedElement().parentElement ;
 		case 'None' :
@@ -110,4 +111,25 @@
 }
 
+// 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.
 FCKSelection.MoveToAncestorNode = function( nodeTagName )
@@ -156,3 +178,8 @@
 }
 
+FCKSelection.SelectedHTML = function()
+{
+	return FCK.EditorDocument.selection.createRange().htmlText;
+}
 
+
Index: /FCKeditor/branches/developers/mjk/editor/_source/internals/fcktablehandler.js
===================================================================
--- /FCKeditor/branches/developers/mjk/editor/_source/internals/fcktablehandler.js	(revision 242)
+++ /FCKeditor/branches/developers/mjk/editor/_source/internals/fcktablehandler.js	(revision 243)
@@ -1,5 +1,5 @@
 ﻿/*
  * FCKeditor - The text editor for Internet - http://www.fckeditor.net
- * Copyright (C) 2003-2007 Frederico Caldeira Knabben
+ * Copyright ( C ) 2003-2007 Frederico Caldeira Knabben
  *
  * == BEGIN LICENSE ==
@@ -8,11 +8,11 @@
  * choice:
  *
- *  - GNU General Public License Version 2 or later (the "GPL")
+ *  - 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")
+ *  - 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")
+ *  - Mozilla Public License Version 1.1 or later ( the "MPL" )
  *    http://www.mozilla.org/MPL/MPL-1.1.html
  *
@@ -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] );
+		}
+	}
+	if ( !row  ) 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.children.length == 1 )
+		table.parentNode.parentNode.removeChild( table.parentNode );
+	else
+		table.parentNode.removeChild( table  ) ;
 }
 
@@ -83,5 +105,5 @@
 {
 	// Get the cell where the selection is placed in.
-	var oCell = FCKSelection.MoveToAncestorNode('TD') || FCKSelection.MoveToAncestorNode('TH') ;
+	var oCell = FCKSelection.MoveToAncestorNode( 'TD' ) || FCKSelection.MoveToAncestorNode( 'TH' ) ;
 
 	if ( !oCell ) return ;
@@ -103,5 +125,5 @@
 			continue ;
 
-		oCell = oRow.cells[iIndex-1].cloneNode(false) ;
+		oCell = oRow.cells[iIndex-1].cloneNode( false ) ;
 
 		if ( FCKBrowserInfo.IsGecko )
@@ -119,8 +141,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 ;
@@ -300,5 +332,18 @@
 			return c ;
 	}
-
+	
+	return null ;
+}
+
+// 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 ;
 }
@@ -384,2 +429,374 @@
 	}
 }
+
+//Returns TRUE if any cell has width set
+FCKTableHandler.HasCellWidths = function( table )
+{
+	for ( var r = 0; r < table.rows.length; r++ )
+	{
+		for ( var c = 0; c < table.rows[r].cells.length; c++ )
+		{
+			if ( table.rows[r].cells[c].width ) return true;
+		}
+	}
+	return false;
+}
+
+//Clears all cell widths/heights ( letting the browser size everything )
+FCKTableHandler.ClearCellWidths = function( table )
+{
+	for ( var r = 0; r < table.rows.length; r++ )
+	{
+		for ( var c = 0; c < table.rows[r].cells.length; c++ )
+		{
+			table.rows[r].cells[c].width = "";
+			table.rows[r].cells[c].height = "";
+			table.rows[r].cells[c].removeAttribute( "WIDTH" );
+			table.rows[r].cells[c].removeAttribute( "HEIGHT" );
+		}
+	}
+}
+
+//Cleanup table widths. If bPercent, recalculates table widths in %. If bClear,
+//moves all table widths as early as possible
+
+FCKTableHandler.CleanupTableWidths = function( table, bPercent, bClear, aMapIn )
+{
+	var aMap = aMapIn ? aMapIn : this._CreateTableMap( table ) ;
+	var nCols = aMap[0].length;
+	var nRows = aMap.length;
+	var nTotalWidth = 0;
+	var aSizeCells = new Array();
+	var aSizes = new Array();
+	//work the table column-by-column
+	for ( var nCol = 0; nCol < nCols; nCol++ )
+	{
+		var nMax = 0;
+		var oCell = null;
+		//walk the rows for a specific column -- find the topmost non-colspan'd item
+		//and the maximum pixel width ( according to the browser )
+		for ( var nRow = 0; nRow < nRows; nRow++ )
+		{
+			if ( aMap[nRow][nCol].colSpan > 1 ) continue;
+			//use topmost non-colspan'd cell to put the width in
+			if ( !oCell ) oCell = aMap[nRow][nCol];
+			if ( aMap[nRow][nCol].offsetWidth > nMax ) nMax = aMap[nRow][nCol].offsetWidth;
+		}
+		aSizes[nCol] = nMax;
+		nTotalWidth += nMax;
+		aSizeCells[nCol] = oCell;
+	}
+	//if we were asked for percentage width, go through and convert the sizes to %. note
+	//that we do this based on the calculated width of all the cells; this is more
+	//reliable because offsetWidth, et al., includes table borders, padding, etc.
+	for ( var nCol = 0; nCol < aSizeCells.length; nCol++ )
+	{
+		if ( bPercent )
+		{
+			var nWidth = Math.round( 100 * (aSizeCells[nCol].offsetWidth/nTotalWidth ));
+			if ( nWidth == 0 ) nWidth = 1;
+			strWidth =  nWidth + "%";
+		}
+		else
+		{
+			strWidth =  aSizes[nCol];
+		}
+
+		//set all width attributes
+		for ( var nRow = 0; nRow < nRows; nRow++ )
+		{
+			if ( aMap[nRow][nCol].colSpan == 1 )
+			{
+				aMap[nRow][nCol].width = bClear ? '' : strWidth;
+				if ( bClear ) aMap[nRow][nCol].removeAttribute( "width" );
+				aSizeCells[nCol].width = strWidth;
+			}
+		}
+	}
+}
+
+// Move the cursor into the next ( or previous ) cell
+FCKTableHandler.MoveToNextCell = function( bRev )
+{
+	var aCells = FCKTableHandler.GetSelectedCells();
+	if ( aCells.length == 0 ) return;
+	var oCell = aCells[0];
+	var oNextCell = bRev ? oCell.previousSibling: oCell.nextSibling;
+	if ( !oNextCell )
+	{
+		var oNext;
+		var oRow = FCKTools.GetElementAscensor( oCell,"TR" );
+		if ( bRev )
+		{
+			if ( !(oNext = oRow.previousSibling )) return;
+			oNextCell=oNext.cells[oNext.cells.length - 1];
+		}
+		else
+		{
+			if ( !(oNext = oRow.nextSibling )) return;
+			oNextCell=oNext.cells[0];
+		}
+	}
+	FCKSelection.SelectNode( oNextCell );
+	FCKSelection.Collapse();
+}
+//////////////////////////////////////////////////////////////////
+// Table Sizer
+//
+
+
+// Returns the closest sizeable cell to point (or the left of the specified point
+// if between cells). Generally, this will be a heading cell (i.e. a cell in
+// the first row). If *all* the candidate cells are colspan'd (heaven forbid),
+// don't allow sizing. x and y are in client coordinates
+
+FCKTableHandler.SizableCellFromPoint = function( table, ncx, ncy )
+{
+	var aRows = table.rows ;
+	var x = ncx - this._CalcPosition( table )[0];
+	for ( var i = 0 ; i < aRows.length ; i++  )
+	{
+		for ( var j = 0; j < aRows[i].cells.length - 1; j++ )
+		{
+			if ( aRows[i].cells[j + 1].offsetLeft > x )
+			{
+				if ( aRows[i].cells[j].colSpan < 2 )
+				{
+					return aRows[i].cells[j];
+				}
+				else
+				{
+					break;
+				}
+			}	
+		}
+	}
+	return null;
+}
+
+// Creates the table resize bar. If a table resize bar is present, uses it. You
+// must explicitly destroy the table resize bar with DestroyResizeBar after use.
+FCKTableHandler.CreateResizeBar = function()
+{
+	if ( this.ResizeBar ) return this.ResizeBar;
+	var oBar;	
+	oBar = FCK.EditorDocument.createElement( "SPAN" );
+
+	// setup the bar
+	oBar.id = '__FCKResizeBar';
+	oBar.style.position = "absolute";
+	oBar.style.top = "0px";
+	oBar.style.left = "0px";
+	oBar.style.height = "0px";
+	oBar.style.width = "2px";
+	oBar.style.borderLeft = "1px solid #0033FF";
+	oBar.style.display = "none";
+	oBar.style.cursor = "e-resize";
+
+	FCK.EditorDocument.body.appendChild( oBar );
+	this.ResizeBar = oBar;
+	return oBar;
+}
+
+// Destroys the table resize bar
+FCKTableHandler.DestroyResizeBar = function()
+{
+	if ( !this.ResizeBar ) return;
+	this.ResizeBar.parentNode.removeChild( FCKTableHandler.ResizeBar );
+	this.ResizeBar = null;
+}
+
+// Figures out whether we want to size or let the browser do its thing. We can
+// size if the table is the target and we're between cells, OR if we're on
+// a table cell and on the far right edge of the cell within 3px of the edge
+// ( allows us to easily size tables with thin borders )
+
+FCKTableHandler.CanSizeHere = function( ev, cell, tbl )
+{
+	var elem = ev.srcElement || ev.originalTarget;
+	var aCellLoc = this._CalcPosition( cell );
+	var aTableLoc = this._CalcPosition( tbl );
+	//in the td client area, but not on the edge
+	if ( elem != tbl ) return ( (aCellLoc[0] + cell.offsetWidth - ev.clientX ) < 3);
+	//on the table edge
+	if ( (aTableLoc[0] + tbl.offsetWidth - ev.clientX ) < 3 ||
+		( aTableLoc[0] - ev.clientX ) < 3 ||
+		( aTableLoc[1] + tbl.offsetHeight - ev.clientY < 3 ) ||
+		( aTableLoc[1] - ev.clientY < 3 )) return false;
+	return true;
+}
+
+
+// Sets up table sizing
+FCKTableHandler.StartTableSizing = function( ev, cell, tbl )
+{
+	if ( !cell ) return null;
+	this.tableMap = this._CreateTableMap( tbl ) ;
+	var aCellLoc = this._GetCellLocation( this.tableMap, cell );				//returns [row,col]
+	if ( !aCellLoc ) return null;
+	//we're in the last column, so we can't size
+	if ( aCellLoc[1] == this.tableMap[aCellLoc[0]].length - 1 ) return null;
+	var nTarget = aCellLoc[1] + 1;
+	this.adjacentCell = null;
+	for ( var i=0; i < this.tableMap.length; i++ )
+	{
+		if ( this.tableMap[i][nTarget].colSpan < 2 )
+		{
+			this.adjacentCell = this.tableMap[i][nTarget];
+			break;
+		}
+	}
+	if ( this.adjacentCell == null ) return null;	//can't size, no adjacent col
+	this.targetCell = cell;
+	//ok. we have everything we need. off we go.
+	
+	//create the resize bar
+	this.pixWidths = !( this.targetCell.width.search('%' ) == -1 || !this.targetCell.width);
+	var oVBar = this.CreateResizeBar();
+	//oVBar.style.left = FCK.EditorDocument.body.scrollLeft + this._CalcPosition( cell ) + cell.offsetWidth;
+	//this.origPos = FCK.EditorDocument.body.scrollLeft + ev.clientX;
+	this.origPos = FCK.EditorDocument.body.scrollLeft + this._CalcPosition( cell )[0] + cell.offsetWidth;
+	oVBar.style.left = this.origPos;
+	oVBar.style.cursor = "e-resize";
+	oVBar.setAttribute( "UNSELECTABLE","on" );
+	tbl.setAttribute( "UNSELECTABLE","on" );
+	this.sizeOffset = ev.clientX - this.origPos;
+	//minimum size is always the left edge of the cell + some safety margin.
+	//max size is always the right edge of the next cell - some safety margin
+	this.minSize = FCK.EditorDocument.body.scrollLeft + this._CalcPosition( cell )[0] + 10;
+	this.maxSize = FCK.EditorDocument.body.scrollLeft + this._CalcPosition( this.adjacentCell )[0] + this.adjacentCell.offsetWidth - 10;
+	oVBar.style.top = this._CalcPosition( tbl )[1];
+	oVBar.style.height = tbl.clientHeight + ( tbl.border*2 );
+	oVBar.style.display = "inline";
+	this.CleanupTableWidths( tbl,false, true,this.tableMap );
+	return true;
+}
+
+FCKTableHandler.FinishTableSizing = function()
+{
+	var tbl = FCKTools.GetElementAscensor( this.targetCell,"TABLE" );
+	var nTargetDiff = this.ResizeBar.offsetLeft - this.origPos;
+	//widths are in pixels after StartTableSizing, so this is safe
+	tbl.style.cursor = '';
+	if ( tbl.runtimeStyle ) tbl.runtimeStyle.cursor = '';
+	this.targetCell.width = parseInt( this.targetCell.width ) + nTargetDiff;
+	this.adjacentCell.width = parseInt( this.adjacentCell.width ) - nTargetDiff;
+	this.DestroyResizeBar();
+	this.CleanupTableWidths( tbl,this.pixWidths,true,this.tableMap );
+	this.targetCell = null;
+	this.origPos = null;
+	tbl.removeAttribute( "UNSELECTABLE" );
+	if ( FCKBrowserInfo.IsGecko  ) tbl.style.MozUserSelect = "";
+}
+
+// Sizes the table to the given mouse position
+FCKTableHandler.SizeTo = function( x )
+{
+	var nPos = x - this.sizeOffset;
+	if ( nPos > this.maxSize ) nPos = this.maxSize;
+	if ( nPos < this.minSize ) nPos = this.minSize;
+	//runtimeStyle is way faster under IE
+	if ( this.ResizeBar.runtimeStyle )
+		this.ResizeBar.runtimeStyle.left = nPos;
+	else
+		this.ResizeBar.style.left = nPos;
+	if ( FCKBrowserInfo.IsGecko && FCK.EditorDocument.selection.type != 'None' ) FCK.EditorDocument.selection.collapse();
+}
+
+// returns TRUE if we are actively sizing a table
+FCKTableHandler.IsTableSizing = function()
+{
+	return ( this.targetCell != null );
+}
+
+// figure out where ( with respect to the edge of the parent ) a given table/cell is
+FCKTableHandler._CalcPosition = function( ob )
+{
+	var oParent=ob;
+	var nY = 0;
+	var nX = 0;
+	while ( oParent && oParent.tagName != "BODY" )
+	{
+		nX += oParent.offsetLeft;
+		nY += oParent.offsetTop;
+		oParent = oParent.offsetParent;
+	}
+	return [nX,nY];
+}
+
+FCKTableHandler.tbl_MouseDown = function ( FCK, e )
+{
+	var elem = e.srcElement || e.originalTarget;
+	var strTag = elem ? elem.tagName.toUpperCase() : null;
+	//find the table we're part of, if we are
+	if ( elem && (strTag == 'TABLE' || strTag == 'TD' || strTag == 'TH' ) )
+	{
+		FCKTableHandler.targetCell = null;
+		var oTable = FCKTools.GetElementAscensor( elem, "TABLE" );
+		//figure out if there's a cell we can size
+		var oCell = FCKTableHandler.SizableCellFromPoint( oTable, e.clientX, e.clientY );
+		if ( !oCell ) return true;
+		if ( FCKTableHandler.CanSizeHere( e,oCell,oTable ) )
+		{
+			if ( FCKTableHandler.StartTableSizing( e,oCell, oTable ) )
+			{
+				if ( oTable.runtimeStyle ) oTable.runtimeStyle.cursor = "e-resize";
+				if ( FCKBrowserInfo.IsGecko  ) oTable.style.MozUserSelect = "none";
+				e.cancelBubble	= true ;
+				e.returnValue	= false ;
+				return false;
+			}
+		}
+	}
+	return true;
+}
+
+FCKTableHandler.tbl_MouseUp = function ( FCK, e )
+{
+	if ( FCKTableHandler.IsTableSizing( )) FCKTableHandler.FinishTableSizing();
+}
+
+FCKTableHandler.tbl_MouseMove = function ( FCK, e )
+{
+	var elem = e.srcElement || e.originalTarget;
+	if ( FCKTableHandler.IsTableSizing() )
+	{
+		FCKTableHandler.SizeTo( e.clientX );
+		e.cancelBubble	= true ;
+		e.returnValue	= false ;
+		return false;
+	}
+	
+	if ( elem.tagName.toUpperCase() == 'TABLE' )
+	{
+		//let the browser handle global sizing and move if the user is on
+		//the RH edge of a table
+		if ( elem.clientWidth - e.offsetX < 3 ||
+			elem.clientHeight - e.offsetY < 3 ||
+			e.offsetX < 2 || e.offsetY < 2 )
+		{
+			elem.style.cursor = "";	
+			return true;
+		}
+		//block browser sizing -- we're going to do it ourselves, thanks
+		if ( elem.runtimeStyle ) elem.runtimeStyle.cursor = "e-resize";
+		e.cancelBubble	= true ;
+		e.returnValue	= false ;
+		return false;
+	}
+	else if ( elem.tagName.toUpperCase() == 'TD' )
+	{
+	    var tbl = FCKTools.GetElementAscensor( elem, "TABLE" );
+		if ( e.offsetX >= (elem.offsetWidth - 4 ))
+		{
+			e.cancelBubble	= true ;
+			e.returnValue	= false ;
+			return false;
+	    }
+	}
+	return true;
+}
+
+FCK.Events.AttachEvent( "OnMouseMove", FCKTableHandler.tbl_MouseMove );
+FCK.Events.AttachEvent( "OnMouseDown", FCKTableHandler.tbl_MouseDown );
+FCK.Events.AttachEvent( "OnMouseUp", FCKTableHandler.tbl_MouseUp );
Index: /FCKeditor/branches/developers/mjk/editor/_source/internals/fcktools.js
===================================================================
--- /FCKeditor/branches/developers/mjk/editor/_source/internals/fcktools.js	(revision 242)
+++ /FCKeditor/branches/developers/mjk/editor/_source/internals/fcktools.js	(revision 243)
@@ -94,4 +94,23 @@
 
 	return text ;
+}
+
+//convert text to Proper Case
+FCKTools.ProperCase = function( text )
+{
+	var strPC = text.toLowerCase();
+	return strPC.replace(/(\S)(\S*\s*)/g,
+						function(str,p1,p2) 
+							{return p1.toUpperCase()+p2});
+}
+
+FCKTools.HTMLToText = function( st )
+{
+	if ( !st ) 
+		return null;
+		
+	st = st.replace(/<([^>]*?)>/g,'');
+	st = st.replace(/&nbsp;/gi,' ');
+	return st;
 }
 
