annotate static/js/tiny_mce/plugins/table/editor_plugin_src.js @ 645:99f7917702ca

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