JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.0
[ckeditor.git] / _source / plugins / tabletools / plugin.js
diff --git a/_source/plugins/tabletools/plugin.js b/_source/plugins/tabletools/plugin.js
new file mode 100644 (file)
index 0000000..d68954a
--- /dev/null
@@ -0,0 +1,701 @@
+/*\r
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.\r
+For licensing, see LICENSE.html or http://ckeditor.com/license\r
+*/\r
+\r
+(function()\r
+{\r
+       function removeRawAttribute( $node, attr )\r
+       {\r
+               if ( CKEDITOR.env.ie )\r
+                       $node.removeAttribute( attr );\r
+               else\r
+                       delete $node[ attr ];\r
+       }\r
+\r
+       var cellNodeRegex = /^(?:td|th)$/;\r
+\r
+       function getSelectedCells( selection )\r
+       {\r
+               // Walker will try to split text nodes, which will make the current selection\r
+               // invalid. So save bookmarks before doing anything.\r
+               var bookmarks = selection.createBookmarks();\r
+\r
+               var ranges = selection.getRanges();\r
+               var retval = [];\r
+               var database = {};\r
+\r
+               function moveOutOfCellGuard( node )\r
+               {\r
+                       // Apply to the first cell only.\r
+                       if ( retval.length > 0 )\r
+                               return;\r
+\r
+                       // If we are exiting from the first </td>, then the td should definitely be\r
+                       // included.\r
+                       if ( node.type == CKEDITOR.NODE_ELEMENT && cellNodeRegex.test( node.getName() )\r
+                                       && !node.getCustomData( 'selected_cell' ) )\r
+                       {\r
+                               CKEDITOR.dom.element.setMarker( database, node, 'selected_cell', true );\r
+                               retval.push( node );\r
+                       }\r
+               }\r
+\r
+               for ( var i = 0 ; i < ranges.length ; i++ )\r
+               {\r
+                       var range = ranges[ i ];\r
+\r
+                       if ( range.collapsed )\r
+                       {\r
+                               // Walker does not handle collapsed ranges yet - fall back to old API.\r
+                               var startNode = range.getCommonAncestor();\r
+                               var nearestCell = startNode.getAscendant( 'td', true ) || startNode.getAscendant( 'th', true );\r
+                               if ( nearestCell )\r
+                                       retval.push( nearestCell );\r
+                       }\r
+                       else\r
+                       {\r
+                               var walker = new CKEDITOR.dom.walker( range );\r
+                               var node;\r
+                               walker.guard = moveOutOfCellGuard;\r
+\r
+                               while ( ( node = walker.next() ) )\r
+                               {\r
+                                       // If may be possible for us to have a range like this:\r
+                                       // <td>^1</td><td>^2</td>\r
+                                       // The 2nd td shouldn't be included.\r
+                                       //\r
+                                       // So we have to take care to include a td we've entered only when we've\r
+                                       // walked into its children.\r
+\r
+                                       var parent = node.getParent();\r
+                                       if ( parent && cellNodeRegex.test( parent.getName() ) && !parent.getCustomData( 'selected_cell' ) )\r
+                                       {\r
+                                               CKEDITOR.dom.element.setMarker( database, parent, 'selected_cell', true );\r
+                                               retval.push( parent );\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               CKEDITOR.dom.element.clearAllMarkers( database );\r
+\r
+               // Restore selection position.\r
+               selection.selectBookmarks( bookmarks );\r
+\r
+               return retval;\r
+       }\r
+\r
+       function createTableMap( $refCell )\r
+       {\r
+               var refCell = new CKEDITOR.dom.element( $refCell );\r
+               var $table = ( refCell.getName() == 'table' ? $refCell : refCell.getAscendant( 'table' ) ).$;\r
+               var $rows = $table.rows;\r
+\r
+               // Row and column counters.\r
+               var r = -1;\r
+               var map = [];\r
+               for ( var i = 0 ; i < $rows.length ; i++ )\r
+               {\r
+                       r++;\r
+                       if ( !map[ r ] )\r
+                               map[ r ] = [];\r
+\r
+                       var c = -1;\r
+\r
+                       for ( var j = 0 ; j < $rows[ i ].cells.length ; j++ )\r
+                       {\r
+                               var $cell = $rows[ i ].cells[ j ];\r
+\r
+                               c++;\r
+                               while ( map[ r ][ c ] )\r
+                                       c++;\r
+\r
+                               var colSpan = isNaN( $cell.colSpan ) ? 1 : $cell.colSpan;\r
+                               var rowSpan = isNaN( $cell.rowSpan ) ? 1 : $cell.rowSpan;\r
+\r
+                               for ( var rs = 0 ; rs < rowSpan ; rs++ )\r
+                               {\r
+                                       if ( !map[ r + rs ] )\r
+                                               map[ r + rs ] = [];\r
+\r
+                                       for ( var cs = 0 ; cs < colSpan ; cs++ )\r
+                                               map [ r + rs ][ c + cs ] = $rows[ i ].cells[ j ];\r
+                               }\r
+\r
+                               c += colSpan - 1;\r
+                       }\r
+               }\r
+\r
+               return map;\r
+       }\r
+\r
+       function installTableMap( tableMap, $table )\r
+       {\r
+               /*\r
+                * IE BUG: rowSpan is always 1 in IE if the cell isn't attached to a row. So\r
+                * store is separately in another attribute. (#1917)\r
+                */\r
+               var rowSpanAttr = CKEDITOR.env.ie ? '_cke_rowspan' : 'rowSpan';\r
+\r
+               /*\r
+                * Disconnect all the cells in tableMap from their parents, set all colSpan\r
+                * and rowSpan attributes to 1.\r
+                */\r
+               for ( var i = 0 ; i < tableMap.length ; i++ )\r
+               {\r
+                       for ( var j = 0 ; j < tableMap[ i ].length ; j++ )\r
+                       {\r
+                               var $cell = tableMap[ i ][ j ];\r
+                               if ( $cell.parentNode )\r
+                                       $cell.parentNode.removeChild( $cell );\r
+                               $cell.colSpan = $cell[ rowSpanAttr ] = 1;\r
+                       }\r
+               }\r
+\r
+               // Scan by rows and set colSpan.\r
+               var maxCol = 0;\r
+               for ( i = 0 ; i < tableMap.length ; i++ )\r
+               {\r
+                       for ( j = 0 ; j < tableMap[ i ].length ; j++ )\r
+                       {\r
+                               $cell = tableMap[ i ][ j ];\r
+                               if ( !$cell )\r
+                                       continue;\r
+                               if ( j > maxCol )\r
+                                       maxCol = j;\r
+                               if ( $cell[ '_cke_colScanned' ] )\r
+                                       continue;\r
+                               if ( tableMap[ i ][ j - 1 ] == $cell )\r
+                                       $cell.colSpan++;\r
+                               if ( tableMap[ i ][ j + 1 ] != $cell )\r
+                                       $cell[ '_cke_colScanned' ] = 1;\r
+                       }\r
+               }\r
+\r
+               // Scan by columns and set rowSpan.\r
+               for ( i = 0 ; i <= maxCol ; i++ )\r
+               {\r
+                       for ( j = 0 ; j < tableMap.length ; j++ )\r
+                       {\r
+                               if ( !tableMap[ j ] )\r
+                                       continue;\r
+                               $cell = tableMap[ j ][ i ];\r
+                               if ( !$cell || $cell[ '_cke_rowScanned' ] )\r
+                                       continue;\r
+                               if ( tableMap[ j - 1 ] && tableMap[ j - 1 ][ i ] == $cell )\r
+                                       $cell[ rowSpanAttr ]++;\r
+                               if ( !tableMap[ j + 1 ] || tableMap[ j + 1 ][ i ] != $cell  )\r
+                                       $cell[ '_cke_rowScanned' ] = 1;\r
+                       }\r
+               }\r
+\r
+               // Clear all temporary flags.\r
+               for ( i = 0 ; i < tableMap.length ; i++ )\r
+               {\r
+                       for ( j = 0 ; j < tableMap[ i ].length ; j++ )\r
+                       {\r
+                               $cell = tableMap[ i ][ j ];\r
+                               removeRawAttribute( $cell, '_cke_colScanned' );\r
+                               removeRawAttribute( $cell, '_cke_rowScanned' );\r
+                       }\r
+               }\r
+\r
+               // Insert physical rows and columns to table.\r
+               for ( i = 0 ; i < tableMap.length ; i++ )\r
+               {\r
+                       var $row = $table.ownerDocument.createElement( 'tr' );\r
+                       for ( j = 0 ; j < tableMap[ i ].length ; )\r
+                       {\r
+                               $cell = tableMap[ i ][ j ];\r
+                               if ( tableMap[ i - 1 ] && tableMap[ i - 1 ][ j ] == $cell )\r
+                               {\r
+                                       j += $cell.colSpan;\r
+                                       continue;\r
+                               }\r
+                               $row.appendChild( $cell );\r
+                               if ( rowSpanAttr != 'rowSpan' )\r
+                               {\r
+                                       $cell.rowSpan = $cell[ rowSpanAttr ];\r
+                                       $cell.removeAttribute( rowSpanAttr );\r
+                               }\r
+                               j += $cell.colSpan;\r
+                               if ( $cell.colSpan == 1 )\r
+                                       $cell.removeAttribute( 'colSpan' );\r
+                               if ( $cell.rowSpan == 1 )\r
+                                       $cell.removeAttribute( 'rowSpan' );\r
+                       }\r
+\r
+                       if ( CKEDITOR.env.ie )\r
+                               $table.rows[ i ].replaceNode( $row );\r
+                       else\r
+                       {\r
+                               var dest = new CKEDITOR.dom.element( $table.rows[ i ] );\r
+                               var src = new CKEDITOR.dom.element( $row );\r
+                               dest.setHtml( '' );\r
+                               src.moveChildren( dest );\r
+                       }\r
+               }\r
+       }\r
+\r
+       function clearRow( $tr )\r
+       {\r
+               // Get the array of row's cells.\r
+               var $cells = $tr.cells;\r
+\r
+               // Empty all cells.\r
+               for ( var i = 0 ; i < $cells.length ; i++ )\r
+               {\r
+                       $cells[ i ].innerHTML = '';\r
+\r
+                       if ( !CKEDITOR.env.ie )\r
+                               ( new CKEDITOR.dom.element( $cells[ i ] ) ).appendBogus();\r
+               }\r
+       }\r
+\r
+       function insertRow( selection, insertBefore )\r
+       {\r
+               // Get the row where the selection is placed in.\r
+               var row = selection.getStartElement().getAscendant( 'tr' );\r
+               if ( !row )\r
+                       return;\r
+\r
+               // Create a clone of the row.\r
+               var newRow = row.clone( true );\r
+\r
+               // Insert the new row before of it.\r
+               newRow.insertBefore( row );\r
+\r
+               // Clean one of the rows to produce the illusion of inserting an empty row\r
+               // before or after.\r
+               clearRow( insertBefore ? newRow.$ : row.$ );\r
+       }\r
+\r
+       function deleteRows( selectionOrRow )\r
+       {\r
+               if ( selectionOrRow instanceof CKEDITOR.dom.selection )\r
+               {\r
+                       var cells = getSelectedCells( selectionOrRow );\r
+                       var rowsToDelete = [];\r
+\r
+                       // Queue up the rows - it's possible and likely that we have duplicates.\r
+                       for ( var i = 0 ; i < cells.length ; i++ )\r
+                       {\r
+                               var row = cells[ i ].getParent();\r
+                               rowsToDelete[ row.$.rowIndex ] = row;\r
+                       }\r
+\r
+                       for ( i = rowsToDelete.length ; i >= 0 ; i-- )\r
+                       {\r
+                               if ( rowsToDelete[ i ] )\r
+                                       deleteRows( rowsToDelete[ i ] );\r
+                       }\r
+               }\r
+               else if ( selectionOrRow instanceof CKEDITOR.dom.element )\r
+               {\r
+                       var table = selectionOrRow.getAscendant( 'table' );\r
+\r
+                       if ( table.$.rows.length == 1 )\r
+                               table.remove();\r
+                       else\r
+                               selectionOrRow.remove();\r
+               }\r
+       }\r
+\r
+       function insertColumn( selection, insertBefore )\r
+       {\r
+               // Get the cell where the selection is placed in.\r
+               var startElement = selection.getStartElement();\r
+               var cell = startElement.getAscendant( 'td', true ) || startElement.getAscendant( 'th', true );\r
+\r
+               if ( !cell )\r
+                       return;\r
+\r
+               // Get the cell's table.\r
+               var table = cell.getAscendant( 'table' );\r
+               var cellIndex = cell.$.cellIndex;\r
+\r
+               // Loop through all rows available in the table.\r
+               for ( var i = 0 ; i < table.$.rows.length ; i++ )\r
+               {\r
+                       var $row = table.$.rows[ i ];\r
+\r
+                       // If the row doesn't have enough cells, ignore it.\r
+                       if ( $row.cells.length < ( cellIndex + 1 ) )\r
+                               continue;\r
+\r
+                       cell = new CKEDITOR.dom.element( $row.cells[ cellIndex ].cloneNode( false ) );\r
+\r
+                       if ( !CKEDITOR.env.ie )\r
+                               cell.appendBogus();\r
+\r
+                       // Get back the currently selected cell.\r
+                       var baseCell = new CKEDITOR.dom.element( $row.cells[ cellIndex ] );\r
+                       if ( insertBefore )\r
+                               cell.insertBefore( baseCell );\r
+                       else\r
+                               cell.insertAfter( baseCell );\r
+               }\r
+       }\r
+\r
+       function deleteColumns( selectionOrCell )\r
+       {\r
+               if ( selectionOrCell instanceof CKEDITOR.dom.selection )\r
+               {\r
+                       var colsToDelete = getSelectedCells( selectionOrCell );\r
+                       for ( var i = colsToDelete.length ; i >= 0 ; i-- )\r
+                       {\r
+                               if ( colsToDelete[ i ] )\r
+                                       deleteColumns( colsToDelete[ i ] );\r
+                       }\r
+               }\r
+               else if ( selectionOrCell instanceof CKEDITOR.dom.element )\r
+               {\r
+                       // Get the cell's table.\r
+                       var table = selectionOrCell.getAscendant( 'table' );\r
+\r
+                       // Get the cell index.\r
+                       var cellIndex = selectionOrCell.$.cellIndex;\r
+\r
+                       /*\r
+                        * Loop through all rows from down to up, coz it's possible that some rows\r
+                        * will be deleted.\r
+                        */\r
+                       for ( i = table.$.rows.length - 1 ; i >= 0 ; i-- )\r
+                       {\r
+                               // Get the row.\r
+                               var row = new CKEDITOR.dom.element( table.$.rows[ i ] );\r
+\r
+                               // If the cell to be removed is the first one and the row has just one cell.\r
+                               if ( !cellIndex && row.$.cells.length == 1 )\r
+                               {\r
+                                       deleteRows( row );\r
+                                       continue;\r
+                               }\r
+\r
+                               // Else, just delete the cell.\r
+                               if ( row.$.cells[ cellIndex ] )\r
+                                       row.$.removeChild( row.$.cells[ cellIndex ] );\r
+                       }\r
+               }\r
+       }\r
+\r
+       function insertCell( selection, insertBefore )\r
+       {\r
+               var startElement = selection.getStartElement();\r
+               var cell = startElement.getAscendant( 'td', true ) || startElement.getAscendant( 'th', true );\r
+\r
+               if ( !cell )\r
+                       return;\r
+\r
+               // Create the new cell element to be added.\r
+               var newCell = cell.clone();\r
+               if ( !CKEDITOR.env.ie )\r
+                       newCell.appendBogus();\r
+\r
+               if ( insertBefore )\r
+                       newCell.insertBefore( cell );\r
+               else\r
+                       newCell.insertAfter( cell );\r
+       }\r
+\r
+       function deleteCells( selectionOrCell )\r
+       {\r
+               if ( selectionOrCell instanceof CKEDITOR.dom.selection )\r
+               {\r
+                       var cellsToDelete = getSelectedCells( selectionOrCell );\r
+                       for ( var i = cellsToDelete.length - 1 ; i >= 0 ; i-- )\r
+                               deleteCells( cellsToDelete[ i ] );\r
+               }\r
+               else if ( selectionOrCell instanceof CKEDITOR.dom.element )\r
+               {\r
+                       if ( selectionOrCell.getParent().getChildCount() == 1 )\r
+                               selectionOrCell.getParent().remove();\r
+                       else\r
+                               selectionOrCell.remove();\r
+               }\r
+       }\r
+\r
+       // Context menu on table caption incorrect (#3834)\r
+       var contextMenuTags = { thead : 1, tbody : 1, tfoot : 1, td : 1, tr : 1, th : 1 };\r
+\r
+       CKEDITOR.plugins.tabletools =\r
+       {\r
+               init : function( editor )\r
+               {\r
+                       var lang = editor.lang.table;\r
+\r
+                       editor.addCommand( 'cellProperties', new CKEDITOR.dialogCommand( 'cellProperties' ) );\r
+                       CKEDITOR.dialog.add( 'cellProperties', this.path + 'dialogs/tableCell.js' );\r
+\r
+                       editor.addCommand( 'tableDelete',\r
+                               {\r
+                                       exec : function( editor )\r
+                                       {\r
+                                               var selection = editor.getSelection();\r
+                                               var startElement = selection && selection.getStartElement();\r
+                                               var table = startElement && startElement.getAscendant( 'table', true );\r
+\r
+                                               if ( !table )\r
+                                                       return;\r
+\r
+                                               // Maintain the selection point at where the table was deleted.\r
+                                               selection.selectElement( table );\r
+                                               var range = selection.getRanges()[0];\r
+                                               range.collapse();\r
+                                               selection.selectRanges( [ range ] );\r
+\r
+                                               // If the table's parent has only one child, remove it as well.\r
+                                               if ( table.getParent().getChildCount() == 1 )\r
+                                                       table.getParent().remove();\r
+                                               else\r
+                                                       table.remove();\r
+                                       }\r
+                               } );\r
+\r
+                       editor.addCommand( 'rowDelete',\r
+                               {\r
+                                       exec : function( editor )\r
+                                       {\r
+                                               var selection = editor.getSelection();\r
+                                               deleteRows( selection );\r
+                                       }\r
+                               } );\r
+\r
+                       editor.addCommand( 'rowInsertBefore',\r
+                               {\r
+                                       exec : function( editor )\r
+                                       {\r
+                                               var selection = editor.getSelection();\r
+                                               insertRow( selection, true );\r
+                                       }\r
+                               } );\r
+\r
+                       editor.addCommand( 'rowInsertAfter',\r
+                               {\r
+                                       exec : function( editor )\r
+                                       {\r
+                                               var selection = editor.getSelection();\r
+                                               insertRow( selection );\r
+                                       }\r
+                               } );\r
+\r
+                       editor.addCommand( 'columnDelete',\r
+                               {\r
+                                       exec : function( editor )\r
+                                       {\r
+                                               var selection = editor.getSelection();\r
+                                               deleteColumns( selection );\r
+                                       }\r
+                               } );\r
+\r
+                       editor.addCommand( 'columnInsertBefore',\r
+                               {\r
+                                       exec : function( editor )\r
+                                       {\r
+                                               var selection = editor.getSelection();\r
+                                               insertColumn( selection, true );\r
+                                       }\r
+                               } );\r
+\r
+                       editor.addCommand( 'columnInsertAfter',\r
+                               {\r
+                                       exec : function( editor )\r
+                                       {\r
+                                               var selection = editor.getSelection();\r
+                                               insertColumn( selection );\r
+                                       }\r
+                               } );\r
+\r
+                       editor.addCommand( 'cellDelete',\r
+                               {\r
+                                       exec : function( editor )\r
+                                       {\r
+                                               var selection = editor.getSelection();\r
+                                               deleteCells( selection );\r
+                                       }\r
+                               } );\r
+\r
+                       editor.addCommand( 'cellInsertBefore',\r
+                               {\r
+                                       exec : function( editor )\r
+                                       {\r
+                                               var selection = editor.getSelection();\r
+                                               insertCell( selection, true );\r
+                                       }\r
+                               } );\r
+\r
+                       editor.addCommand( 'cellInsertAfter',\r
+                               {\r
+                                       exec : function( editor )\r
+                                       {\r
+                                               var selection = editor.getSelection();\r
+                                               insertCell( selection );\r
+                                       }\r
+                               } );\r
+\r
+                       // If the "menu" plugin is loaded, register the menu items.\r
+                       if ( editor.addMenuItems )\r
+                       {\r
+                               editor.addMenuItems(\r
+                                       {\r
+                                               tablecell :\r
+                                               {\r
+                                                       label : lang.cell.menu,\r
+                                                       group : 'tablecell',\r
+                                                       order : 1,\r
+                                                       getItems : function()\r
+                                                       {\r
+                                                               var cells = getSelectedCells( editor.getSelection() );\r
+                                                               return {\r
+                                                                       tablecell_insertBefore : CKEDITOR.TRISTATE_OFF,\r
+                                                                       tablecell_insertAfter : CKEDITOR.TRISTATE_OFF,\r
+                                                                       tablecell_delete : CKEDITOR.TRISTATE_OFF,\r
+                                                                       tablecell_properties : cells.length > 0 ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED\r
+                                                               };\r
+                                                       }\r
+                                               },\r
+\r
+                                               tablecell_insertBefore :\r
+                                               {\r
+                                                       label : lang.cell.insertBefore,\r
+                                                       group : 'tablecell',\r
+                                                       command : 'cellInsertBefore',\r
+                                                       order : 5\r
+                                               },\r
+\r
+                                               tablecell_insertAfter :\r
+                                               {\r
+                                                       label : lang.cell.insertAfter,\r
+                                                       group : 'tablecell',\r
+                                                       command : 'cellInsertAfter',\r
+                                                       order : 10\r
+                                               },\r
+\r
+                                               tablecell_delete :\r
+                                               {\r
+                                                       label : lang.cell.deleteCell,\r
+                                                       group : 'tablecell',\r
+                                                       command : 'cellDelete',\r
+                                                       order : 15\r
+                                               },\r
+\r
+                                               tablecell_properties :\r
+                                               {\r
+                                                       label : lang.cell.title,\r
+                                                       group : 'tablecellproperties',\r
+                                                       command : 'cellProperties',\r
+                                                       order : 20\r
+                                               },\r
+\r
+                                               tablerow :\r
+                                               {\r
+                                                       label : lang.row.menu,\r
+                                                       group : 'tablerow',\r
+                                                       order : 1,\r
+                                                       getItems : function()\r
+                                                       {\r
+                                                               return {\r
+                                                                       tablerow_insertBefore : CKEDITOR.TRISTATE_OFF,\r
+                                                                       tablerow_insertAfter : CKEDITOR.TRISTATE_OFF,\r
+                                                                       tablerow_delete : CKEDITOR.TRISTATE_OFF\r
+                                                               };\r
+                                                       }\r
+                                               },\r
+\r
+                                               tablerow_insertBefore :\r
+                                               {\r
+                                                       label : lang.row.insertBefore,\r
+                                                       group : 'tablerow',\r
+                                                       command : 'rowInsertBefore',\r
+                                                       order : 5\r
+                                               },\r
+\r
+                                               tablerow_insertAfter :\r
+                                               {\r
+                                                       label : lang.row.insertAfter,\r
+                                                       group : 'tablerow',\r
+                                                       command : 'rowInsertAfter',\r
+                                                       order : 10\r
+                                               },\r
+\r
+                                               tablerow_delete :\r
+                                               {\r
+                                                       label : lang.row.deleteRow,\r
+                                                       group : 'tablerow',\r
+                                                       command : 'rowDelete',\r
+                                                       order : 15\r
+                                               },\r
+\r
+                                               tablecolumn :\r
+                                               {\r
+                                                       label : lang.column.menu,\r
+                                                       group : 'tablecolumn',\r
+                                                       order : 1,\r
+                                                       getItems : function()\r
+                                                       {\r
+                                                               return {\r
+                                                                       tablecolumn_insertBefore : CKEDITOR.TRISTATE_OFF,\r
+                                                                       tablecolumn_insertAfter : CKEDITOR.TRISTATE_OFF,\r
+                                                                       tablecolumn_delete : CKEDITOR.TRISTATE_OFF\r
+                                                               };\r
+                                                       }\r
+                                               },\r
+\r
+                                               tablecolumn_insertBefore :\r
+                                               {\r
+                                                       label : lang.column.insertBefore,\r
+                                                       group : 'tablecolumn',\r
+                                                       command : 'columnInsertBefore',\r
+                                                       order : 5\r
+                                               },\r
+\r
+                                               tablecolumn_insertAfter :\r
+                                               {\r
+                                                       label : lang.column.insertAfter,\r
+                                                       group : 'tablecolumn',\r
+                                                       command : 'columnInsertAfter',\r
+                                                       order : 10\r
+                                               },\r
+\r
+                                               tablecolumn_delete :\r
+                                               {\r
+                                                       label : lang.column.deleteColumn,\r
+                                                       group : 'tablecolumn',\r
+                                                       command : 'columnDelete',\r
+                                                       order : 15\r
+                                               }\r
+                                       });\r
+                       }\r
+\r
+                       // If the "contextmenu" plugin is laoded, register the listeners.\r
+                       if ( editor.contextMenu )\r
+                       {\r
+                               editor.contextMenu.addListener( function( element, selection )\r
+                                       {\r
+                                               if ( !element )\r
+                                                       return null;\r
+\r
+                                               while ( element )\r
+                                               {\r
+                                                       if ( element.getName() in contextMenuTags )\r
+                                                       {\r
+                                                               return {\r
+                                                                       tablecell : CKEDITOR.TRISTATE_OFF,\r
+                                                                       tablerow : CKEDITOR.TRISTATE_OFF,\r
+                                                                       tablecolumn : CKEDITOR.TRISTATE_OFF\r
+                                                               };\r
+                                                       }\r
+                                                       element = element.getParent();\r
+                                               }\r
+\r
+                                               return null;\r
+                                       } );\r
+                       }\r
+               },\r
+\r
+               getSelectedCells : getSelectedCells\r
+\r
+       };\r
+       CKEDITOR.plugins.add( 'tabletools', CKEDITOR.plugins.tabletools );\r
+})();\r