JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
d68954a52a420bd0cc68e287c8da934894f4a1b0
[ckeditor.git] / _source / plugins / tabletools / plugin.js
1 /*\r
2 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.\r
3 For licensing, see LICENSE.html or http://ckeditor.com/license\r
4 */\r
5 \r
6 (function()\r
7 {\r
8         function removeRawAttribute( $node, attr )\r
9         {\r
10                 if ( CKEDITOR.env.ie )\r
11                         $node.removeAttribute( attr );\r
12                 else\r
13                         delete $node[ attr ];\r
14         }\r
15 \r
16         var cellNodeRegex = /^(?:td|th)$/;\r
17 \r
18         function getSelectedCells( selection )\r
19         {\r
20                 // Walker will try to split text nodes, which will make the current selection\r
21                 // invalid. So save bookmarks before doing anything.\r
22                 var bookmarks = selection.createBookmarks();\r
23 \r
24                 var ranges = selection.getRanges();\r
25                 var retval = [];\r
26                 var database = {};\r
27 \r
28                 function moveOutOfCellGuard( node )\r
29                 {\r
30                         // Apply to the first cell only.\r
31                         if ( retval.length > 0 )\r
32                                 return;\r
33 \r
34                         // If we are exiting from the first </td>, then the td should definitely be\r
35                         // included.\r
36                         if ( node.type == CKEDITOR.NODE_ELEMENT && cellNodeRegex.test( node.getName() )\r
37                                         && !node.getCustomData( 'selected_cell' ) )\r
38                         {\r
39                                 CKEDITOR.dom.element.setMarker( database, node, 'selected_cell', true );\r
40                                 retval.push( node );\r
41                         }\r
42                 }\r
43 \r
44                 for ( var i = 0 ; i < ranges.length ; i++ )\r
45                 {\r
46                         var range = ranges[ i ];\r
47 \r
48                         if ( range.collapsed )\r
49                         {\r
50                                 // Walker does not handle collapsed ranges yet - fall back to old API.\r
51                                 var startNode = range.getCommonAncestor();\r
52                                 var nearestCell = startNode.getAscendant( 'td', true ) || startNode.getAscendant( 'th', true );\r
53                                 if ( nearestCell )\r
54                                         retval.push( nearestCell );\r
55                         }\r
56                         else\r
57                         {\r
58                                 var walker = new CKEDITOR.dom.walker( range );\r
59                                 var node;\r
60                                 walker.guard = moveOutOfCellGuard;\r
61 \r
62                                 while ( ( node = walker.next() ) )\r
63                                 {\r
64                                         // If may be possible for us to have a range like this:\r
65                                         // <td>^1</td><td>^2</td>\r
66                                         // The 2nd td shouldn't be included.\r
67                                         //\r
68                                         // So we have to take care to include a td we've entered only when we've\r
69                                         // walked into its children.\r
70 \r
71                                         var parent = node.getParent();\r
72                                         if ( parent && cellNodeRegex.test( parent.getName() ) && !parent.getCustomData( 'selected_cell' ) )\r
73                                         {\r
74                                                 CKEDITOR.dom.element.setMarker( database, parent, 'selected_cell', true );\r
75                                                 retval.push( parent );\r
76                                         }\r
77                                 }\r
78                         }\r
79                 }\r
80 \r
81                 CKEDITOR.dom.element.clearAllMarkers( database );\r
82 \r
83                 // Restore selection position.\r
84                 selection.selectBookmarks( bookmarks );\r
85 \r
86                 return retval;\r
87         }\r
88 \r
89         function createTableMap( $refCell )\r
90         {\r
91                 var refCell = new CKEDITOR.dom.element( $refCell );\r
92                 var $table = ( refCell.getName() == 'table' ? $refCell : refCell.getAscendant( 'table' ) ).$;\r
93                 var $rows = $table.rows;\r
94 \r
95                 // Row and column counters.\r
96                 var r = -1;\r
97                 var map = [];\r
98                 for ( var i = 0 ; i < $rows.length ; i++ )\r
99                 {\r
100                         r++;\r
101                         if ( !map[ r ] )\r
102                                 map[ r ] = [];\r
103 \r
104                         var c = -1;\r
105 \r
106                         for ( var j = 0 ; j < $rows[ i ].cells.length ; j++ )\r
107                         {\r
108                                 var $cell = $rows[ i ].cells[ j ];\r
109 \r
110                                 c++;\r
111                                 while ( map[ r ][ c ] )\r
112                                         c++;\r
113 \r
114                                 var colSpan = isNaN( $cell.colSpan ) ? 1 : $cell.colSpan;\r
115                                 var rowSpan = isNaN( $cell.rowSpan ) ? 1 : $cell.rowSpan;\r
116 \r
117                                 for ( var rs = 0 ; rs < rowSpan ; rs++ )\r
118                                 {\r
119                                         if ( !map[ r + rs ] )\r
120                                                 map[ r + rs ] = [];\r
121 \r
122                                         for ( var cs = 0 ; cs < colSpan ; cs++ )\r
123                                                 map [ r + rs ][ c + cs ] = $rows[ i ].cells[ j ];\r
124                                 }\r
125 \r
126                                 c += colSpan - 1;\r
127                         }\r
128                 }\r
129 \r
130                 return map;\r
131         }\r
132 \r
133         function installTableMap( tableMap, $table )\r
134         {\r
135                 /*\r
136                  * IE BUG: rowSpan is always 1 in IE if the cell isn't attached to a row. So\r
137                  * store is separately in another attribute. (#1917)\r
138                  */\r
139                 var rowSpanAttr = CKEDITOR.env.ie ? '_cke_rowspan' : 'rowSpan';\r
140 \r
141                 /*\r
142                  * Disconnect all the cells in tableMap from their parents, set all colSpan\r
143                  * and rowSpan attributes to 1.\r
144                  */\r
145                 for ( var i = 0 ; i < tableMap.length ; i++ )\r
146                 {\r
147                         for ( var j = 0 ; j < tableMap[ i ].length ; j++ )\r
148                         {\r
149                                 var $cell = tableMap[ i ][ j ];\r
150                                 if ( $cell.parentNode )\r
151                                         $cell.parentNode.removeChild( $cell );\r
152                                 $cell.colSpan = $cell[ rowSpanAttr ] = 1;\r
153                         }\r
154                 }\r
155 \r
156                 // Scan by rows and set colSpan.\r
157                 var maxCol = 0;\r
158                 for ( i = 0 ; i < tableMap.length ; i++ )\r
159                 {\r
160                         for ( j = 0 ; j < tableMap[ i ].length ; j++ )\r
161                         {\r
162                                 $cell = tableMap[ i ][ j ];\r
163                                 if ( !$cell )\r
164                                         continue;\r
165                                 if ( j > maxCol )\r
166                                         maxCol = j;\r
167                                 if ( $cell[ '_cke_colScanned' ] )\r
168                                         continue;\r
169                                 if ( tableMap[ i ][ j - 1 ] == $cell )\r
170                                         $cell.colSpan++;\r
171                                 if ( tableMap[ i ][ j + 1 ] != $cell )\r
172                                         $cell[ '_cke_colScanned' ] = 1;\r
173                         }\r
174                 }\r
175 \r
176                 // Scan by columns and set rowSpan.\r
177                 for ( i = 0 ; i <= maxCol ; i++ )\r
178                 {\r
179                         for ( j = 0 ; j < tableMap.length ; j++ )\r
180                         {\r
181                                 if ( !tableMap[ j ] )\r
182                                         continue;\r
183                                 $cell = tableMap[ j ][ i ];\r
184                                 if ( !$cell || $cell[ '_cke_rowScanned' ] )\r
185                                         continue;\r
186                                 if ( tableMap[ j - 1 ] && tableMap[ j - 1 ][ i ] == $cell )\r
187                                         $cell[ rowSpanAttr ]++;\r
188                                 if ( !tableMap[ j + 1 ] || tableMap[ j + 1 ][ i ] != $cell  )\r
189                                         $cell[ '_cke_rowScanned' ] = 1;\r
190                         }\r
191                 }\r
192 \r
193                 // Clear all temporary flags.\r
194                 for ( i = 0 ; i < tableMap.length ; i++ )\r
195                 {\r
196                         for ( j = 0 ; j < tableMap[ i ].length ; j++ )\r
197                         {\r
198                                 $cell = tableMap[ i ][ j ];\r
199                                 removeRawAttribute( $cell, '_cke_colScanned' );\r
200                                 removeRawAttribute( $cell, '_cke_rowScanned' );\r
201                         }\r
202                 }\r
203 \r
204                 // Insert physical rows and columns to table.\r
205                 for ( i = 0 ; i < tableMap.length ; i++ )\r
206                 {\r
207                         var $row = $table.ownerDocument.createElement( 'tr' );\r
208                         for ( j = 0 ; j < tableMap[ i ].length ; )\r
209                         {\r
210                                 $cell = tableMap[ i ][ j ];\r
211                                 if ( tableMap[ i - 1 ] && tableMap[ i - 1 ][ j ] == $cell )\r
212                                 {\r
213                                         j += $cell.colSpan;\r
214                                         continue;\r
215                                 }\r
216                                 $row.appendChild( $cell );\r
217                                 if ( rowSpanAttr != 'rowSpan' )\r
218                                 {\r
219                                         $cell.rowSpan = $cell[ rowSpanAttr ];\r
220                                         $cell.removeAttribute( rowSpanAttr );\r
221                                 }\r
222                                 j += $cell.colSpan;\r
223                                 if ( $cell.colSpan == 1 )\r
224                                         $cell.removeAttribute( 'colSpan' );\r
225                                 if ( $cell.rowSpan == 1 )\r
226                                         $cell.removeAttribute( 'rowSpan' );\r
227                         }\r
228 \r
229                         if ( CKEDITOR.env.ie )\r
230                                 $table.rows[ i ].replaceNode( $row );\r
231                         else\r
232                         {\r
233                                 var dest = new CKEDITOR.dom.element( $table.rows[ i ] );\r
234                                 var src = new CKEDITOR.dom.element( $row );\r
235                                 dest.setHtml( '' );\r
236                                 src.moveChildren( dest );\r
237                         }\r
238                 }\r
239         }\r
240 \r
241         function clearRow( $tr )\r
242         {\r
243                 // Get the array of row's cells.\r
244                 var $cells = $tr.cells;\r
245 \r
246                 // Empty all cells.\r
247                 for ( var i = 0 ; i < $cells.length ; i++ )\r
248                 {\r
249                         $cells[ i ].innerHTML = '';\r
250 \r
251                         if ( !CKEDITOR.env.ie )\r
252                                 ( new CKEDITOR.dom.element( $cells[ i ] ) ).appendBogus();\r
253                 }\r
254         }\r
255 \r
256         function insertRow( selection, insertBefore )\r
257         {\r
258                 // Get the row where the selection is placed in.\r
259                 var row = selection.getStartElement().getAscendant( 'tr' );\r
260                 if ( !row )\r
261                         return;\r
262 \r
263                 // Create a clone of the row.\r
264                 var newRow = row.clone( true );\r
265 \r
266                 // Insert the new row before of it.\r
267                 newRow.insertBefore( row );\r
268 \r
269                 // Clean one of the rows to produce the illusion of inserting an empty row\r
270                 // before or after.\r
271                 clearRow( insertBefore ? newRow.$ : row.$ );\r
272         }\r
273 \r
274         function deleteRows( selectionOrRow )\r
275         {\r
276                 if ( selectionOrRow instanceof CKEDITOR.dom.selection )\r
277                 {\r
278                         var cells = getSelectedCells( selectionOrRow );\r
279                         var rowsToDelete = [];\r
280 \r
281                         // Queue up the rows - it's possible and likely that we have duplicates.\r
282                         for ( var i = 0 ; i < cells.length ; i++ )\r
283                         {\r
284                                 var row = cells[ i ].getParent();\r
285                                 rowsToDelete[ row.$.rowIndex ] = row;\r
286                         }\r
287 \r
288                         for ( i = rowsToDelete.length ; i >= 0 ; i-- )\r
289                         {\r
290                                 if ( rowsToDelete[ i ] )\r
291                                         deleteRows( rowsToDelete[ i ] );\r
292                         }\r
293                 }\r
294                 else if ( selectionOrRow instanceof CKEDITOR.dom.element )\r
295                 {\r
296                         var table = selectionOrRow.getAscendant( 'table' );\r
297 \r
298                         if ( table.$.rows.length == 1 )\r
299                                 table.remove();\r
300                         else\r
301                                 selectionOrRow.remove();\r
302                 }\r
303         }\r
304 \r
305         function insertColumn( selection, insertBefore )\r
306         {\r
307                 // Get the cell where the selection is placed in.\r
308                 var startElement = selection.getStartElement();\r
309                 var cell = startElement.getAscendant( 'td', true ) || startElement.getAscendant( 'th', true );\r
310 \r
311                 if ( !cell )\r
312                         return;\r
313 \r
314                 // Get the cell's table.\r
315                 var table = cell.getAscendant( 'table' );\r
316                 var cellIndex = cell.$.cellIndex;\r
317 \r
318                 // Loop through all rows available in the table.\r
319                 for ( var i = 0 ; i < table.$.rows.length ; i++ )\r
320                 {\r
321                         var $row = table.$.rows[ i ];\r
322 \r
323                         // If the row doesn't have enough cells, ignore it.\r
324                         if ( $row.cells.length < ( cellIndex + 1 ) )\r
325                                 continue;\r
326 \r
327                         cell = new CKEDITOR.dom.element( $row.cells[ cellIndex ].cloneNode( false ) );\r
328 \r
329                         if ( !CKEDITOR.env.ie )\r
330                                 cell.appendBogus();\r
331 \r
332                         // Get back the currently selected cell.\r
333                         var baseCell = new CKEDITOR.dom.element( $row.cells[ cellIndex ] );\r
334                         if ( insertBefore )\r
335                                 cell.insertBefore( baseCell );\r
336                         else\r
337                                 cell.insertAfter( baseCell );\r
338                 }\r
339         }\r
340 \r
341         function deleteColumns( selectionOrCell )\r
342         {\r
343                 if ( selectionOrCell instanceof CKEDITOR.dom.selection )\r
344                 {\r
345                         var colsToDelete = getSelectedCells( selectionOrCell );\r
346                         for ( var i = colsToDelete.length ; i >= 0 ; i-- )\r
347                         {\r
348                                 if ( colsToDelete[ i ] )\r
349                                         deleteColumns( colsToDelete[ i ] );\r
350                         }\r
351                 }\r
352                 else if ( selectionOrCell instanceof CKEDITOR.dom.element )\r
353                 {\r
354                         // Get the cell's table.\r
355                         var table = selectionOrCell.getAscendant( 'table' );\r
356 \r
357                         // Get the cell index.\r
358                         var cellIndex = selectionOrCell.$.cellIndex;\r
359 \r
360                         /*\r
361                          * Loop through all rows from down to up, coz it's possible that some rows\r
362                          * will be deleted.\r
363                          */\r
364                         for ( i = table.$.rows.length - 1 ; i >= 0 ; i-- )\r
365                         {\r
366                                 // Get the row.\r
367                                 var row = new CKEDITOR.dom.element( table.$.rows[ i ] );\r
368 \r
369                                 // If the cell to be removed is the first one and the row has just one cell.\r
370                                 if ( !cellIndex && row.$.cells.length == 1 )\r
371                                 {\r
372                                         deleteRows( row );\r
373                                         continue;\r
374                                 }\r
375 \r
376                                 // Else, just delete the cell.\r
377                                 if ( row.$.cells[ cellIndex ] )\r
378                                         row.$.removeChild( row.$.cells[ cellIndex ] );\r
379                         }\r
380                 }\r
381         }\r
382 \r
383         function insertCell( selection, insertBefore )\r
384         {\r
385                 var startElement = selection.getStartElement();\r
386                 var cell = startElement.getAscendant( 'td', true ) || startElement.getAscendant( 'th', true );\r
387 \r
388                 if ( !cell )\r
389                         return;\r
390 \r
391                 // Create the new cell element to be added.\r
392                 var newCell = cell.clone();\r
393                 if ( !CKEDITOR.env.ie )\r
394                         newCell.appendBogus();\r
395 \r
396                 if ( insertBefore )\r
397                         newCell.insertBefore( cell );\r
398                 else\r
399                         newCell.insertAfter( cell );\r
400         }\r
401 \r
402         function deleteCells( selectionOrCell )\r
403         {\r
404                 if ( selectionOrCell instanceof CKEDITOR.dom.selection )\r
405                 {\r
406                         var cellsToDelete = getSelectedCells( selectionOrCell );\r
407                         for ( var i = cellsToDelete.length - 1 ; i >= 0 ; i-- )\r
408                                 deleteCells( cellsToDelete[ i ] );\r
409                 }\r
410                 else if ( selectionOrCell instanceof CKEDITOR.dom.element )\r
411                 {\r
412                         if ( selectionOrCell.getParent().getChildCount() == 1 )\r
413                                 selectionOrCell.getParent().remove();\r
414                         else\r
415                                 selectionOrCell.remove();\r
416                 }\r
417         }\r
418 \r
419         // Context menu on table caption incorrect (#3834)\r
420         var contextMenuTags = { thead : 1, tbody : 1, tfoot : 1, td : 1, tr : 1, th : 1 };\r
421 \r
422         CKEDITOR.plugins.tabletools =\r
423         {\r
424                 init : function( editor )\r
425                 {\r
426                         var lang = editor.lang.table;\r
427 \r
428                         editor.addCommand( 'cellProperties', new CKEDITOR.dialogCommand( 'cellProperties' ) );\r
429                         CKEDITOR.dialog.add( 'cellProperties', this.path + 'dialogs/tableCell.js' );\r
430 \r
431                         editor.addCommand( 'tableDelete',\r
432                                 {\r
433                                         exec : function( editor )\r
434                                         {\r
435                                                 var selection = editor.getSelection();\r
436                                                 var startElement = selection && selection.getStartElement();\r
437                                                 var table = startElement && startElement.getAscendant( 'table', true );\r
438 \r
439                                                 if ( !table )\r
440                                                         return;\r
441 \r
442                                                 // Maintain the selection point at where the table was deleted.\r
443                                                 selection.selectElement( table );\r
444                                                 var range = selection.getRanges()[0];\r
445                                                 range.collapse();\r
446                                                 selection.selectRanges( [ range ] );\r
447 \r
448                                                 // If the table's parent has only one child, remove it as well.\r
449                                                 if ( table.getParent().getChildCount() == 1 )\r
450                                                         table.getParent().remove();\r
451                                                 else\r
452                                                         table.remove();\r
453                                         }\r
454                                 } );\r
455 \r
456                         editor.addCommand( 'rowDelete',\r
457                                 {\r
458                                         exec : function( editor )\r
459                                         {\r
460                                                 var selection = editor.getSelection();\r
461                                                 deleteRows( selection );\r
462                                         }\r
463                                 } );\r
464 \r
465                         editor.addCommand( 'rowInsertBefore',\r
466                                 {\r
467                                         exec : function( editor )\r
468                                         {\r
469                                                 var selection = editor.getSelection();\r
470                                                 insertRow( selection, true );\r
471                                         }\r
472                                 } );\r
473 \r
474                         editor.addCommand( 'rowInsertAfter',\r
475                                 {\r
476                                         exec : function( editor )\r
477                                         {\r
478                                                 var selection = editor.getSelection();\r
479                                                 insertRow( selection );\r
480                                         }\r
481                                 } );\r
482 \r
483                         editor.addCommand( 'columnDelete',\r
484                                 {\r
485                                         exec : function( editor )\r
486                                         {\r
487                                                 var selection = editor.getSelection();\r
488                                                 deleteColumns( selection );\r
489                                         }\r
490                                 } );\r
491 \r
492                         editor.addCommand( 'columnInsertBefore',\r
493                                 {\r
494                                         exec : function( editor )\r
495                                         {\r
496                                                 var selection = editor.getSelection();\r
497                                                 insertColumn( selection, true );\r
498                                         }\r
499                                 } );\r
500 \r
501                         editor.addCommand( 'columnInsertAfter',\r
502                                 {\r
503                                         exec : function( editor )\r
504                                         {\r
505                                                 var selection = editor.getSelection();\r
506                                                 insertColumn( selection );\r
507                                         }\r
508                                 } );\r
509 \r
510                         editor.addCommand( 'cellDelete',\r
511                                 {\r
512                                         exec : function( editor )\r
513                                         {\r
514                                                 var selection = editor.getSelection();\r
515                                                 deleteCells( selection );\r
516                                         }\r
517                                 } );\r
518 \r
519                         editor.addCommand( 'cellInsertBefore',\r
520                                 {\r
521                                         exec : function( editor )\r
522                                         {\r
523                                                 var selection = editor.getSelection();\r
524                                                 insertCell( selection, true );\r
525                                         }\r
526                                 } );\r
527 \r
528                         editor.addCommand( 'cellInsertAfter',\r
529                                 {\r
530                                         exec : function( editor )\r
531                                         {\r
532                                                 var selection = editor.getSelection();\r
533                                                 insertCell( selection );\r
534                                         }\r
535                                 } );\r
536 \r
537                         // If the "menu" plugin is loaded, register the menu items.\r
538                         if ( editor.addMenuItems )\r
539                         {\r
540                                 editor.addMenuItems(\r
541                                         {\r
542                                                 tablecell :\r
543                                                 {\r
544                                                         label : lang.cell.menu,\r
545                                                         group : 'tablecell',\r
546                                                         order : 1,\r
547                                                         getItems : function()\r
548                                                         {\r
549                                                                 var cells = getSelectedCells( editor.getSelection() );\r
550                                                                 return {\r
551                                                                         tablecell_insertBefore : CKEDITOR.TRISTATE_OFF,\r
552                                                                         tablecell_insertAfter : CKEDITOR.TRISTATE_OFF,\r
553                                                                         tablecell_delete : CKEDITOR.TRISTATE_OFF,\r
554                                                                         tablecell_properties : cells.length > 0 ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED\r
555                                                                 };\r
556                                                         }\r
557                                                 },\r
558 \r
559                                                 tablecell_insertBefore :\r
560                                                 {\r
561                                                         label : lang.cell.insertBefore,\r
562                                                         group : 'tablecell',\r
563                                                         command : 'cellInsertBefore',\r
564                                                         order : 5\r
565                                                 },\r
566 \r
567                                                 tablecell_insertAfter :\r
568                                                 {\r
569                                                         label : lang.cell.insertAfter,\r
570                                                         group : 'tablecell',\r
571                                                         command : 'cellInsertAfter',\r
572                                                         order : 10\r
573                                                 },\r
574 \r
575                                                 tablecell_delete :\r
576                                                 {\r
577                                                         label : lang.cell.deleteCell,\r
578                                                         group : 'tablecell',\r
579                                                         command : 'cellDelete',\r
580                                                         order : 15\r
581                                                 },\r
582 \r
583                                                 tablecell_properties :\r
584                                                 {\r
585                                                         label : lang.cell.title,\r
586                                                         group : 'tablecellproperties',\r
587                                                         command : 'cellProperties',\r
588                                                         order : 20\r
589                                                 },\r
590 \r
591                                                 tablerow :\r
592                                                 {\r
593                                                         label : lang.row.menu,\r
594                                                         group : 'tablerow',\r
595                                                         order : 1,\r
596                                                         getItems : function()\r
597                                                         {\r
598                                                                 return {\r
599                                                                         tablerow_insertBefore : CKEDITOR.TRISTATE_OFF,\r
600                                                                         tablerow_insertAfter : CKEDITOR.TRISTATE_OFF,\r
601                                                                         tablerow_delete : CKEDITOR.TRISTATE_OFF\r
602                                                                 };\r
603                                                         }\r
604                                                 },\r
605 \r
606                                                 tablerow_insertBefore :\r
607                                                 {\r
608                                                         label : lang.row.insertBefore,\r
609                                                         group : 'tablerow',\r
610                                                         command : 'rowInsertBefore',\r
611                                                         order : 5\r
612                                                 },\r
613 \r
614                                                 tablerow_insertAfter :\r
615                                                 {\r
616                                                         label : lang.row.insertAfter,\r
617                                                         group : 'tablerow',\r
618                                                         command : 'rowInsertAfter',\r
619                                                         order : 10\r
620                                                 },\r
621 \r
622                                                 tablerow_delete :\r
623                                                 {\r
624                                                         label : lang.row.deleteRow,\r
625                                                         group : 'tablerow',\r
626                                                         command : 'rowDelete',\r
627                                                         order : 15\r
628                                                 },\r
629 \r
630                                                 tablecolumn :\r
631                                                 {\r
632                                                         label : lang.column.menu,\r
633                                                         group : 'tablecolumn',\r
634                                                         order : 1,\r
635                                                         getItems : function()\r
636                                                         {\r
637                                                                 return {\r
638                                                                         tablecolumn_insertBefore : CKEDITOR.TRISTATE_OFF,\r
639                                                                         tablecolumn_insertAfter : CKEDITOR.TRISTATE_OFF,\r
640                                                                         tablecolumn_delete : CKEDITOR.TRISTATE_OFF\r
641                                                                 };\r
642                                                         }\r
643                                                 },\r
644 \r
645                                                 tablecolumn_insertBefore :\r
646                                                 {\r
647                                                         label : lang.column.insertBefore,\r
648                                                         group : 'tablecolumn',\r
649                                                         command : 'columnInsertBefore',\r
650                                                         order : 5\r
651                                                 },\r
652 \r
653                                                 tablecolumn_insertAfter :\r
654                                                 {\r
655                                                         label : lang.column.insertAfter,\r
656                                                         group : 'tablecolumn',\r
657                                                         command : 'columnInsertAfter',\r
658                                                         order : 10\r
659                                                 },\r
660 \r
661                                                 tablecolumn_delete :\r
662                                                 {\r
663                                                         label : lang.column.deleteColumn,\r
664                                                         group : 'tablecolumn',\r
665                                                         command : 'columnDelete',\r
666                                                         order : 15\r
667                                                 }\r
668                                         });\r
669                         }\r
670 \r
671                         // If the "contextmenu" plugin is laoded, register the listeners.\r
672                         if ( editor.contextMenu )\r
673                         {\r
674                                 editor.contextMenu.addListener( function( element, selection )\r
675                                         {\r
676                                                 if ( !element )\r
677                                                         return null;\r
678 \r
679                                                 while ( element )\r
680                                                 {\r
681                                                         if ( element.getName() in contextMenuTags )\r
682                                                         {\r
683                                                                 return {\r
684                                                                         tablecell : CKEDITOR.TRISTATE_OFF,\r
685                                                                         tablerow : CKEDITOR.TRISTATE_OFF,\r
686                                                                         tablecolumn : CKEDITOR.TRISTATE_OFF\r
687                                                                 };\r
688                                                         }\r
689                                                         element = element.getParent();\r
690                                                 }\r
691 \r
692                                                 return null;\r
693                                         } );\r
694                         }\r
695                 },\r
696 \r
697                 getSelectedCells : getSelectedCells\r
698 \r
699         };\r
700         CKEDITOR.plugins.add( 'tabletools', CKEDITOR.plugins.tabletools );\r
701 })();\r