tagging as ATutor 1.5.4-release
[atutor.git] / jscripts / tiny_mce / plugins / table / editor_plugin_src.js
1 /**\r
2  * $RCSfile: editor_plugin_src.js,v $\r
3  * $Revision: 1.38 $\r
4  * $Date: 2006/02/11 18:53:51 $\r
5  *\r
6  * @author Moxiecode\r
7  * @copyright Copyright © 2004-2006, Moxiecode Systems AB, All rights reserved.\r
8  */\r
9 \r
10 /* Import plugin specific language pack */\r
11 tinyMCE.importPluginLanguagePack('table', 'en,tr,ar,cs,da,de,el,es,fi,fr_ca,hu,it,ja,ko,nl,nb,pl,pt,pt_br,sv,tw,zh_cn,fr,de,he,nb,ru,ru_KOI8-R,ru_UTF-8,nn,cy,is,zh_tw,zh_tw_utf8,sk');\r
12 \r
13 var TinyMCE_TablePlugin = {\r
14         getInfo : function() {\r
15                 return {\r
16                         longname : 'Tables',\r
17                         author : 'Moxiecode Systems',\r
18                         authorurl : 'http://tinymce.moxiecode.com',\r
19                         infourl : 'http://tinymce.moxiecode.com/tinymce/docs/plugin_table.html',\r
20                         version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion\r
21                 };\r
22         },\r
23 \r
24         initInstance : function(inst) {\r
25                 if (tinyMCE.isGecko) {\r
26                         var doc = inst.getDoc();\r
27                         tinyMCE.addEvent(doc, "mouseup", TinyMCE_TablePlugin._mouseDownHandler);\r
28                 }\r
29 \r
30                 inst.tableRowClipboard = null;\r
31         },\r
32 \r
33         /**\r
34          * Returns the HTML contents of the table control.\r
35          */\r
36         getControlHTML : function(control_name) {\r
37                 var controls = new Array(\r
38                         ['table', 'table.gif', 'lang_table_desc', 'mceInsertTable', true],\r
39                         ['delete_col', 'table_delete_col.gif', 'lang_table_delete_col_desc', 'mceTableDeleteCol'],\r
40                         ['delete_row', 'table_delete_row.gif', 'lang_table_delete_row_desc', 'mceTableDeleteRow'],\r
41                         ['col_after', 'table_insert_col_after.gif', 'lang_table_col_after_desc', 'mceTableInsertColAfter'],\r
42                         ['col_before', 'table_insert_col_before.gif', 'lang_table_col_before_desc', 'mceTableInsertColBefore'],\r
43                         ['row_after', 'table_insert_row_after.gif', 'lang_table_row_after_desc', 'mceTableInsertRowAfter'],\r
44                         ['row_before', 'table_insert_row_before.gif', 'lang_table_row_before_desc', 'mceTableInsertRowBefore'],\r
45                         ['row_props', 'table_row_props.gif', 'lang_table_row_desc', 'mceTableRowProps', true],\r
46                         ['cell_props', 'table_cell_props.gif', 'lang_table_cell_desc', 'mceTableCellProps', true],\r
47                         ['split_cells', 'table_split_cells.gif', 'lang_table_split_cells_desc', 'mceTableSplitCells', true],\r
48                         ['merge_cells', 'table_merge_cells.gif', 'lang_table_merge_cells_desc', 'mceTableMergeCells', true]);\r
49 \r
50                 // Render table control\r
51                 for (var i=0; i<controls.length; i++) {\r
52                         var but = controls[i];\r
53                         var cmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + but[3] + '\', ' + (but.length > 4 ? but[4] : false) + (but.length > 5 ? ', \'' + but[5] + '\'' : '') + ');return false;';\r
54 \r
55                         if (but[0] == control_name)\r
56                                 return tinyMCE.getButtonHTML(control_name, but[2], '{$pluginurl}/images/'+ but[1], but[3], (but.length > 4 ? but[4] : false));\r
57                 }\r
58 \r
59                 // Special tablecontrols\r
60                 if (control_name == "tablecontrols") {\r
61                         var html = "";\r
62 \r
63                         html += tinyMCE.getControlHTML("table");\r
64                         html += tinyMCE.getControlHTML("separator");\r
65                         html += tinyMCE.getControlHTML("row_props");\r
66                         html += tinyMCE.getControlHTML("cell_props");\r
67                         html += tinyMCE.getControlHTML("separator");\r
68                         html += tinyMCE.getControlHTML("row_before");\r
69                         html += tinyMCE.getControlHTML("row_after");\r
70                         html += tinyMCE.getControlHTML("delete_row");\r
71                         html += tinyMCE.getControlHTML("separator");\r
72                         html += tinyMCE.getControlHTML("col_before");\r
73                         html += tinyMCE.getControlHTML("col_after");\r
74                         html += tinyMCE.getControlHTML("delete_col");\r
75                         html += tinyMCE.getControlHTML("separator");\r
76                         html += tinyMCE.getControlHTML("split_cells");\r
77                         html += tinyMCE.getControlHTML("merge_cells");\r
78 \r
79                         return html;\r
80                 }\r
81 \r
82                 return "";\r
83         },\r
84 \r
85         /**\r
86          * Executes the table commands.\r
87          */\r
88         execCommand : function(editor_id, element, command, user_interface, value) {\r
89                 // Is table command\r
90                 switch (command) {\r
91                         case "mceInsertTable":\r
92                         case "mceTableRowProps":\r
93                         case "mceTableCellProps":\r
94                         case "mceTableSplitCells":\r
95                         case "mceTableMergeCells":\r
96                         case "mceTableInsertRowBefore":\r
97                         case "mceTableInsertRowAfter":\r
98                         case "mceTableDeleteRow":\r
99                         case "mceTableInsertColBefore":\r
100                         case "mceTableInsertColAfter":\r
101                         case "mceTableDeleteCol":\r
102                         case "mceTableCutRow":\r
103                         case "mceTableCopyRow":\r
104                         case "mceTablePasteRowBefore":\r
105                         case "mceTablePasteRowAfter":\r
106                         case "mceTableDelete":\r
107                                 var inst = tinyMCE.getInstanceById(editor_id);\r
108 \r
109                                 inst.execCommand('mceBeginUndoLevel');\r
110                                 TinyMCE_TablePlugin._doExecCommand(editor_id, element, command, user_interface, value);\r
111                                 inst.execCommand('mceEndUndoLevel');\r
112 \r
113                                 return true;\r
114                 }\r
115 \r
116                 // Pass to next handler in chain\r
117                 return false;\r
118         },\r
119 \r
120         handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {\r
121                 var colspan = "1", rowspan = "1";\r
122 \r
123                 var inst = tinyMCE.getInstanceById(editor_id);\r
124 \r
125                 // Reset table controls\r
126                 tinyMCE.switchClass(editor_id + '_table', 'mceButtonNormal');\r
127                 tinyMCE.switchClass(editor_id + '_row_props', 'mceButtonDisabled');\r
128                 tinyMCE.switchClass(editor_id + '_cell_props', 'mceButtonDisabled');\r
129                 tinyMCE.switchClass(editor_id + '_row_before', 'mceButtonDisabled');\r
130                 tinyMCE.switchClass(editor_id + '_row_after', 'mceButtonDisabled');\r
131                 tinyMCE.switchClass(editor_id + '_delete_row', 'mceButtonDisabled');\r
132                 tinyMCE.switchClass(editor_id + '_col_before', 'mceButtonDisabled');\r
133                 tinyMCE.switchClass(editor_id + '_col_after', 'mceButtonDisabled');\r
134                 tinyMCE.switchClass(editor_id + '_delete_col', 'mceButtonDisabled');\r
135                 tinyMCE.switchClass(editor_id + '_split_cells', 'mceButtonDisabled');\r
136                 tinyMCE.switchClass(editor_id + '_merge_cells', 'mceButtonDisabled');\r
137 \r
138                 // Within a td element\r
139                 if (tdElm = tinyMCE.getParentElement(node, "td,th")) {\r
140                         tinyMCE.switchClass(editor_id + '_cell_props', 'mceButtonSelected');\r
141                         tinyMCE.switchClass(editor_id + '_row_before', 'mceButtonNormal');\r
142                         tinyMCE.switchClass(editor_id + '_row_after', 'mceButtonNormal');\r
143                         tinyMCE.switchClass(editor_id + '_delete_row', 'mceButtonNormal');\r
144                         tinyMCE.switchClass(editor_id + '_col_before', 'mceButtonNormal');\r
145                         tinyMCE.switchClass(editor_id + '_col_after', 'mceButtonNormal');\r
146                         tinyMCE.switchClass(editor_id + '_delete_col', 'mceButtonNormal');\r
147 \r
148                         colspan = tinyMCE.getAttrib(tdElm, "colspan");\r
149                         rowspan = tinyMCE.getAttrib(tdElm, "rowspan");\r
150 \r
151                         colspan = colspan == "" ? "1" : colspan;\r
152                         rowspan = rowspan == "" ? "1" : rowspan;\r
153 \r
154                         if (colspan != "1" || rowspan != "1")\r
155                                 tinyMCE.switchClass(editor_id + '_split_cells', 'mceButtonNormal');\r
156                 }\r
157 \r
158                 // Within a tr element\r
159                 if (tinyMCE.getParentElement(node, "tr"))\r
160                         tinyMCE.switchClass(editor_id + '_row_props', 'mceButtonSelected');\r
161 \r
162                 // Within table\r
163                 if (tinyMCE.getParentElement(node, "table")) {\r
164                         tinyMCE.switchClass(editor_id + '_table', 'mceButtonSelected');\r
165                         tinyMCE.switchClass(editor_id + '_merge_cells', 'mceButtonNormal');\r
166                 }\r
167         },\r
168 \r
169         // Private plugin internal methods\r
170 \r
171         _mouseDownHandler : function(e) {\r
172                 var elm = tinyMCE.isMSIE ? event.srcElement : e.target;\r
173                 var focusElm = tinyMCE.selectedInstance.getFocusElement();\r
174 \r
175                 // If press on special Mozilla create TD/TR thingie\r
176                 if (elm.nodeName == "BODY" && (focusElm.nodeName == "TD" || focusElm.nodeName == "TH" || (focusElm.parentNode && focusElm.parentNode.nodeName == "TD") ||(focusElm.parentNode && focusElm.parentNode.nodeName == "TH") )) {\r
177                         window.setTimeout(function() {\r
178                                 var tableElm = tinyMCE.getParentElement(focusElm, "table");\r
179                                 tinyMCE.handleVisualAid(tableElm, true, tinyMCE.settings['visual'], tinyMCE.selectedInstance);\r
180                         }, 10);\r
181                 }\r
182         },\r
183 \r
184         /**\r
185          * Executes the table commands.\r
186          */\r
187         _doExecCommand : function(editor_id, element, command, user_interface, value) {\r
188                 var inst = tinyMCE.getInstanceById(editor_id);\r
189                 var focusElm = inst.getFocusElement();\r
190                 var trElm = tinyMCE.getParentElement(focusElm, "tr");\r
191                 var tdElm = tinyMCE.getParentElement(focusElm, "td,th");\r
192                 var tableElm = tinyMCE.getParentElement(focusElm, "table");\r
193                 var doc = inst.contentWindow.document;\r
194                 var tableBorder = tableElm ? tableElm.getAttribute("border") : "";\r
195 \r
196                 // Get first TD if no TD found\r
197                 if (trElm && tdElm == null)\r
198                         tdElm = trElm.cells[0];\r
199 \r
200                 // ------- Inner functions ---------\r
201                 function inArray(ar, v) {\r
202                         for (var i=0; i<ar.length; i++) {\r
203                                 // Is array\r
204                                 if (ar[i].length > 0 && inArray(ar[i], v))\r
205                                         return true;\r
206 \r
207                                 // Found value\r
208                                 if (ar[i] == v)\r
209                                         return true;\r
210                         }\r
211 \r
212                         return false;\r
213                 }\r
214 \r
215                 function makeTD() {\r
216                         var newTD = doc.createElement("td");\r
217                         newTD.innerHTML = "&nbsp;";\r
218                 }\r
219 \r
220                 function getColRowSpan(td) {\r
221                         var colspan = tinyMCE.getAttrib(td, "colspan");\r
222                         var rowspan = tinyMCE.getAttrib(td, "rowspan");\r
223 \r
224                         colspan = colspan == "" ? 1 : parseInt(colspan);\r
225                         rowspan = rowspan == "" ? 1 : parseInt(rowspan);\r
226 \r
227                         return {colspan : colspan, rowspan : rowspan};\r
228                 }\r
229 \r
230                 function getCellPos(grid, td) {\r
231                         for (var y=0; y<grid.length; y++) {\r
232                                 for (var x=0; x<grid[y].length; x++) {\r
233                                         if (grid[y][x] == td)\r
234                                                 return {cellindex : x, rowindex : y};\r
235                                 }\r
236                         }\r
237 \r
238                         return null;\r
239                 }\r
240 \r
241                 function getCell(grid, row, col) {\r
242                         if (grid[row] && grid[row][col])\r
243                                 return grid[row][col];\r
244 \r
245                         return null;\r
246                 }\r
247 \r
248                 function getTableGrid(table) {\r
249                         var grid = new Array();\r
250                         var rows = table.rows;\r
251 \r
252                         for (var y=0; y<rows.length; y++) {\r
253                                 for (var x=0; x<rows[y].cells.length; x++) {\r
254                                         var td = rows[y].cells[x];\r
255                                         var sd = getColRowSpan(td);\r
256 \r
257                                         // All ready filled\r
258                                         for (xstart = x; grid[y] && grid[y][xstart]; xstart++) ;\r
259 \r
260                                         // Fill box\r
261                                         for (var y2=y; y2<y+sd['rowspan']; y2++) {\r
262                                                 if (!grid[y2])\r
263                                                         grid[y2] = new Array();\r
264 \r
265                                                 for (var x2=xstart; x2<xstart+sd['colspan']; x2++) {\r
266                                                         grid[y2][x2] = td;\r
267                                                 }\r
268                                         }\r
269                                 }\r
270                         }\r
271 \r
272                         return grid;\r
273                 }\r
274 \r
275                 function trimRow(table, tr, td, new_tr) {\r
276                         var grid = getTableGrid(table);\r
277                         var cpos = getCellPos(grid, td);\r
278 \r
279                         // Time to crop away some\r
280                         if (new_tr.cells.length != tr.childNodes.length) {\r
281                                 var cells = tr.childNodes;\r
282                                 var lastElm = null;\r
283 \r
284                                 for (var x=0; td = getCell(grid, cpos.rowindex, x); x++) {\r
285                                         var remove = true;\r
286                                         var sd = getColRowSpan(td);\r
287 \r
288                                         // Remove due to rowspan\r
289                                         if (inArray(cells, td)) {\r
290                                                 new_tr.childNodes[x]._delete = true;\r
291                                         } else if ((lastElm == null || td != lastElm) && sd.colspan > 1) { // Remove due to colspan\r
292                                                 for (var i=x; i<x+td.colSpan; i++)\r
293                                                         new_tr.childNodes[i]._delete = true;\r
294                                         }\r
295 \r
296                                         if ((lastElm == null || td != lastElm) && sd.rowspan > 1)\r
297                                                 td.rowSpan = sd.rowspan + 1;\r
298 \r
299                                         lastElm = td;\r
300                                 }\r
301 \r
302                                 deleteMarked(tableElm);\r
303                         }\r
304                 }\r
305 \r
306                 function prevElm(node, name) {\r
307                         while ((node = node.previousSibling) != null) {\r
308                                 if (node.nodeName == name)\r
309                                         return node;\r
310                         }\r
311 \r
312                         return null;\r
313                 }\r
314 \r
315                 function nextElm(node, names) {\r
316                         var namesAr = names.split(',');\r
317 \r
318                         while ((node = node.nextSibling) != null) {\r
319                                 for (var i=0; i<namesAr.length; i++) {\r
320                                         if (node.nodeName.toLowerCase() == namesAr[i].toLowerCase() )\r
321                                                 return node;\r
322                                 }\r
323                         }\r
324 \r
325                         return null;\r
326                 }\r
327 \r
328                 function deleteMarked(tbl) {\r
329                         if (tbl.rows == 0)\r
330                                 return;\r
331 \r
332                         var tr = tbl.rows[0];\r
333                         do {\r
334                                 var next = nextElm(tr, "TR");\r
335 \r
336                                 // Delete row\r
337                                 if (tr._delete) {\r
338                                         tr.parentNode.removeChild(tr);\r
339                                         continue;\r
340                                 }\r
341 \r
342                                 // Delete cells\r
343                                 var td = tr.cells[0];\r
344                                 if (td.cells > 1) {\r
345                                         do {\r
346                                                 var nexttd = nextElm(td, "TD,TH");\r
347 \r
348                                                 if (td._delete)\r
349                                                         td.parentNode.removeChild(td);\r
350                                         } while ((td = nexttd) != null);\r
351                                 }\r
352                         } while ((tr = next) != null);\r
353                 }\r
354 \r
355                 function addRows(td_elm, tr_elm, rowspan) {\r
356                         // Add rows\r
357                         td_elm.rowSpan = 1;\r
358                         var trNext = nextElm(tr_elm, "TR");\r
359                         for (var i=1; i<rowspan && trNext; i++) {\r
360                                 var newTD = doc.createElement("td");\r
361                                 newTD.innerHTML = "&nbsp;";\r
362 \r
363                                 if (tinyMCE.isMSIE)\r
364                                         trNext.insertBefore(newTD, trNext.cells(td_elm.cellIndex));\r
365                                 else\r
366                                         trNext.insertBefore(newTD, trNext.cells[td_elm.cellIndex]);\r
367 \r
368                                 trNext = nextElm(trNext, "TR");\r
369                         }\r
370                 }\r
371 \r
372                 function copyRow(doc, table, tr) {\r
373                         var grid = getTableGrid(table);\r
374                         var newTR = tr.cloneNode(false);\r
375                         var cpos = getCellPos(grid, tr.cells[0]);\r
376                         var lastCell = null;\r
377                         var tableBorder = tinyMCE.getAttrib(table, "border");\r
378                         var tdElm = null;\r
379 \r
380                         for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {\r
381                                 var newTD = null;\r
382 \r
383                                 if (lastCell != tdElm) {\r
384                                         for (var i=0; i<tr.cells.length; i++) {\r
385                                                 if (tdElm == tr.cells[i]) {\r
386                                                         newTD = tdElm.cloneNode(true);\r
387                                                         break;\r
388                                                 }\r
389                                         }\r
390                                 }\r
391 \r
392                                 if (newTD == null) {\r
393                                         newTD = doc.createElement("td");\r
394                                         newTD.innerHTML = "&nbsp;";\r
395                                 }\r
396 \r
397                                 // Reset col/row span\r
398                                 newTD.colSpan = 1;\r
399                                 newTD.rowSpan = 1;\r
400 \r
401                                 newTR.appendChild(newTD);\r
402 \r
403                                 lastCell = tdElm;\r
404                         }\r
405 \r
406                         return newTR;\r
407                 }\r
408 \r
409                 // ---- Commands -----\r
410 \r
411                 // Handle commands\r
412                 switch (command) {\r
413                         case "mceTableRowProps":\r
414                                 if (trElm == null)\r
415                                         return true;\r
416 \r
417                                 if (user_interface) {\r
418                                         // Setup template\r
419                                         var template = new Array();\r
420 \r
421                                         template['file'] = '../../plugins/table/row.htm';\r
422                                         template['width'] = 380;\r
423                                         template['height'] = 295;\r
424 \r
425                                         // Language specific width and height addons\r
426                                         template['width'] += tinyMCE.getLang('lang_table_rowprops_delta_width', 0);\r
427                                         template['height'] += tinyMCE.getLang('lang_table_rowprops_delta_height', 0);\r
428 \r
429                                         // Open window\r
430                                         tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes"});\r
431                                 }\r
432 \r
433                                 return true;\r
434 \r
435                         case "mceTableCellProps":\r
436                                 if (tdElm == null)\r
437                                         return true;\r
438 \r
439                                 if (user_interface) {\r
440                                         // Setup template\r
441                                         var template = new Array();\r
442 \r
443                                         template['file'] = '../../plugins/table/cell.htm';\r
444                                         template['width'] = 380;\r
445                                         template['height'] = 295;\r
446 \r
447                                         // Language specific width and height addons\r
448                                         template['width'] += tinyMCE.getLang('lang_table_cellprops_delta_width', 0);\r
449                                         template['height'] += tinyMCE.getLang('lang_table_cellprops_delta_height', 0);\r
450 \r
451                                         // Open window\r
452                                         tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes"});\r
453                                 }\r
454 \r
455                                 return true;\r
456 \r
457                         case "mceInsertTable":\r
458                                 if (user_interface) {\r
459                                         // Setup template\r
460                                         var template = new Array();\r
461 \r
462                                         template['file'] = '../../plugins/table/table.htm';\r
463                                         template['width'] = 380;\r
464                                         template['height'] = 295;\r
465 \r
466                                         // Language specific width and height addons\r
467                                         template['width'] += tinyMCE.getLang('lang_table_table_delta_width', 0);\r
468                                         template['height'] += tinyMCE.getLang('lang_table_table_delta_height', 0);\r
469 \r
470                                         // Open window\r
471                                         tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes", action : value});\r
472                                 }\r
473 \r
474                                 return true;\r
475 \r
476                         case "mceTableDelete":\r
477                                 var table = tinyMCE.getParentElement(inst.getFocusElement(), "table");\r
478                                 if (table) {\r
479                                         table.parentNode.removeChild(table);\r
480                                         inst.repaint();\r
481                                 }\r
482                                 return true;\r
483 \r
484                         case "mceTableSplitCells":\r
485                         case "mceTableMergeCells":\r
486                         case "mceTableInsertRowBefore":\r
487                         case "mceTableInsertRowAfter":\r
488                         case "mceTableDeleteRow":\r
489                         case "mceTableInsertColBefore":\r
490                         case "mceTableInsertColAfter":\r
491                         case "mceTableDeleteCol":\r
492                         case "mceTableCutRow":\r
493                         case "mceTableCopyRow":\r
494                         case "mceTablePasteRowBefore":\r
495                         case "mceTablePasteRowAfter":\r
496                                 // No table just return (invalid command)\r
497                                 if (!tableElm)\r
498                                         return true;\r
499 \r
500                                 // Table has a tbody use that reference\r
501                                 // Changed logic by ApTest 2005.07.12 (www.aptest.com)\r
502                                 // Now lookk at the focused element and take its parentNode.  That will be a tbody or a table.\r
503                                 if (tableElm != trElm.parentNode)\r
504                                         tableElm = trElm.parentNode;\r
505 \r
506                                 if (tableElm && trElm) {\r
507                                         switch (command) {\r
508                                                 case "mceTableInsertRowBefore":\r
509                                                         if (!trElm || !tdElm)\r
510                                                                 return true;\r
511 \r
512                                                         var grid = getTableGrid(tableElm);\r
513                                                         var cpos = getCellPos(grid, tdElm);\r
514                                                         var newTR = doc.createElement("tr");\r
515                                                         var lastTDElm = null;\r
516 \r
517                                                         cpos.rowindex--;\r
518                                                         if (cpos.rowindex < 0)\r
519                                                                 cpos.rowindex = 0;\r
520 \r
521                                                         // Create cells\r
522                                                         for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {\r
523                                                                 if (tdElm != lastTDElm) {\r
524                                                                         var sd = getColRowSpan(tdElm);\r
525 \r
526                                                                         if (sd['rowspan'] == 1) {\r
527                                                                                 var newTD = doc.createElement("td");\r
528 \r
529                                                                                 newTD.innerHTML = "&nbsp;";\r
530                                                                                 newTD.colSpan = tdElm.colSpan;\r
531 \r
532                                                                                 newTR.appendChild(newTD);\r
533                                                                         } else\r
534                                                                                 tdElm.rowSpan = sd['rowspan'] + 1;\r
535 \r
536                                                                         lastTDElm = tdElm;\r
537                                                                 }\r
538                                                         }\r
539 \r
540                                                         trElm.parentNode.insertBefore(newTR, trElm);\r
541                                                 break;\r
542 \r
543                                                 case "mceTableCutRow":\r
544                                                         if (!trElm || !tdElm)\r
545                                                                 return true;\r
546 \r
547                                                         inst.tableRowClipboard = copyRow(doc, tableElm, trElm);\r
548                                                         inst.execCommand("mceTableDeleteRow");\r
549                                                         break;\r
550 \r
551                                                 case "mceTableCopyRow":\r
552                                                         if (!trElm || !tdElm)\r
553                                                                 return true;\r
554 \r
555                                                         inst.tableRowClipboard = copyRow(doc, tableElm, trElm);\r
556                                                         break;\r
557 \r
558                                                 case "mceTablePasteRowBefore":\r
559                                                         if (!trElm || !tdElm)\r
560                                                                 return true;\r
561 \r
562                                                         var newTR = inst.tableRowClipboard.cloneNode(true);\r
563 \r
564                                                         var prevTR = prevElm(trElm, "TR");\r
565                                                         if (prevTR != null)\r
566                                                                 trimRow(tableElm, prevTR, prevTR.cells[0], newTR);\r
567 \r
568                                                         trElm.parentNode.insertBefore(newTR, trElm);\r
569                                                         break;\r
570 \r
571                                                 case "mceTablePasteRowAfter":\r
572                                                         if (!trElm || !tdElm)\r
573                                                                 return true;\r
574                                                         \r
575                                                         var nextTR = nextElm(trElm, "TR");\r
576                                                         var newTR = inst.tableRowClipboard.cloneNode(true);\r
577 \r
578                                                         trimRow(tableElm, trElm, tdElm, newTR);\r
579 \r
580                                                         if (nextTR == null)\r
581                                                                 trElm.parentNode.appendChild(newTR);\r
582                                                         else\r
583                                                                 nextTR.parentNode.insertBefore(newTR, nextTR);\r
584 \r
585                                                         break;\r
586 \r
587                                                 case "mceTableInsertRowAfter":\r
588                                                         if (!trElm || !tdElm)\r
589                                                                 return true;\r
590 \r
591                                                         var grid = getTableGrid(tableElm);\r
592                                                         var cpos = getCellPos(grid, tdElm);\r
593                                                         var newTR = doc.createElement("tr");\r
594                                                         var lastTDElm = null;\r
595 \r
596                                                         // Create cells\r
597                                                         for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {\r
598                                                                 if (tdElm != lastTDElm) {\r
599                                                                         var sd = getColRowSpan(tdElm);\r
600 \r
601                                                                         if (sd['rowspan'] == 1) {\r
602                                                                                 var newTD = doc.createElement("td");\r
603 \r
604                                                                                 newTD.innerHTML = "&nbsp;";\r
605                                                                                 newTD.colSpan = tdElm.colSpan;\r
606 \r
607                                                                                 newTR.appendChild(newTD);\r
608                                                                         } else\r
609                                                                                 tdElm.rowSpan = sd['rowspan'] + 1;\r
610 \r
611                                                                         lastTDElm = tdElm;\r
612                                                                 }\r
613                                                         }\r
614 \r
615                                                         if (newTR.hasChildNodes()) {\r
616                                                                 var nextTR = nextElm(trElm, "TR");\r
617                                                                 if (nextTR)\r
618                                                                         nextTR.parentNode.insertBefore(newTR, nextTR);\r
619                                                                 else\r
620                                                                         tableElm.appendChild(newTR);\r
621                                                         }\r
622                                                 break;\r
623 \r
624                                                 case "mceTableDeleteRow":\r
625                                                         if (!trElm || !tdElm)\r
626                                                                 return true;\r
627                 \r
628                                                         var grid = getTableGrid(tableElm);\r
629                                                         var cpos = getCellPos(grid, tdElm);\r
630 \r
631                                                         // Only one row, remove whole table\r
632                                                         if (grid.length == 1) {\r
633                                                                 tableElm.parentNode.removeChild(tableElm);\r
634                                                                 return true;\r
635                                                         }\r
636 \r
637                                                         // Move down row spanned cells\r
638                                                         var cells = trElm.cells;\r
639                                                         var nextTR = nextElm(trElm, "TR");\r
640                                                         for (var x=0; x<cells.length; x++) {\r
641                                                                 if (cells[x].rowSpan > 1) {\r
642                                                                         var newTD = cells[x].cloneNode(true);\r
643                                                                         var sd = getColRowSpan(cells[x]);\r
644 \r
645                                                                         newTD.rowSpan = sd.rowspan - 1;\r
646 \r
647                                                                         var nextTD = nextTR.cells[x];\r
648 \r
649                                                                         if (nextTD == null)\r
650                                                                                 nextTR.appendChild(newTD);\r
651                                                                         else\r
652                                                                                 nextTR.insertBefore(newTD, nextTD);\r
653                                                                 }\r
654                                                         }\r
655 \r
656                                                         // Delete cells\r
657                                                         var lastTDElm = null;\r
658                                                         for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {\r
659                                                                 if (tdElm != lastTDElm) {\r
660                                                                         var sd = getColRowSpan(tdElm);\r
661 \r
662                                                                         if (sd.rowspan > 1) {\r
663                                                                                 tdElm.rowSpan = sd.rowspan - 1;\r
664                                                                         } else {\r
665                                                                                 trElm = tdElm.parentNode;\r
666 \r
667                                                                                 if (trElm.parentNode)\r
668                                                                                         trElm._delete = true;\r
669                                                                         }\r
670 \r
671                                                                         lastTDElm = tdElm;\r
672                                                                 }\r
673                                                         }\r
674 \r
675                                                         deleteMarked(tableElm);\r
676 \r
677                                                         cpos.rowindex--;\r
678                                                         if (cpos.rowindex < 0)\r
679                                                                 cpos.rowindex = 0;\r
680 \r
681                                                         inst.selection.selectNode(getCell(grid, cpos.rowindex, 0), true, true);\r
682                                                 break;\r
683 \r
684                                                 case "mceTableInsertColBefore":\r
685                                                         if (!trElm || !tdElm)\r
686                                                                 return true;\r
687 \r
688                                                         var grid = getTableGrid(tableElm);\r
689                                                         var cpos = getCellPos(grid, tdElm);\r
690                                                         var lastTDElm = null;\r
691 \r
692                                                         for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {\r
693                                                                 if (tdElm != lastTDElm) {\r
694                                                                         var sd = getColRowSpan(tdElm);\r
695 \r
696                                                                         if (sd['colspan'] == 1) {\r
697                                                                                 var newTD = doc.createElement(tdElm.nodeName);\r
698 \r
699                                                                                 newTD.innerHTML = "&nbsp;";\r
700                                                                                 newTD.rowSpan = tdElm.rowSpan;\r
701 \r
702                                                                                 tdElm.parentNode.insertBefore(newTD, tdElm);\r
703                                                                         } else\r
704                                                                                 tdElm.colSpan++;\r
705 \r
706                                                                         lastTDElm = tdElm;\r
707                                                                 }\r
708                                                         }\r
709                                                 break;\r
710 \r
711                                                 case "mceTableInsertColAfter":\r
712                                                         if (!trElm || !tdElm)\r
713                                                                 return true;\r
714 \r
715                                                         var grid = getTableGrid(tableElm);\r
716                                                         var cpos = getCellPos(grid, tdElm);\r
717                                                         var lastTDElm = null;\r
718 \r
719                                                         for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {\r
720                                                                 if (tdElm != lastTDElm) {\r
721                                                                         var sd = getColRowSpan(tdElm);\r
722 \r
723                                                                         if (sd['colspan'] == 1) {\r
724                                                                                 var newTD = doc.createElement(tdElm.nodeName);\r
725 \r
726                                                                                 newTD.innerHTML = "&nbsp;";\r
727                                                                                 newTD.rowSpan = tdElm.rowSpan;\r
728 \r
729                                                                                 var nextTD = nextElm(tdElm, "TD,TH");\r
730                                                                                 if (nextTD == null)\r
731                                                                                         tdElm.parentNode.appendChild(newTD);\r
732                                                                                 else\r
733                                                                                         nextTD.parentNode.insertBefore(newTD, nextTD);\r
734                                                                         } else\r
735                                                                                 tdElm.colSpan++;\r
736 \r
737                                                                         lastTDElm = tdElm;\r
738                                                                 }\r
739                                                         }\r
740                                                 break;\r
741 \r
742                                                 case "mceTableDeleteCol":\r
743                                                         if (!trElm || !tdElm)\r
744                                                                 return true;\r
745 \r
746                                                         var grid = getTableGrid(tableElm);\r
747                                                         var cpos = getCellPos(grid, tdElm);\r
748                                                         var lastTDElm = null;\r
749 \r
750                                                         // Only one col, remove whole table\r
751                                                         if (grid.length > 1 && grid[0].length <= 1) {\r
752                                                                 tableElm.parentNode.removeChild(tableElm);\r
753                                                                 return true;\r
754                                                         }\r
755 \r
756                                                         // Delete cells\r
757                                                         for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {\r
758                                                                 if (tdElm != lastTDElm) {\r
759                                                                         var sd = getColRowSpan(tdElm);\r
760 \r
761                                                                         if (sd['colspan'] > 1)\r
762                                                                                 tdElm.colSpan = sd['colspan'] - 1;\r
763                                                                         else {\r
764                                                                                 if (tdElm.parentNode)\r
765                                                                                         tdElm.parentNode.removeChild(tdElm);\r
766                                                                         }\r
767 \r
768                                                                         lastTDElm = tdElm;\r
769                                                                 }\r
770                                                         }\r
771 \r
772                                                         cpos.cellindex--;\r
773                                                         if (cpos.cellindex < 0)\r
774                                                                 cpos.cellindex = 0;\r
775 \r
776                                                         inst.selection.selectNode(getCell(grid, 0, cpos.cellindex), true, true);\r
777                                                 break;\r
778 \r
779                                         case "mceTableSplitCells":\r
780                                                 if (!trElm || !tdElm)\r
781                                                         return true;\r
782 \r
783                                                 var spandata = getColRowSpan(tdElm);\r
784 \r
785                                                 var colspan = spandata["colspan"];\r
786                                                 var rowspan = spandata["rowspan"];\r
787 \r
788                                                 // Needs splitting\r
789                                                 if (colspan > 1 || rowspan > 1) {\r
790                                                         // Generate cols\r
791                                                         tdElm.colSpan = 1;\r
792                                                         for (var i=1; i<colspan; i++) {\r
793                                                                 var newTD = doc.createElement("td");\r
794 \r
795                                                                 newTD.innerHTML = "&nbsp;";\r
796 \r
797                                                                 trElm.insertBefore(newTD, nextElm(tdElm, "TD,TH"));\r
798 \r
799                                                                 if (rowspan > 1)\r
800                                                                         addRows(newTD, trElm, rowspan);\r
801                                                         }\r
802 \r
803                                                         addRows(tdElm, trElm, rowspan);\r
804                                                 }\r
805 \r
806                                                 // Apply visual aids\r
807                                                 tableElm = tinyMCE.getParentElement(inst.getFocusElement(), "table");\r
808                                                 break;\r
809 \r
810                                         case "mceTableMergeCells":\r
811                                                 var rows = new Array();\r
812                                                 var sel = inst.getSel();\r
813                                                 var grid = getTableGrid(tableElm);\r
814 \r
815                                                 if (tinyMCE.isMSIE || sel.rangeCount == 1) {\r
816                                                         if (user_interface) {\r
817                                                                 // Setup template\r
818                                                                 var template = new Array();\r
819                                                                 var sp = getColRowSpan(tdElm);\r
820 \r
821                                                                 template['file'] = '../../plugins/table/merge_cells.htm';\r
822                                                                 template['width'] = 250;\r
823                                                                 template['height'] = 105 + (tinyMCE.isNS7 ? 25 : 0);\r
824 \r
825                                                                 // Language specific width and height addons\r
826                                                                 template['width'] += tinyMCE.getLang('lang_table_merge_cells_delta_width', 0);\r
827                                                                 template['height'] += tinyMCE.getLang('lang_table_merge_cells_delta_height', 0);\r
828 \r
829                                                                 // Open window\r
830                                                                 tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes", action : "update", numcols : sp.colspan, numrows : sp.rowspan});\r
831 \r
832                                                                 return true;\r
833                                                         } else {\r
834                                                                 var numRows = parseInt(value['numrows']);\r
835                                                                 var numCols = parseInt(value['numcols']);\r
836                                                                 var cpos = getCellPos(grid, tdElm);\r
837 \r
838                                                                 if (("" + numRows) == "NaN")\r
839                                                                         numRows = 1;\r
840 \r
841                                                                 if (("" + numCols) == "NaN")\r
842                                                                         numCols = 1;\r
843 \r
844                                                                 // Get rows and cells\r
845                                                                 var tRows = tableElm.rows;\r
846                                                                 for (var y=cpos.rowindex; y<grid.length; y++) {\r
847                                                                         var rowCells = new Array();\r
848 \r
849                                                                         for (var x=cpos.cellindex; x<grid[y].length; x++) {\r
850                                                                                 var td = getCell(grid, y, x);\r
851 \r
852                                                                                 if (td && !inArray(rows, td) && !inArray(rowCells, td)) {\r
853                                                                                         var cp = getCellPos(grid, td);\r
854 \r
855                                                                                         // Within range\r
856                                                                                         if (cp.cellindex < cpos.cellindex+numCols && cp.rowindex < cpos.rowindex+numRows)\r
857                                                                                                 rowCells[rowCells.length] = td;\r
858                                                                                 }\r
859                                                                         }\r
860 \r
861                                                                         if (rowCells.length > 0)\r
862                                                                                 rows[rows.length] = rowCells;\r
863                                                                 }\r
864 \r
865                                                                 //return true;\r
866                                                         }\r
867                                                 } else {\r
868                                                         var cells = new Array();\r
869                                                         var sel = inst.getSel();\r
870                                                         var lastTR = null;\r
871                                                         var curRow = null;\r
872                                                         var x1 = -1, y1 = -1, x2, y2;\r
873 \r
874                                                         // Only one cell selected, whats the point?\r
875                                                         if (sel.rangeCount < 2)\r
876                                                                 return true;\r
877 \r
878                                                         // Get all selected cells\r
879                                                         for (var i=0; i<sel.rangeCount; i++) {\r
880                                                                 var rng = sel.getRangeAt(i);\r
881                                                                 var tdElm = rng.startContainer.childNodes[rng.startOffset];\r
882 \r
883                                                                 if (!tdElm)\r
884                                                                         break;\r
885 \r
886                                                                 if (tdElm.nodeName == "TD")\r
887                                                                         cells[cells.length] = tdElm;\r
888                                                         }\r
889 \r
890                                                         // Get rows and cells\r
891                                                         var tRows = tableElm.rows;\r
892                                                         for (var y=0; y<tRows.length; y++) {\r
893                                                                 var rowCells = new Array();\r
894 \r
895                                                                 for (var x=0; x<tRows[y].cells.length; x++) {\r
896                                                                         var td = tRows[y].cells[x];\r
897 \r
898                                                                         for (var i=0; i<cells.length; i++) {\r
899                                                                                 if (td == cells[i]) {\r
900                                                                                         rowCells[rowCells.length] = td;\r
901                                                                                 }\r
902                                                                         }\r
903                                                                 }\r
904 \r
905                                                                 if (rowCells.length > 0)\r
906                                                                         rows[rows.length] = rowCells;\r
907                                                         }\r
908 \r
909                                                         // Find selected cells in grid and box\r
910                                                         var curRow = new Array();\r
911                                                         var lastTR = null;\r
912                                                         for (var y=0; y<grid.length; y++) {\r
913                                                                 for (var x=0; x<grid[y].length; x++) {\r
914                                                                         grid[y][x]._selected = false;\r
915 \r
916                                                                         for (var i=0; i<cells.length; i++) {\r
917                                                                                 if (grid[y][x] == cells[i]) {\r
918                                                                                         // Get start pos\r
919                                                                                         if (x1 == -1) {\r
920                                                                                                 x1 = x;\r
921                                                                                                 y1 = y;\r
922                                                                                         }\r
923 \r
924                                                                                         // Get end pos\r
925                                                                                         x2 = x;\r
926                                                                                         y2 = y;\r
927 \r
928                                                                                         grid[y][x]._selected = true;\r
929                                                                                 }\r
930                                                                         }\r
931                                                                 }\r
932                                                         }\r
933 \r
934                                                         // Is there gaps, if so deny\r
935                                                         for (var y=y1; y<=y2; y++) {\r
936                                                                 for (var x=x1; x<=x2; x++) {\r
937                                                                         if (!grid[y][x]._selected) {\r
938                                                                                 alert("Invalid selection for merge.");\r
939                                                                                 return true;\r
940                                                                         }\r
941                                                                 }\r
942                                                         }\r
943                                                 }\r
944 \r
945                                                 // Validate selection and get total rowspan and colspan\r
946                                                 var rowSpan = 1, colSpan = 1;\r
947 \r
948                                                 // Validate horizontal and get total colspan\r
949                                                 var lastRowSpan = -1;\r
950                                                 for (var y=0; y<rows.length; y++) {\r
951                                                         var rowColSpan = 0;\r
952 \r
953                                                         for (var x=0; x<rows[y].length; x++) {\r
954                                                                 var sd = getColRowSpan(rows[y][x]);\r
955 \r
956                                                                 rowColSpan += sd['colspan'];\r
957 \r
958                                                                 if (lastRowSpan != -1 && sd['rowspan'] != lastRowSpan) {\r
959                                                                         alert("Invalid selection for merge.");\r
960                                                                         return true;\r
961                                                                 }\r
962 \r
963                                                                 lastRowSpan = sd['rowspan'];\r
964                                                         }\r
965 \r
966                                                         if (rowColSpan > colSpan)\r
967                                                                 colSpan = rowColSpan;\r
968 \r
969                                                         lastRowSpan = -1;\r
970                                                 }\r
971 \r
972                                                 // Validate vertical and get total rowspan\r
973                                                 var lastColSpan = -1;\r
974                                                 for (var x=0; x<rows[0].length; x++) {\r
975                                                         var colRowSpan = 0;\r
976 \r
977                                                         for (var y=0; y<rows.length; y++) {\r
978                                                                 var sd = getColRowSpan(rows[y][x]);\r
979 \r
980                                                                 colRowSpan += sd['rowspan'];\r
981 \r
982                                                                 if (lastColSpan != -1 && sd['colspan'] != lastColSpan) {\r
983                                                                         alert("Invalid selection for merge.");\r
984                                                                         return true;\r
985                                                                 }\r
986 \r
987                                                                 lastColSpan = sd['colspan'];\r
988                                                         }\r
989 \r
990                                                         if (colRowSpan > rowSpan)\r
991                                                                 rowSpan = colRowSpan;\r
992 \r
993                                                         lastColSpan = -1;\r
994                                                 }\r
995 \r
996                                                 // Setup td\r
997                                                 tdElm = rows[0][0];\r
998                                                 tdElm.rowSpan = rowSpan;\r
999                                                 tdElm.colSpan = colSpan;\r
1000 \r
1001                                                 // Merge cells\r
1002                                                 for (var y=0; y<rows.length; y++) {\r
1003                                                         for (var x=0; x<rows[y].length; x++) {\r
1004                                                                 var html = rows[y][x].innerHTML;\r
1005                                                                 var chk = tinyMCE.regexpReplace(html, "[ \t\r\n]", "");\r
1006 \r
1007                                                                 if (chk != "<br/>" && chk != "<br>" && chk != "&nbsp;" && (x+y > 0))\r
1008                                                                         tdElm.innerHTML += html;\r
1009 \r
1010                                                                 // Not current cell\r
1011                                                                 if (rows[y][x] != tdElm && !rows[y][x]._deleted) {\r
1012                                                                         var cpos = getCellPos(grid, rows[y][x]);\r
1013                                                                         var tr = rows[y][x].parentNode;\r
1014 \r
1015                                                                         tr.removeChild(rows[y][x]);\r
1016                                                                         rows[y][x]._deleted = true;\r
1017 \r
1018                                                                         // Empty TR, remove it\r
1019                                                                         if (!tr.hasChildNodes()) {\r
1020                                                                                 tr.parentNode.removeChild(tr);\r
1021 \r
1022                                                                                 var lastCell = null;\r
1023                                                                                 for (var x=0; cellElm = getCell(grid, cpos.rowindex, x); x++) {\r
1024                                                                                         if (cellElm != lastCell && cellElm.rowSpan > 1)\r
1025                                                                                                 cellElm.rowSpan--;\r
1026 \r
1027                                                                                         lastCell = cellElm;\r
1028                                                                                 }\r
1029 \r
1030                                                                                 if (tdElm.rowSpan > 1)\r
1031                                                                                         tdElm.rowSpan--;\r
1032                                                                         }\r
1033                                                                 }\r
1034                                                         }\r
1035                                                 }\r
1036 \r
1037                                                 break;\r
1038                                         }\r
1039 \r
1040                                         tableElm = tinyMCE.getParentElement(inst.getFocusElement(), "table");\r
1041                                         tinyMCE.handleVisualAid(tableElm, true, tinyMCE.settings['visual'], tinyMCE.selectedInstance);\r
1042                                         tinyMCE.triggerNodeChange();\r
1043                                         inst.repaint();\r
1044                                 }\r
1045 \r
1046                         return true;\r
1047                 }\r
1048 \r
1049                 // Pass to next handler in chain\r
1050                 return false;\r
1051         }\r
1052 };\r
1053 \r
1054 tinyMCE.addPlugin("table", TinyMCE_TablePlugin);\r