Index: /CKEditor/trunk/CHANGES.html
===================================================================
--- /CKEditor/trunk/CHANGES.html	(revision 6327)
+++ /CKEditor/trunk/CHANGES.html	(revision 6328)
@@ -95,4 +95,5 @@
 		<li><a href="http://dev.ckeditor.com/ticket/6630">#6630</a> :  Empty pre output variants among browsers.</li>
 		<li><a href="http://dev.ckeditor.com/ticket/6615">#6615</a> :  [IE7] tableresize usability enhancement.</li>
+		<li><a href="http://dev.ckeditor.com/ticket/6568">#6568</a> :  Insert table row/column doesn't work with spanning.</li>
 	</ul>
 	<h3>
Index: /CKEditor/trunk/_source/plugins/tabletools/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/tabletools/plugin.js	(revision 6327)
+++ /CKEditor/trunk/_source/plugins/tabletools/plugin.js	(revision 6328)
@@ -6,12 +6,4 @@
 (function()
 {
-	function removeRawAttribute( $node, attr )
-	{
-		if ( CKEDITOR.env.ie )
-			$node.removeAttribute( attr );
-		else
-			delete $node[ attr ];
-	}
-
 	var cellNodeRegex = /^(?:td|th)$/;
 
@@ -124,35 +116,48 @@
 	}
 
-	function clearRow( $tr )
-	{
-		// Get the array of row's cells.
-		var $cells = $tr.cells;
-
-		// Empty all cells.
-		for ( var i = 0 ; i < $cells.length ; i++ )
-		{
-			$cells[ i ].innerHTML = '';
-
-			if ( !CKEDITOR.env.ie )
-				( new CKEDITOR.dom.element( $cells[ i ] ) ).appendBogus();
-		}
-	}
-
 	function insertRow( selection, insertBefore )
 	{
-		// Get the row where the selection is placed in.
-		var row = selection.getStartElement().getAscendant( 'tr' );
-		if ( !row )
-			return;
-
-		// Create a clone of the row.
-		var newRow = row.clone( 1 );
+		var cells = getSelectedCells( selection ),
+				firstCell = cells[ 0 ],
+				table = firstCell.getAscendant( 'table' ),
+				doc = firstCell.getDocument(),
+				startRow = cells[ 0 ].getParent(),
+				startRowIndex = startRow.$.rowIndex,
+				lastCell = cells[ cells.length - 1 ],
+				endRowIndex = lastCell.getParent().$.rowIndex + lastCell.$.rowSpan - 1,
+				endRow = new CKEDITOR.dom.element( table.$.rows[ endRowIndex ] ),
+				rowIndex = insertBefore ? startRowIndex : endRowIndex,
+				row = insertBefore ? startRow : endRow;
+
+		var map = CKEDITOR.tools.buildTableMap( table ),
+				cloneRow = map[ rowIndex ],
+				nextRow = insertBefore ? map[ rowIndex - 1 ] : map[ rowIndex + 1 ],
+				width = map[0].length;
+
+		var newRow = doc.createElement( 'tr' );
+		for ( var i = 0; i < width; i++ )
+		{
+			var cell;
+			// Check whether there's a spanning row here, do not break it.
+			if ( cloneRow[ i ].rowSpan > 1 && nextRow && cloneRow[ i ] == nextRow[ i ] )
+			{
+				cell = cloneRow[ i ];
+				cell.rowSpan += 1;
+			}
+			else
+			{
+				cell = new CKEDITOR.dom.element( cloneRow[ i ] ).clone();
+				cell.removeAttribute( 'rowSpan' );
+				!CKEDITOR.env.ie && cell.appendBogus();
+				newRow.append( cell );
+				cell = cell.$;
+			}
+
+			i += cell.colSpan - 1;
+		}
 
 		insertBefore ?
-			newRow.insertBefore( row ) :
-			newRow.insertAfter( row );
-
-		// Clean the new row.
-		clearRow( newRow.$ );
+		newRow.insertBefore( row ) :
+		newRow.insertAfter( row );
 	}
 
@@ -162,24 +167,48 @@
 		{
 			var cells = getSelectedCells( selectionOrRow ),
-				cellsCount = cells.length,
-				rowsToDelete = [],
-				cursorPosition,
-				previousRowIndex,
-				nextRowIndex;
-
-			// Queue up the rows - it's possible and likely that we have duplicates.
-			for ( var i = 0 ; i < cellsCount ; i++ )
-			{
-				var row = cells[ i ].getParent(),
-						rowIndex = row.$.rowIndex;
-
-				!i && ( previousRowIndex = rowIndex - 1 );
-				rowsToDelete[ rowIndex ] = row;
-				i == cellsCount - 1 && ( nextRowIndex = rowIndex + 1 );
-			}
-
-			var table = row.getAscendant( 'table' ),
-					rows =  table.$.rows,
-					rowCount = rows.length;
+					firstCell = cells[ 0 ],
+					table = firstCell.getAscendant( 'table' ),
+					map = CKEDITOR.tools.buildTableMap( table ),
+					startRow = cells[ 0 ].getParent(),
+					startRowIndex = startRow.$.rowIndex,
+					lastCell = cells[ cells.length - 1 ],
+					endRowIndex = lastCell.getParent().$.rowIndex + lastCell.$.rowSpan - 1,
+					rowsToDelete = [];
+
+			// Delete cell or reduce cell spans by checking through the table map.
+			for ( var i = startRowIndex; i <= endRowIndex; i++ )
+			{
+				var mapRow = map[ i ],
+						row = new CKEDITOR.dom.element( table.$.rows[ i ] );
+
+				for ( var j = 0; j < mapRow.length; j++ )
+				{
+					var cell = new CKEDITOR.dom.element( mapRow[ j ] ),
+							cellRowIndex = cell.getParent().$.rowIndex;
+
+					if ( cell.$.rowSpan == 1 )
+						cell.remove();
+					// Row spanned cell.
+					else
+					{
+						// Span row of the cell, reduce spanning.
+						cell.$.rowSpan -= 1;
+						// Root row of the cell, root cell to next row.
+						if ( cellRowIndex == i )
+						{
+							var nextMapRow = map[ i + 1 ];
+							nextMapRow[ j - 1 ] ?
+							cell.insertAfter( new CKEDITOR.dom.element( nextMapRow[ j - 1 ] ) )
+									: new CKEDITOR.dom.element( table.$.rows[ i + 1 ] ).append( cell, 1 );
+						}
+					}
+
+					j += cell.$.colSpan - 1;
+				}
+
+				rowsToDelete.push( row );
+			}
+
+			var rows = table.$.rows;
 
 			// Where to put the cursor after rows been deleted?
@@ -187,14 +216,8 @@
 			// 2. Into previous sibling row if any;
 			// 3. Into table's parent element if it's the very last row.
-			cursorPosition = new CKEDITOR.dom.element(
-				nextRowIndex < rowCount && table.$.rows[ nextRowIndex ] ||
-				previousRowIndex > 0 && table.$.rows[ previousRowIndex ] ||
-				table.$.parentNode );
+			var cursorPosition =  new CKEDITOR.dom.element( rows[ startRowIndex ] || rows[ startRowIndex - 1 ] || table.$.parentNode );
 
 			for ( i = rowsToDelete.length ; i >= 0 ; i-- )
-			{
-				if ( rowsToDelete[ i ] )
-					deleteRows( rowsToDelete[ i ] );
-			}
+				deleteRows( rowsToDelete[ i ] );
 
 			return cursorPosition;
@@ -209,42 +232,138 @@
 				selectionOrRow.remove();
 		}
-
-		return 0;
+	}
+
+	function getCellColIndex( cell, isStart )
+	{
+		var row = cell.getParent(),
+			rowCells = row.$.cells;
+
+		var colIndex = 0;
+		for ( var i = 0; i < rowCells.length; i++ )
+		{
+			var mapCell = rowCells[ i ];
+			colIndex += isStart ? 1 : mapCell.colSpan;
+			if ( mapCell == cell.$ )
+				break;
+		}
+
+		return colIndex -1;
+	}
+
+	function getColumnsIndices( cells, isStart )
+	{
+		var retval = isStart ? Infinity : 0;
+		for ( var i = 0; i < cells.length; i++ )
+		{
+			var colIndex = getCellColIndex( cells[ i ], isStart );
+			if ( isStart ? colIndex < retval  : colIndex > retval )
+				retval = colIndex;
+		}
+		return retval;
 	}
 
 	function insertColumn( selection, insertBefore )
 	{
-		// Get the cell where the selection is placed in.
-		var startElement = selection.getStartElement();
-		var cell = startElement.getAscendant( 'td', 1 ) || startElement.getAscendant( 'th', 1 );
-
-		if ( !cell )
-			return;
-
-		// Get the cell's table.
-		var table = cell.getAscendant( 'table' );
-		var cellIndex = cell.$.cellIndex;
-
-		// Loop through all rows available in the table.
-		for ( var i = 0 ; i < table.$.rows.length ; i++ )
-		{
-			var $row = table.$.rows[ i ];
-
-			// If the row doesn't have enough cells, ignore it.
-			if ( $row.cells.length < ( cellIndex + 1 ) )
-				continue;
-
-			cell = ( new CKEDITOR.dom.element( $row.cells[ cellIndex ] ) ).clone( 0 );
-
-			if ( !CKEDITOR.env.ie )
-				cell.appendBogus();
-
-			// Get back the currently selected cell.
-			var baseCell = new CKEDITOR.dom.element( $row.cells[ cellIndex ] );
-			if ( insertBefore )
-				cell.insertBefore( baseCell );
+		var cells = getSelectedCells( selection ),
+			firstCell = cells[ 0 ],
+			table = firstCell.getAscendant( 'table' ),
+			startCol =  getColumnsIndices( cells, 1 ),
+			lastCol =  getColumnsIndices( cells ),
+			colIndex = insertBefore? startCol : lastCol;
+
+		var map = CKEDITOR.tools.buildTableMap( table ),
+			cloneCol = [],
+			nextCol = [],
+			height = map.length;
+
+		for ( var i = 0; i < height; i++ )
+		{
+			cloneCol.push( map[ i ][ colIndex ] );
+			var nextCell = insertBefore ? map[ i ][ colIndex - 1 ] : map[ i ][ colIndex + 1 ];
+			nextCell && nextCol.push( nextCell );
+		}
+
+		for ( i = 0; i < height; i++ )
+		{
+			var cell;
+			// Check whether there's a spanning column here, do not break it.
+			if ( cloneCol[ i ].colSpan > 1
+				&& nextCol.length
+				&& nextCol[ i ] == cloneCol[ i ] )
+			{
+				cell = cloneCol[ i ];
+				cell.colSpan += 1;
+			}
 			else
-				cell.insertAfter( baseCell );
-		}
+			{
+				cell = new CKEDITOR.dom.element( cloneCol[ i ] ).clone();
+				cell.removeAttribute( 'colSpan' );
+				!CKEDITOR.env.ie && cell.appendBogus();
+				cell[ insertBefore? 'insertBefore' : 'insertAfter' ].call( cell, new CKEDITOR.dom.element ( cloneCol[ i ] ) );
+				cell = cell.$;
+			}
+
+			i += cell.rowSpan - 1;
+		}
+	}
+
+	function deleteColumns( selectionOrCell )
+	{
+		var cells = getSelectedCells( selectionOrCell ),
+				firstCell = cells[ 0 ],
+				lastCell = cells[ cells.length - 1 ],
+				table = firstCell.getAscendant( 'table' ),
+				map = CKEDITOR.tools.buildTableMap( table ),
+				startColIndex,
+				endColIndex,
+				rowsToDelete = [];
+
+		// Figure out selected cells' column indices.
+		for ( var i = 0, rows = map.length; i < rows; i++ )
+		{
+			for ( var j = 0, cols = map[ i ].length; j < cols; j++ )
+			{
+				if ( map[ i ][ j ] == firstCell.$ )
+					startColIndex = j;
+				if ( map[ i ][ j ] == lastCell.$ )
+					endColIndex = j;
+			}
+		}
+
+		// Delete cell or reduce cell spans by checking through the table map.
+		for ( i = startColIndex; i <= endColIndex; i++ )
+		{
+			for ( j = 0; j < map.length; j++ )
+			{
+				var mapRow = map[ j ],
+					row = new CKEDITOR.dom.element( table.$.rows[ j ] ),
+					cell = new CKEDITOR.dom.element( mapRow[ i ] );
+
+				if ( cell.$.colSpan == 1 )
+					cell.remove();
+				// Reduce the col spans.
+				else
+					cell.$.colSpan -= 1;
+
+				j += cell.$.rowSpan - 1;
+
+				if ( !row.$.cells.length )
+					rowsToDelete.push( row );
+			}
+		}
+
+		var firstRowCells = table.$.rows[ 0 ] && table.$.rows[ 0 ].cells;
+
+		// Where to put the cursor after columns been deleted?
+		// 1. Into next cell of the first row if any;
+		// 2. Into previous cell of the first row if any;
+		// 3. Into table's parent element;
+		var cursorPosition =  new CKEDITOR.dom.element( firstRowCells[ startColIndex ] || ( startColIndex ? firstRowCells[ startColIndex - 1 ] : table.$.parentNode ) );
+
+		// Delete table rows only if all columns are gone (do not remove empty row).
+		if ( rowsToDelete.length == rows )
+			table.remove();
+
+		return cursorPosition;
 	}
 
