34 }); |
34 }); |
35 |
35 |
36 ed.onInit.add(function() { |
36 ed.onInit.add(function() { |
37 if (ed && ed.plugins.contextmenu) { |
37 if (ed && ed.plugins.contextmenu) { |
38 ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) { |
38 ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) { |
39 var sm; |
39 var sm, se = ed.selection, el = se.getNode() || ed.getBody(); |
40 |
40 |
41 if (ed.dom.getParent(e, 'td') || ed.dom.getParent(e, 'th')) { |
41 if (ed.dom.getParent(e, 'td') || ed.dom.getParent(e, 'th')) { |
42 m.removeAll(); |
42 m.removeAll(); |
|
43 |
|
44 if (el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) { |
|
45 m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true}); |
|
46 m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'}); |
|
47 m.addSeparator(); |
|
48 } |
|
49 |
|
50 if (el.nodeName == 'IMG' && el.className.indexOf('mceItem') == -1) { |
|
51 m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true}); |
|
52 m.addSeparator(); |
|
53 } |
|
54 |
43 m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', ui : true, value : {action : 'insert'}}); |
55 m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', ui : true, value : {action : 'insert'}}); |
44 m.add({title : 'table.props_desc', icon : 'table_props', cmd : 'mceInsertTable', ui : true}); |
56 m.add({title : 'table.props_desc', icon : 'table_props', cmd : 'mceInsertTable', ui : true}); |
45 m.add({title : 'table.del', icon : 'delete_table', cmd : 'mceTableDelete', ui : true}); |
57 m.add({title : 'table.del', icon : 'delete_table', cmd : 'mceTableDelete', ui : true}); |
46 m.addSeparator(); |
58 m.addSeparator(); |
47 |
59 |
72 m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', ui : true}); |
84 m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', ui : true}); |
73 }); |
85 }); |
74 } |
86 } |
75 }); |
87 }); |
76 |
88 |
77 // Block delete on gecko inside TD:s. Gecko is removing table elements and then produces incorrect tables |
|
78 // The backspace key also removed TD:s but this one can not be blocked |
|
79 if (tinymce.isGecko) { |
|
80 ed.onKeyPress.add(function(ed, e) { |
|
81 var n; |
|
82 |
|
83 if (e.keyCode == 46) { |
|
84 n = ed.dom.getParent(ed.selection.getNode(), 'TD,TH'); |
|
85 if (n && (!n.hasChildNodes() || (n.childNodes.length == 1 && n.firstChild.nodeName == 'BR'))) |
|
86 tinymce.dom.Event.cancel(e); |
|
87 } |
|
88 }); |
|
89 } |
|
90 |
|
91 // Add undo level when new rows are created using the tab key |
89 // Add undo level when new rows are created using the tab key |
92 ed.onKeyDown.add(function(ed, e) { |
90 ed.onKeyDown.add(function(ed, e) { |
93 if (e.keyCode == 9 && ed.dom.getParent(ed.selection.getNode(), 'TABLE')) |
91 if (e.keyCode == 9 && ed.dom.getParent(ed.selection.getNode(), 'TABLE')) { |
|
92 if (!tinymce.isGecko && !tinymce.isOpera) { |
|
93 tinyMCE.execInstanceCommand(ed.editorId, "mceTableMoveToNextRow", true); |
|
94 return tinymce.dom.Event.cancel(e); |
|
95 } |
|
96 |
94 ed.undoManager.add(); |
97 ed.undoManager.add(); |
|
98 } |
95 }); |
99 }); |
|
100 |
|
101 // Select whole table is a table border is clicked |
|
102 if (!tinymce.isIE) { |
|
103 if (ed.getParam('table_selection', true)) { |
|
104 ed.onClick.add(function(ed, e) { |
|
105 e = e.target; |
|
106 |
|
107 if (e.nodeName === 'TABLE') |
|
108 ed.selection.select(e); |
|
109 }); |
|
110 } |
|
111 } |
96 |
112 |
97 ed.onNodeChange.add(function(ed, cm, n) { |
113 ed.onNodeChange.add(function(ed, cm, n) { |
98 var p = ed.dom.getParent(n, 'td,th,caption'); |
114 var p = ed.dom.getParent(n, 'td,th,caption'); |
99 |
115 |
100 cm.setActive('table', !!p); |
116 cm.setActive('table', n.nodeName === 'TABLE' || !!p); |
101 if (p && p.nodeName === 'CAPTION') |
117 if (p && p.nodeName === 'CAPTION') |
102 p = null; |
118 p = null; |
103 |
119 |
104 cm.setDisabled('delete_table', !p); |
120 cm.setDisabled('delete_table', !p); |
105 cm.setDisabled('delete_col', !p); |
121 cm.setDisabled('delete_col', !p); |
112 cm.setDisabled('row_props', !p); |
128 cm.setDisabled('row_props', !p); |
113 cm.setDisabled('cell_props', !p); |
129 cm.setDisabled('cell_props', !p); |
114 cm.setDisabled('split_cells', !p || (parseInt(ed.dom.getAttrib(p, 'colspan', '1')) < 2 && parseInt(ed.dom.getAttrib(p, 'rowspan', '1')) < 2)); |
130 cm.setDisabled('split_cells', !p || (parseInt(ed.dom.getAttrib(p, 'colspan', '1')) < 2 && parseInt(ed.dom.getAttrib(p, 'rowspan', '1')) < 2)); |
115 cm.setDisabled('merge_cells', !p); |
131 cm.setDisabled('merge_cells', !p); |
116 }); |
132 }); |
|
133 |
|
134 // Padd empty table cells |
|
135 if (!tinymce.isIE) { |
|
136 ed.onBeforeSetContent.add(function(ed, o) { |
|
137 if (o.initial) |
|
138 o.content = o.content.replace(/<(td|th)([^>]+|)>\s*<\/(td|th)>/g, tinymce.isOpera ? '<$1$2> </$1>' : '<$1$2><br mce_bogus="1" /></$1>'); |
|
139 }); |
|
140 } |
117 }, |
141 }, |
118 |
142 |
119 execCommand : function(cmd, ui, val) { |
143 execCommand : function(cmd, ui, val) { |
120 var ed = this.editor, b; |
144 var ed = this.editor, b; |
121 |
145 |
122 // Is table command |
146 // Is table command |
123 switch (cmd) { |
147 switch (cmd) { |
|
148 case "mceTableMoveToNextRow": |
124 case "mceInsertTable": |
149 case "mceInsertTable": |
125 case "mceTableRowProps": |
150 case "mceTableRowProps": |
126 case "mceTableCellProps": |
151 case "mceTableCellProps": |
127 case "mceTableSplitCells": |
152 case "mceTableSplitCells": |
128 case "mceTableMergeCells": |
153 case "mceTableMergeCells": |
244 return grid[row][col]; |
269 return grid[row][col]; |
245 |
270 |
246 return null; |
271 return null; |
247 } |
272 } |
248 |
273 |
|
274 function getNextCell(table, cell) { |
|
275 var cells = [], x = 0, i, j, cell, nextCell; |
|
276 |
|
277 for (i = 0; i < table.rows.length; i++) |
|
278 for (j = 0; j < table.rows[i].cells.length; j++, x++) |
|
279 cells[x] = table.rows[i].cells[j]; |
|
280 |
|
281 for (i = 0; i < cells.length; i++) |
|
282 if (cells[i] == cell) |
|
283 if (nextCell = cells[i+1]) |
|
284 return nextCell; |
|
285 } |
|
286 |
249 function getTableGrid(table) { |
287 function getTableGrid(table) { |
250 var grid = new Array(), rows = table.rows, x, y, td, sd, xstart, x2, y2; |
288 var grid = [], rows = table.rows, x, y, td, sd, xstart, x2, y2; |
251 |
289 |
252 for (y=0; y<rows.length; y++) { |
290 for (y=0; y<rows.length; y++) { |
253 for (x=0; x<rows[y].cells.length; x++) { |
291 for (x=0; x<rows[y].cells.length; x++) { |
254 td = rows[y].cells[x]; |
292 td = rows[y].cells[x]; |
255 sd = getColRowSpan(td); |
293 sd = getColRowSpan(td); |
411 |
449 |
412 // ---- Commands ----- |
450 // ---- Commands ----- |
413 |
451 |
414 // Handle commands |
452 // Handle commands |
415 switch (command) { |
453 switch (command) { |
|
454 case "mceTableMoveToNextRow": |
|
455 var nextCell = getNextCell(tableElm, tdElm); |
|
456 |
|
457 if (!nextCell) { |
|
458 inst.execCommand("mceTableInsertRowAfter", tdElm); |
|
459 nextCell = getNextCell(tableElm, tdElm); |
|
460 } |
|
461 |
|
462 inst.selection.select(nextCell); |
|
463 inst.selection.collapse(true); |
|
464 |
|
465 return true; |
|
466 |
416 case "mceTableRowProps": |
467 case "mceTableRowProps": |
417 if (trElm == null) |
468 if (trElm == null) |
418 return true; |
469 return true; |
419 |
470 |
420 if (user_interface) { |
471 if (user_interface) { |
839 numCols = 1; |
890 numCols = 1; |
840 |
891 |
841 // Get rows and cells |
892 // Get rows and cells |
842 var tRows = tableElm.rows; |
893 var tRows = tableElm.rows; |
843 for (var y=cpos.rowindex; y<grid.length; y++) { |
894 for (var y=cpos.rowindex; y<grid.length; y++) { |
844 var rowCells = new Array(); |
895 var rowCells = []; |
845 |
896 |
846 for (var x=cpos.cellindex; x<grid[y].length; x++) { |
897 for (var x=cpos.cellindex; x<grid[y].length; x++) { |
847 var td = getCell(grid, y, x); |
898 var td = getCell(grid, y, x); |
848 |
899 |
849 if (td && !inArray(rows, td) && !inArray(rowCells, td)) { |
900 if (td && !inArray(rows, td) && !inArray(rowCells, td)) { |
878 var tdElm = rng.startContainer.childNodes[rng.startOffset]; |
935 var tdElm = rng.startContainer.childNodes[rng.startOffset]; |
879 |
936 |
880 if (!tdElm) |
937 if (!tdElm) |
881 break; |
938 break; |
882 |
939 |
883 if (tdElm.nodeName == "TD") |
940 if (tdElm.nodeName == "TD" || tdElm.nodeName == "TH") |
884 cells[cells.length] = tdElm; |
941 cells[cells.length] = tdElm; |
885 } |
942 } |
886 |
943 |
887 // Get rows and cells |
944 // Get rows and cells |
888 var tRows = tableElm.rows; |
945 var tRows = tableElm.rows; |
889 for (var y=0; y<tRows.length; y++) { |
946 for (var y=0; y<tRows.length; y++) { |
890 var rowCells = new Array(); |
947 var rowCells = []; |
891 |
948 |
892 for (var x=0; x<tRows[y].cells.length; x++) { |
949 for (var x=0; x<tRows[y].cells.length; x++) { |
893 var td = tRows[y].cells[x]; |
950 var td = tRows[y].cells[x]; |
894 |
951 |
895 for (var i=0; i<cells.length; i++) { |
952 for (var i=0; i<cells.length; i++) { |
902 if (rowCells.length > 0) |
959 if (rowCells.length > 0) |
903 rows[rows.length] = rowCells; |
960 rows[rows.length] = rowCells; |
904 } |
961 } |
905 |
962 |
906 // Find selected cells in grid and box |
963 // Find selected cells in grid and box |
907 var curRow = new Array(); |
964 var curRow = []; |
908 var lastTR = null; |
965 var lastTR = null; |
909 for (var y=0; y<grid.length; y++) { |
966 for (var y=0; y<grid.length; y++) { |
910 for (var x=0; x<grid[y].length; x++) { |
967 for (var x=0; x<grid[y].length; x++) { |
911 grid[y][x]._selected = false; |
968 grid[y][x]._selected = false; |
912 |
969 |