]> git.donarmstrong.com Git - roundcube.git/blob - program/js/tiny_mce/plugins/table/editor_plugin_src.js
Merge commit 'upstream/0.2_alpha' into experimental-import
[roundcube.git] / program / js / tiny_mce / plugins / table / editor_plugin_src.js
1 /**\r
2  * $Id: editor_plugin_src.js 768 2008-04-04 13:52:49Z spocke $\r
3  *\r
4  * @author Moxiecode\r
5  * @copyright Copyright © 2004-2008, Moxiecode Systems AB, All rights reserved.\r
6  */\r
7 \r
8 (function() {\r
9         var each = tinymce.each;\r
10 \r
11         tinymce.create('tinymce.plugins.TablePlugin', {\r
12                 init : function(ed, url) {\r
13                         var t = this;\r
14 \r
15                         t.editor = ed;\r
16                         t.url = url;\r
17 \r
18                         // Register buttons\r
19                         each([\r
20                                 ['table', 'table.desc', 'mceInsertTable', true],\r
21                                 ['delete_table', 'table.del', 'mceTableDelete'],\r
22                                 ['delete_col', 'table.delete_col_desc', 'mceTableDeleteCol'],\r
23                                 ['delete_row', 'table.delete_row_desc', 'mceTableDeleteRow'],\r
24                                 ['col_after', 'table.col_after_desc', 'mceTableInsertColAfter'],\r
25                                 ['col_before', 'table.col_before_desc', 'mceTableInsertColBefore'],\r
26                                 ['row_after', 'table.row_after_desc', 'mceTableInsertRowAfter'],\r
27                                 ['row_before', 'table.row_before_desc', 'mceTableInsertRowBefore'],\r
28                                 ['row_props', 'table.row_desc', 'mceTableRowProps', true],\r
29                                 ['cell_props', 'table.cell_desc', 'mceTableCellProps', true],\r
30                                 ['split_cells', 'table.split_cells_desc', 'mceTableSplitCells', true],\r
31                                 ['merge_cells', 'table.merge_cells_desc', 'mceTableMergeCells', true]\r
32                         ], function(c) {\r
33                                 ed.addButton(c[0], {title : c[1], cmd : c[2], ui : c[3]});\r
34                         });\r
35 \r
36                         ed.onInit.add(function() {\r
37                                 if (ed && ed.plugins.contextmenu) {\r
38                                         ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) {\r
39                                                 var sm, se = ed.selection, el = se.getNode() || ed.getBody();\r
40 \r
41                                                 if (ed.dom.getParent(e, 'td') || ed.dom.getParent(e, 'th')) {\r
42                                                         m.removeAll();\r
43 \r
44                                                         if (el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) {\r
45                                                                 m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true});\r
46                                                                 m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'});\r
47                                                                 m.addSeparator();\r
48                                                         }\r
49 \r
50                                                         if (el.nodeName == 'IMG' && el.className.indexOf('mceItem') == -1) {\r
51                                                                 m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true});\r
52                                                                 m.addSeparator();\r
53                                                         }\r
54 \r
55                                                         m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', ui : true, value : {action : 'insert'}});\r
56                                                         m.add({title : 'table.props_desc', icon : 'table_props', cmd : 'mceInsertTable', ui : true});\r
57                                                         m.add({title : 'table.del', icon : 'delete_table', cmd : 'mceTableDelete', ui : true});\r
58                                                         m.addSeparator();\r
59 \r
60                                                         // Cell menu\r
61                                                         sm = m.addMenu({title : 'table.cell'});\r
62                                                         sm.add({title : 'table.cell_desc', icon : 'cell_props', cmd : 'mceTableCellProps', ui : true});\r
63                                                         sm.add({title : 'table.split_cells_desc', icon : 'split_cells', cmd : 'mceTableSplitCells', ui : true});\r
64                                                         sm.add({title : 'table.merge_cells_desc', icon : 'merge_cells', cmd : 'mceTableMergeCells', ui : true});\r
65 \r
66                                                         // Row menu\r
67                                                         sm = m.addMenu({title : 'table.row'});\r
68                                                         sm.add({title : 'table.row_desc', icon : 'row_props', cmd : 'mceTableRowProps', ui : true});\r
69                                                         sm.add({title : 'table.row_before_desc', icon : 'row_before', cmd : 'mceTableInsertRowBefore'});\r
70                                                         sm.add({title : 'table.row_after_desc', icon : 'row_after', cmd : 'mceTableInsertRowAfter'});\r
71                                                         sm.add({title : 'table.delete_row_desc', icon : 'delete_row', cmd : 'mceTableDeleteRow'});\r
72                                                         sm.addSeparator();\r
73                                                         sm.add({title : 'table.cut_row_desc', icon : 'cut', cmd : 'mceTableCutRow'});\r
74                                                         sm.add({title : 'table.copy_row_desc', icon : 'copy', cmd : 'mceTableCopyRow'});\r
75                                                         sm.add({title : 'table.paste_row_before_desc', icon : 'paste', cmd : 'mceTablePasteRowBefore'});\r
76                                                         sm.add({title : 'table.paste_row_after_desc', icon : 'paste', cmd : 'mceTablePasteRowAfter'});\r
77 \r
78                                                         // Column menu\r
79                                                         sm = m.addMenu({title : 'table.col'});\r
80                                                         sm.add({title : 'table.col_before_desc', icon : 'col_before', cmd : 'mceTableInsertColBefore'});\r
81                                                         sm.add({title : 'table.col_after_desc', icon : 'col_after', cmd : 'mceTableInsertColAfter'});\r
82                                                         sm.add({title : 'table.delete_col_desc', icon : 'delete_col', cmd : 'mceTableDeleteCol'});\r
83                                                 } else\r
84                                                         m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', ui : true});\r
85                                         });\r
86                                 }\r
87                         });\r
88 \r
89                         // Add undo level when new rows are created using the tab key\r
90                         ed.onKeyDown.add(function(ed, e) {\r
91                                 if (e.keyCode == 9 && ed.dom.getParent(ed.selection.getNode(), 'TABLE'))\r
92                                         ed.undoManager.add();\r
93                         });\r
94 \r
95                         ed.onNodeChange.add(function(ed, cm, n) {\r
96                                 var p = ed.dom.getParent(n, 'td,th,caption');\r
97 \r
98                                 cm.setActive('table', !!p);\r
99                                 if (p && p.nodeName === 'CAPTION')\r
100                                         p = null;\r
101 \r
102                                 cm.setDisabled('delete_table', !p);\r
103                                 cm.setDisabled('delete_col', !p);\r
104                                 cm.setDisabled('delete_table', !p);\r
105                                 cm.setDisabled('delete_row', !p);\r
106                                 cm.setDisabled('col_after', !p);\r
107                                 cm.setDisabled('col_before', !p);\r
108                                 cm.setDisabled('row_after', !p);\r
109                                 cm.setDisabled('row_before', !p);\r
110                                 cm.setDisabled('row_props', !p);\r
111                                 cm.setDisabled('cell_props', !p);\r
112                                 cm.setDisabled('split_cells', !p || (parseInt(ed.dom.getAttrib(p, 'colspan', '1')) < 2 && parseInt(ed.dom.getAttrib(p, 'rowspan', '1')) < 2));\r
113                                 cm.setDisabled('merge_cells', !p);\r
114                         });\r
115 \r
116                         // Padd empty table cells\r
117                         if (!tinymce.isIE) {\r
118                                 ed.onBeforeSetContent.add(function(ed, o) {\r
119                                         if (o.initial)\r
120                                                 o.content = o.content.replace(/<(td|th)([^>]+|)>\s*<\/(td|th)>/g, tinymce.isOpera ? '<$1$2>&nbsp;</$1>' : '<$1$2><br mce_bogus="1" /></$1>');\r
121                                 });\r
122                         }\r
123                 },\r
124 \r
125                 execCommand : function(cmd, ui, val) {\r
126                         var ed = this.editor, b;\r
127 \r
128                         // Is table command\r
129                         switch (cmd) {\r
130                                 case "mceInsertTable":\r
131                                 case "mceTableRowProps":\r
132                                 case "mceTableCellProps":\r
133                                 case "mceTableSplitCells":\r
134                                 case "mceTableMergeCells":\r
135                                 case "mceTableInsertRowBefore":\r
136                                 case "mceTableInsertRowAfter":\r
137                                 case "mceTableDeleteRow":\r
138                                 case "mceTableInsertColBefore":\r
139                                 case "mceTableInsertColAfter":\r
140                                 case "mceTableDeleteCol":\r
141                                 case "mceTableCutRow":\r
142                                 case "mceTableCopyRow":\r
143                                 case "mceTablePasteRowBefore":\r
144                                 case "mceTablePasteRowAfter":\r
145                                 case "mceTableDelete":\r
146                                         ed.execCommand('mceBeginUndoLevel');\r
147                                         this._doExecCommand(cmd, ui, val);\r
148                                         ed.execCommand('mceEndUndoLevel');\r
149 \r
150                                         return true;\r
151                         }\r
152 \r
153                         // Pass to next handler in chain\r
154                         return false;\r
155                 },\r
156 \r
157                 getInfo : function() {\r
158                         return {\r
159                                 longname : 'Tables',\r
160                                 author : 'Moxiecode Systems AB',\r
161                                 authorurl : 'http://tinymce.moxiecode.com',\r
162                                 infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/table',\r
163                                 version : tinymce.majorVersion + "." + tinymce.minorVersion\r
164                         };\r
165                 },\r
166 \r
167                 // Private plugin internal methods\r
168 \r
169                 /**\r
170                  * Executes the table commands.\r
171                  */\r
172                 _doExecCommand : function(command, user_interface, value) {\r
173                         var inst = this.editor, ed = inst, url = this.url;\r
174                         var focusElm = inst.selection.getNode();\r
175                         var trElm = inst.dom.getParent(focusElm, "tr");\r
176                         var tdElm = inst.dom.getParent(focusElm, "td,th");\r
177                         var tableElm = inst.dom.getParent(focusElm, "table");\r
178                         var doc = inst.contentWindow.document;\r
179                         var tableBorder = tableElm ? tableElm.getAttribute("border") : "";\r
180 \r
181                         // Get first TD if no TD found\r
182                         if (trElm && tdElm == null)\r
183                                 tdElm = trElm.cells[0];\r
184 \r
185                         function inArray(ar, v) {\r
186                                 for (var i=0; i<ar.length; i++) {\r
187                                         // Is array\r
188                                         if (ar[i].length > 0 && inArray(ar[i], v))\r
189                                                 return true;\r
190 \r
191                                         // Found value\r
192                                         if (ar[i] == v)\r
193                                                 return true;\r
194                                 }\r
195 \r
196                                 return false;\r
197                         }\r
198 \r
199                         function select(dx, dy) {\r
200                                 var td;\r
201 \r
202                                 grid = getTableGrid(tableElm);\r
203                                 dx = dx || 0;\r
204                                 dy = dy || 0;\r
205                                 dx = Math.max(cpos.cellindex + dx, 0);\r
206                                 dy = Math.max(cpos.rowindex + dy, 0);\r
207 \r
208                                 // Recalculate grid and select\r
209                                 inst.execCommand('mceRepaint');\r
210                                 td = getCell(grid, dy, dx);\r
211 \r
212                                 if (td) {\r
213                                         inst.selection.select(td.firstChild || td);\r
214                                         inst.selection.collapse(1);\r
215                                 }\r
216                         };\r
217 \r
218                         function makeTD() {\r
219                                 var newTD = doc.createElement("td");\r
220 \r
221                                 if (!tinymce.isIE)\r
222                                         newTD.innerHTML = '<br mce_bogus="1"/>';\r
223                         }\r
224 \r
225                         function getColRowSpan(td) {\r
226                                 var colspan = inst.dom.getAttrib(td, "colspan");\r
227                                 var rowspan = inst.dom.getAttrib(td, "rowspan");\r
228 \r
229                                 colspan = colspan == "" ? 1 : parseInt(colspan);\r
230                                 rowspan = rowspan == "" ? 1 : parseInt(rowspan);\r
231 \r
232                                 return {colspan : colspan, rowspan : rowspan};\r
233                         }\r
234 \r
235                         function getCellPos(grid, td) {\r
236                                 var x, y;\r
237 \r
238                                 for (y=0; y<grid.length; y++) {\r
239                                         for (x=0; x<grid[y].length; x++) {\r
240                                                 if (grid[y][x] == td)\r
241                                                         return {cellindex : x, rowindex : y};\r
242                                         }\r
243                                 }\r
244 \r
245                                 return null;\r
246                         }\r
247 \r
248                         function getCell(grid, row, col) {\r
249                                 if (grid[row] && grid[row][col])\r
250                                         return grid[row][col];\r
251 \r
252                                 return null;\r
253                         }\r
254 \r
255                         function getTableGrid(table) {\r
256                                 var grid = [], rows = table.rows, x, y, td, sd, xstart, x2, y2;\r
257 \r
258                                 for (y=0; y<rows.length; y++) {\r
259                                         for (x=0; x<rows[y].cells.length; x++) {\r
260                                                 td = rows[y].cells[x];\r
261                                                 sd = getColRowSpan(td);\r
262 \r
263                                                 // All ready filled\r
264                                                 for (xstart = x; grid[y] && grid[y][xstart]; xstart++) ;\r
265 \r
266                                                 // Fill box\r
267                                                 for (y2=y; y2<y+sd['rowspan']; y2++) {\r
268                                                         if (!grid[y2])\r
269                                                                 grid[y2] = [];\r
270 \r
271                                                         for (x2=xstart; x2<xstart+sd['colspan']; x2++)\r
272                                                                 grid[y2][x2] = td;\r
273                                                 }\r
274                                         }\r
275                                 }\r
276 \r
277                                 return grid;\r
278                         }\r
279 \r
280                         function trimRow(table, tr, td, new_tr) {\r
281                                 var grid = getTableGrid(table), cpos = getCellPos(grid, td);\r
282                                 var cells, lastElm;\r
283 \r
284                                 // Time to crop away some\r
285                                 if (new_tr.cells.length != tr.childNodes.length) {\r
286                                         cells = tr.childNodes;\r
287                                         lastElm = null;\r
288 \r
289                                         for (var x=0; td = getCell(grid, cpos.rowindex, x); x++) {\r
290                                                 var remove = true;\r
291                                                 var sd = getColRowSpan(td);\r
292 \r
293                                                 // Remove due to rowspan\r
294                                                 if (inArray(cells, td)) {\r
295                                                         new_tr.childNodes[x]._delete = true;\r
296                                                 } else if ((lastElm == null || td != lastElm) && sd.colspan > 1) { // Remove due to colspan\r
297                                                         for (var i=x; i<x+td.colSpan; i++)\r
298                                                                 new_tr.childNodes[i]._delete = true;\r
299                                                 }\r
300 \r
301                                                 if ((lastElm == null || td != lastElm) && sd.rowspan > 1)\r
302                                                         td.rowSpan = sd.rowspan + 1;\r
303 \r
304                                                 lastElm = td;\r
305                                         }\r
306 \r
307                                         deleteMarked(tableElm);\r
308                                 }\r
309                         }\r
310 \r
311                         function prevElm(node, name) {\r
312                                 while ((node = node.previousSibling) != null) {\r
313                                         if (node.nodeName == name)\r
314                                                 return node;\r
315                                 }\r
316 \r
317                                 return null;\r
318                         }\r
319 \r
320                         function nextElm(node, names) {\r
321                                 var namesAr = names.split(',');\r
322 \r
323                                 while ((node = node.nextSibling) != null) {\r
324                                         for (var i=0; i<namesAr.length; i++) {\r
325                                                 if (node.nodeName.toLowerCase() == namesAr[i].toLowerCase() )\r
326                                                         return node;\r
327                                         }\r
328                                 }\r
329 \r
330                                 return null;\r
331                         }\r
332 \r
333                         function deleteMarked(tbl) {\r
334                                 if (tbl.rows == 0)\r
335                                         return;\r
336 \r
337                                 var tr = tbl.rows[0];\r
338                                 do {\r
339                                         var next = nextElm(tr, "TR");\r
340 \r
341                                         // Delete row\r
342                                         if (tr._delete) {\r
343                                                 tr.parentNode.removeChild(tr);\r
344                                                 continue;\r
345                                         }\r
346 \r
347                                         // Delete cells\r
348                                         var td = tr.cells[0];\r
349                                         if (td.cells > 1) {\r
350                                                 do {\r
351                                                         var nexttd = nextElm(td, "TD,TH");\r
352 \r
353                                                         if (td._delete)\r
354                                                                 td.parentNode.removeChild(td);\r
355                                                 } while ((td = nexttd) != null);\r
356                                         }\r
357                                 } while ((tr = next) != null);\r
358                         }\r
359 \r
360                         function addRows(td_elm, tr_elm, rowspan) {\r
361                                 // Add rows\r
362                                 td_elm.rowSpan = 1;\r
363                                 var trNext = nextElm(tr_elm, "TR");\r
364                                 for (var i=1; i<rowspan && trNext; i++) {\r
365                                         var newTD = doc.createElement("td");\r
366 \r
367                                         if (!tinymce.isIE)\r
368                                                 newTD.innerHTML = '<br mce_bogus="1"/>';\r
369 \r
370                                         if (tinymce.isIE)\r
371                                                 trNext.insertBefore(newTD, trNext.cells(td_elm.cellIndex));\r
372                                         else\r
373                                                 trNext.insertBefore(newTD, trNext.cells[td_elm.cellIndex]);\r
374 \r
375                                         trNext = nextElm(trNext, "TR");\r
376                                 }\r
377                         }\r
378 \r
379                         function copyRow(doc, table, tr) {\r
380                                 var grid = getTableGrid(table);\r
381                                 var newTR = tr.cloneNode(false);\r
382                                 var cpos = getCellPos(grid, tr.cells[0]);\r
383                                 var lastCell = null;\r
384                                 var tableBorder = inst.dom.getAttrib(table, "border");\r
385                                 var tdElm = null;\r
386 \r
387                                 for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {\r
388                                         var newTD = null;\r
389 \r
390                                         if (lastCell != tdElm) {\r
391                                                 for (var i=0; i<tr.cells.length; i++) {\r
392                                                         if (tdElm == tr.cells[i]) {\r
393                                                                 newTD = tdElm.cloneNode(true);\r
394                                                                 break;\r
395                                                         }\r
396                                                 }\r
397                                         }\r
398 \r
399                                         if (newTD == null) {\r
400                                                 newTD = doc.createElement("td");\r
401 \r
402                                                 if (!tinymce.isIE)\r
403                                                         newTD.innerHTML = '<br mce_bogus="1"/>';\r
404                                         }\r
405 \r
406                                         // Reset col/row span\r
407                                         newTD.colSpan = 1;\r
408                                         newTD.rowSpan = 1;\r
409 \r
410                                         newTR.appendChild(newTD);\r
411 \r
412                                         lastCell = tdElm;\r
413                                 }\r
414 \r
415                                 return newTR;\r
416                         }\r
417 \r
418                         // ---- Commands -----\r
419 \r
420                         // Handle commands\r
421                         switch (command) {\r
422                                 case "mceTableRowProps":\r
423                                         if (trElm == null)\r
424                                                 return true;\r
425 \r
426                                         if (user_interface) {\r
427                                                 inst.windowManager.open({\r
428                                                         url : url + '/row.htm',\r
429                                                         width : 400 + parseInt(inst.getLang('table.rowprops_delta_width', 0)),\r
430                                                         height : 295 + parseInt(inst.getLang('table.rowprops_delta_height', 0)),\r
431                                                         inline : 1\r
432                                                 }, {\r
433                                                         plugin_url : url\r
434                                                 });\r
435                                         }\r
436 \r
437                                         return true;\r
438 \r
439                                 case "mceTableCellProps":\r
440                                         if (tdElm == null)\r
441                                                 return true;\r
442 \r
443                                         if (user_interface) {\r
444                                                 inst.windowManager.open({\r
445                                                         url : url + '/cell.htm',\r
446                                                         width : 400 + parseInt(inst.getLang('table.cellprops_delta_width', 0)),\r
447                                                         height : 295 + parseInt(inst.getLang('table.cellprops_delta_height', 0)),\r
448                                                         inline : 1\r
449                                                 }, {\r
450                                                         plugin_url : url\r
451                                                 });\r
452                                         }\r
453 \r
454                                         return true;\r
455 \r
456                                 case "mceInsertTable":\r
457                                         if (user_interface) {\r
458                                                 inst.windowManager.open({\r
459                                                         url : url + '/table.htm',\r
460                                                         width : 400 + parseInt(inst.getLang('table.table_delta_width', 0)),\r
461                                                         height : 320 + parseInt(inst.getLang('table.table_delta_height', 0)),\r
462                                                         inline : 1\r
463                                                 }, {\r
464                                                         plugin_url : url,\r
465                                                         action : value ? value.action : 0\r
466                                                 });\r
467                                         }\r
468 \r
469                                         return true;\r
470 \r
471                                 case "mceTableDelete":\r
472                                         var table = inst.dom.getParent(inst.selection.getNode(), "table");\r
473                                         if (table) {\r
474                                                 table.parentNode.removeChild(table);\r
475                                                 inst.execCommand('mceRepaint');\r
476                                         }\r
477                                         return true;\r
478 \r
479                                 case "mceTableSplitCells":\r
480                                 case "mceTableMergeCells":\r
481                                 case "mceTableInsertRowBefore":\r
482                                 case "mceTableInsertRowAfter":\r
483                                 case "mceTableDeleteRow":\r
484                                 case "mceTableInsertColBefore":\r
485                                 case "mceTableInsertColAfter":\r
486                                 case "mceTableDeleteCol":\r
487                                 case "mceTableCutRow":\r
488                                 case "mceTableCopyRow":\r
489                                 case "mceTablePasteRowBefore":\r
490                                 case "mceTablePasteRowAfter":\r
491                                         // No table just return (invalid command)\r
492                                         if (!tableElm)\r
493                                                 return true;\r
494 \r
495                                         // Table has a tbody use that reference\r
496                                         // Changed logic by ApTest 2005.07.12 (www.aptest.com)\r
497                                         // Now lookk at the focused element and take its parentNode.  That will be a tbody or a table.\r
498                                         if (trElm && tableElm != trElm.parentNode)\r
499                                                 tableElm = trElm.parentNode;\r
500 \r
501                                         if (tableElm && trElm) {\r
502                                                 switch (command) {\r
503                                                         case "mceTableCutRow":\r
504                                                                 if (!trElm || !tdElm)\r
505                                                                         return true;\r
506 \r
507                                                                 inst.tableRowClipboard = copyRow(doc, tableElm, trElm);\r
508                                                                 inst.execCommand("mceTableDeleteRow");\r
509                                                                 break;\r
510 \r
511                                                         case "mceTableCopyRow":\r
512                                                                 if (!trElm || !tdElm)\r
513                                                                         return true;\r
514 \r
515                                                                 inst.tableRowClipboard = copyRow(doc, tableElm, trElm);\r
516                                                                 break;\r
517 \r
518                                                         case "mceTablePasteRowBefore":\r
519                                                                 if (!trElm || !tdElm)\r
520                                                                         return true;\r
521 \r
522                                                                 var newTR = inst.tableRowClipboard.cloneNode(true);\r
523 \r
524                                                                 var prevTR = prevElm(trElm, "TR");\r
525                                                                 if (prevTR != null)\r
526                                                                         trimRow(tableElm, prevTR, prevTR.cells[0], newTR);\r
527 \r
528                                                                 trElm.parentNode.insertBefore(newTR, trElm);\r
529                                                                 break;\r
530 \r
531                                                         case "mceTablePasteRowAfter":\r
532                                                                 if (!trElm || !tdElm)\r
533                                                                         return true;\r
534                                                                 \r
535                                                                 var nextTR = nextElm(trElm, "TR");\r
536                                                                 var newTR = inst.tableRowClipboard.cloneNode(true);\r
537 \r
538                                                                 trimRow(tableElm, trElm, tdElm, newTR);\r
539 \r
540                                                                 if (nextTR == null)\r
541                                                                         trElm.parentNode.appendChild(newTR);\r
542                                                                 else\r
543                                                                         nextTR.parentNode.insertBefore(newTR, nextTR);\r
544 \r
545                                                                 break;\r
546 \r
547                                                         case "mceTableInsertRowBefore":\r
548                                                                 if (!trElm || !tdElm)\r
549                                                                         return true;\r
550 \r
551                                                                 var grid = getTableGrid(tableElm);\r
552                                                                 var cpos = getCellPos(grid, tdElm);\r
553                                                                 var newTR = doc.createElement("tr");\r
554                                                                 var lastTDElm = null;\r
555 \r
556                                                                 cpos.rowindex--;\r
557                                                                 if (cpos.rowindex < 0)\r
558                                                                         cpos.rowindex = 0;\r
559 \r
560                                                                 // Create cells\r
561                                                                 for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {\r
562                                                                         if (tdElm != lastTDElm) {\r
563                                                                                 var sd = getColRowSpan(tdElm);\r
564 \r
565                                                                                 if (sd['rowspan'] == 1) {\r
566                                                                                         var newTD = doc.createElement("td");\r
567 \r
568                                                                                         if (!tinymce.isIE)\r
569                                                                                                 newTD.innerHTML = '<br mce_bogus="1"/>';\r
570 \r
571                                                                                         newTD.colSpan = tdElm.colSpan;\r
572 \r
573                                                                                         newTR.appendChild(newTD);\r
574                                                                                 } else\r
575                                                                                         tdElm.rowSpan = sd['rowspan'] + 1;\r
576 \r
577                                                                                 lastTDElm = tdElm;\r
578                                                                         }\r
579                                                                 }\r
580 \r
581                                                                 trElm.parentNode.insertBefore(newTR, trElm);\r
582                                                                 select(0, 1);\r
583                                                         break;\r
584 \r
585                                                         case "mceTableInsertRowAfter":\r
586                                                                 if (!trElm || !tdElm)\r
587                                                                         return true;\r
588 \r
589                                                                 var grid = getTableGrid(tableElm);\r
590                                                                 var cpos = getCellPos(grid, tdElm);\r
591                                                                 var newTR = doc.createElement("tr");\r
592                                                                 var lastTDElm = null;\r
593 \r
594                                                                 // Create cells\r
595                                                                 for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {\r
596                                                                         if (tdElm != lastTDElm) {\r
597                                                                                 var sd = getColRowSpan(tdElm);\r
598 \r
599                                                                                 if (sd['rowspan'] == 1) {\r
600                                                                                         var newTD = doc.createElement("td");\r
601 \r
602                                                                                         if (!tinymce.isIE)\r
603                                                                                                 newTD.innerHTML = '<br mce_bogus="1"/>';\r
604 \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 \r
623                                                                 select(0, 1);\r
624                                                         break;\r
625 \r
626                                                         case "mceTableDeleteRow":\r
627                                                                 if (!trElm || !tdElm)\r
628                                                                         return true;\r
629 \r
630                                                                 var grid = getTableGrid(tableElm);\r
631                                                                 var cpos = getCellPos(grid, tdElm);\r
632 \r
633                                                                 // Only one row, remove whole table\r
634                                                                 if (grid.length == 1) {\r
635                                                                         inst.dom.remove(inst.dom.getParent(tableElm, "table"));\r
636                                                                         return true;\r
637                                                                 }\r
638 \r
639                                                                 // Move down row spanned cells\r
640                                                                 var cells = trElm.cells;\r
641                                                                 var nextTR = nextElm(trElm, "TR");\r
642                                                                 for (var x=0; x<cells.length; x++) {\r
643                                                                         if (cells[x].rowSpan > 1) {\r
644                                                                                 var newTD = cells[x].cloneNode(true);\r
645                                                                                 var sd = getColRowSpan(cells[x]);\r
646 \r
647                                                                                 newTD.rowSpan = sd.rowspan - 1;\r
648 \r
649                                                                                 var nextTD = nextTR.cells[x];\r
650 \r
651                                                                                 if (nextTD == null)\r
652                                                                                         nextTR.appendChild(newTD);\r
653                                                                                 else\r
654                                                                                         nextTR.insertBefore(newTD, nextTD);\r
655                                                                         }\r
656                                                                 }\r
657 \r
658                                                                 // Delete cells\r
659                                                                 var lastTDElm = null;\r
660                                                                 for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {\r
661                                                                         if (tdElm != lastTDElm) {\r
662                                                                                 var sd = getColRowSpan(tdElm);\r
663 \r
664                                                                                 if (sd.rowspan > 1) {\r
665                                                                                         tdElm.rowSpan = sd.rowspan - 1;\r
666                                                                                 } else {\r
667                                                                                         trElm = tdElm.parentNode;\r
668 \r
669                                                                                         if (trElm.parentNode)\r
670                                                                                                 trElm._delete = true;\r
671                                                                                 }\r
672 \r
673                                                                                 lastTDElm = tdElm;\r
674                                                                         }\r
675                                                                 }\r
676 \r
677                                                                 deleteMarked(tableElm);\r
678 \r
679                                                                 select(0, -1);\r
680                                                         break;\r
681 \r
682                                                         case "mceTableInsertColBefore":\r
683                                                                 if (!trElm || !tdElm)\r
684                                                                         return true;\r
685 \r
686                                                                 var grid = getTableGrid(tableElm);\r
687                                                                 var cpos = getCellPos(grid, tdElm);\r
688                                                                 var lastTDElm = null;\r
689 \r
690                                                                 for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {\r
691                                                                         if (tdElm != lastTDElm) {\r
692                                                                                 var sd = getColRowSpan(tdElm);\r
693 \r
694                                                                                 if (sd['colspan'] == 1) {\r
695                                                                                         var newTD = doc.createElement(tdElm.nodeName);\r
696 \r
697                                                                                         if (!tinymce.isIE)\r
698                                                                                                 newTD.innerHTML = '<br mce_bogus="1"/>';\r
699 \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 \r
710                                                                 select();\r
711                                                         break;\r
712 \r
713                                                         case "mceTableInsertColAfter":\r
714                                                                 if (!trElm || !tdElm)\r
715                                                                         return true;\r
716 \r
717                                                                 var grid = getTableGrid(tableElm);\r
718                                                                 var cpos = getCellPos(grid, tdElm);\r
719                                                                 var lastTDElm = null;\r
720 \r
721                                                                 for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {\r
722                                                                         if (tdElm != lastTDElm) {\r
723                                                                                 var sd = getColRowSpan(tdElm);\r
724 \r
725                                                                                 if (sd['colspan'] == 1) {\r
726                                                                                         var newTD = doc.createElement(tdElm.nodeName);\r
727 \r
728                                                                                         if (!tinymce.isIE)\r
729                                                                                                 newTD.innerHTML = '<br mce_bogus="1"/>';\r
730 \r
731                                                                                         newTD.rowSpan = tdElm.rowSpan;\r
732 \r
733                                                                                         var nextTD = nextElm(tdElm, "TD,TH");\r
734                                                                                         if (nextTD == null)\r
735                                                                                                 tdElm.parentNode.appendChild(newTD);\r
736                                                                                         else\r
737                                                                                                 nextTD.parentNode.insertBefore(newTD, nextTD);\r
738                                                                                 } else\r
739                                                                                         tdElm.colSpan++;\r
740 \r
741                                                                                 lastTDElm = tdElm;\r
742                                                                         }\r
743                                                                 }\r
744 \r
745                                                                 select(1);\r
746                                                         break;\r
747 \r
748                                                         case "mceTableDeleteCol":\r
749                                                                 if (!trElm || !tdElm)\r
750                                                                         return true;\r
751 \r
752                                                                 var grid = getTableGrid(tableElm);\r
753                                                                 var cpos = getCellPos(grid, tdElm);\r
754                                                                 var lastTDElm = null;\r
755 \r
756                                                                 // Only one col, remove whole table\r
757                                                                 if (grid.length > 1 && grid[0].length <= 1) {\r
758                                                                         inst.dom.remove(inst.dom.getParent(tableElm, "table"));\r
759                                                                         return true;\r
760                                                                 }\r
761 \r
762                                                                 // Delete cells\r
763                                                                 for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {\r
764                                                                         if (tdElm != lastTDElm) {\r
765                                                                                 var sd = getColRowSpan(tdElm);\r
766 \r
767                                                                                 if (sd['colspan'] > 1)\r
768                                                                                         tdElm.colSpan = sd['colspan'] - 1;\r
769                                                                                 else {\r
770                                                                                         if (tdElm.parentNode)\r
771                                                                                                 tdElm.parentNode.removeChild(tdElm);\r
772                                                                                 }\r
773 \r
774                                                                                 lastTDElm = tdElm;\r
775                                                                         }\r
776                                                                 }\r
777 \r
778                                                                 select(-1);\r
779                                                         break;\r
780 \r
781                                                 case "mceTableSplitCells":\r
782                                                         if (!trElm || !tdElm)\r
783                                                                 return true;\r
784 \r
785                                                         var spandata = getColRowSpan(tdElm);\r
786 \r
787                                                         var colspan = spandata["colspan"];\r
788                                                         var rowspan = spandata["rowspan"];\r
789 \r
790                                                         // Needs splitting\r
791                                                         if (colspan > 1 || rowspan > 1) {\r
792                                                                 // Generate cols\r
793                                                                 tdElm.colSpan = 1;\r
794                                                                 for (var i=1; i<colspan; i++) {\r
795                                                                         var newTD = doc.createElement("td");\r
796 \r
797                                                                         if (!tinymce.isIE)\r
798                                                                                 newTD.innerHTML = '<br mce_bogus="1"/>';\r
799 \r
800                                                                         trElm.insertBefore(newTD, nextElm(tdElm, "TD,TH"));\r
801 \r
802                                                                         if (rowspan > 1)\r
803                                                                                 addRows(newTD, trElm, rowspan);\r
804                                                                 }\r
805 \r
806                                                                 addRows(tdElm, trElm, rowspan);\r
807                                                         }\r
808 \r
809                                                         // Apply visual aids\r
810                                                         tableElm = inst.dom.getParent(inst.selection.getNode(), "table");\r
811                                                         break;\r
812 \r
813                                                 case "mceTableMergeCells":\r
814                                                         var rows = [];\r
815                                                         var sel = inst.selection.getSel();\r
816                                                         var grid = getTableGrid(tableElm);\r
817 \r
818                                                         if (tinymce.isIE || sel.rangeCount == 1) {\r
819                                                                 if (user_interface) {\r
820                                                                         // Setup template\r
821                                                                         var sp = getColRowSpan(tdElm);\r
822 \r
823                                                                         inst.windowManager.open({\r
824                                                                                 url : url + '/merge_cells.htm',\r
825                                                                                 width : 240 + parseInt(inst.getLang('table.merge_cells_delta_width', 0)),\r
826                                                                                 height : 110 + parseInt(inst.getLang('table.merge_cells_delta_height', 0)),\r
827                                                                                 inline : 1\r
828                                                                         }, {\r
829                                                                                 action : "update",\r
830                                                                                 numcols : sp.colspan,\r
831                                                                                 numrows : sp.rowspan,\r
832                                                                                 plugin_url : url\r
833                                                                         });\r
834 \r
835                                                                         return true;\r
836                                                                 } else {\r
837                                                                         var numRows = parseInt(value['numrows']);\r
838                                                                         var numCols = parseInt(value['numcols']);\r
839                                                                         var cpos = getCellPos(grid, tdElm);\r
840 \r
841                                                                         if (("" + numRows) == "NaN")\r
842                                                                                 numRows = 1;\r
843 \r
844                                                                         if (("" + numCols) == "NaN")\r
845                                                                                 numCols = 1;\r
846 \r
847                                                                         // Get rows and cells\r
848                                                                         var tRows = tableElm.rows;\r
849                                                                         for (var y=cpos.rowindex; y<grid.length; y++) {\r
850                                                                                 var rowCells = [];\r
851 \r
852                                                                                 for (var x=cpos.cellindex; x<grid[y].length; x++) {\r
853                                                                                         var td = getCell(grid, y, x);\r
854 \r
855                                                                                         if (td && !inArray(rows, td) && !inArray(rowCells, td)) {\r
856                                                                                                 var cp = getCellPos(grid, td);\r
857 \r
858                                                                                                 // Within range\r
859                                                                                                 if (cp.cellindex < cpos.cellindex+numCols && cp.rowindex < cpos.rowindex+numRows)\r
860                                                                                                         rowCells[rowCells.length] = td;\r
861                                                                                         }\r
862                                                                                 }\r
863 \r
864                                                                                 if (rowCells.length > 0)\r
865                                                                                         rows[rows.length] = rowCells;\r
866 \r
867                                                                                 var td = getCell(grid, cpos.rowindex, cpos.cellindex);\r
868                                                                                 each(ed.dom.select('br', td), function(e, i) {\r
869                                                                                         if (i > 0 && ed.dom.getAttrib('mce_bogus'))\r
870                                                                                                 ed.dom.remove(e);\r
871                                                                                 });\r
872                                                                         }\r
873 \r
874                                                                         //return true;\r
875                                                                 }\r
876                                                         } else {\r
877                                                                 var cells = [];\r
878                                                                 var sel = inst.selection.getSel();\r
879                                                                 var lastTR = null;\r
880                                                                 var curRow = null;\r
881                                                                 var x1 = -1, y1 = -1, x2, y2;\r
882 \r
883                                                                 // Only one cell selected, whats the point?\r
884                                                                 if (sel.rangeCount < 2)\r
885                                                                         return true;\r
886 \r
887                                                                 // Get all selected cells\r
888                                                                 for (var i=0; i<sel.rangeCount; i++) {\r
889                                                                         var rng = sel.getRangeAt(i);\r
890                                                                         var tdElm = rng.startContainer.childNodes[rng.startOffset];\r
891 \r
892                                                                         if (!tdElm)\r
893                                                                                 break;\r
894 \r
895                                                                         if (tdElm.nodeName == "TD")\r
896                                                                                 cells[cells.length] = tdElm;\r
897                                                                 }\r
898 \r
899                                                                 // Get rows and cells\r
900                                                                 var tRows = tableElm.rows;\r
901                                                                 for (var y=0; y<tRows.length; y++) {\r
902                                                                         var rowCells = [];\r
903 \r
904                                                                         for (var x=0; x<tRows[y].cells.length; x++) {\r
905                                                                                 var td = tRows[y].cells[x];\r
906 \r
907                                                                                 for (var i=0; i<cells.length; i++) {\r
908                                                                                         if (td == cells[i]) {\r
909                                                                                                 rowCells[rowCells.length] = td;\r
910                                                                                         }\r
911                                                                                 }\r
912                                                                         }\r
913 \r
914                                                                         if (rowCells.length > 0)\r
915                                                                                 rows[rows.length] = rowCells;\r
916                                                                 }\r
917 \r
918                                                                 // Find selected cells in grid and box\r
919                                                                 var curRow = [];\r
920                                                                 var lastTR = null;\r
921                                                                 for (var y=0; y<grid.length; y++) {\r
922                                                                         for (var x=0; x<grid[y].length; x++) {\r
923                                                                                 grid[y][x]._selected = false;\r
924 \r
925                                                                                 for (var i=0; i<cells.length; i++) {\r
926                                                                                         if (grid[y][x] == cells[i]) {\r
927                                                                                                 // Get start pos\r
928                                                                                                 if (x1 == -1) {\r
929                                                                                                         x1 = x;\r
930                                                                                                         y1 = y;\r
931                                                                                                 }\r
932 \r
933                                                                                                 // Get end pos\r
934                                                                                                 x2 = x;\r
935                                                                                                 y2 = y;\r
936 \r
937                                                                                                 grid[y][x]._selected = true;\r
938                                                                                         }\r
939                                                                                 }\r
940                                                                         }\r
941                                                                 }\r
942 \r
943                                                                 // Is there gaps, if so deny\r
944                                                                 for (var y=y1; y<=y2; y++) {\r
945                                                                         for (var x=x1; x<=x2; x++) {\r
946                                                                                 if (!grid[y][x]._selected) {\r
947                                                                                         alert("Invalid selection for merge.");\r
948                                                                                         return true;\r
949                                                                                 }\r
950                                                                         }\r
951                                                                 }\r
952                                                         }\r
953 \r
954                                                         // Validate selection and get total rowspan and colspan\r
955                                                         var rowSpan = 1, colSpan = 1;\r
956 \r
957                                                         // Validate horizontal and get total colspan\r
958                                                         var lastRowSpan = -1;\r
959                                                         for (var y=0; y<rows.length; y++) {\r
960                                                                 var rowColSpan = 0;\r
961 \r
962                                                                 for (var x=0; x<rows[y].length; x++) {\r
963                                                                         var sd = getColRowSpan(rows[y][x]);\r
964 \r
965                                                                         rowColSpan += sd['colspan'];\r
966 \r
967                                                                         if (lastRowSpan != -1 && sd['rowspan'] != lastRowSpan) {\r
968                                                                                 alert("Invalid selection for merge.");\r
969                                                                                 return true;\r
970                                                                         }\r
971 \r
972                                                                         lastRowSpan = sd['rowspan'];\r
973                                                                 }\r
974 \r
975                                                                 if (rowColSpan > colSpan)\r
976                                                                         colSpan = rowColSpan;\r
977 \r
978                                                                 lastRowSpan = -1;\r
979                                                         }\r
980 \r
981                                                         // Validate vertical and get total rowspan\r
982                                                         var lastColSpan = -1;\r
983                                                         for (var x=0; x<rows[0].length; x++) {\r
984                                                                 var colRowSpan = 0;\r
985 \r
986                                                                 for (var y=0; y<rows.length; y++) {\r
987                                                                         var sd = getColRowSpan(rows[y][x]);\r
988 \r
989                                                                         colRowSpan += sd['rowspan'];\r
990 \r
991                                                                         if (lastColSpan != -1 && sd['colspan'] != lastColSpan) {\r
992                                                                                 alert("Invalid selection for merge.");\r
993                                                                                 return true;\r
994                                                                         }\r
995 \r
996                                                                         lastColSpan = sd['colspan'];\r
997                                                                 }\r
998 \r
999                                                                 if (colRowSpan > rowSpan)\r
1000                                                                         rowSpan = colRowSpan;\r
1001 \r
1002                                                                 lastColSpan = -1;\r
1003                                                         }\r
1004 \r
1005                                                         // Setup td\r
1006                                                         tdElm = rows[0][0];\r
1007                                                         tdElm.rowSpan = rowSpan;\r
1008                                                         tdElm.colSpan = colSpan;\r
1009 \r
1010                                                         // Merge cells\r
1011                                                         for (var y=0; y<rows.length; y++) {\r
1012                                                                 for (var x=0; x<rows[y].length; x++) {\r
1013                                                                         var html = rows[y][x].innerHTML;\r
1014                                                                         var chk = html.replace(/[ \t\r\n]/g, "");\r
1015 \r
1016                                                                         if (chk != "<br/>" && chk != "<br>" && chk != '<br mce_bogus="1"/>' && (x+y > 0))\r
1017                                                                                 tdElm.innerHTML += html;\r
1018 \r
1019                                                                         // Not current cell\r
1020                                                                         if (rows[y][x] != tdElm && !rows[y][x]._deleted) {\r
1021                                                                                 var cpos = getCellPos(grid, rows[y][x]);\r
1022                                                                                 var tr = rows[y][x].parentNode;\r
1023 \r
1024                                                                                 tr.removeChild(rows[y][x]);\r
1025                                                                                 rows[y][x]._deleted = true;\r
1026 \r
1027                                                                                 // Empty TR, remove it\r
1028                                                                                 if (!tr.hasChildNodes()) {\r
1029                                                                                         tr.parentNode.removeChild(tr);\r
1030 \r
1031                                                                                         var lastCell = null;\r
1032                                                                                         for (var x=0; cellElm = getCell(grid, cpos.rowindex, x); x++) {\r
1033                                                                                                 if (cellElm != lastCell && cellElm.rowSpan > 1)\r
1034                                                                                                         cellElm.rowSpan--;\r
1035 \r
1036                                                                                                 lastCell = cellElm;\r
1037                                                                                         }\r
1038 \r
1039                                                                                         if (tdElm.rowSpan > 1)\r
1040                                                                                                 tdElm.rowSpan--;\r
1041                                                                                 }\r
1042                                                                         }\r
1043                                                                 }\r
1044                                                         }\r
1045 \r
1046                                                         // Remove all but one bogus br\r
1047                                                         each(ed.dom.select('br', tdElm), function(e, i) {\r
1048                                                                 if (i > 0 && ed.dom.getAttrib(e, 'mce_bogus'))\r
1049                                                                         ed.dom.remove(e);\r
1050                                                         });\r
1051 \r
1052                                                         break;\r
1053                                                 }\r
1054 \r
1055                                                 tableElm = inst.dom.getParent(inst.selection.getNode(), "table");\r
1056                                                 inst.addVisual(tableElm);\r
1057                                                 inst.nodeChanged();\r
1058                                         }\r
1059 \r
1060                                 return true;\r
1061                         }\r
1062 \r
1063                         // Pass to next handler in chain\r
1064                         return false;\r
1065                 }\r
1066         });\r
1067 \r
1068         // Register plugin\r
1069         tinymce.PluginManager.add('table', tinymce.plugins.TablePlugin);\r
1070 })();