Mercurial > hg > AnnotationManager
comparison WebContent/jscripts/tiny_mce/plugins/table/editor_plugin_src.js @ 5:0be9d53a6967
editor for annotations
author | dwinter |
---|---|
date | Tue, 13 Dec 2011 17:43:46 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4:c32080f364c6 | 5:0be9d53a6967 |
---|---|
1 /** | |
2 * editor_plugin_src.js | |
3 * | |
4 * Copyright 2009, Moxiecode Systems AB | |
5 * Released under LGPL License. | |
6 * | |
7 * License: http://tinymce.moxiecode.com/license | |
8 * Contributing: http://tinymce.moxiecode.com/contributing | |
9 */ | |
10 | |
11 (function(tinymce) { | |
12 var each = tinymce.each; | |
13 | |
14 // Checks if the selection/caret is at the start of the specified block element | |
15 function isAtStart(rng, par) { | |
16 var doc = par.ownerDocument, rng2 = doc.createRange(), elm; | |
17 | |
18 rng2.setStartBefore(par); | |
19 rng2.setEnd(rng.endContainer, rng.endOffset); | |
20 | |
21 elm = doc.createElement('body'); | |
22 elm.appendChild(rng2.cloneContents()); | |
23 | |
24 // Check for text characters of other elements that should be treated as content | |
25 return elm.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi, '-').replace(/<[^>]+>/g, '').length == 0; | |
26 }; | |
27 | |
28 function getSpanVal(td, name) { | |
29 return parseInt(td.getAttribute(name) || 1); | |
30 } | |
31 | |
32 /** | |
33 * Table Grid class. | |
34 */ | |
35 function TableGrid(table, dom, selection) { | |
36 var grid, startPos, endPos, selectedCell; | |
37 | |
38 buildGrid(); | |
39 selectedCell = dom.getParent(selection.getStart(), 'th,td'); | |
40 if (selectedCell) { | |
41 startPos = getPos(selectedCell); | |
42 endPos = findEndPos(); | |
43 selectedCell = getCell(startPos.x, startPos.y); | |
44 } | |
45 | |
46 function cloneNode(node, children) { | |
47 node = node.cloneNode(children); | |
48 node.removeAttribute('id'); | |
49 | |
50 return node; | |
51 } | |
52 | |
53 function buildGrid() { | |
54 var startY = 0; | |
55 | |
56 grid = []; | |
57 | |
58 each(['thead', 'tbody', 'tfoot'], function(part) { | |
59 var rows = dom.select('> ' + part + ' tr', table); | |
60 | |
61 each(rows, function(tr, y) { | |
62 y += startY; | |
63 | |
64 each(dom.select('> td, > th', tr), function(td, x) { | |
65 var x2, y2, rowspan, colspan; | |
66 | |
67 // Skip over existing cells produced by rowspan | |
68 if (grid[y]) { | |
69 while (grid[y][x]) | |
70 x++; | |
71 } | |
72 | |
73 // Get col/rowspan from cell | |
74 rowspan = getSpanVal(td, 'rowspan'); | |
75 colspan = getSpanVal(td, 'colspan'); | |
76 | |
77 // Fill out rowspan/colspan right and down | |
78 for (y2 = y; y2 < y + rowspan; y2++) { | |
79 if (!grid[y2]) | |
80 grid[y2] = []; | |
81 | |
82 for (x2 = x; x2 < x + colspan; x2++) { | |
83 grid[y2][x2] = { | |
84 part : part, | |
85 real : y2 == y && x2 == x, | |
86 elm : td, | |
87 rowspan : rowspan, | |
88 colspan : colspan | |
89 }; | |
90 } | |
91 } | |
92 }); | |
93 }); | |
94 | |
95 startY += rows.length; | |
96 }); | |
97 }; | |
98 | |
99 function getCell(x, y) { | |
100 var row; | |
101 | |
102 row = grid[y]; | |
103 if (row) | |
104 return row[x]; | |
105 }; | |
106 | |
107 function setSpanVal(td, name, val) { | |
108 if (td) { | |
109 val = parseInt(val); | |
110 | |
111 if (val === 1) | |
112 td.removeAttribute(name, 1); | |
113 else | |
114 td.setAttribute(name, val, 1); | |
115 } | |
116 } | |
117 | |
118 function isCellSelected(cell) { | |
119 return cell && (dom.hasClass(cell.elm, 'mceSelected') || cell == selectedCell); | |
120 }; | |
121 | |
122 function getSelectedRows() { | |
123 var rows = []; | |
124 | |
125 each(table.rows, function(row) { | |
126 each(row.cells, function(cell) { | |
127 if (dom.hasClass(cell, 'mceSelected') || cell == selectedCell.elm) { | |
128 rows.push(row); | |
129 return false; | |
130 } | |
131 }); | |
132 }); | |
133 | |
134 return rows; | |
135 }; | |
136 | |
137 function deleteTable() { | |
138 var rng = dom.createRng(); | |
139 | |
140 rng.setStartAfter(table); | |
141 rng.setEndAfter(table); | |
142 | |
143 selection.setRng(rng); | |
144 | |
145 dom.remove(table); | |
146 }; | |
147 | |
148 function cloneCell(cell) { | |
149 var formatNode; | |
150 | |
151 // Clone formats | |
152 tinymce.walk(cell, function(node) { | |
153 var curNode; | |
154 | |
155 if (node.nodeType == 3) { | |
156 each(dom.getParents(node.parentNode, null, cell).reverse(), function(node) { | |
157 node = cloneNode(node, false); | |
158 | |
159 if (!formatNode) | |
160 formatNode = curNode = node; | |
161 else if (curNode) | |
162 curNode.appendChild(node); | |
163 | |
164 curNode = node; | |
165 }); | |
166 | |
167 // Add something to the inner node | |
168 if (curNode) | |
169 curNode.innerHTML = tinymce.isIE ? ' ' : '<br data-mce-bogus="1" />'; | |
170 | |
171 return false; | |
172 } | |
173 }, 'childNodes'); | |
174 | |
175 cell = cloneNode(cell, false); | |
176 setSpanVal(cell, 'rowSpan', 1); | |
177 setSpanVal(cell, 'colSpan', 1); | |
178 | |
179 if (formatNode) { | |
180 cell.appendChild(formatNode); | |
181 } else { | |
182 if (!tinymce.isIE) | |
183 cell.innerHTML = '<br data-mce-bogus="1" />'; | |
184 } | |
185 | |
186 return cell; | |
187 }; | |
188 | |
189 function cleanup() { | |
190 var rng = dom.createRng(); | |
191 | |
192 // Empty rows | |
193 each(dom.select('tr', table), function(tr) { | |
194 if (tr.cells.length == 0) | |
195 dom.remove(tr); | |
196 }); | |
197 | |
198 // Empty table | |
199 if (dom.select('tr', table).length == 0) { | |
200 rng.setStartAfter(table); | |
201 rng.setEndAfter(table); | |
202 selection.setRng(rng); | |
203 dom.remove(table); | |
204 return; | |
205 } | |
206 | |
207 // Empty header/body/footer | |
208 each(dom.select('thead,tbody,tfoot', table), function(part) { | |
209 if (part.rows.length == 0) | |
210 dom.remove(part); | |
211 }); | |
212 | |
213 // Restore selection to start position if it still exists | |
214 buildGrid(); | |
215 | |
216 // Restore the selection to the closest table position | |
217 row = grid[Math.min(grid.length - 1, startPos.y)]; | |
218 if (row) { | |
219 selection.select(row[Math.min(row.length - 1, startPos.x)].elm, true); | |
220 selection.collapse(true); | |
221 } | |
222 }; | |
223 | |
224 function fillLeftDown(x, y, rows, cols) { | |
225 var tr, x2, r, c, cell; | |
226 | |
227 tr = grid[y][x].elm.parentNode; | |
228 for (r = 1; r <= rows; r++) { | |
229 tr = dom.getNext(tr, 'tr'); | |
230 | |
231 if (tr) { | |
232 // Loop left to find real cell | |
233 for (x2 = x; x2 >= 0; x2--) { | |
234 cell = grid[y + r][x2].elm; | |
235 | |
236 if (cell.parentNode == tr) { | |
237 // Append clones after | |
238 for (c = 1; c <= cols; c++) | |
239 dom.insertAfter(cloneCell(cell), cell); | |
240 | |
241 break; | |
242 } | |
243 } | |
244 | |
245 if (x2 == -1) { | |
246 // Insert nodes before first cell | |
247 for (c = 1; c <= cols; c++) | |
248 tr.insertBefore(cloneCell(tr.cells[0]), tr.cells[0]); | |
249 } | |
250 } | |
251 } | |
252 }; | |
253 | |
254 function split() { | |
255 each(grid, function(row, y) { | |
256 each(row, function(cell, x) { | |
257 var colSpan, rowSpan, newCell, i; | |
258 | |
259 if (isCellSelected(cell)) { | |
260 cell = cell.elm; | |
261 colSpan = getSpanVal(cell, 'colspan'); | |
262 rowSpan = getSpanVal(cell, 'rowspan'); | |
263 | |
264 if (colSpan > 1 || rowSpan > 1) { | |
265 setSpanVal(cell, 'rowSpan', 1); | |
266 setSpanVal(cell, 'colSpan', 1); | |
267 | |
268 // Insert cells right | |
269 for (i = 0; i < colSpan - 1; i++) | |
270 dom.insertAfter(cloneCell(cell), cell); | |
271 | |
272 fillLeftDown(x, y, rowSpan - 1, colSpan); | |
273 } | |
274 } | |
275 }); | |
276 }); | |
277 }; | |
278 | |
279 function merge(cell, cols, rows) { | |
280 var startX, startY, endX, endY, x, y, startCell, endCell, cell, children, count; | |
281 | |
282 // Use specified cell and cols/rows | |
283 if (cell) { | |
284 pos = getPos(cell); | |
285 startX = pos.x; | |
286 startY = pos.y; | |
287 endX = startX + (cols - 1); | |
288 endY = startY + (rows - 1); | |
289 } else { | |
290 // Use selection | |
291 startX = startPos.x; | |
292 startY = startPos.y; | |
293 endX = endPos.x; | |
294 endY = endPos.y; | |
295 } | |
296 | |
297 // Find start/end cells | |
298 startCell = getCell(startX, startY); | |
299 endCell = getCell(endX, endY); | |
300 | |
301 // Check if the cells exists and if they are of the same part for example tbody = tbody | |
302 if (startCell && endCell && startCell.part == endCell.part) { | |
303 // Split and rebuild grid | |
304 split(); | |
305 buildGrid(); | |
306 | |
307 // Set row/col span to start cell | |
308 startCell = getCell(startX, startY).elm; | |
309 setSpanVal(startCell, 'colSpan', (endX - startX) + 1); | |
310 setSpanVal(startCell, 'rowSpan', (endY - startY) + 1); | |
311 | |
312 // Remove other cells and add it's contents to the start cell | |
313 for (y = startY; y <= endY; y++) { | |
314 for (x = startX; x <= endX; x++) { | |
315 if (!grid[y] || !grid[y][x]) | |
316 continue; | |
317 | |
318 cell = grid[y][x].elm; | |
319 | |
320 if (cell != startCell) { | |
321 // Move children to startCell | |
322 children = tinymce.grep(cell.childNodes); | |
323 each(children, function(node) { | |
324 startCell.appendChild(node); | |
325 }); | |
326 | |
327 // Remove bogus nodes if there is children in the target cell | |
328 if (children.length) { | |
329 children = tinymce.grep(startCell.childNodes); | |
330 count = 0; | |
331 each(children, function(node) { | |
332 if (node.nodeName == 'BR' && dom.getAttrib(node, 'data-mce-bogus') && count++ < children.length - 1) | |
333 startCell.removeChild(node); | |
334 }); | |
335 } | |
336 | |
337 // Remove cell | |
338 dom.remove(cell); | |
339 } | |
340 } | |
341 } | |
342 | |
343 // Remove empty rows etc and restore caret location | |
344 cleanup(); | |
345 } | |
346 }; | |
347 | |
348 function insertRow(before) { | |
349 var posY, cell, lastCell, x, rowElm, newRow, newCell, otherCell, rowSpan; | |
350 | |
351 // Find first/last row | |
352 each(grid, function(row, y) { | |
353 each(row, function(cell, x) { | |
354 if (isCellSelected(cell)) { | |
355 cell = cell.elm; | |
356 rowElm = cell.parentNode; | |
357 newRow = cloneNode(rowElm, false); | |
358 posY = y; | |
359 | |
360 if (before) | |
361 return false; | |
362 } | |
363 }); | |
364 | |
365 if (before) | |
366 return !posY; | |
367 }); | |
368 | |
369 for (x = 0; x < grid[0].length; x++) { | |
370 // Cell not found could be because of an invalid table structure | |
371 if (!grid[posY][x]) | |
372 continue; | |
373 | |
374 cell = grid[posY][x].elm; | |
375 | |
376 if (cell != lastCell) { | |
377 if (!before) { | |
378 rowSpan = getSpanVal(cell, 'rowspan'); | |
379 if (rowSpan > 1) { | |
380 setSpanVal(cell, 'rowSpan', rowSpan + 1); | |
381 continue; | |
382 } | |
383 } else { | |
384 // Check if cell above can be expanded | |
385 if (posY > 0 && grid[posY - 1][x]) { | |
386 otherCell = grid[posY - 1][x].elm; | |
387 rowSpan = getSpanVal(otherCell, 'rowSpan'); | |
388 if (rowSpan > 1) { | |
389 setSpanVal(otherCell, 'rowSpan', rowSpan + 1); | |
390 continue; | |
391 } | |
392 } | |
393 } | |
394 | |
395 // Insert new cell into new row | |
396 newCell = cloneCell(cell); | |
397 setSpanVal(newCell, 'colSpan', cell.colSpan); | |
398 | |
399 newRow.appendChild(newCell); | |
400 | |
401 lastCell = cell; | |
402 } | |
403 } | |
404 | |
405 if (newRow.hasChildNodes()) { | |
406 if (!before) | |
407 dom.insertAfter(newRow, rowElm); | |
408 else | |
409 rowElm.parentNode.insertBefore(newRow, rowElm); | |
410 } | |
411 }; | |
412 | |
413 function insertCol(before) { | |
414 var posX, lastCell; | |
415 | |
416 // Find first/last column | |
417 each(grid, function(row, y) { | |
418 each(row, function(cell, x) { | |
419 if (isCellSelected(cell)) { | |
420 posX = x; | |
421 | |
422 if (before) | |
423 return false; | |
424 } | |
425 }); | |
426 | |
427 if (before) | |
428 return !posX; | |
429 }); | |
430 | |
431 each(grid, function(row, y) { | |
432 var cell, rowSpan, colSpan; | |
433 | |
434 if (!row[posX]) | |
435 return; | |
436 | |
437 cell = row[posX].elm; | |
438 if (cell != lastCell) { | |
439 colSpan = getSpanVal(cell, 'colspan'); | |
440 rowSpan = getSpanVal(cell, 'rowspan'); | |
441 | |
442 if (colSpan == 1) { | |
443 if (!before) { | |
444 dom.insertAfter(cloneCell(cell), cell); | |
445 fillLeftDown(posX, y, rowSpan - 1, colSpan); | |
446 } else { | |
447 cell.parentNode.insertBefore(cloneCell(cell), cell); | |
448 fillLeftDown(posX, y, rowSpan - 1, colSpan); | |
449 } | |
450 } else | |
451 setSpanVal(cell, 'colSpan', cell.colSpan + 1); | |
452 | |
453 lastCell = cell; | |
454 } | |
455 }); | |
456 }; | |
457 | |
458 function deleteCols() { | |
459 var cols = []; | |
460 | |
461 // Get selected column indexes | |
462 each(grid, function(row, y) { | |
463 each(row, function(cell, x) { | |
464 if (isCellSelected(cell) && tinymce.inArray(cols, x) === -1) { | |
465 each(grid, function(row) { | |
466 var cell = row[x].elm, colSpan; | |
467 | |
468 colSpan = getSpanVal(cell, 'colSpan'); | |
469 | |
470 if (colSpan > 1) | |
471 setSpanVal(cell, 'colSpan', colSpan - 1); | |
472 else | |
473 dom.remove(cell); | |
474 }); | |
475 | |
476 cols.push(x); | |
477 } | |
478 }); | |
479 }); | |
480 | |
481 cleanup(); | |
482 }; | |
483 | |
484 function deleteRows() { | |
485 var rows; | |
486 | |
487 function deleteRow(tr) { | |
488 var nextTr, pos, lastCell; | |
489 | |
490 nextTr = dom.getNext(tr, 'tr'); | |
491 | |
492 // Move down row spanned cells | |
493 each(tr.cells, function(cell) { | |
494 var rowSpan = getSpanVal(cell, 'rowSpan'); | |
495 | |
496 if (rowSpan > 1) { | |
497 setSpanVal(cell, 'rowSpan', rowSpan - 1); | |
498 pos = getPos(cell); | |
499 fillLeftDown(pos.x, pos.y, 1, 1); | |
500 } | |
501 }); | |
502 | |
503 // Delete cells | |
504 pos = getPos(tr.cells[0]); | |
505 each(grid[pos.y], function(cell) { | |
506 var rowSpan; | |
507 | |
508 cell = cell.elm; | |
509 | |
510 if (cell != lastCell) { | |
511 rowSpan = getSpanVal(cell, 'rowSpan'); | |
512 | |
513 if (rowSpan <= 1) | |
514 dom.remove(cell); | |
515 else | |
516 setSpanVal(cell, 'rowSpan', rowSpan - 1); | |
517 | |
518 lastCell = cell; | |
519 } | |
520 }); | |
521 }; | |
522 | |
523 // Get selected rows and move selection out of scope | |
524 rows = getSelectedRows(); | |
525 | |
526 // Delete all selected rows | |
527 each(rows.reverse(), function(tr) { | |
528 deleteRow(tr); | |
529 }); | |
530 | |
531 cleanup(); | |
532 }; | |
533 | |
534 function cutRows() { | |
535 var rows = getSelectedRows(); | |
536 | |
537 dom.remove(rows); | |
538 cleanup(); | |
539 | |
540 return rows; | |
541 }; | |
542 | |
543 function copyRows() { | |
544 var rows = getSelectedRows(); | |
545 | |
546 each(rows, function(row, i) { | |
547 rows[i] = cloneNode(row, true); | |
548 }); | |
549 | |
550 return rows; | |
551 }; | |
552 | |
553 function pasteRows(rows, before) { | |
554 var selectedRows = getSelectedRows(), | |
555 targetRow = selectedRows[before ? 0 : selectedRows.length - 1], | |
556 targetCellCount = targetRow.cells.length; | |
557 | |
558 // Calc target cell count | |
559 each(grid, function(row) { | |
560 var match; | |
561 | |
562 targetCellCount = 0; | |
563 each(row, function(cell, x) { | |
564 if (cell.real) | |
565 targetCellCount += cell.colspan; | |
566 | |
567 if (cell.elm.parentNode == targetRow) | |
568 match = 1; | |
569 }); | |
570 | |
571 if (match) | |
572 return false; | |
573 }); | |
574 | |
575 if (!before) | |
576 rows.reverse(); | |
577 | |
578 each(rows, function(row) { | |
579 var cellCount = row.cells.length, cell; | |
580 | |
581 // Remove col/rowspans | |
582 for (i = 0; i < cellCount; i++) { | |
583 cell = row.cells[i]; | |
584 setSpanVal(cell, 'colSpan', 1); | |
585 setSpanVal(cell, 'rowSpan', 1); | |
586 } | |
587 | |
588 // Needs more cells | |
589 for (i = cellCount; i < targetCellCount; i++) | |
590 row.appendChild(cloneCell(row.cells[cellCount - 1])); | |
591 | |
592 // Needs less cells | |
593 for (i = targetCellCount; i < cellCount; i++) | |
594 dom.remove(row.cells[i]); | |
595 | |
596 // Add before/after | |
597 if (before) | |
598 targetRow.parentNode.insertBefore(row, targetRow); | |
599 else | |
600 dom.insertAfter(row, targetRow); | |
601 }); | |
602 }; | |
603 | |
604 function getPos(target) { | |
605 var pos; | |
606 | |
607 each(grid, function(row, y) { | |
608 each(row, function(cell, x) { | |
609 if (cell.elm == target) { | |
610 pos = {x : x, y : y}; | |
611 return false; | |
612 } | |
613 }); | |
614 | |
615 return !pos; | |
616 }); | |
617 | |
618 return pos; | |
619 }; | |
620 | |
621 function setStartCell(cell) { | |
622 startPos = getPos(cell); | |
623 }; | |
624 | |
625 function findEndPos() { | |
626 var pos, maxX, maxY; | |
627 | |
628 maxX = maxY = 0; | |
629 | |
630 each(grid, function(row, y) { | |
631 each(row, function(cell, x) { | |
632 var colSpan, rowSpan; | |
633 | |
634 if (isCellSelected(cell)) { | |
635 cell = grid[y][x]; | |
636 | |
637 if (x > maxX) | |
638 maxX = x; | |
639 | |
640 if (y > maxY) | |
641 maxY = y; | |
642 | |
643 if (cell.real) { | |
644 colSpan = cell.colspan - 1; | |
645 rowSpan = cell.rowspan - 1; | |
646 | |
647 if (colSpan) { | |
648 if (x + colSpan > maxX) | |
649 maxX = x + colSpan; | |
650 } | |
651 | |
652 if (rowSpan) { | |
653 if (y + rowSpan > maxY) | |
654 maxY = y + rowSpan; | |
655 } | |
656 } | |
657 } | |
658 }); | |
659 }); | |
660 | |
661 return {x : maxX, y : maxY}; | |
662 }; | |
663 | |
664 function setEndCell(cell) { | |
665 var startX, startY, endX, endY, maxX, maxY, colSpan, rowSpan; | |
666 | |
667 endPos = getPos(cell); | |
668 | |
669 if (startPos && endPos) { | |
670 // Get start/end positions | |
671 startX = Math.min(startPos.x, endPos.x); | |
672 startY = Math.min(startPos.y, endPos.y); | |
673 endX = Math.max(startPos.x, endPos.x); | |
674 endY = Math.max(startPos.y, endPos.y); | |
675 | |
676 // Expand end positon to include spans | |
677 maxX = endX; | |
678 maxY = endY; | |
679 | |
680 // Expand startX | |
681 for (y = startY; y <= maxY; y++) { | |
682 cell = grid[y][startX]; | |
683 | |
684 if (!cell.real) { | |
685 if (startX - (cell.colspan - 1) < startX) | |
686 startX -= cell.colspan - 1; | |
687 } | |
688 } | |
689 | |
690 // Expand startY | |
691 for (x = startX; x <= maxX; x++) { | |
692 cell = grid[startY][x]; | |
693 | |
694 if (!cell.real) { | |
695 if (startY - (cell.rowspan - 1) < startY) | |
696 startY -= cell.rowspan - 1; | |
697 } | |
698 } | |
699 | |
700 // Find max X, Y | |
701 for (y = startY; y <= endY; y++) { | |
702 for (x = startX; x <= endX; x++) { | |
703 cell = grid[y][x]; | |
704 | |
705 if (cell.real) { | |
706 colSpan = cell.colspan - 1; | |
707 rowSpan = cell.rowspan - 1; | |
708 | |
709 if (colSpan) { | |
710 if (x + colSpan > maxX) | |
711 maxX = x + colSpan; | |
712 } | |
713 | |
714 if (rowSpan) { | |
715 if (y + rowSpan > maxY) | |
716 maxY = y + rowSpan; | |
717 } | |
718 } | |
719 } | |
720 } | |
721 | |
722 // Remove current selection | |
723 dom.removeClass(dom.select('td.mceSelected,th.mceSelected'), 'mceSelected'); | |
724 | |
725 // Add new selection | |
726 for (y = startY; y <= maxY; y++) { | |
727 for (x = startX; x <= maxX; x++) { | |
728 if (grid[y][x]) | |
729 dom.addClass(grid[y][x].elm, 'mceSelected'); | |
730 } | |
731 } | |
732 } | |
733 }; | |
734 | |
735 // Expose to public | |
736 tinymce.extend(this, { | |
737 deleteTable : deleteTable, | |
738 split : split, | |
739 merge : merge, | |
740 insertRow : insertRow, | |
741 insertCol : insertCol, | |
742 deleteCols : deleteCols, | |
743 deleteRows : deleteRows, | |
744 cutRows : cutRows, | |
745 copyRows : copyRows, | |
746 pasteRows : pasteRows, | |
747 getPos : getPos, | |
748 setStartCell : setStartCell, | |
749 setEndCell : setEndCell | |
750 }); | |
751 }; | |
752 | |
753 tinymce.create('tinymce.plugins.TablePlugin', { | |
754 init : function(ed, url) { | |
755 var winMan, clipboardRows, hasCellSelection = true; // Might be selected cells on reload | |
756 | |
757 function createTableGrid(node) { | |
758 var selection = ed.selection, tblElm = ed.dom.getParent(node || selection.getNode(), 'table'); | |
759 | |
760 if (tblElm) | |
761 return new TableGrid(tblElm, ed.dom, selection); | |
762 }; | |
763 | |
764 function cleanup() { | |
765 // Restore selection possibilities | |
766 ed.getBody().style.webkitUserSelect = ''; | |
767 | |
768 if (hasCellSelection) { | |
769 ed.dom.removeClass(ed.dom.select('td.mceSelected,th.mceSelected'), 'mceSelected'); | |
770 hasCellSelection = false; | |
771 } | |
772 }; | |
773 | |
774 // Register buttons | |
775 each([ | |
776 ['table', 'table.desc', 'mceInsertTable', true], | |
777 ['delete_table', 'table.del', 'mceTableDelete'], | |
778 ['delete_col', 'table.delete_col_desc', 'mceTableDeleteCol'], | |
779 ['delete_row', 'table.delete_row_desc', 'mceTableDeleteRow'], | |
780 ['col_after', 'table.col_after_desc', 'mceTableInsertColAfter'], | |
781 ['col_before', 'table.col_before_desc', 'mceTableInsertColBefore'], | |
782 ['row_after', 'table.row_after_desc', 'mceTableInsertRowAfter'], | |
783 ['row_before', 'table.row_before_desc', 'mceTableInsertRowBefore'], | |
784 ['row_props', 'table.row_desc', 'mceTableRowProps', true], | |
785 ['cell_props', 'table.cell_desc', 'mceTableCellProps', true], | |
786 ['split_cells', 'table.split_cells_desc', 'mceTableSplitCells', true], | |
787 ['merge_cells', 'table.merge_cells_desc', 'mceTableMergeCells', true] | |
788 ], function(c) { | |
789 ed.addButton(c[0], {title : c[1], cmd : c[2], ui : c[3]}); | |
790 }); | |
791 | |
792 // Select whole table is a table border is clicked | |
793 if (!tinymce.isIE) { | |
794 ed.onClick.add(function(ed, e) { | |
795 e = e.target; | |
796 | |
797 if (e.nodeName === 'TABLE') { | |
798 ed.selection.select(e); | |
799 ed.nodeChanged(); | |
800 } | |
801 }); | |
802 } | |
803 | |
804 ed.onPreProcess.add(function(ed, args) { | |
805 var nodes, i, node, dom = ed.dom, value; | |
806 | |
807 nodes = dom.select('table', args.node); | |
808 i = nodes.length; | |
809 while (i--) { | |
810 node = nodes[i]; | |
811 dom.setAttrib(node, 'data-mce-style', ''); | |
812 | |
813 if ((value = dom.getAttrib(node, 'width'))) { | |
814 dom.setStyle(node, 'width', value); | |
815 dom.setAttrib(node, 'width', ''); | |
816 } | |
817 | |
818 if ((value = dom.getAttrib(node, 'height'))) { | |
819 dom.setStyle(node, 'height', value); | |
820 dom.setAttrib(node, 'height', ''); | |
821 } | |
822 } | |
823 }); | |
824 | |
825 // Handle node change updates | |
826 ed.onNodeChange.add(function(ed, cm, n) { | |
827 var p; | |
828 | |
829 n = ed.selection.getStart(); | |
830 p = ed.dom.getParent(n, 'td,th,caption'); | |
831 cm.setActive('table', n.nodeName === 'TABLE' || !!p); | |
832 | |
833 // Disable table tools if we are in caption | |
834 if (p && p.nodeName === 'CAPTION') | |
835 p = 0; | |
836 | |
837 cm.setDisabled('delete_table', !p); | |
838 cm.setDisabled('delete_col', !p); | |
839 cm.setDisabled('delete_table', !p); | |
840 cm.setDisabled('delete_row', !p); | |
841 cm.setDisabled('col_after', !p); | |
842 cm.setDisabled('col_before', !p); | |
843 cm.setDisabled('row_after', !p); | |
844 cm.setDisabled('row_before', !p); | |
845 cm.setDisabled('row_props', !p); | |
846 cm.setDisabled('cell_props', !p); | |
847 cm.setDisabled('split_cells', !p); | |
848 cm.setDisabled('merge_cells', !p); | |
849 }); | |
850 | |
851 ed.onInit.add(function(ed) { | |
852 var startTable, startCell, dom = ed.dom, tableGrid; | |
853 | |
854 winMan = ed.windowManager; | |
855 | |
856 // Add cell selection logic | |
857 ed.onMouseDown.add(function(ed, e) { | |
858 if (e.button != 2) { | |
859 cleanup(); | |
860 | |
861 startCell = dom.getParent(e.target, 'td,th'); | |
862 startTable = dom.getParent(startCell, 'table'); | |
863 } | |
864 }); | |
865 | |
866 dom.bind(ed.getDoc(), 'mouseover', function(e) { | |
867 var sel, table, target = e.target; | |
868 | |
869 if (startCell && (tableGrid || target != startCell) && (target.nodeName == 'TD' || target.nodeName == 'TH')) { | |
870 table = dom.getParent(target, 'table'); | |
871 if (table == startTable) { | |
872 if (!tableGrid) { | |
873 tableGrid = createTableGrid(table); | |
874 tableGrid.setStartCell(startCell); | |
875 | |
876 ed.getBody().style.webkitUserSelect = 'none'; | |
877 } | |
878 | |
879 tableGrid.setEndCell(target); | |
880 hasCellSelection = true; | |
881 } | |
882 | |
883 // Remove current selection | |
884 sel = ed.selection.getSel(); | |
885 | |
886 try { | |
887 if (sel.removeAllRanges) | |
888 sel.removeAllRanges(); | |
889 else | |
890 sel.empty(); | |
891 } catch (ex) { | |
892 // IE9 might throw errors here | |
893 } | |
894 | |
895 e.preventDefault(); | |
896 } | |
897 }); | |
898 | |
899 ed.onMouseUp.add(function(ed, e) { | |
900 var rng, sel = ed.selection, selectedCells, nativeSel = sel.getSel(), walker, node, lastNode, endNode; | |
901 | |
902 // Move selection to startCell | |
903 if (startCell) { | |
904 if (tableGrid) | |
905 ed.getBody().style.webkitUserSelect = ''; | |
906 | |
907 function setPoint(node, start) { | |
908 var walker = new tinymce.dom.TreeWalker(node, node); | |
909 | |
910 do { | |
911 // Text node | |
912 if (node.nodeType == 3 && tinymce.trim(node.nodeValue).length != 0) { | |
913 if (start) | |
914 rng.setStart(node, 0); | |
915 else | |
916 rng.setEnd(node, node.nodeValue.length); | |
917 | |
918 return; | |
919 } | |
920 | |
921 // BR element | |
922 if (node.nodeName == 'BR') { | |
923 if (start) | |
924 rng.setStartBefore(node); | |
925 else | |
926 rng.setEndBefore(node); | |
927 | |
928 return; | |
929 } | |
930 } while (node = (start ? walker.next() : walker.prev())); | |
931 } | |
932 | |
933 // Try to expand text selection as much as we can only Gecko supports cell selection | |
934 selectedCells = dom.select('td.mceSelected,th.mceSelected'); | |
935 if (selectedCells.length > 0) { | |
936 rng = dom.createRng(); | |
937 node = selectedCells[0]; | |
938 endNode = selectedCells[selectedCells.length - 1]; | |
939 rng.setStartBefore(node); | |
940 rng.setEndAfter(node); | |
941 | |
942 setPoint(node, 1); | |
943 walker = new tinymce.dom.TreeWalker(node, dom.getParent(selectedCells[0], 'table')); | |
944 | |
945 do { | |
946 if (node.nodeName == 'TD' || node.nodeName == 'TH') { | |
947 if (!dom.hasClass(node, 'mceSelected')) | |
948 break; | |
949 | |
950 lastNode = node; | |
951 } | |
952 } while (node = walker.next()); | |
953 | |
954 setPoint(lastNode); | |
955 | |
956 sel.setRng(rng); | |
957 } | |
958 | |
959 ed.nodeChanged(); | |
960 startCell = tableGrid = startTable = null; | |
961 } | |
962 }); | |
963 | |
964 ed.onKeyUp.add(function(ed, e) { | |
965 cleanup(); | |
966 }); | |
967 | |
968 ed.onKeyDown.add(function (ed, e) { | |
969 fixTableCellSelection(ed); | |
970 }); | |
971 | |
972 ed.onMouseDown.add(function (ed, e) { | |
973 if (e.button != 2) { | |
974 fixTableCellSelection(ed); | |
975 } | |
976 }); | |
977 function tableCellSelected(ed, rng, n, currentCell) { | |
978 // The decision of when a table cell is selected is somewhat involved. The fact that this code is | |
979 // required is actually a pointer to the root cause of this bug. A cell is selected when the start | |
980 // and end offsets are 0, the start container is a text, and the selection node is either a TR (most cases) | |
981 // or the parent of the table (in the case of the selection containing the last cell of a table). | |
982 var TEXT_NODE = 3, table = ed.dom.getParent(rng.startContainer, 'TABLE'), | |
983 tableParent, allOfCellSelected, tableCellSelection; | |
984 if (table) | |
985 tableParent = table.parentNode; | |
986 allOfCellSelected =rng.startContainer.nodeType == TEXT_NODE && | |
987 rng.startOffset == 0 && | |
988 rng.endOffset == 0 && | |
989 currentCell && | |
990 (n.nodeName=="TR" || n==tableParent); | |
991 tableCellSelection = (n.nodeName=="TD"||n.nodeName=="TH")&& !currentCell; | |
992 return allOfCellSelected || tableCellSelection; | |
993 // return false; | |
994 } | |
995 | |
996 // this nasty hack is here to work around some WebKit selection bugs. | |
997 function fixTableCellSelection(ed) { | |
998 if (!tinymce.isWebKit) | |
999 return; | |
1000 | |
1001 var rng = ed.selection.getRng(); | |
1002 var n = ed.selection.getNode(); | |
1003 var currentCell = ed.dom.getParent(rng.startContainer, 'TD,TH'); | |
1004 | |
1005 if (!tableCellSelected(ed, rng, n, currentCell)) | |
1006 return; | |
1007 if (!currentCell) { | |
1008 currentCell=n; | |
1009 } | |
1010 | |
1011 // Get the very last node inside the table cell | |
1012 var end = currentCell.lastChild; | |
1013 while (end.lastChild) | |
1014 end = end.lastChild; | |
1015 | |
1016 // Select the entire table cell. Nothing outside of the table cell should be selected. | |
1017 rng.setEnd(end, end.nodeValue.length); | |
1018 ed.selection.setRng(rng); | |
1019 } | |
1020 ed.plugins.table.fixTableCellSelection=fixTableCellSelection; | |
1021 | |
1022 // Add context menu | |
1023 if (ed && ed.plugins.contextmenu) { | |
1024 ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) { | |
1025 var sm, se = ed.selection, el = se.getNode() || ed.getBody(); | |
1026 | |
1027 if (ed.dom.getParent(e, 'td') || ed.dom.getParent(e, 'th') || ed.dom.select('td.mceSelected,th.mceSelected').length) { | |
1028 m.removeAll(); | |
1029 | |
1030 if (el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) { | |
1031 m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true}); | |
1032 m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'}); | |
1033 m.addSeparator(); | |
1034 } | |
1035 | |
1036 if (el.nodeName == 'IMG' && el.className.indexOf('mceItem') == -1) { | |
1037 m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true}); | |
1038 m.addSeparator(); | |
1039 } | |
1040 | |
1041 m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', value : {action : 'insert'}}); | |
1042 m.add({title : 'table.props_desc', icon : 'table_props', cmd : 'mceInsertTable'}); | |
1043 m.add({title : 'table.del', icon : 'delete_table', cmd : 'mceTableDelete'}); | |
1044 m.addSeparator(); | |
1045 | |
1046 // Cell menu | |
1047 sm = m.addMenu({title : 'table.cell'}); | |
1048 sm.add({title : 'table.cell_desc', icon : 'cell_props', cmd : 'mceTableCellProps'}); | |
1049 sm.add({title : 'table.split_cells_desc', icon : 'split_cells', cmd : 'mceTableSplitCells'}); | |
1050 sm.add({title : 'table.merge_cells_desc', icon : 'merge_cells', cmd : 'mceTableMergeCells'}); | |
1051 | |
1052 // Row menu | |
1053 sm = m.addMenu({title : 'table.row'}); | |
1054 sm.add({title : 'table.row_desc', icon : 'row_props', cmd : 'mceTableRowProps'}); | |
1055 sm.add({title : 'table.row_before_desc', icon : 'row_before', cmd : 'mceTableInsertRowBefore'}); | |
1056 sm.add({title : 'table.row_after_desc', icon : 'row_after', cmd : 'mceTableInsertRowAfter'}); | |
1057 sm.add({title : 'table.delete_row_desc', icon : 'delete_row', cmd : 'mceTableDeleteRow'}); | |
1058 sm.addSeparator(); | |
1059 sm.add({title : 'table.cut_row_desc', icon : 'cut', cmd : 'mceTableCutRow'}); | |
1060 sm.add({title : 'table.copy_row_desc', icon : 'copy', cmd : 'mceTableCopyRow'}); | |
1061 sm.add({title : 'table.paste_row_before_desc', icon : 'paste', cmd : 'mceTablePasteRowBefore'}).setDisabled(!clipboardRows); | |
1062 sm.add({title : 'table.paste_row_after_desc', icon : 'paste', cmd : 'mceTablePasteRowAfter'}).setDisabled(!clipboardRows); | |
1063 | |
1064 // Column menu | |
1065 sm = m.addMenu({title : 'table.col'}); | |
1066 sm.add({title : 'table.col_before_desc', icon : 'col_before', cmd : 'mceTableInsertColBefore'}); | |
1067 sm.add({title : 'table.col_after_desc', icon : 'col_after', cmd : 'mceTableInsertColAfter'}); | |
1068 sm.add({title : 'table.delete_col_desc', icon : 'delete_col', cmd : 'mceTableDeleteCol'}); | |
1069 } else | |
1070 m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable'}); | |
1071 }); | |
1072 } | |
1073 | |
1074 // Fix to allow navigating up and down in a table in WebKit browsers. | |
1075 if (tinymce.isWebKit) { | |
1076 function moveSelection(ed, e) { | |
1077 var VK = tinymce.VK; | |
1078 var key = e.keyCode; | |
1079 | |
1080 function handle(upBool, sourceNode, event) { | |
1081 var siblingDirection = upBool ? 'previousSibling' : 'nextSibling'; | |
1082 var currentRow = ed.dom.getParent(sourceNode, 'tr'); | |
1083 var siblingRow = currentRow[siblingDirection]; | |
1084 | |
1085 if (siblingRow) { | |
1086 moveCursorToRow(ed, sourceNode, siblingRow, upBool); | |
1087 tinymce.dom.Event.cancel(event); | |
1088 return true; | |
1089 } else { | |
1090 var tableNode = ed.dom.getParent(currentRow, 'table'); | |
1091 var middleNode = currentRow.parentNode; | |
1092 var parentNodeName = middleNode.nodeName.toLowerCase(); | |
1093 if (parentNodeName === 'tbody' || parentNodeName === (upBool ? 'tfoot' : 'thead')) { | |
1094 var targetParent = getTargetParent(upBool, tableNode, middleNode, 'tbody'); | |
1095 if (targetParent !== null) { | |
1096 return moveToRowInTarget(upBool, targetParent, sourceNode, event); | |
1097 } | |
1098 } | |
1099 return escapeTable(upBool, currentRow, siblingDirection, tableNode, event); | |
1100 } | |
1101 } | |
1102 | |
1103 function getTargetParent(upBool, topNode, secondNode, nodeName) { | |
1104 var tbodies = ed.dom.select('>' + nodeName, topNode); | |
1105 var position = tbodies.indexOf(secondNode); | |
1106 if (upBool && position === 0 || !upBool && position === tbodies.length - 1) { | |
1107 return getFirstHeadOrFoot(upBool, topNode); | |
1108 } else if (position === -1) { | |
1109 var topOrBottom = secondNode.tagName.toLowerCase() === 'thead' ? 0 : tbodies.length - 1; | |
1110 return tbodies[topOrBottom]; | |
1111 } else { | |
1112 return tbodies[position + (upBool ? -1 : 1)]; | |
1113 } | |
1114 } | |
1115 | |
1116 function getFirstHeadOrFoot(upBool, parent) { | |
1117 var tagName = upBool ? 'thead' : 'tfoot'; | |
1118 var headOrFoot = ed.dom.select('>' + tagName, parent); | |
1119 return headOrFoot.length !== 0 ? headOrFoot[0] : null; | |
1120 } | |
1121 | |
1122 function moveToRowInTarget(upBool, targetParent, sourceNode, event) { | |
1123 var targetRow = getChildForDirection(targetParent, upBool); | |
1124 targetRow && moveCursorToRow(ed, sourceNode, targetRow, upBool); | |
1125 tinymce.dom.Event.cancel(event); | |
1126 return true; | |
1127 } | |
1128 | |
1129 function escapeTable(upBool, currentRow, siblingDirection, table, event) { | |
1130 var tableSibling = table[siblingDirection]; | |
1131 if (tableSibling) { | |
1132 moveCursorToStartOfElement(tableSibling); | |
1133 return true; | |
1134 } else { | |
1135 var parentCell = ed.dom.getParent(table, 'td,th'); | |
1136 if (parentCell) { | |
1137 return handle(upBool, parentCell, event); | |
1138 } else { | |
1139 var backUpSibling = getChildForDirection(currentRow, !upBool); | |
1140 moveCursorToStartOfElement(backUpSibling); | |
1141 return tinymce.dom.Event.cancel(event); | |
1142 } | |
1143 } | |
1144 } | |
1145 | |
1146 function getChildForDirection(parent, up) { | |
1147 return parent && parent[up ? 'lastChild' : 'firstChild']; | |
1148 } | |
1149 | |
1150 function moveCursorToStartOfElement(n) { | |
1151 ed.selection.setCursorLocation(n, 0); | |
1152 } | |
1153 | |
1154 function isVerticalMovement() { | |
1155 return key == VK.UP || key == VK.DOWN; | |
1156 } | |
1157 | |
1158 function isInTable(ed) { | |
1159 var node = ed.selection.getNode(); | |
1160 var currentRow = ed.dom.getParent(node, 'tr'); | |
1161 return currentRow !== null; | |
1162 } | |
1163 | |
1164 function columnIndex(column) { | |
1165 var colIndex = 0; | |
1166 var c = column; | |
1167 while (c.previousSibling) { | |
1168 c = c.previousSibling; | |
1169 colIndex = colIndex + getSpanVal(c, "colspan"); | |
1170 } | |
1171 return colIndex; | |
1172 } | |
1173 | |
1174 function findColumn(rowElement, columnIndex) { | |
1175 var c = 0; | |
1176 var r = 0; | |
1177 each(rowElement.children, function(cell, i) { | |
1178 c = c + getSpanVal(cell, "colspan"); | |
1179 r = i; | |
1180 if (c > columnIndex) | |
1181 return false; | |
1182 }); | |
1183 return r; | |
1184 } | |
1185 | |
1186 function moveCursorToRow(ed, node, row, upBool) { | |
1187 var srcColumnIndex = columnIndex(ed.dom.getParent(node, 'td,th')); | |
1188 var tgtColumnIndex = findColumn(row, srcColumnIndex); | |
1189 var tgtNode = row.childNodes[tgtColumnIndex]; | |
1190 var rowCellTarget = getChildForDirection(tgtNode, upBool); | |
1191 moveCursorToStartOfElement(rowCellTarget || tgtNode); | |
1192 } | |
1193 | |
1194 function shouldFixCaret(preBrowserNode) { | |
1195 var newNode = ed.selection.getNode(); | |
1196 var newParent = ed.dom.getParent(newNode, 'td,th'); | |
1197 var oldParent = ed.dom.getParent(preBrowserNode, 'td,th'); | |
1198 return newParent && newParent !== oldParent && checkSameParentTable(newParent, oldParent) | |
1199 } | |
1200 | |
1201 function checkSameParentTable(nodeOne, NodeTwo) { | |
1202 return ed.dom.getParent(nodeOne, 'TABLE') === ed.dom.getParent(NodeTwo, 'TABLE'); | |
1203 } | |
1204 | |
1205 if (isVerticalMovement() && isInTable(ed)) { | |
1206 var preBrowserNode = ed.selection.getNode(); | |
1207 setTimeout(function() { | |
1208 if (shouldFixCaret(preBrowserNode)) { | |
1209 handle(!e.shiftKey && key === VK.UP, preBrowserNode, e); | |
1210 } | |
1211 }, 0); | |
1212 } | |
1213 } | |
1214 | |
1215 ed.onKeyDown.add(moveSelection); | |
1216 } | |
1217 | |
1218 // Fixes an issue on Gecko where it's impossible to place the caret behind a table | |
1219 // This fix will force a paragraph element after the table but only when the forced_root_block setting is enabled | |
1220 if (!tinymce.isIE) { | |
1221 function fixTableCaretPos() { | |
1222 var last; | |
1223 | |
1224 // Skip empty text nodes form the end | |
1225 for (last = ed.getBody().lastChild; last && last.nodeType == 3 && !last.nodeValue.length; last = last.previousSibling) ; | |
1226 | |
1227 if (last && last.nodeName == 'TABLE') | |
1228 ed.dom.add(ed.getBody(), 'p', null, '<br mce_bogus="1" />'); | |
1229 }; | |
1230 | |
1231 // Fixes an bug where it's impossible to place the caret before a table in Gecko | |
1232 // this fix solves it by detecting when the caret is at the beginning of such a table | |
1233 // and then manually moves the caret infront of the table | |
1234 if (tinymce.isGecko) { | |
1235 ed.onKeyDown.add(function(ed, e) { | |
1236 var rng, table, dom = ed.dom; | |
1237 | |
1238 // On gecko it's not possible to place the caret before a table | |
1239 if (e.keyCode == 37 || e.keyCode == 38) { | |
1240 rng = ed.selection.getRng(); | |
1241 table = dom.getParent(rng.startContainer, 'table'); | |
1242 | |
1243 if (table && ed.getBody().firstChild == table) { | |
1244 if (isAtStart(rng, table)) { | |
1245 rng = dom.createRng(); | |
1246 | |
1247 rng.setStartBefore(table); | |
1248 rng.setEndBefore(table); | |
1249 | |
1250 ed.selection.setRng(rng); | |
1251 | |
1252 e.preventDefault(); | |
1253 } | |
1254 } | |
1255 } | |
1256 }); | |
1257 } | |
1258 | |
1259 ed.onKeyUp.add(fixTableCaretPos); | |
1260 ed.onSetContent.add(fixTableCaretPos); | |
1261 ed.onVisualAid.add(fixTableCaretPos); | |
1262 | |
1263 ed.onPreProcess.add(function(ed, o) { | |
1264 var last = o.node.lastChild; | |
1265 | |
1266 if (last && last.childNodes.length == 1 && last.firstChild.nodeName == 'BR') | |
1267 ed.dom.remove(last); | |
1268 }); | |
1269 | |
1270 fixTableCaretPos(); | |
1271 ed.startContent = ed.getContent({format : 'raw'}); | |
1272 } | |
1273 }); | |
1274 | |
1275 // Register action commands | |
1276 each({ | |
1277 mceTableSplitCells : function(grid) { | |
1278 grid.split(); | |
1279 }, | |
1280 | |
1281 mceTableMergeCells : function(grid) { | |
1282 var rowSpan, colSpan, cell; | |
1283 | |
1284 cell = ed.dom.getParent(ed.selection.getNode(), 'th,td'); | |
1285 if (cell) { | |
1286 rowSpan = cell.rowSpan; | |
1287 colSpan = cell.colSpan; | |
1288 } | |
1289 | |
1290 if (!ed.dom.select('td.mceSelected,th.mceSelected').length) { | |
1291 winMan.open({ | |
1292 url : url + '/merge_cells.htm', | |
1293 width : 240 + parseInt(ed.getLang('table.merge_cells_delta_width', 0)), | |
1294 height : 110 + parseInt(ed.getLang('table.merge_cells_delta_height', 0)), | |
1295 inline : 1 | |
1296 }, { | |
1297 rows : rowSpan, | |
1298 cols : colSpan, | |
1299 onaction : function(data) { | |
1300 grid.merge(cell, data.cols, data.rows); | |
1301 }, | |
1302 plugin_url : url | |
1303 }); | |
1304 } else | |
1305 grid.merge(); | |
1306 }, | |
1307 | |
1308 mceTableInsertRowBefore : function(grid) { | |
1309 grid.insertRow(true); | |
1310 }, | |
1311 | |
1312 mceTableInsertRowAfter : function(grid) { | |
1313 grid.insertRow(); | |
1314 }, | |
1315 | |
1316 mceTableInsertColBefore : function(grid) { | |
1317 grid.insertCol(true); | |
1318 }, | |
1319 | |
1320 mceTableInsertColAfter : function(grid) { | |
1321 grid.insertCol(); | |
1322 }, | |
1323 | |
1324 mceTableDeleteCol : function(grid) { | |
1325 grid.deleteCols(); | |
1326 }, | |
1327 | |
1328 mceTableDeleteRow : function(grid) { | |
1329 grid.deleteRows(); | |
1330 }, | |
1331 | |
1332 mceTableCutRow : function(grid) { | |
1333 clipboardRows = grid.cutRows(); | |
1334 }, | |
1335 | |
1336 mceTableCopyRow : function(grid) { | |
1337 clipboardRows = grid.copyRows(); | |
1338 }, | |
1339 | |
1340 mceTablePasteRowBefore : function(grid) { | |
1341 grid.pasteRows(clipboardRows, true); | |
1342 }, | |
1343 | |
1344 mceTablePasteRowAfter : function(grid) { | |
1345 grid.pasteRows(clipboardRows); | |
1346 }, | |
1347 | |
1348 mceTableDelete : function(grid) { | |
1349 grid.deleteTable(); | |
1350 } | |
1351 }, function(func, name) { | |
1352 ed.addCommand(name, function() { | |
1353 var grid = createTableGrid(); | |
1354 | |
1355 if (grid) { | |
1356 func(grid); | |
1357 ed.execCommand('mceRepaint'); | |
1358 cleanup(); | |
1359 } | |
1360 }); | |
1361 }); | |
1362 | |
1363 // Register dialog commands | |
1364 each({ | |
1365 mceInsertTable : function(val) { | |
1366 winMan.open({ | |
1367 url : url + '/table.htm', | |
1368 width : 400 + parseInt(ed.getLang('table.table_delta_width', 0)), | |
1369 height : 320 + parseInt(ed.getLang('table.table_delta_height', 0)), | |
1370 inline : 1 | |
1371 }, { | |
1372 plugin_url : url, | |
1373 action : val ? val.action : 0 | |
1374 }); | |
1375 }, | |
1376 | |
1377 mceTableRowProps : function() { | |
1378 winMan.open({ | |
1379 url : url + '/row.htm', | |
1380 width : 400 + parseInt(ed.getLang('table.rowprops_delta_width', 0)), | |
1381 height : 295 + parseInt(ed.getLang('table.rowprops_delta_height', 0)), | |
1382 inline : 1 | |
1383 }, { | |
1384 plugin_url : url | |
1385 }); | |
1386 }, | |
1387 | |
1388 mceTableCellProps : function() { | |
1389 winMan.open({ | |
1390 url : url + '/cell.htm', | |
1391 width : 400 + parseInt(ed.getLang('table.cellprops_delta_width', 0)), | |
1392 height : 295 + parseInt(ed.getLang('table.cellprops_delta_height', 0)), | |
1393 inline : 1 | |
1394 }, { | |
1395 plugin_url : url | |
1396 }); | |
1397 } | |
1398 }, function(func, name) { | |
1399 ed.addCommand(name, function(ui, val) { | |
1400 func(val); | |
1401 }); | |
1402 }); | |
1403 } | |
1404 }); | |
1405 | |
1406 // Register plugin | |
1407 tinymce.PluginManager.add('table', tinymce.plugins.TablePlugin); | |
1408 })(tinymce); |