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 | /**
|
---|
29 | * Table Grid class.
|
---|
30 | */
|
---|
31 | function TableGrid(table, dom, selection) {
|
---|
32 | var grid, startPos, endPos, selectedCell;
|
---|
33 |
|
---|
34 | buildGrid();
|
---|
35 | selectedCell = dom.getParent(selection.getStart(), 'th,td');
|
---|
36 | if (selectedCell) {
|
---|
37 | startPos = getPos(selectedCell);
|
---|
38 | endPos = findEndPos();
|
---|
39 | selectedCell = getCell(startPos.x, startPos.y);
|
---|
40 | }
|
---|
41 |
|
---|
42 | function cloneNode(node, children) {
|
---|
43 | node = node.cloneNode(children);
|
---|
44 | node.removeAttribute('id');
|
---|
45 |
|
---|
46 | return node;
|
---|
47 | }
|
---|
48 |
|
---|
49 | function buildGrid() {
|
---|
50 | var startY = 0;
|
---|
51 |
|
---|
52 | grid = [];
|
---|
53 |
|
---|
54 | each(['thead', 'tbody', 'tfoot'], function(part) {
|
---|
55 | var rows = dom.select('> ' + part + ' tr', table);
|
---|
56 |
|
---|
57 | each(rows, function(tr, y) {
|
---|
58 | y += startY;
|
---|
59 |
|
---|
60 | each(dom.select('> td, > th', tr), function(td, x) {
|
---|
61 | var x2, y2, rowspan, colspan;
|
---|
62 |
|
---|
63 | // Skip over existing cells produced by rowspan
|
---|
64 | if (grid[y]) {
|
---|
65 | while (grid[y][x])
|
---|
66 | x++;
|
---|
67 | }
|
---|
68 |
|
---|
69 | // Get col/rowspan from cell
|
---|
70 | rowspan = getSpanVal(td, 'rowspan');
|
---|
71 | colspan = getSpanVal(td, 'colspan');
|
---|
72 |
|
---|
73 | // Fill out rowspan/colspan right and down
|
---|
74 | for (y2 = y; y2 < y + rowspan; y2++) {
|
---|
75 | if (!grid[y2])
|
---|
76 | grid[y2] = [];
|
---|
77 |
|
---|
78 | for (x2 = x; x2 < x + colspan; x2++) {
|
---|
79 | grid[y2][x2] = {
|
---|
80 | part : part,
|
---|
81 | real : y2 == y && x2 == x,
|
---|
82 | elm : td,
|
---|
83 | rowspan : rowspan,
|
---|
84 | colspan : colspan
|
---|
85 | };
|
---|
86 | }
|
---|
87 | }
|
---|
88 | });
|
---|
89 | });
|
---|
90 |
|
---|
91 | startY += rows.length;
|
---|
92 | });
|
---|
93 | };
|
---|
94 |
|
---|
95 | function getCell(x, y) {
|
---|
96 | var row;
|
---|
97 |
|
---|
98 | row = grid[y];
|
---|
99 | if (row)
|
---|
100 | return row[x];
|
---|
101 | };
|
---|
102 |
|
---|
103 | function getSpanVal(td, name) {
|
---|
104 | return parseInt(td.getAttribute(name) || 1);
|
---|
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;
|
---|
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 | ed.dom.removeClass(ed.dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
|
---|
768 | };
|
---|
769 |
|
---|
770 | // Register buttons
|
---|
771 | each([
|
---|
772 | ['table', 'table.desc', 'mceInsertTable', true],
|
---|
773 | ['delete_table', 'table.del', 'mceTableDelete'],
|
---|
774 | ['delete_col', 'table.delete_col_desc', 'mceTableDeleteCol'],
|
---|
775 | ['delete_row', 'table.delete_row_desc', 'mceTableDeleteRow'],
|
---|
776 | ['col_after', 'table.col_after_desc', 'mceTableInsertColAfter'],
|
---|
777 | ['col_before', 'table.col_before_desc', 'mceTableInsertColBefore'],
|
---|
778 | ['row_after', 'table.row_after_desc', 'mceTableInsertRowAfter'],
|
---|
779 | ['row_before', 'table.row_before_desc', 'mceTableInsertRowBefore'],
|
---|
780 | ['row_props', 'table.row_desc', 'mceTableRowProps', true],
|
---|
781 | ['cell_props', 'table.cell_desc', 'mceTableCellProps', true],
|
---|
782 | ['split_cells', 'table.split_cells_desc', 'mceTableSplitCells', true],
|
---|
783 | ['merge_cells', 'table.merge_cells_desc', 'mceTableMergeCells', true]
|
---|
784 | ], function(c) {
|
---|
785 | ed.addButton(c[0], {title : c[1], cmd : c[2], ui : c[3]});
|
---|
786 | });
|
---|
787 |
|
---|
788 | // Select whole table is a table border is clicked
|
---|
789 | if (!tinymce.isIE) {
|
---|
790 | ed.onClick.add(function(ed, e) {
|
---|
791 | e = e.target;
|
---|
792 |
|
---|
793 | if (e.nodeName === 'TABLE') {
|
---|
794 | ed.selection.select(e);
|
---|
795 | ed.nodeChanged();
|
---|
796 | }
|
---|
797 | });
|
---|
798 | }
|
---|
799 |
|
---|
800 | ed.onPreProcess.add(function(ed, args) {
|
---|
801 | var nodes, i, node, dom = ed.dom, value;
|
---|
802 |
|
---|
803 | nodes = dom.select('table', args.node);
|
---|
804 | i = nodes.length;
|
---|
805 | while (i--) {
|
---|
806 | node = nodes[i];
|
---|
807 | dom.setAttrib(node, 'data-mce-style', '');
|
---|
808 |
|
---|
809 | if ((value = dom.getAttrib(node, 'width'))) {
|
---|
810 | dom.setStyle(node, 'width', value);
|
---|
811 | dom.setAttrib(node, 'width', '');
|
---|
812 | }
|
---|
813 |
|
---|
814 | if ((value = dom.getAttrib(node, 'height'))) {
|
---|
815 | dom.setStyle(node, 'height', value);
|
---|
816 | dom.setAttrib(node, 'height', '');
|
---|
817 | }
|
---|
818 | }
|
---|
819 | });
|
---|
820 |
|
---|
821 | // Handle node change updates
|
---|
822 | ed.onNodeChange.add(function(ed, cm, n) {
|
---|
823 | var p;
|
---|
824 |
|
---|
825 | n = ed.selection.getStart();
|
---|
826 | p = ed.dom.getParent(n, 'td,th,caption');
|
---|
827 | cm.setActive('table', n.nodeName === 'TABLE' || !!p);
|
---|
828 |
|
---|
829 | // Disable table tools if we are in caption
|
---|
830 | if (p && p.nodeName === 'CAPTION')
|
---|
831 | p = 0;
|
---|
832 |
|
---|
833 | cm.setDisabled('delete_table', !p);
|
---|
834 | cm.setDisabled('delete_col', !p);
|
---|
835 | cm.setDisabled('delete_table', !p);
|
---|
836 | cm.setDisabled('delete_row', !p);
|
---|
837 | cm.setDisabled('col_after', !p);
|
---|
838 | cm.setDisabled('col_before', !p);
|
---|
839 | cm.setDisabled('row_after', !p);
|
---|
840 | cm.setDisabled('row_before', !p);
|
---|
841 | cm.setDisabled('row_props', !p);
|
---|
842 | cm.setDisabled('cell_props', !p);
|
---|
843 | cm.setDisabled('split_cells', !p);
|
---|
844 | cm.setDisabled('merge_cells', !p);
|
---|
845 | });
|
---|
846 |
|
---|
847 | ed.onInit.add(function(ed) {
|
---|
848 | var startTable, startCell, dom = ed.dom, tableGrid;
|
---|
849 |
|
---|
850 | winMan = ed.windowManager;
|
---|
851 |
|
---|
852 | // Add cell selection logic
|
---|
853 | ed.onMouseDown.add(function(ed, e) {
|
---|
854 | if (e.button != 2) {
|
---|
855 | cleanup();
|
---|
856 |
|
---|
857 | startCell = dom.getParent(e.target, 'td,th');
|
---|
858 | startTable = dom.getParent(startCell, 'table');
|
---|
859 | }
|
---|
860 | });
|
---|
861 |
|
---|
862 | dom.bind(ed.getDoc(), 'mouseover', function(e) {
|
---|
863 | var sel, table, target = e.target;
|
---|
864 |
|
---|
865 | if (startCell && (tableGrid || target != startCell) && (target.nodeName == 'TD' || target.nodeName == 'TH')) {
|
---|
866 | table = dom.getParent(target, 'table');
|
---|
867 | if (table == startTable) {
|
---|
868 | if (!tableGrid) {
|
---|
869 | tableGrid = createTableGrid(table);
|
---|
870 | tableGrid.setStartCell(startCell);
|
---|
871 |
|
---|
872 | ed.getBody().style.webkitUserSelect = 'none';
|
---|
873 | }
|
---|
874 |
|
---|
875 | tableGrid.setEndCell(target);
|
---|
876 | }
|
---|
877 |
|
---|
878 | // Remove current selection
|
---|
879 | sel = ed.selection.getSel();
|
---|
880 |
|
---|
881 | try {
|
---|
882 | if (sel.removeAllRanges)
|
---|
883 | sel.removeAllRanges();
|
---|
884 | else
|
---|
885 | sel.empty();
|
---|
886 | } catch (ex) {
|
---|
887 | // IE9 might throw errors here
|
---|
888 | }
|
---|
889 |
|
---|
890 | e.preventDefault();
|
---|
891 | }
|
---|
892 | });
|
---|
893 |
|
---|
894 | ed.onMouseUp.add(function(ed, e) {
|
---|
895 | var rng, sel = ed.selection, selectedCells, nativeSel = sel.getSel(), walker, node, lastNode, endNode;
|
---|
896 |
|
---|
897 | // Move selection to startCell
|
---|
898 | if (startCell) {
|
---|
899 | if (tableGrid)
|
---|
900 | ed.getBody().style.webkitUserSelect = '';
|
---|
901 |
|
---|
902 | function setPoint(node, start) {
|
---|
903 | var walker = new tinymce.dom.TreeWalker(node, node);
|
---|
904 |
|
---|
905 | do {
|
---|
906 | // Text node
|
---|
907 | if (node.nodeType == 3 && tinymce.trim(node.nodeValue).length != 0) {
|
---|
908 | if (start)
|
---|
909 | rng.setStart(node, 0);
|
---|
910 | else
|
---|
911 | rng.setEnd(node, node.nodeValue.length);
|
---|
912 |
|
---|
913 | return;
|
---|
914 | }
|
---|
915 |
|
---|
916 | // BR element
|
---|
917 | if (node.nodeName == 'BR') {
|
---|
918 | if (start)
|
---|
919 | rng.setStartBefore(node);
|
---|
920 | else
|
---|
921 | rng.setEndBefore(node);
|
---|
922 |
|
---|
923 | return;
|
---|
924 | }
|
---|
925 | } while (node = (start ? walker.next() : walker.prev()));
|
---|
926 | };
|
---|
927 |
|
---|
928 | // Try to expand text selection as much as we can only Gecko supports cell selection
|
---|
929 | selectedCells = dom.select('td.mceSelected,th.mceSelected');
|
---|
930 | if (selectedCells.length > 0) {
|
---|
931 | rng = dom.createRng();
|
---|
932 | node = selectedCells[0];
|
---|
933 | endNode = selectedCells[selectedCells.length - 1];
|
---|
934 |
|
---|
935 | setPoint(node, 1);
|
---|
936 | walker = new tinymce.dom.TreeWalker(node, dom.getParent(selectedCells[0], 'table'));
|
---|
937 |
|
---|
938 | do {
|
---|
939 | if (node.nodeName == 'TD' || node.nodeName == 'TH') {
|
---|
940 | if (!dom.hasClass(node, 'mceSelected'))
|
---|
941 | break;
|
---|
942 |
|
---|
943 | lastNode = node;
|
---|
944 | }
|
---|
945 | } while (node = walker.next());
|
---|
946 |
|
---|
947 | setPoint(lastNode);
|
---|
948 |
|
---|
949 | sel.setRng(rng);
|
---|
950 | }
|
---|
951 |
|
---|
952 | ed.nodeChanged();
|
---|
953 | startCell = tableGrid = startTable = null;
|
---|
954 | }
|
---|
955 | });
|
---|
956 |
|
---|
957 | ed.onKeyUp.add(function(ed, e) {
|
---|
958 | cleanup();
|
---|
959 | });
|
---|
960 |
|
---|
961 | // Add context menu
|
---|
962 | if (ed && ed.plugins.contextmenu) {
|
---|
963 | ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) {
|
---|
964 | var sm, se = ed.selection, el = se.getNode() || ed.getBody();
|
---|
965 |
|
---|
966 | if (ed.dom.getParent(e, 'td') || ed.dom.getParent(e, 'th') || ed.dom.select('td.mceSelected,th.mceSelected').length) {
|
---|
967 | m.removeAll();
|
---|
968 |
|
---|
969 | if (el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) {
|
---|
970 | m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true});
|
---|
971 | m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'});
|
---|
972 | m.addSeparator();
|
---|
973 | }
|
---|
974 |
|
---|
975 | if (el.nodeName == 'IMG' && el.className.indexOf('mceItem') == -1) {
|
---|
976 | m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true});
|
---|
977 | m.addSeparator();
|
---|
978 | }
|
---|
979 |
|
---|
980 | m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', value : {action : 'insert'}});
|
---|
981 | m.add({title : 'table.props_desc', icon : 'table_props', cmd : 'mceInsertTable'});
|
---|
982 | m.add({title : 'table.del', icon : 'delete_table', cmd : 'mceTableDelete'});
|
---|
983 | m.addSeparator();
|
---|
984 |
|
---|
985 | // Cell menu
|
---|
986 | sm = m.addMenu({title : 'table.cell'});
|
---|
987 | sm.add({title : 'table.cell_desc', icon : 'cell_props', cmd : 'mceTableCellProps'});
|
---|
988 | sm.add({title : 'table.split_cells_desc', icon : 'split_cells', cmd : 'mceTableSplitCells'});
|
---|
989 | sm.add({title : 'table.merge_cells_desc', icon : 'merge_cells', cmd : 'mceTableMergeCells'});
|
---|
990 |
|
---|
991 | // Row menu
|
---|
992 | sm = m.addMenu({title : 'table.row'});
|
---|
993 | sm.add({title : 'table.row_desc', icon : 'row_props', cmd : 'mceTableRowProps'});
|
---|
994 | sm.add({title : 'table.row_before_desc', icon : 'row_before', cmd : 'mceTableInsertRowBefore'});
|
---|
995 | sm.add({title : 'table.row_after_desc', icon : 'row_after', cmd : 'mceTableInsertRowAfter'});
|
---|
996 | sm.add({title : 'table.delete_row_desc', icon : 'delete_row', cmd : 'mceTableDeleteRow'});
|
---|
997 | sm.addSeparator();
|
---|
998 | sm.add({title : 'table.cut_row_desc', icon : 'cut', cmd : 'mceTableCutRow'});
|
---|
999 | sm.add({title : 'table.copy_row_desc', icon : 'copy', cmd : 'mceTableCopyRow'});
|
---|
1000 | sm.add({title : 'table.paste_row_before_desc', icon : 'paste', cmd : 'mceTablePasteRowBefore'}).setDisabled(!clipboardRows);
|
---|
1001 | sm.add({title : 'table.paste_row_after_desc', icon : 'paste', cmd : 'mceTablePasteRowAfter'}).setDisabled(!clipboardRows);
|
---|
1002 |
|
---|
1003 | // Column menu
|
---|
1004 | sm = m.addMenu({title : 'table.col'});
|
---|
1005 | sm.add({title : 'table.col_before_desc', icon : 'col_before', cmd : 'mceTableInsertColBefore'});
|
---|
1006 | sm.add({title : 'table.col_after_desc', icon : 'col_after', cmd : 'mceTableInsertColAfter'});
|
---|
1007 | sm.add({title : 'table.delete_col_desc', icon : 'delete_col', cmd : 'mceTableDeleteCol'});
|
---|
1008 | } else
|
---|
1009 | m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable'});
|
---|
1010 | });
|
---|
1011 | }
|
---|
1012 |
|
---|
1013 | // Fixes an issue on Gecko where it's impossible to place the caret behind a table
|
---|
1014 | // This fix will force a paragraph element after the table but only when the forced_root_block setting is enabled
|
---|
1015 | if (!tinymce.isIE) {
|
---|
1016 | function fixTableCaretPos() {
|
---|
1017 | var last;
|
---|
1018 |
|
---|
1019 | // Skip empty text nodes form the end
|
---|
1020 | for (last = ed.getBody().lastChild; last && last.nodeType == 3 && !last.nodeValue.length; last = last.previousSibling) ;
|
---|
1021 |
|
---|
1022 | if (last && last.nodeName == 'TABLE')
|
---|
1023 | ed.dom.add(ed.getBody(), 'p', null, '<br mce_bogus="1" />');
|
---|
1024 | };
|
---|
1025 |
|
---|
1026 | // Fixes an bug where it's impossible to place the caret before a table in Gecko
|
---|
1027 | // this fix solves it by detecting when the caret is at the beginning of such a table
|
---|
1028 | // and then manually moves the caret infront of the table
|
---|
1029 | if (tinymce.isGecko) {
|
---|
1030 | ed.onKeyDown.add(function(ed, e) {
|
---|
1031 | var rng, table, dom = ed.dom;
|
---|
1032 |
|
---|
1033 | // On gecko it's not possible to place the caret before a table
|
---|
1034 | if (e.keyCode == 37 || e.keyCode == 38) {
|
---|
1035 | rng = ed.selection.getRng();
|
---|
1036 | table = dom.getParent(rng.startContainer, 'table');
|
---|
1037 |
|
---|
1038 | if (table && ed.getBody().firstChild == table) {
|
---|
1039 | if (isAtStart(rng, table)) {
|
---|
1040 | rng = dom.createRng();
|
---|
1041 |
|
---|
1042 | rng.setStartBefore(table);
|
---|
1043 | rng.setEndBefore(table);
|
---|
1044 |
|
---|
1045 | ed.selection.setRng(rng);
|
---|
1046 |
|
---|
1047 | e.preventDefault();
|
---|
1048 | }
|
---|
1049 | }
|
---|
1050 | }
|
---|
1051 | });
|
---|
1052 | }
|
---|
1053 |
|
---|
1054 | ed.onKeyUp.add(fixTableCaretPos);
|
---|
1055 | ed.onSetContent.add(fixTableCaretPos);
|
---|
1056 | ed.onVisualAid.add(fixTableCaretPos);
|
---|
1057 |
|
---|
1058 | ed.onPreProcess.add(function(ed, o) {
|
---|
1059 | var last = o.node.lastChild;
|
---|
1060 |
|
---|
1061 | if (last && last.childNodes.length == 1 && last.firstChild.nodeName == 'BR')
|
---|
1062 | ed.dom.remove(last);
|
---|
1063 | });
|
---|
1064 |
|
---|
1065 | fixTableCaretPos();
|
---|
1066 | }
|
---|
1067 | });
|
---|
1068 |
|
---|
1069 | // Register action commands
|
---|
1070 | each({
|
---|
1071 | mceTableSplitCells : function(grid) {
|
---|
1072 | grid.split();
|
---|
1073 | },
|
---|
1074 |
|
---|
1075 | mceTableMergeCells : function(grid) {
|
---|
1076 | var rowSpan, colSpan, cell;
|
---|
1077 |
|
---|
1078 | cell = ed.dom.getParent(ed.selection.getNode(), 'th,td');
|
---|
1079 | if (cell) {
|
---|
1080 | rowSpan = cell.rowSpan;
|
---|
1081 | colSpan = cell.colSpan;
|
---|
1082 | }
|
---|
1083 |
|
---|
1084 | if (!ed.dom.select('td.mceSelected,th.mceSelected').length) {
|
---|
1085 | winMan.open({
|
---|
1086 | url : url + '/merge_cells.htm',
|
---|
1087 | width : 240 + parseInt(ed.getLang('table.merge_cells_delta_width', 0)),
|
---|
1088 | height : 110 + parseInt(ed.getLang('table.merge_cells_delta_height', 0)),
|
---|
1089 | inline : 1
|
---|
1090 | }, {
|
---|
1091 | rows : rowSpan,
|
---|
1092 | cols : colSpan,
|
---|
1093 | onaction : function(data) {
|
---|
1094 | grid.merge(cell, data.cols, data.rows);
|
---|
1095 | },
|
---|
1096 | plugin_url : url
|
---|
1097 | });
|
---|
1098 | } else
|
---|
1099 | grid.merge();
|
---|
1100 | },
|
---|
1101 |
|
---|
1102 | mceTableInsertRowBefore : function(grid) {
|
---|
1103 | grid.insertRow(true);
|
---|
1104 | },
|
---|
1105 |
|
---|
1106 | mceTableInsertRowAfter : function(grid) {
|
---|
1107 | grid.insertRow();
|
---|
1108 | },
|
---|
1109 |
|
---|
1110 | mceTableInsertColBefore : function(grid) {
|
---|
1111 | grid.insertCol(true);
|
---|
1112 | },
|
---|
1113 |
|
---|
1114 | mceTableInsertColAfter : function(grid) {
|
---|
1115 | grid.insertCol();
|
---|
1116 | },
|
---|
1117 |
|
---|
1118 | mceTableDeleteCol : function(grid) {
|
---|
1119 | grid.deleteCols();
|
---|
1120 | },
|
---|
1121 |
|
---|
1122 | mceTableDeleteRow : function(grid) {
|
---|
1123 | grid.deleteRows();
|
---|
1124 | },
|
---|
1125 |
|
---|
1126 | mceTableCutRow : function(grid) {
|
---|
1127 | clipboardRows = grid.cutRows();
|
---|
1128 | },
|
---|
1129 |
|
---|
1130 | mceTableCopyRow : function(grid) {
|
---|
1131 | clipboardRows = grid.copyRows();
|
---|
1132 | },
|
---|
1133 |
|
---|
1134 | mceTablePasteRowBefore : function(grid) {
|
---|
1135 | grid.pasteRows(clipboardRows, true);
|
---|
1136 | },
|
---|
1137 |
|
---|
1138 | mceTablePasteRowAfter : function(grid) {
|
---|
1139 | grid.pasteRows(clipboardRows);
|
---|
1140 | },
|
---|
1141 |
|
---|
1142 | mceTableDelete : function(grid) {
|
---|
1143 | grid.deleteTable();
|
---|
1144 | }
|
---|
1145 | }, function(func, name) {
|
---|
1146 | ed.addCommand(name, function() {
|
---|
1147 | var grid = createTableGrid();
|
---|
1148 |
|
---|
1149 | if (grid) {
|
---|
1150 | func(grid);
|
---|
1151 | ed.execCommand('mceRepaint');
|
---|
1152 | cleanup();
|
---|
1153 | }
|
---|
1154 | });
|
---|
1155 | });
|
---|
1156 |
|
---|
1157 | // Register dialog commands
|
---|
1158 | each({
|
---|
1159 | mceInsertTable : function(val) {
|
---|
1160 | winMan.open({
|
---|
1161 | url : url + '/table.htm',
|
---|
1162 | width : 400 + parseInt(ed.getLang('table.table_delta_width', 0)),
|
---|
1163 | height : 320 + parseInt(ed.getLang('table.table_delta_height', 0)),
|
---|
1164 | inline : 1
|
---|
1165 | }, {
|
---|
1166 | plugin_url : url,
|
---|
1167 | action : val ? val.action : 0
|
---|
1168 | });
|
---|
1169 | },
|
---|
1170 |
|
---|
1171 | mceTableRowProps : function() {
|
---|
1172 | winMan.open({
|
---|
1173 | url : url + '/row.htm',
|
---|
1174 | width : 400 + parseInt(ed.getLang('table.rowprops_delta_width', 0)),
|
---|
1175 | height : 295 + parseInt(ed.getLang('table.rowprops_delta_height', 0)),
|
---|
1176 | inline : 1
|
---|
1177 | }, {
|
---|
1178 | plugin_url : url
|
---|
1179 | });
|
---|
1180 | },
|
---|
1181 |
|
---|
1182 | mceTableCellProps : function() {
|
---|
1183 | winMan.open({
|
---|
1184 | url : url + '/cell.htm',
|
---|
1185 | width : 400 + parseInt(ed.getLang('table.cellprops_delta_width', 0)),
|
---|
1186 | height : 295 + parseInt(ed.getLang('table.cellprops_delta_height', 0)),
|
---|
1187 | inline : 1
|
---|
1188 | }, {
|
---|
1189 | plugin_url : url
|
---|
1190 | });
|
---|
1191 | }
|
---|
1192 | }, function(func, name) {
|
---|
1193 | ed.addCommand(name, function(ui, val) {
|
---|
1194 | func(val);
|
---|
1195 | });
|
---|
1196 | });
|
---|
1197 | }
|
---|
1198 | });
|
---|
1199 |
|
---|
1200 | // Register plugin
|
---|
1201 | tinymce.PluginManager.add('table', tinymce.plugins.TablePlugin);
|
---|
1202 | })(tinymce); |
---|