1 |
8 |
ahitrov@rambler.ru |
/** |
2 |
|
|
* $Id: editor_plugin_src.js 953 2008-11-04 10:16:50Z spocke $ |
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> </$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 |
|
|
})(); |