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