Mercurial > public > sg101
comparison media/js/tiny_mce/plugins/table/editor_plugin_src.js @ 45:a5b4c5ce0658
Breaking down and controlling all media files, including javascript libraries.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Fri, 19 Jun 2009 03:16:03 +0000 |
parents | |
children | 149c3567fec1 |
comparison
equal
deleted
inserted
replaced
44:08cd19c1ee50 | 45:a5b4c5ce0658 |
---|---|
1 /** | |
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 })(); |