@@ -285,54 +404,4 @@
 
 		return targetCell ?  new CKEDITOR.dom.element( targetCell ) :  table.getPrevious();
-	}
-
-	function deleteColumns( selectionOrCell )
-	{
-		if ( selectionOrCell instanceof CKEDITOR.dom.selection )
-		{
-			var colsToDelete = getSelectedCells( selectionOrCell ),
-				elementToFocus = getFocusElementAfterDelCols( colsToDelete );
-
-			for ( var i = colsToDelete.length - 1 ; i >= 0 ; i-- )
-			{
-				if ( colsToDelete[ i ] )
-					deleteColumns( colsToDelete[ i ] );
-			}
-
-			return elementToFocus;
-		}
-		else if ( selectionOrCell instanceof CKEDITOR.dom.element )
-		{
-			// Get the cell's table.
-			var table = selectionOrCell.getAscendant( 'table' );
-			if ( !table )
-				return null;
-
-			// Get the cell index.
-			var cellIndex = selectionOrCell.$.cellIndex;
-
-			/*
-			 * Loop through all rows from down to up, coz it's possible that some rows
-			 * will be deleted.
-			 */
-			for ( i = table.$.rows.length - 1 ; i >= 0 ; i-- )
-			{
-				// Get the row.
-				var row = new CKEDITOR.dom.element( table.$.rows[ i ] );
-
-				// If the cell to be removed is the first one and the row has just one cell.
-				if ( !cellIndex && row.$.cells.length == 1 )
-				{
-					deleteRows( row );
-					continue;
-				}
-
-				// Else, just delete the cell.
-				if ( row.$.cells[ cellIndex ] )
-					row.$.removeChild( row.$.cells[ cellIndex ] );
-			}
-		}
-
-		return null;
 	}
 
