src/pyams_skin/resources/js/ext/tinymce/dev/plugins/table/plugin.js
changeset 557 bca7a7e058a3
equal deleted inserted replaced
-1:000000000000 557:bca7a7e058a3
       
     1 /**
       
     2  * Compiled inline version. (Library mode)
       
     3  */
       
     4 
       
     5 /*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */
       
     6 /*globals $code */
       
     7 
       
     8 (function(exports, undefined) {
       
     9 	"use strict";
       
    10 
       
    11 	var modules = {};
       
    12 
       
    13 	function require(ids, callback) {
       
    14 		var module, defs = [];
       
    15 
       
    16 		for (var i = 0; i < ids.length; ++i) {
       
    17 			module = modules[ids[i]] || resolve(ids[i]);
       
    18 			if (!module) {
       
    19 				throw 'module definition dependecy not found: ' + ids[i];
       
    20 			}
       
    21 
       
    22 			defs.push(module);
       
    23 		}
       
    24 
       
    25 		callback.apply(null, defs);
       
    26 	}
       
    27 
       
    28 	function define(id, dependencies, definition) {
       
    29 		if (typeof id !== 'string') {
       
    30 			throw 'invalid module definition, module id must be defined and be a string';
       
    31 		}
       
    32 
       
    33 		if (dependencies === undefined) {
       
    34 			throw 'invalid module definition, dependencies must be specified';
       
    35 		}
       
    36 
       
    37 		if (definition === undefined) {
       
    38 			throw 'invalid module definition, definition function must be specified';
       
    39 		}
       
    40 
       
    41 		require(dependencies, function() {
       
    42 			modules[id] = definition.apply(null, arguments);
       
    43 		});
       
    44 	}
       
    45 
       
    46 	function defined(id) {
       
    47 		return !!modules[id];
       
    48 	}
       
    49 
       
    50 	function resolve(id) {
       
    51 		var target = exports;
       
    52 		var fragments = id.split(/[.\/]/);
       
    53 
       
    54 		for (var fi = 0; fi < fragments.length; ++fi) {
       
    55 			if (!target[fragments[fi]]) {
       
    56 				return;
       
    57 			}
       
    58 
       
    59 			target = target[fragments[fi]];
       
    60 		}
       
    61 
       
    62 		return target;
       
    63 	}
       
    64 
       
    65 	function expose(ids) {
       
    66 		for (var i = 0; i < ids.length; i++) {
       
    67 			var target = exports;
       
    68 			var id = ids[i];
       
    69 			var fragments = id.split(/[.\/]/);
       
    70 
       
    71 			for (var fi = 0; fi < fragments.length - 1; ++fi) {
       
    72 				if (target[fragments[fi]] === undefined) {
       
    73 					target[fragments[fi]] = {};
       
    74 				}
       
    75 
       
    76 				target = target[fragments[fi]];
       
    77 			}
       
    78 
       
    79 			target[fragments[fragments.length - 1]] = modules[id];
       
    80 		}
       
    81 	}
       
    82 
       
    83 // Included from: js/tinymce/plugins/table/classes/TableGrid.js
       
    84 
       
    85 /**
       
    86  * TableGrid.js
       
    87  *
       
    88  * Copyright, Moxiecode Systems AB
       
    89  * Released under LGPL License.
       
    90  *
       
    91  * License: http://www.tinymce.com/license
       
    92  * Contributing: http://www.tinymce.com/contributing
       
    93  */
       
    94 
       
    95 /**
       
    96  * This class creates a grid out of a table element. This
       
    97  * makes it a whole lot easier to handle complex tables with
       
    98  * col/row spans.
       
    99  *
       
   100  * @class tinymce.tableplugin.TableGrid
       
   101  * @private
       
   102  */
       
   103 define("tinymce/tableplugin/TableGrid", [
       
   104 	"tinymce/util/Tools",
       
   105 	"tinymce/Env"
       
   106 ], function(Tools, Env) {
       
   107 	var each = Tools.each;
       
   108 
       
   109 	function getSpanVal(td, name) {
       
   110 		return parseInt(td.getAttribute(name) || 1, 10);
       
   111 	}
       
   112 
       
   113 	return function(editor, table) {
       
   114 		var grid, gridWidth, startPos, endPos, selectedCell, selection = editor.selection, dom = selection.dom;
       
   115 
       
   116 		function buildGrid() {
       
   117 			var startY = 0;
       
   118 
       
   119 			grid = [];
       
   120 			gridWidth = 0;
       
   121 
       
   122 			each(['thead', 'tbody', 'tfoot'], function(part) {
       
   123 				var rows = dom.select('> ' + part + ' tr', table);
       
   124 
       
   125 				each(rows, function(tr, y) {
       
   126 					y += startY;
       
   127 
       
   128 					each(dom.select('> td, > th', tr), function(td, x) {
       
   129 						var x2, y2, rowspan, colspan;
       
   130 
       
   131 						// Skip over existing cells produced by rowspan
       
   132 						if (grid[y]) {
       
   133 							while (grid[y][x]) {
       
   134 								x++;
       
   135 							}
       
   136 						}
       
   137 
       
   138 						// Get col/rowspan from cell
       
   139 						rowspan = getSpanVal(td, 'rowspan');
       
   140 						colspan = getSpanVal(td, 'colspan');
       
   141 
       
   142 						// Fill out rowspan/colspan right and down
       
   143 						for (y2 = y; y2 < y + rowspan; y2++) {
       
   144 							if (!grid[y2]) {
       
   145 								grid[y2] = [];
       
   146 							}
       
   147 
       
   148 							for (x2 = x; x2 < x + colspan; x2++) {
       
   149 								grid[y2][x2] = {
       
   150 									part: part,
       
   151 									real: y2 == y && x2 == x,
       
   152 									elm: td,
       
   153 									rowspan: rowspan,
       
   154 									colspan: colspan
       
   155 								};
       
   156 							}
       
   157 						}
       
   158 
       
   159 						gridWidth = Math.max(gridWidth, x + 1);
       
   160 					});
       
   161 				});
       
   162 
       
   163 				startY += rows.length;
       
   164 			});
       
   165 		}
       
   166 
       
   167 		function cloneNode(node, children) {
       
   168 			node = node.cloneNode(children);
       
   169 			node.removeAttribute('id');
       
   170 
       
   171 			return node;
       
   172 		}
       
   173 
       
   174 		function getCell(x, y) {
       
   175 			var row;
       
   176 
       
   177 			row = grid[y];
       
   178 			if (row) {
       
   179 				return row[x];
       
   180 			}
       
   181 		}
       
   182 
       
   183 		function setSpanVal(td, name, val) {
       
   184 			if (td) {
       
   185 				val = parseInt(val, 10);
       
   186 
       
   187 				if (val === 1) {
       
   188 					td.removeAttribute(name, 1);
       
   189 				} else {
       
   190 					td.setAttribute(name, val, 1);
       
   191 				}
       
   192 			}
       
   193 		}
       
   194 
       
   195 		function isCellSelected(cell) {
       
   196 			return cell && (dom.hasClass(cell.elm, 'mce-item-selected') || cell == selectedCell);
       
   197 		}
       
   198 
       
   199 		function getSelectedRows() {
       
   200 			var rows = [];
       
   201 
       
   202 			each(table.rows, function(row) {
       
   203 				each(row.cells, function(cell) {
       
   204 					if (dom.hasClass(cell, 'mce-item-selected') || (selectedCell && cell == selectedCell.elm)) {
       
   205 						rows.push(row);
       
   206 						return false;
       
   207 					}
       
   208 				});
       
   209 			});
       
   210 
       
   211 			return rows;
       
   212 		}
       
   213 
       
   214 		function deleteTable() {
       
   215 			var rng = dom.createRng();
       
   216 
       
   217 			rng.setStartAfter(table);
       
   218 			rng.setEndAfter(table);
       
   219 
       
   220 			selection.setRng(rng);
       
   221 
       
   222 			dom.remove(table);
       
   223 		}
       
   224 
       
   225 		function cloneCell(cell) {
       
   226 			var formatNode, cloneFormats = {};
       
   227 
       
   228 			if (editor.settings.table_clone_elements !== false) {
       
   229 				cloneFormats = Tools.makeMap(
       
   230 					(editor.settings.table_clone_elements || 'strong em b i span font h1 h2 h3 h4 h5 h6 p div').toUpperCase(),
       
   231 					/[ ,]/
       
   232 				);
       
   233 			}
       
   234 
       
   235 			// Clone formats
       
   236 			Tools.walk(cell, function(node) {
       
   237 				var curNode;
       
   238 
       
   239 				if (node.nodeType == 3) {
       
   240 					each(dom.getParents(node.parentNode, null, cell).reverse(), function(node) {
       
   241 						if (!cloneFormats[node.nodeName]) {
       
   242 							return;
       
   243 						}
       
   244 
       
   245 						node = cloneNode(node, false);
       
   246 
       
   247 						if (!formatNode) {
       
   248 							formatNode = curNode = node;
       
   249 						} else if (curNode) {
       
   250 							curNode.appendChild(node);
       
   251 						}
       
   252 
       
   253 						curNode = node;
       
   254 					});
       
   255 
       
   256 					// Add something to the inner node
       
   257 					if (curNode) {
       
   258 						curNode.innerHTML = Env.ie ? '&nbsp;' : '<br data-mce-bogus="1" />';
       
   259 					}
       
   260 
       
   261 					return false;
       
   262 				}
       
   263 			}, 'childNodes');
       
   264 
       
   265 			cell = cloneNode(cell, false);
       
   266 			setSpanVal(cell, 'rowSpan', 1);
       
   267 			setSpanVal(cell, 'colSpan', 1);
       
   268 
       
   269 			if (formatNode) {
       
   270 				cell.appendChild(formatNode);
       
   271 			} else {
       
   272 				if (!Env.ie || Env.ie > 10) {
       
   273 					cell.innerHTML = '<br data-mce-bogus="1" />';
       
   274 				}
       
   275 			}
       
   276 
       
   277 			return cell;
       
   278 		}
       
   279 
       
   280 		function cleanup() {
       
   281 			var rng = dom.createRng(), row;
       
   282 
       
   283 			// Empty rows
       
   284 			each(dom.select('tr', table), function(tr) {
       
   285 				if (tr.cells.length === 0) {
       
   286 					dom.remove(tr);
       
   287 				}
       
   288 			});
       
   289 
       
   290 			// Empty table
       
   291 			if (dom.select('tr', table).length === 0) {
       
   292 				rng.setStartBefore(table);
       
   293 				rng.setEndBefore(table);
       
   294 				selection.setRng(rng);
       
   295 				dom.remove(table);
       
   296 				return;
       
   297 			}
       
   298 
       
   299 			// Empty header/body/footer
       
   300 			each(dom.select('thead,tbody,tfoot', table), function(part) {
       
   301 				if (part.rows.length === 0) {
       
   302 					dom.remove(part);
       
   303 				}
       
   304 			});
       
   305 
       
   306 			// Restore selection to start position if it still exists
       
   307 			buildGrid();
       
   308 
       
   309 			// If we have a valid startPos object
       
   310 			if (startPos) {
       
   311 				// Restore the selection to the closest table position
       
   312 				row = grid[Math.min(grid.length - 1, startPos.y)];
       
   313 				if (row) {
       
   314 					selection.select(row[Math.min(row.length - 1, startPos.x)].elm, true);
       
   315 					selection.collapse(true);
       
   316 				}
       
   317 			}
       
   318 		}
       
   319 
       
   320 		function fillLeftDown(x, y, rows, cols) {
       
   321 			var tr, x2, r, c, cell;
       
   322 
       
   323 			tr = grid[y][x].elm.parentNode;
       
   324 			for (r = 1; r <= rows; r++) {
       
   325 				tr = dom.getNext(tr, 'tr');
       
   326 
       
   327 				if (tr) {
       
   328 					// Loop left to find real cell
       
   329 					for (x2 = x; x2 >= 0; x2--) {
       
   330 						cell = grid[y + r][x2].elm;
       
   331 
       
   332 						if (cell.parentNode == tr) {
       
   333 							// Append clones after
       
   334 							for (c = 1; c <= cols; c++) {
       
   335 								dom.insertAfter(cloneCell(cell), cell);
       
   336 							}
       
   337 
       
   338 							break;
       
   339 						}
       
   340 					}
       
   341 
       
   342 					if (x2 == -1) {
       
   343 						// Insert nodes before first cell
       
   344 						for (c = 1; c <= cols; c++) {
       
   345 							tr.insertBefore(cloneCell(tr.cells[0]), tr.cells[0]);
       
   346 						}
       
   347 					}
       
   348 				}
       
   349 			}
       
   350 		}
       
   351 
       
   352 		function split() {
       
   353 			each(grid, function(row, y) {
       
   354 				each(row, function(cell, x) {
       
   355 					var colSpan, rowSpan, i;
       
   356 
       
   357 					if (isCellSelected(cell)) {
       
   358 						cell = cell.elm;
       
   359 						colSpan = getSpanVal(cell, 'colspan');
       
   360 						rowSpan = getSpanVal(cell, 'rowspan');
       
   361 
       
   362 						if (colSpan > 1 || rowSpan > 1) {
       
   363 							setSpanVal(cell, 'rowSpan', 1);
       
   364 							setSpanVal(cell, 'colSpan', 1);
       
   365 
       
   366 							// Insert cells right
       
   367 							for (i = 0; i < colSpan - 1; i++) {
       
   368 								dom.insertAfter(cloneCell(cell), cell);
       
   369 							}
       
   370 
       
   371 							fillLeftDown(x, y, rowSpan - 1, colSpan);
       
   372 						}
       
   373 					}
       
   374 				});
       
   375 			});
       
   376 		}
       
   377 
       
   378 		function merge(cell, cols, rows) {
       
   379 			var pos, startX, startY, endX, endY, x, y, startCell, endCell, children, count;
       
   380 
       
   381 			// Use specified cell and cols/rows
       
   382 			if (cell) {
       
   383 				pos = getPos(cell);
       
   384 				startX = pos.x;
       
   385 				startY = pos.y;
       
   386 				endX = startX + (cols - 1);
       
   387 				endY = startY + (rows - 1);
       
   388 			} else {
       
   389 				startPos = endPos = null;
       
   390 
       
   391 				// Calculate start/end pos by checking for selected cells in grid works better with context menu
       
   392 				each(grid, function(row, y) {
       
   393 					each(row, function(cell, x) {
       
   394 						if (isCellSelected(cell)) {
       
   395 							if (!startPos) {
       
   396 								startPos = {x: x, y: y};
       
   397 							}
       
   398 
       
   399 							endPos = {x: x, y: y};
       
   400 						}
       
   401 					});
       
   402 				});
       
   403 
       
   404 				// Use selection, but make sure startPos is valid before accessing
       
   405 				if (startPos) {
       
   406 					startX = startPos.x;
       
   407 					startY = startPos.y;
       
   408 					endX = endPos.x;
       
   409 					endY = endPos.y;
       
   410 				}
       
   411 			}
       
   412 
       
   413 			// Find start/end cells
       
   414 			startCell = getCell(startX, startY);
       
   415 			endCell = getCell(endX, endY);
       
   416 
       
   417 			// Check if the cells exists and if they are of the same part for example tbody = tbody
       
   418 			if (startCell && endCell && startCell.part == endCell.part) {
       
   419 				// Split and rebuild grid
       
   420 				split();
       
   421 				buildGrid();
       
   422 
       
   423 				// Set row/col span to start cell
       
   424 				startCell = getCell(startX, startY).elm;
       
   425 				setSpanVal(startCell, 'colSpan', (endX - startX) + 1);
       
   426 				setSpanVal(startCell, 'rowSpan', (endY - startY) + 1);
       
   427 
       
   428 				// Remove other cells and add it's contents to the start cell
       
   429 				for (y = startY; y <= endY; y++) {
       
   430 					for (x = startX; x <= endX; x++) {
       
   431 						if (!grid[y] || !grid[y][x]) {
       
   432 							continue;
       
   433 						}
       
   434 
       
   435 						cell = grid[y][x].elm;
       
   436 
       
   437 						/*jshint loopfunc:true */
       
   438 						/*eslint no-loop-func:0 */
       
   439 						if (cell != startCell) {
       
   440 							// Move children to startCell
       
   441 							children = Tools.grep(cell.childNodes);
       
   442 							each(children, function(node) {
       
   443 								startCell.appendChild(node);
       
   444 							});
       
   445 
       
   446 							// Remove bogus nodes if there is children in the target cell
       
   447 							if (children.length) {
       
   448 								children = Tools.grep(startCell.childNodes);
       
   449 								count = 0;
       
   450 								each(children, function(node) {
       
   451 									if (node.nodeName == 'BR' && dom.getAttrib(node, 'data-mce-bogus') && count++ < children.length - 1) {
       
   452 										startCell.removeChild(node);
       
   453 									}
       
   454 								});
       
   455 							}
       
   456 
       
   457 							dom.remove(cell);
       
   458 						}
       
   459 					}
       
   460 				}
       
   461 
       
   462 				// Remove empty rows etc and restore caret location
       
   463 				cleanup();
       
   464 			}
       
   465 		}
       
   466 
       
   467 		function insertRow(before) {
       
   468 			var posY, cell, lastCell, x, rowElm, newRow, newCell, otherCell, rowSpan;
       
   469 
       
   470 			// Find first/last row
       
   471 			each(grid, function(row, y) {
       
   472 				each(row, function(cell) {
       
   473 					if (isCellSelected(cell)) {
       
   474 						cell = cell.elm;
       
   475 						rowElm = cell.parentNode;
       
   476 						newRow = cloneNode(rowElm, false);
       
   477 						posY = y;
       
   478 
       
   479 						if (before) {
       
   480 							return false;
       
   481 						}
       
   482 					}
       
   483 				});
       
   484 
       
   485 				if (before) {
       
   486 					return !posY;
       
   487 				}
       
   488 			});
       
   489 
       
   490 			// If posY is undefined there is nothing for us to do here...just return to avoid crashing below
       
   491 			if (posY === undefined) {
       
   492 				return;
       
   493 			}
       
   494 
       
   495 			for (x = 0; x < grid[0].length; x++) {
       
   496 				// Cell not found could be because of an invalid table structure
       
   497 				if (!grid[posY][x]) {
       
   498 					continue;
       
   499 				}
       
   500 
       
   501 				cell = grid[posY][x].elm;
       
   502 
       
   503 				if (cell != lastCell) {
       
   504 					if (!before) {
       
   505 						rowSpan = getSpanVal(cell, 'rowspan');
       
   506 						if (rowSpan > 1) {
       
   507 							setSpanVal(cell, 'rowSpan', rowSpan + 1);
       
   508 							continue;
       
   509 						}
       
   510 					} else {
       
   511 						// Check if cell above can be expanded
       
   512 						if (posY > 0 && grid[posY - 1][x]) {
       
   513 							otherCell = grid[posY - 1][x].elm;
       
   514 							rowSpan = getSpanVal(otherCell, 'rowSpan');
       
   515 							if (rowSpan > 1) {
       
   516 								setSpanVal(otherCell, 'rowSpan', rowSpan + 1);
       
   517 								continue;
       
   518 							}
       
   519 						}
       
   520 					}
       
   521 
       
   522 					// Insert new cell into new row
       
   523 					newCell = cloneCell(cell);
       
   524 					setSpanVal(newCell, 'colSpan', cell.colSpan);
       
   525 
       
   526 					newRow.appendChild(newCell);
       
   527 
       
   528 					lastCell = cell;
       
   529 				}
       
   530 			}
       
   531 
       
   532 			if (newRow.hasChildNodes()) {
       
   533 				if (!before) {
       
   534 					dom.insertAfter(newRow, rowElm);
       
   535 				} else {
       
   536 					rowElm.parentNode.insertBefore(newRow, rowElm);
       
   537 				}
       
   538 			}
       
   539 		}
       
   540 
       
   541 		function insertCol(before) {
       
   542 			var posX, lastCell;
       
   543 
       
   544 			// Find first/last column
       
   545 			each(grid, function(row) {
       
   546 				each(row, function(cell, x) {
       
   547 					if (isCellSelected(cell)) {
       
   548 						posX = x;
       
   549 
       
   550 						if (before) {
       
   551 							return false;
       
   552 						}
       
   553 					}
       
   554 				});
       
   555 
       
   556 				if (before) {
       
   557 					return !posX;
       
   558 				}
       
   559 			});
       
   560 
       
   561 			each(grid, function(row, y) {
       
   562 				var cell, rowSpan, colSpan;
       
   563 
       
   564 				if (!row[posX]) {
       
   565 					return;
       
   566 				}
       
   567 
       
   568 				cell = row[posX].elm;
       
   569 				if (cell != lastCell) {
       
   570 					colSpan = getSpanVal(cell, 'colspan');
       
   571 					rowSpan = getSpanVal(cell, 'rowspan');
       
   572 
       
   573 					if (colSpan == 1) {
       
   574 						if (!before) {
       
   575 							dom.insertAfter(cloneCell(cell), cell);
       
   576 							fillLeftDown(posX, y, rowSpan - 1, colSpan);
       
   577 						} else {
       
   578 							cell.parentNode.insertBefore(cloneCell(cell), cell);
       
   579 							fillLeftDown(posX, y, rowSpan - 1, colSpan);
       
   580 						}
       
   581 					} else {
       
   582 						setSpanVal(cell, 'colSpan', cell.colSpan + 1);
       
   583 					}
       
   584 
       
   585 					lastCell = cell;
       
   586 				}
       
   587 			});
       
   588 		}
       
   589 
       
   590 		function deleteCols() {
       
   591 			var cols = [];
       
   592 
       
   593 			// Get selected column indexes
       
   594 			each(grid, function(row) {
       
   595 				each(row, function(cell, x) {
       
   596 					if (isCellSelected(cell) && Tools.inArray(cols, x) === -1) {
       
   597 						each(grid, function(row) {
       
   598 							var cell = row[x].elm, colSpan;
       
   599 
       
   600 							colSpan = getSpanVal(cell, 'colSpan');
       
   601 
       
   602 							if (colSpan > 1) {
       
   603 								setSpanVal(cell, 'colSpan', colSpan - 1);
       
   604 							} else {
       
   605 								dom.remove(cell);
       
   606 							}
       
   607 						});
       
   608 
       
   609 						cols.push(x);
       
   610 					}
       
   611 				});
       
   612 			});
       
   613 
       
   614 			cleanup();
       
   615 		}
       
   616 
       
   617 		function deleteRows() {
       
   618 			var rows;
       
   619 
       
   620 			function deleteRow(tr) {
       
   621 				var pos, lastCell;
       
   622 
       
   623 				// Move down row spanned cells
       
   624 				each(tr.cells, function(cell) {
       
   625 					var rowSpan = getSpanVal(cell, 'rowSpan');
       
   626 
       
   627 					if (rowSpan > 1) {
       
   628 						setSpanVal(cell, 'rowSpan', rowSpan - 1);
       
   629 						pos = getPos(cell);
       
   630 						fillLeftDown(pos.x, pos.y, 1, 1);
       
   631 					}
       
   632 				});
       
   633 
       
   634 				// Delete cells
       
   635 				pos = getPos(tr.cells[0]);
       
   636 				each(grid[pos.y], function(cell) {
       
   637 					var rowSpan;
       
   638 
       
   639 					cell = cell.elm;
       
   640 
       
   641 					if (cell != lastCell) {
       
   642 						rowSpan = getSpanVal(cell, 'rowSpan');
       
   643 
       
   644 						if (rowSpan <= 1) {
       
   645 							dom.remove(cell);
       
   646 						} else {
       
   647 							setSpanVal(cell, 'rowSpan', rowSpan - 1);
       
   648 						}
       
   649 
       
   650 						lastCell = cell;
       
   651 					}
       
   652 				});
       
   653 			}
       
   654 
       
   655 			// Get selected rows and move selection out of scope
       
   656 			rows = getSelectedRows();
       
   657 
       
   658 			// Delete all selected rows
       
   659 			each(rows.reverse(), function(tr) {
       
   660 				deleteRow(tr);
       
   661 			});
       
   662 
       
   663 			cleanup();
       
   664 		}
       
   665 
       
   666 		function cutRows() {
       
   667 			var rows = getSelectedRows();
       
   668 
       
   669 			dom.remove(rows);
       
   670 			cleanup();
       
   671 
       
   672 			return rows;
       
   673 		}
       
   674 
       
   675 		function copyRows() {
       
   676 			var rows = getSelectedRows();
       
   677 
       
   678 			each(rows, function(row, i) {
       
   679 				rows[i] = cloneNode(row, true);
       
   680 			});
       
   681 
       
   682 			return rows;
       
   683 		}
       
   684 
       
   685 		function pasteRows(rows, before) {
       
   686 			var selectedRows = getSelectedRows(),
       
   687 				targetRow = selectedRows[before ? 0 : selectedRows.length - 1],
       
   688 				targetCellCount = targetRow.cells.length;
       
   689 
       
   690 			// Nothing to paste
       
   691 			if (!rows) {
       
   692 				return;
       
   693 			}
       
   694 
       
   695 			// Calc target cell count
       
   696 			each(grid, function(row) {
       
   697 				var match;
       
   698 
       
   699 				targetCellCount = 0;
       
   700 				each(row, function(cell) {
       
   701 					if (cell.real) {
       
   702 						targetCellCount += cell.colspan;
       
   703 					}
       
   704 
       
   705 					if (cell.elm.parentNode == targetRow) {
       
   706 						match = 1;
       
   707 					}
       
   708 				});
       
   709 
       
   710 				if (match) {
       
   711 					return false;
       
   712 				}
       
   713 			});
       
   714 
       
   715 			if (!before) {
       
   716 				rows.reverse();
       
   717 			}
       
   718 
       
   719 			each(rows, function(row) {
       
   720 				var i, cellCount = row.cells.length, cell;
       
   721 
       
   722 				// Remove col/rowspans
       
   723 				for (i = 0; i < cellCount; i++) {
       
   724 					cell = row.cells[i];
       
   725 					setSpanVal(cell, 'colSpan', 1);
       
   726 					setSpanVal(cell, 'rowSpan', 1);
       
   727 				}
       
   728 
       
   729 				// Needs more cells
       
   730 				for (i = cellCount; i < targetCellCount; i++) {
       
   731 					row.appendChild(cloneCell(row.cells[cellCount - 1]));
       
   732 				}
       
   733 
       
   734 				// Needs less cells
       
   735 				for (i = targetCellCount; i < cellCount; i++) {
       
   736 					dom.remove(row.cells[i]);
       
   737 				}
       
   738 
       
   739 				// Add before/after
       
   740 				if (before) {
       
   741 					targetRow.parentNode.insertBefore(row, targetRow);
       
   742 				} else {
       
   743 					dom.insertAfter(row, targetRow);
       
   744 				}
       
   745 			});
       
   746 
       
   747 			// Remove current selection
       
   748 			dom.removeClass(dom.select('td.mce-item-selected,th.mce-item-selected'), 'mce-item-selected');
       
   749 		}
       
   750 
       
   751 		function getPos(target) {
       
   752 			var pos;
       
   753 
       
   754 			each(grid, function(row, y) {
       
   755 				each(row, function(cell, x) {
       
   756 					if (cell.elm == target) {
       
   757 						pos = {x: x, y: y};
       
   758 						return false;
       
   759 					}
       
   760 				});
       
   761 
       
   762 				return !pos;
       
   763 			});
       
   764 
       
   765 			return pos;
       
   766 		}
       
   767 
       
   768 		function setStartCell(cell) {
       
   769 			startPos = getPos(cell);
       
   770 		}
       
   771 
       
   772 		function findEndPos() {
       
   773 			var maxX, maxY;
       
   774 
       
   775 			maxX = maxY = 0;
       
   776 
       
   777 			each(grid, function(row, y) {
       
   778 				each(row, function(cell, x) {
       
   779 					var colSpan, rowSpan;
       
   780 
       
   781 					if (isCellSelected(cell)) {
       
   782 						cell = grid[y][x];
       
   783 
       
   784 						if (x > maxX) {
       
   785 							maxX = x;
       
   786 						}
       
   787 
       
   788 						if (y > maxY) {
       
   789 							maxY = y;
       
   790 						}
       
   791 
       
   792 						if (cell.real) {
       
   793 							colSpan = cell.colspan - 1;
       
   794 							rowSpan = cell.rowspan - 1;
       
   795 
       
   796 							if (colSpan) {
       
   797 								if (x + colSpan > maxX) {
       
   798 									maxX = x + colSpan;
       
   799 								}
       
   800 							}
       
   801 
       
   802 							if (rowSpan) {
       
   803 								if (y + rowSpan > maxY) {
       
   804 									maxY = y + rowSpan;
       
   805 								}
       
   806 							}
       
   807 						}
       
   808 					}
       
   809 				});
       
   810 			});
       
   811 
       
   812 			return {x: maxX, y: maxY};
       
   813 		}
       
   814 
       
   815 		function setEndCell(cell) {
       
   816 			var startX, startY, endX, endY, maxX, maxY, colSpan, rowSpan, x, y;
       
   817 
       
   818 			endPos = getPos(cell);
       
   819 
       
   820 			if (startPos && endPos) {
       
   821 				// Get start/end positions
       
   822 				startX = Math.min(startPos.x, endPos.x);
       
   823 				startY = Math.min(startPos.y, endPos.y);
       
   824 				endX = Math.max(startPos.x, endPos.x);
       
   825 				endY = Math.max(startPos.y, endPos.y);
       
   826 
       
   827 				// Expand end positon to include spans
       
   828 				maxX = endX;
       
   829 				maxY = endY;
       
   830 
       
   831 				// Expand startX
       
   832 				for (y = startY; y <= maxY; y++) {
       
   833 					cell = grid[y][startX];
       
   834 
       
   835 					if (!cell.real) {
       
   836 						if (startX - (cell.colspan - 1) < startX) {
       
   837 							startX -= cell.colspan - 1;
       
   838 						}
       
   839 					}
       
   840 				}
       
   841 
       
   842 				// Expand startY
       
   843 				for (x = startX; x <= maxX; x++) {
       
   844 					cell = grid[startY][x];
       
   845 
       
   846 					if (!cell.real) {
       
   847 						if (startY - (cell.rowspan - 1) < startY) {
       
   848 							startY -= cell.rowspan - 1;
       
   849 						}
       
   850 					}
       
   851 				}
       
   852 
       
   853 				// Find max X, Y
       
   854 				for (y = startY; y <= endY; y++) {
       
   855 					for (x = startX; x <= endX; x++) {
       
   856 						cell = grid[y][x];
       
   857 
       
   858 						if (cell.real) {
       
   859 							colSpan = cell.colspan - 1;
       
   860 							rowSpan = cell.rowspan - 1;
       
   861 
       
   862 							if (colSpan) {
       
   863 								if (x + colSpan > maxX) {
       
   864 									maxX = x + colSpan;
       
   865 								}
       
   866 							}
       
   867 
       
   868 							if (rowSpan) {
       
   869 								if (y + rowSpan > maxY) {
       
   870 									maxY = y + rowSpan;
       
   871 								}
       
   872 							}
       
   873 						}
       
   874 					}
       
   875 				}
       
   876 
       
   877 				// Remove current selection
       
   878 				dom.removeClass(dom.select('td.mce-item-selected,th.mce-item-selected'), 'mce-item-selected');
       
   879 
       
   880 				// Add new selection
       
   881 				for (y = startY; y <= maxY; y++) {
       
   882 					for (x = startX; x <= maxX; x++) {
       
   883 						if (grid[y][x]) {
       
   884 							dom.addClass(grid[y][x].elm, 'mce-item-selected');
       
   885 						}
       
   886 					}
       
   887 				}
       
   888 			}
       
   889 		}
       
   890 
       
   891 		function moveRelIdx(cellElm, delta) {
       
   892 			var pos, index, cell;
       
   893 
       
   894 			pos = getPos(cellElm);
       
   895 			index = pos.y * gridWidth + pos.x;
       
   896 
       
   897 			do {
       
   898 				index += delta;
       
   899 				cell = getCell(index % gridWidth, Math.floor(index / gridWidth));
       
   900 
       
   901 				if (!cell) {
       
   902 					break;
       
   903 				}
       
   904 
       
   905 				if (cell.elm != cellElm) {
       
   906 					selection.select(cell.elm, true);
       
   907 
       
   908 					if (dom.isEmpty(cell.elm)) {
       
   909 						selection.collapse(true);
       
   910 					}
       
   911 
       
   912 					return true;
       
   913 				}
       
   914 			} while (cell.elm == cellElm);
       
   915 
       
   916 			return false;
       
   917 		}
       
   918 
       
   919 		table = table || dom.getParent(selection.getStart(), 'table');
       
   920 
       
   921 		buildGrid();
       
   922 
       
   923 		selectedCell = dom.getParent(selection.getStart(), 'th,td');
       
   924 		if (selectedCell) {
       
   925 			startPos = getPos(selectedCell);
       
   926 			endPos = findEndPos();
       
   927 			selectedCell = getCell(startPos.x, startPos.y);
       
   928 		}
       
   929 
       
   930 		Tools.extend(this, {
       
   931 			deleteTable: deleteTable,
       
   932 			split: split,
       
   933 			merge: merge,
       
   934 			insertRow: insertRow,
       
   935 			insertCol: insertCol,
       
   936 			deleteCols: deleteCols,
       
   937 			deleteRows: deleteRows,
       
   938 			cutRows: cutRows,
       
   939 			copyRows: copyRows,
       
   940 			pasteRows: pasteRows,
       
   941 			getPos: getPos,
       
   942 			setStartCell: setStartCell,
       
   943 			setEndCell: setEndCell,
       
   944 			moveRelIdx: moveRelIdx,
       
   945 			refresh: buildGrid
       
   946 		});
       
   947 	};
       
   948 });
       
   949 
       
   950 // Included from: js/tinymce/plugins/table/classes/Quirks.js
       
   951 
       
   952 /**
       
   953  * Quirks.js
       
   954  *
       
   955  * Copyright, Moxiecode Systems AB
       
   956  * Released under LGPL License.
       
   957  *
       
   958  * License: http://www.tinymce.com/license
       
   959  * Contributing: http://www.tinymce.com/contributing
       
   960  */
       
   961 
       
   962 /**
       
   963  * This class includes fixes for various browser quirks.
       
   964  *
       
   965  * @class tinymce.tableplugin.Quirks
       
   966  * @private
       
   967  */
       
   968 define("tinymce/tableplugin/Quirks", [
       
   969 	"tinymce/util/VK",
       
   970 	"tinymce/Env",
       
   971 	"tinymce/util/Tools"
       
   972 ], function(VK, Env, Tools) {
       
   973 	var each = Tools.each;
       
   974 
       
   975 	function getSpanVal(td, name) {
       
   976 		return parseInt(td.getAttribute(name) || 1, 10);
       
   977 	}
       
   978 
       
   979 	return function(editor) {
       
   980 		/**
       
   981 		 * Fixed caret movement around tables on WebKit.
       
   982 		 */
       
   983 		function moveWebKitSelection() {
       
   984 			function eventHandler(e) {
       
   985 				var key = e.keyCode;
       
   986 
       
   987 				function handle(upBool, sourceNode) {
       
   988 					var siblingDirection = upBool ? 'previousSibling' : 'nextSibling';
       
   989 					var currentRow = editor.dom.getParent(sourceNode, 'tr');
       
   990 					var siblingRow = currentRow[siblingDirection];
       
   991 
       
   992 					if (siblingRow) {
       
   993 						moveCursorToRow(editor, sourceNode, siblingRow, upBool);
       
   994 						e.preventDefault();
       
   995 						return true;
       
   996 					} else {
       
   997 						var tableNode = editor.dom.getParent(currentRow, 'table');
       
   998 						var middleNode = currentRow.parentNode;
       
   999 						var parentNodeName = middleNode.nodeName.toLowerCase();
       
  1000 						if (parentNodeName === 'tbody' || parentNodeName === (upBool ? 'tfoot' : 'thead')) {
       
  1001 							var targetParent = getTargetParent(upBool, tableNode, middleNode, 'tbody');
       
  1002 							if (targetParent !== null) {
       
  1003 								return moveToRowInTarget(upBool, targetParent, sourceNode);
       
  1004 							}
       
  1005 						}
       
  1006 						return escapeTable(upBool, currentRow, siblingDirection, tableNode);
       
  1007 					}
       
  1008 				}
       
  1009 
       
  1010 				function getTargetParent(upBool, topNode, secondNode, nodeName) {
       
  1011 					var tbodies = editor.dom.select('>' + nodeName, topNode);
       
  1012 					var position = tbodies.indexOf(secondNode);
       
  1013 					if (upBool && position === 0 || !upBool && position === tbodies.length - 1) {
       
  1014 						return getFirstHeadOrFoot(upBool, topNode);
       
  1015 					} else if (position === -1) {
       
  1016 						var topOrBottom = secondNode.tagName.toLowerCase() === 'thead' ? 0 : tbodies.length - 1;
       
  1017 						return tbodies[topOrBottom];
       
  1018 					} else {
       
  1019 						return tbodies[position + (upBool ? -1 : 1)];
       
  1020 					}
       
  1021 				}
       
  1022 
       
  1023 				function getFirstHeadOrFoot(upBool, parent) {
       
  1024 					var tagName = upBool ? 'thead' : 'tfoot';
       
  1025 					var headOrFoot = editor.dom.select('>' + tagName, parent);
       
  1026 					return headOrFoot.length !== 0 ? headOrFoot[0] : null;
       
  1027 				}
       
  1028 
       
  1029 				function moveToRowInTarget(upBool, targetParent, sourceNode) {
       
  1030 					var targetRow = getChildForDirection(targetParent, upBool);
       
  1031 
       
  1032 					if (targetRow) {
       
  1033 						moveCursorToRow(editor, sourceNode, targetRow, upBool);
       
  1034 					}
       
  1035 
       
  1036 					e.preventDefault();
       
  1037 					return true;
       
  1038 				}
       
  1039 
       
  1040 				function escapeTable(upBool, currentRow, siblingDirection, table) {
       
  1041 					var tableSibling = table[siblingDirection];
       
  1042 
       
  1043 					if (tableSibling) {
       
  1044 						moveCursorToStartOfElement(tableSibling);
       
  1045 						return true;
       
  1046 					} else {
       
  1047 						var parentCell = editor.dom.getParent(table, 'td,th');
       
  1048 						if (parentCell) {
       
  1049 							return handle(upBool, parentCell, e);
       
  1050 						} else {
       
  1051 							var backUpSibling = getChildForDirection(currentRow, !upBool);
       
  1052 							moveCursorToStartOfElement(backUpSibling);
       
  1053 							e.preventDefault();
       
  1054 							return false;
       
  1055 						}
       
  1056 					}
       
  1057 				}
       
  1058 
       
  1059 				function getChildForDirection(parent, up) {
       
  1060 					var child = parent && parent[up ? 'lastChild' : 'firstChild'];
       
  1061 					// BR is not a valid table child to return in this case we return the table cell
       
  1062 					return child && child.nodeName === 'BR' ? editor.dom.getParent(child, 'td,th') : child;
       
  1063 				}
       
  1064 
       
  1065 				function moveCursorToStartOfElement(n) {
       
  1066 					editor.selection.setCursorLocation(n, 0);
       
  1067 				}
       
  1068 
       
  1069 				function isVerticalMovement() {
       
  1070 					return key == VK.UP || key == VK.DOWN;
       
  1071 				}
       
  1072 
       
  1073 				function isInTable(editor) {
       
  1074 					var node = editor.selection.getNode();
       
  1075 					var currentRow = editor.dom.getParent(node, 'tr');
       
  1076 					return currentRow !== null;
       
  1077 				}
       
  1078 
       
  1079 				function columnIndex(column) {
       
  1080 					var colIndex = 0;
       
  1081 					var c = column;
       
  1082 					while (c.previousSibling) {
       
  1083 						c = c.previousSibling;
       
  1084 						colIndex = colIndex + getSpanVal(c, "colspan");
       
  1085 					}
       
  1086 					return colIndex;
       
  1087 				}
       
  1088 
       
  1089 				function findColumn(rowElement, columnIndex) {
       
  1090 					var c = 0, r = 0;
       
  1091 
       
  1092 					each(rowElement.children, function(cell, i) {
       
  1093 						c = c + getSpanVal(cell, "colspan");
       
  1094 						r = i;
       
  1095 						if (c > columnIndex) {
       
  1096 							return false;
       
  1097 						}
       
  1098 					});
       
  1099 					return r;
       
  1100 				}
       
  1101 
       
  1102 				function moveCursorToRow(ed, node, row, upBool) {
       
  1103 					var srcColumnIndex = columnIndex(editor.dom.getParent(node, 'td,th'));
       
  1104 					var tgtColumnIndex = findColumn(row, srcColumnIndex);
       
  1105 					var tgtNode = row.childNodes[tgtColumnIndex];
       
  1106 					var rowCellTarget = getChildForDirection(tgtNode, upBool);
       
  1107 					moveCursorToStartOfElement(rowCellTarget || tgtNode);
       
  1108 				}
       
  1109 
       
  1110 				function shouldFixCaret(preBrowserNode) {
       
  1111 					var newNode = editor.selection.getNode();
       
  1112 					var newParent = editor.dom.getParent(newNode, 'td,th');
       
  1113 					var oldParent = editor.dom.getParent(preBrowserNode, 'td,th');
       
  1114 
       
  1115 					return newParent && newParent !== oldParent && checkSameParentTable(newParent, oldParent);
       
  1116 				}
       
  1117 
       
  1118 				function checkSameParentTable(nodeOne, NodeTwo) {
       
  1119 					return editor.dom.getParent(nodeOne, 'TABLE') === editor.dom.getParent(NodeTwo, 'TABLE');
       
  1120 				}
       
  1121 
       
  1122 				if (isVerticalMovement() && isInTable(editor)) {
       
  1123 					var preBrowserNode = editor.selection.getNode();
       
  1124 					setTimeout(function() {
       
  1125 						if (shouldFixCaret(preBrowserNode)) {
       
  1126 							handle(!e.shiftKey && key === VK.UP, preBrowserNode, e);
       
  1127 						}
       
  1128 					}, 0);
       
  1129 				}
       
  1130 			}
       
  1131 
       
  1132 			editor.on('KeyDown', function(e) {
       
  1133 				eventHandler(e);
       
  1134 			});
       
  1135 		}
       
  1136 
       
  1137 		function fixBeforeTableCaretBug() {
       
  1138 			// Checks if the selection/caret is at the start of the specified block element
       
  1139 			function isAtStart(rng, par) {
       
  1140 				var doc = par.ownerDocument, rng2 = doc.createRange(), elm;
       
  1141 
       
  1142 				rng2.setStartBefore(par);
       
  1143 				rng2.setEnd(rng.endContainer, rng.endOffset);
       
  1144 
       
  1145 				elm = doc.createElement('body');
       
  1146 				elm.appendChild(rng2.cloneContents());
       
  1147 
       
  1148 				// Check for text characters of other elements that should be treated as content
       
  1149 				return elm.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi, '-').replace(/<[^>]+>/g, '').length === 0;
       
  1150 			}
       
  1151 
       
  1152 			// Fixes an bug where it's impossible to place the caret before a table in Gecko
       
  1153 			// this fix solves it by detecting when the caret is at the beginning of such a table
       
  1154 			// and then manually moves the caret infront of the table
       
  1155 			editor.on('KeyDown', function(e) {
       
  1156 				var rng, table, dom = editor.dom;
       
  1157 
       
  1158 				// On gecko it's not possible to place the caret before a table
       
  1159 				if (e.keyCode == 37 || e.keyCode == 38) {
       
  1160 					rng = editor.selection.getRng();
       
  1161 					table = dom.getParent(rng.startContainer, 'table');
       
  1162 
       
  1163 					if (table && editor.getBody().firstChild == table) {
       
  1164 						if (isAtStart(rng, table)) {
       
  1165 							rng = dom.createRng();
       
  1166 
       
  1167 							rng.setStartBefore(table);
       
  1168 							rng.setEndBefore(table);
       
  1169 
       
  1170 							editor.selection.setRng(rng);
       
  1171 
       
  1172 							e.preventDefault();
       
  1173 						}
       
  1174 					}
       
  1175 				}
       
  1176 			});
       
  1177 		}
       
  1178 
       
  1179 		// Fixes an issue on Gecko where it's impossible to place the caret behind a table
       
  1180 		// This fix will force a paragraph element after the table but only when the forced_root_block setting is enabled
       
  1181 		function fixTableCaretPos() {
       
  1182 			editor.on('KeyDown SetContent VisualAid', function() {
       
  1183 				var last;
       
  1184 
       
  1185 				// Skip empty text nodes from the end
       
  1186 				for (last = editor.getBody().lastChild; last; last = last.previousSibling) {
       
  1187 					if (last.nodeType == 3) {
       
  1188 						if (last.nodeValue.length > 0) {
       
  1189 							break;
       
  1190 						}
       
  1191 					} else if (last.nodeType == 1 && (last.tagName == 'BR' || !last.getAttribute('data-mce-bogus'))) {
       
  1192 						break;
       
  1193 					}
       
  1194 				}
       
  1195 
       
  1196 				if (last && last.nodeName == 'TABLE') {
       
  1197 					if (editor.settings.forced_root_block) {
       
  1198 						editor.dom.add(
       
  1199 							editor.getBody(),
       
  1200 							editor.settings.forced_root_block,
       
  1201 							editor.settings.forced_root_block_attrs,
       
  1202 							Env.ie && Env.ie < 11 ? '&nbsp;' : '<br data-mce-bogus="1" />'
       
  1203 						);
       
  1204 					} else {
       
  1205 						editor.dom.add(editor.getBody(), 'br', {'data-mce-bogus': '1'});
       
  1206 					}
       
  1207 				}
       
  1208 			});
       
  1209 
       
  1210 			editor.on('PreProcess', function(o) {
       
  1211 				var last = o.node.lastChild;
       
  1212 
       
  1213 				if (last && (last.nodeName == "BR" || (last.childNodes.length == 1 &&
       
  1214 					(last.firstChild.nodeName == 'BR' || last.firstChild.nodeValue == '\u00a0'))) &&
       
  1215 					last.previousSibling && last.previousSibling.nodeName == "TABLE") {
       
  1216 					editor.dom.remove(last);
       
  1217 				}
       
  1218 			});
       
  1219 		}
       
  1220 
       
  1221 		// this nasty hack is here to work around some WebKit selection bugs.
       
  1222 		function fixTableCellSelection() {
       
  1223 			function tableCellSelected(ed, rng, n, currentCell) {
       
  1224 				// The decision of when a table cell is selected is somewhat involved.  The fact that this code is
       
  1225 				// required is actually a pointer to the root cause of this bug. A cell is selected when the start
       
  1226 				// and end offsets are 0, the start container is a text, and the selection node is either a TR (most cases)
       
  1227 				// or the parent of the table (in the case of the selection containing the last cell of a table).
       
  1228 				var TEXT_NODE = 3, table = ed.dom.getParent(rng.startContainer, 'TABLE');
       
  1229 				var tableParent, allOfCellSelected, tableCellSelection;
       
  1230 
       
  1231 				if (table) {
       
  1232 					tableParent = table.parentNode;
       
  1233 				}
       
  1234 
       
  1235 				allOfCellSelected = rng.startContainer.nodeType == TEXT_NODE &&
       
  1236 					rng.startOffset === 0 &&
       
  1237 					rng.endOffset === 0 &&
       
  1238 					currentCell &&
       
  1239 					(n.nodeName == "TR" || n == tableParent);
       
  1240 
       
  1241 				tableCellSelection = (n.nodeName == "TD" || n.nodeName == "TH") && !currentCell;
       
  1242 
       
  1243 				return allOfCellSelected || tableCellSelection;
       
  1244 			}
       
  1245 
       
  1246 			function fixSelection() {
       
  1247 				var rng = editor.selection.getRng();
       
  1248 				var n = editor.selection.getNode();
       
  1249 				var currentCell = editor.dom.getParent(rng.startContainer, 'TD,TH');
       
  1250 
       
  1251 				if (!tableCellSelected(editor, rng, n, currentCell)) {
       
  1252 					return;
       
  1253 				}
       
  1254 
       
  1255 				if (!currentCell) {
       
  1256 					currentCell = n;
       
  1257 				}
       
  1258 
       
  1259 				// Get the very last node inside the table cell
       
  1260 				var end = currentCell.lastChild;
       
  1261 				while (end.lastChild) {
       
  1262 					end = end.lastChild;
       
  1263 				}
       
  1264 
       
  1265 				// Select the entire table cell. Nothing outside of the table cell should be selected.
       
  1266 				if (end.nodeType == 3) {
       
  1267 					rng.setEnd(end, end.data.length);
       
  1268 					editor.selection.setRng(rng);
       
  1269 				}
       
  1270 			}
       
  1271 
       
  1272 			editor.on('KeyDown', function() {
       
  1273 				fixSelection();
       
  1274 			});
       
  1275 
       
  1276 			editor.on('MouseDown', function(e) {
       
  1277 				if (e.button != 2) {
       
  1278 					fixSelection();
       
  1279 				}
       
  1280 			});
       
  1281 		}
       
  1282 
       
  1283 		/**
       
  1284 		 * Delete table if all cells are selected.
       
  1285 		 */
       
  1286 		function deleteTable() {
       
  1287 			editor.on('keydown', function(e) {
       
  1288 				if ((e.keyCode == VK.DELETE || e.keyCode == VK.BACKSPACE) && !e.isDefaultPrevented()) {
       
  1289 					var table = editor.dom.getParent(editor.selection.getStart(), 'table');
       
  1290 
       
  1291 					if (table) {
       
  1292 						var cells = editor.dom.select('td,th', table), i = cells.length;
       
  1293 						while (i--) {
       
  1294 							if (!editor.dom.hasClass(cells[i], 'mce-item-selected')) {
       
  1295 								return;
       
  1296 							}
       
  1297 						}
       
  1298 
       
  1299 						e.preventDefault();
       
  1300 						editor.execCommand('mceTableDelete');
       
  1301 					}
       
  1302 				}
       
  1303 			});
       
  1304 		}
       
  1305 
       
  1306 		deleteTable();
       
  1307 
       
  1308 		if (Env.webkit) {
       
  1309 			moveWebKitSelection();
       
  1310 			fixTableCellSelection();
       
  1311 		}
       
  1312 
       
  1313 		if (Env.gecko) {
       
  1314 			fixBeforeTableCaretBug();
       
  1315 			fixTableCaretPos();
       
  1316 		}
       
  1317 
       
  1318 		if (Env.ie > 10) {
       
  1319 			fixBeforeTableCaretBug();
       
  1320 			fixTableCaretPos();
       
  1321 		}
       
  1322 	};
       
  1323 });
       
  1324 
       
  1325 // Included from: js/tinymce/plugins/table/classes/CellSelection.js
       
  1326 
       
  1327 /**
       
  1328  * CellSelection.js
       
  1329  *
       
  1330  * Copyright, Moxiecode Systems AB
       
  1331  * Released under LGPL License.
       
  1332  *
       
  1333  * License: http://www.tinymce.com/license
       
  1334  * Contributing: http://www.tinymce.com/contributing
       
  1335  */
       
  1336 
       
  1337 /**
       
  1338  * This class handles table cell selection by faking it using a css class that gets applied
       
  1339  * to cells when dragging the mouse from one cell to another.
       
  1340  *
       
  1341  * @class tinymce.tableplugin.CellSelection
       
  1342  * @private
       
  1343  */
       
  1344 define("tinymce/tableplugin/CellSelection", [
       
  1345 	"tinymce/tableplugin/TableGrid",
       
  1346 	"tinymce/dom/TreeWalker",
       
  1347 	"tinymce/util/Tools"
       
  1348 ], function(TableGrid, TreeWalker, Tools) {
       
  1349 	return function(editor) {
       
  1350 		var dom = editor.dom, tableGrid, startCell, startTable, hasCellSelection = true, resizing;
       
  1351 
       
  1352 		function clear(force) {
       
  1353 			// Restore selection possibilities
       
  1354 			editor.getBody().style.webkitUserSelect = '';
       
  1355 
       
  1356 			if (force || hasCellSelection) {
       
  1357 				editor.dom.removeClass(
       
  1358 					editor.dom.select('td.mce-item-selected,th.mce-item-selected'),
       
  1359 					'mce-item-selected'
       
  1360 				);
       
  1361 
       
  1362 				hasCellSelection = false;
       
  1363 			}
       
  1364 		}
       
  1365 
       
  1366 		function cellSelectionHandler(e) {
       
  1367 			var sel, table, target = e.target;
       
  1368 
       
  1369 			if (resizing) {
       
  1370 				return;
       
  1371 			}
       
  1372 
       
  1373 			if (startCell && (tableGrid || target != startCell) && (target.nodeName == 'TD' || target.nodeName == 'TH')) {
       
  1374 				table = dom.getParent(target, 'table');
       
  1375 				if (table == startTable) {
       
  1376 					if (!tableGrid) {
       
  1377 						tableGrid = new TableGrid(editor, table);
       
  1378 						tableGrid.setStartCell(startCell);
       
  1379 
       
  1380 						editor.getBody().style.webkitUserSelect = 'none';
       
  1381 					}
       
  1382 
       
  1383 					tableGrid.setEndCell(target);
       
  1384 					hasCellSelection = true;
       
  1385 				}
       
  1386 
       
  1387 				// Remove current selection
       
  1388 				sel = editor.selection.getSel();
       
  1389 
       
  1390 				try {
       
  1391 					if (sel.removeAllRanges) {
       
  1392 						sel.removeAllRanges();
       
  1393 					} else {
       
  1394 						sel.empty();
       
  1395 					}
       
  1396 				} catch (ex) {
       
  1397 					// IE9 might throw errors here
       
  1398 				}
       
  1399 
       
  1400 				e.preventDefault();
       
  1401 			}
       
  1402 		}
       
  1403 
       
  1404 		// Add cell selection logic
       
  1405 		editor.on('MouseDown', function(e) {
       
  1406 			if (e.button != 2 && !resizing) {
       
  1407 				clear();
       
  1408 
       
  1409 				startCell = dom.getParent(e.target, 'td,th');
       
  1410 				startTable = dom.getParent(startCell, 'table');
       
  1411 			}
       
  1412 		});
       
  1413 
       
  1414 		editor.on('mouseover', cellSelectionHandler);
       
  1415 
       
  1416 		editor.on('remove', function() {
       
  1417 			dom.unbind(editor.getDoc(), 'mouseover', cellSelectionHandler);
       
  1418 		});
       
  1419 
       
  1420 		editor.on('MouseUp', function() {
       
  1421 			var rng, sel = editor.selection, selectedCells, walker, node, lastNode;
       
  1422 
       
  1423 			function setPoint(node, start) {
       
  1424 				var walker = new TreeWalker(node, node);
       
  1425 
       
  1426 				do {
       
  1427 					// Text node
       
  1428 					if (node.nodeType == 3 && Tools.trim(node.nodeValue).length !== 0) {
       
  1429 						if (start) {
       
  1430 							rng.setStart(node, 0);
       
  1431 						} else {
       
  1432 							rng.setEnd(node, node.nodeValue.length);
       
  1433 						}
       
  1434 
       
  1435 						return;
       
  1436 					}
       
  1437 
       
  1438 					// BR element
       
  1439 					if (node.nodeName == 'BR') {
       
  1440 						if (start) {
       
  1441 							rng.setStartBefore(node);
       
  1442 						} else {
       
  1443 							rng.setEndBefore(node);
       
  1444 						}
       
  1445 
       
  1446 						return;
       
  1447 					}
       
  1448 				} while ((node = (start ? walker.next() : walker.prev())));
       
  1449 			}
       
  1450 
       
  1451 			// Move selection to startCell
       
  1452 			if (startCell) {
       
  1453 				if (tableGrid) {
       
  1454 					editor.getBody().style.webkitUserSelect = '';
       
  1455 				}
       
  1456 
       
  1457 				// Try to expand text selection as much as we can only Gecko supports cell selection
       
  1458 				selectedCells = dom.select('td.mce-item-selected,th.mce-item-selected');
       
  1459 				if (selectedCells.length > 0) {
       
  1460 					rng = dom.createRng();
       
  1461 					node = selectedCells[0];
       
  1462 					rng.setStartBefore(node);
       
  1463 					rng.setEndAfter(node);
       
  1464 
       
  1465 					setPoint(node, 1);
       
  1466 					walker = new TreeWalker(node, dom.getParent(selectedCells[0], 'table'));
       
  1467 
       
  1468 					do {
       
  1469 						if (node.nodeName == 'TD' || node.nodeName == 'TH') {
       
  1470 							if (!dom.hasClass(node, 'mce-item-selected')) {
       
  1471 								break;
       
  1472 							}
       
  1473 
       
  1474 							lastNode = node;
       
  1475 						}
       
  1476 					} while ((node = walker.next()));
       
  1477 
       
  1478 					setPoint(lastNode);
       
  1479 
       
  1480 					sel.setRng(rng);
       
  1481 				}
       
  1482 
       
  1483 				editor.nodeChanged();
       
  1484 				startCell = tableGrid = startTable = null;
       
  1485 			}
       
  1486 		});
       
  1487 
       
  1488 		editor.on('KeyUp Drop SetContent', function(e) {
       
  1489 			clear(e.type == 'setcontent');
       
  1490 			startCell = tableGrid = startTable = null;
       
  1491 			resizing = false;
       
  1492 		});
       
  1493 
       
  1494 		editor.on('ObjectResizeStart ObjectResized', function(e) {
       
  1495 			resizing = e.type != 'objectresized';
       
  1496 		});
       
  1497 
       
  1498 		return {
       
  1499 			clear: clear
       
  1500 		};
       
  1501 	};
       
  1502 });
       
  1503 
       
  1504 // Included from: js/tinymce/plugins/table/classes/Dialogs.js
       
  1505 
       
  1506 /**
       
  1507  * Dialogs.js
       
  1508  *
       
  1509  * Copyright, Moxiecode Systems AB
       
  1510  * Released under LGPL License.
       
  1511  *
       
  1512  * License: http://www.tinymce.com/license
       
  1513  * Contributing: http://www.tinymce.com/contributing
       
  1514  */
       
  1515 
       
  1516 /*eslint dot-notation:0*/
       
  1517 
       
  1518 /**
       
  1519  * ...
       
  1520  *
       
  1521  * @class tinymce.tableplugin.Dialogs
       
  1522  * @private
       
  1523  */
       
  1524 define("tinymce/tableplugin/Dialogs", [
       
  1525 	"tinymce/util/Tools",
       
  1526 	"tinymce/Env"
       
  1527 ], function(Tools, Env) {
       
  1528 	var each = Tools.each;
       
  1529 
       
  1530 	return function(editor) {
       
  1531 		var self = this;
       
  1532 
       
  1533 		function createColorPickAction() {
       
  1534 			var colorPickerCallback = editor.settings.color_picker_callback;
       
  1535 
       
  1536 			if (colorPickerCallback) {
       
  1537 				return function() {
       
  1538 					var self = this;
       
  1539 
       
  1540 					colorPickerCallback.call(
       
  1541 						editor,
       
  1542 						function(value) {
       
  1543 							self.value(value).fire('change');
       
  1544 						},
       
  1545 						self.value()
       
  1546 					);
       
  1547 				};
       
  1548 			}
       
  1549 		}
       
  1550 
       
  1551 		function createStyleForm(dom) {
       
  1552 			return {
       
  1553 				title: 'Advanced',
       
  1554 				type: 'form',
       
  1555 				defaults: {
       
  1556 					onchange: function() {
       
  1557 						updateStyle(dom, this.parents().reverse()[0], this.name() == "style");
       
  1558 					}
       
  1559 				},
       
  1560 				items: [
       
  1561 					{
       
  1562 						label: 'Style',
       
  1563 						name: 'style',
       
  1564 						type: 'textbox'
       
  1565 					},
       
  1566 
       
  1567 					{
       
  1568 						type: 'form',
       
  1569 						padding: 0,
       
  1570 						formItemDefaults: {
       
  1571 							layout: 'grid',
       
  1572 							alignH: ['start', 'right']
       
  1573 						},
       
  1574 						defaults: {
       
  1575 							size: 7
       
  1576 						},
       
  1577 						items: [
       
  1578 							{
       
  1579 								label: 'Border color',
       
  1580 								type: 'colorbox',
       
  1581 								name: 'borderColor',
       
  1582 								onaction: createColorPickAction()
       
  1583 							},
       
  1584 
       
  1585 							{
       
  1586 								label: 'Background color',
       
  1587 								type: 'colorbox',
       
  1588 								name: 'backgroundColor',
       
  1589 								onaction: createColorPickAction()
       
  1590 							}
       
  1591 						]
       
  1592 					}
       
  1593 				]
       
  1594 			};
       
  1595 		}
       
  1596 
       
  1597 		function removePxSuffix(size) {
       
  1598 			return size ? size.replace(/px$/, '') : "";
       
  1599 		}
       
  1600 
       
  1601 		function addSizeSuffix(size) {
       
  1602 			if (/^[0-9]+$/.test(size)) {
       
  1603 				size += "px";
       
  1604 			}
       
  1605 
       
  1606 			return size;
       
  1607 		}
       
  1608 
       
  1609 		function unApplyAlign(elm) {
       
  1610 			each('left center right'.split(' '), function(name) {
       
  1611 				editor.formatter.remove('align' + name, {}, elm);
       
  1612 			});
       
  1613 		}
       
  1614 
       
  1615 		function unApplyVAlign(elm) {
       
  1616 			each('top middle bottom'.split(' '), function(name) {
       
  1617 				editor.formatter.remove('valign' + name, {}, elm);
       
  1618 			});
       
  1619 		}
       
  1620 
       
  1621 		function buildListItems(inputList, itemCallback, startItems) {
       
  1622 			function appendItems(values, output) {
       
  1623 				output = output || [];
       
  1624 
       
  1625 				Tools.each(values, function(item) {
       
  1626 					var menuItem = {text: item.text || item.title};
       
  1627 
       
  1628 					if (item.menu) {
       
  1629 						menuItem.menu = appendItems(item.menu);
       
  1630 					} else {
       
  1631 						menuItem.value = item.value;
       
  1632 
       
  1633 						if (itemCallback) {
       
  1634 							itemCallback(menuItem);
       
  1635 						}
       
  1636 					}
       
  1637 
       
  1638 					output.push(menuItem);
       
  1639 				});
       
  1640 
       
  1641 				return output;
       
  1642 			}
       
  1643 
       
  1644 			return appendItems(inputList, startItems || []);
       
  1645 		}
       
  1646 
       
  1647 		function updateStyle(dom, win, isStyleCtrl) {
       
  1648 			var data = win.toJSON();
       
  1649 			var css = dom.parseStyle(data.style);
       
  1650 
       
  1651 			if (isStyleCtrl) {
       
  1652 				win.find('#borderColor').value(css["border-color"] || '')[0].fire('change');
       
  1653 				win.find('#backgroundColor').value(css["background-color"] || '')[0].fire('change');
       
  1654 			} else {
       
  1655 				css["border-color"] = data.borderColor;
       
  1656 				css["background-color"] = data.backgroundColor;
       
  1657 			}
       
  1658 
       
  1659 			win.find('#style').value(dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
       
  1660 		}
       
  1661 
       
  1662 		function appendStylesToData(dom, data, elm) {
       
  1663 			var css = dom.parseStyle(dom.getAttrib(elm, 'style'));
       
  1664 
       
  1665 			if (css["border-color"]) {
       
  1666 				data.borderColor = css["border-color"];
       
  1667 			}
       
  1668 
       
  1669 			if (css["background-color"]) {
       
  1670 				data.backgroundColor = css["background-color"];
       
  1671 			}
       
  1672 
       
  1673 			data.style = dom.serializeStyle(css);
       
  1674 		}
       
  1675 
       
  1676 		function mergeStyles(dom, elm, styles) {
       
  1677 			var css = dom.parseStyle(dom.getAttrib(elm, 'style'));
       
  1678 
       
  1679 			each(styles, function(style) {
       
  1680 				css[style.name] = style.value;
       
  1681 			});
       
  1682 
       
  1683 			dom.setAttrib(elm, 'style', dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
       
  1684 		}
       
  1685 
       
  1686 		self.tableProps = function() {
       
  1687 			self.table(true);
       
  1688 		};
       
  1689 
       
  1690 		self.table = function(isProps) {
       
  1691 			var dom = editor.dom, tableElm, colsCtrl, rowsCtrl, classListCtrl, data = {}, generalTableForm, stylesToMerge;
       
  1692 
       
  1693 			function onSubmitTableForm() {
       
  1694 
       
  1695 				//Explore the layers of the table till we find the first layer of tds or ths
       
  1696 				function styleTDTH (elm, name, value) {
       
  1697 					if (elm.tagName === "TD" || elm.tagName === "TH") {
       
  1698 						dom.setStyle(elm, name, value);
       
  1699 					} else {
       
  1700 						if (elm.children) {
       
  1701 							for (var i = 0; i < elm.children.length; i++) {
       
  1702 								styleTDTH(elm.children[i], name, value);
       
  1703 							}
       
  1704 						}
       
  1705 					}
       
  1706 				}
       
  1707 
       
  1708 				var captionElm;
       
  1709 
       
  1710 				updateStyle(dom, this);
       
  1711 				data = Tools.extend(data, this.toJSON());
       
  1712 
       
  1713 				if (data["class"] === false) {
       
  1714 					delete data["class"];
       
  1715 				}
       
  1716 
       
  1717 				editor.undoManager.transact(function() {
       
  1718 					if (!tableElm) {
       
  1719 						tableElm = editor.plugins.table.insertTable(data.cols || 1, data.rows || 1);
       
  1720 					}
       
  1721 
       
  1722 					editor.dom.setAttribs(tableElm, {
       
  1723 						style: data.style,
       
  1724 						'class': data['class']
       
  1725 					});
       
  1726 
       
  1727 					if (editor.settings.table_style_by_css) {
       
  1728 						stylesToMerge = [];
       
  1729 						stylesToMerge.push({name: 'border', value: data.border});
       
  1730 						stylesToMerge.push({name: 'border-spacing', value: addSizeSuffix(data.cellspacing)});
       
  1731 						mergeStyles(dom, tableElm, stylesToMerge);
       
  1732 						dom.setAttribs(tableElm, {
       
  1733 							'data-mce-border-color': data.borderColor,
       
  1734 							'data-mce-cell-padding': data.cellpadding,
       
  1735 							'data-mce-border': data.border
       
  1736 						});
       
  1737 						if (tableElm.children) {
       
  1738 							for (var i = 0; i < tableElm.children.length; i++) {
       
  1739 								styleTDTH(tableElm.children[i], 'border', data.border);
       
  1740 								styleTDTH(tableElm.children[i], 'padding', addSizeSuffix(data.cellpadding));
       
  1741 							}
       
  1742 						}
       
  1743 					} else {
       
  1744 						editor.dom.setAttribs(tableElm, {
       
  1745 							border: data.border,
       
  1746 							cellpadding: data.cellpadding,
       
  1747 							cellspacing: data.cellspacing
       
  1748 						});
       
  1749 					}
       
  1750 
       
  1751 					if (dom.getAttrib(tableElm, 'width') && !editor.settings.table_style_by_css) {
       
  1752 						dom.setAttrib(tableElm, 'width', removePxSuffix(data.width));
       
  1753 					} else {
       
  1754 						dom.setStyle(tableElm, 'width', addSizeSuffix(data.width));
       
  1755 					}
       
  1756 
       
  1757 					dom.setStyle(tableElm, 'height', addSizeSuffix(data.height));
       
  1758 
       
  1759 					// Toggle caption on/off
       
  1760 					captionElm = dom.select('caption', tableElm)[0];
       
  1761 
       
  1762 					if (captionElm && !data.caption) {
       
  1763 						dom.remove(captionElm);
       
  1764 					}
       
  1765 
       
  1766 					if (!captionElm && data.caption) {
       
  1767 						captionElm = dom.create('caption');
       
  1768 						captionElm.innerHTML = !Env.ie ? '<br data-mce-bogus="1"/>' : '\u00a0';
       
  1769 						tableElm.insertBefore(captionElm, tableElm.firstChild);
       
  1770 					}
       
  1771 					unApplyAlign(tableElm);
       
  1772 					if (data.align) {
       
  1773 						editor.formatter.apply('align' + data.align, {}, tableElm);
       
  1774 					}
       
  1775 
       
  1776 					editor.focus();
       
  1777 					editor.addVisual();
       
  1778 				});
       
  1779 			}
       
  1780 
       
  1781 			function getTDTHOverallStyle (elm, name) {
       
  1782 				var cells = editor.dom.select("td,th", elm), firstChildStyle;
       
  1783 
       
  1784 				function checkChildren(firstChildStyle, elms) {
       
  1785 
       
  1786 					for (var i = 0; i < elms.length; i++) {
       
  1787 						var currentStyle = dom.getStyle(elms[i], name);
       
  1788 						if (typeof firstChildStyle === "undefined") {
       
  1789 							firstChildStyle = currentStyle;
       
  1790 						}
       
  1791 						if (firstChildStyle != currentStyle) {
       
  1792 							return "";
       
  1793 						}
       
  1794 					}
       
  1795 
       
  1796 					return firstChildStyle;
       
  1797 
       
  1798 				}
       
  1799 
       
  1800 				firstChildStyle = checkChildren(firstChildStyle, cells);
       
  1801 
       
  1802 				return firstChildStyle;
       
  1803 			}
       
  1804 
       
  1805 			if (isProps === true) {
       
  1806 				tableElm = dom.getParent(editor.selection.getStart(), 'table');
       
  1807 
       
  1808 				if (tableElm) {
       
  1809 					data = {
       
  1810 						width: removePxSuffix(dom.getStyle(tableElm, 'width') || dom.getAttrib(tableElm, 'width')),
       
  1811 						height: removePxSuffix(dom.getStyle(tableElm, 'height') || dom.getAttrib(tableElm, 'height')),
       
  1812 						cellspacing: removePxSuffix(dom.getStyle(tableElm, 'border-spacing') ||
       
  1813 							dom.getAttrib(tableElm, 'cellspacing')),
       
  1814 						cellpadding: dom.getAttrib(tableElm, 'data-mce-cell-padding') || dom.getAttrib(tableElm, 'cellpadding') ||
       
  1815 							getTDTHOverallStyle(tableElm, 'padding'),
       
  1816 						border: dom.getAttrib(tableElm, 'data-mce-border') || dom.getAttrib(tableElm, 'border') ||
       
  1817 							getTDTHOverallStyle(tableElm, 'border'),
       
  1818 						borderColor: dom.getAttrib(tableElm, 'data-mce-border-color'),
       
  1819 						caption: !!dom.select('caption', tableElm)[0],
       
  1820 						'class': dom.getAttrib(tableElm, 'class')
       
  1821 					};
       
  1822 
       
  1823 					each('left center right'.split(' '), function(name) {
       
  1824 						if (editor.formatter.matchNode(tableElm, 'align' + name)) {
       
  1825 							data.align = name;
       
  1826 						}
       
  1827 					});
       
  1828 				}
       
  1829 			} else {
       
  1830 				colsCtrl = {label: 'Cols', name: 'cols'};
       
  1831 				rowsCtrl = {label: 'Rows', name: 'rows'};
       
  1832 			}
       
  1833 
       
  1834 			if (editor.settings.table_class_list) {
       
  1835 				if (data["class"]) {
       
  1836 					data["class"] = data["class"].replace(/\s*mce\-item\-table\s*/g, '');
       
  1837 				}
       
  1838 
       
  1839 				classListCtrl = {
       
  1840 					name: 'class',
       
  1841 					type: 'listbox',
       
  1842 					label: 'Class',
       
  1843 					values: buildListItems(
       
  1844 						editor.settings.table_class_list,
       
  1845 						function(item) {
       
  1846 							if (item.value) {
       
  1847 								item.textStyle = function() {
       
  1848 									return editor.formatter.getCssText({block: 'table', classes: [item.value]});
       
  1849 								};
       
  1850 							}
       
  1851 						}
       
  1852 					)
       
  1853 				};
       
  1854 			}
       
  1855 
       
  1856 			generalTableForm = {
       
  1857 				type: 'form',
       
  1858 				layout: 'flex',
       
  1859 				direction: 'column',
       
  1860 				labelGapCalc: 'children',
       
  1861 				padding: 0,
       
  1862 				items: [
       
  1863 					{
       
  1864 						type: 'form',
       
  1865 						labelGapCalc: false,
       
  1866 						padding: 0,
       
  1867 						layout: 'grid',
       
  1868 						columns: 2,
       
  1869 						defaults: {
       
  1870 							type: 'textbox',
       
  1871 							maxWidth: 50
       
  1872 						},
       
  1873 						items: (editor.settings.table_appearance_options !== false) ? [
       
  1874 							colsCtrl,
       
  1875 							rowsCtrl,
       
  1876 							{label: 'Width', name: 'width'},
       
  1877 							{label: 'Height', name: 'height'},
       
  1878 							{label: 'Cell spacing', name: 'cellspacing'},
       
  1879 							{label: 'Cell padding', name: 'cellpadding'},
       
  1880 							{label: 'Border', name: 'border'},
       
  1881 							{label: 'Caption', name: 'caption', type: 'checkbox'}
       
  1882 						] : [
       
  1883 							colsCtrl,
       
  1884 							rowsCtrl,
       
  1885 							{label: 'Width', name: 'width'},
       
  1886 							{label: 'Height', name: 'height'}
       
  1887 						]
       
  1888 					},
       
  1889 
       
  1890 					{
       
  1891 						label: 'Alignment',
       
  1892 						name: 'align',
       
  1893 						type: 'listbox',
       
  1894 						text: 'None',
       
  1895 						values: [
       
  1896 							{text: 'None', value: ''},
       
  1897 							{text: 'Left', value: 'left'},
       
  1898 							{text: 'Center', value: 'center'},
       
  1899 							{text: 'Right', value: 'right'}
       
  1900 						]
       
  1901 					},
       
  1902 
       
  1903 					classListCtrl
       
  1904 				]
       
  1905 			};
       
  1906 
       
  1907 			if (editor.settings.table_advtab !== false) {
       
  1908 				appendStylesToData(dom, data, tableElm);
       
  1909 
       
  1910 				editor.windowManager.open({
       
  1911 					title: "Table properties",
       
  1912 					data: data,
       
  1913 					bodyType: 'tabpanel',
       
  1914 					body: [
       
  1915 						{
       
  1916 							title: 'General',
       
  1917 							type: 'form',
       
  1918 							items: generalTableForm
       
  1919 						},
       
  1920 						createStyleForm(dom)
       
  1921 					],
       
  1922 
       
  1923 					onsubmit: onSubmitTableForm
       
  1924 				});
       
  1925 			} else {
       
  1926 				editor.windowManager.open({
       
  1927 					title: "Table properties",
       
  1928 					data: data,
       
  1929 					body: generalTableForm,
       
  1930 					onsubmit: onSubmitTableForm
       
  1931 				});
       
  1932 			}
       
  1933 		};
       
  1934 
       
  1935 		self.merge = function(grid, cell) {
       
  1936 			editor.windowManager.open({
       
  1937 				title: "Merge cells",
       
  1938 				body: [
       
  1939 					{label: 'Cols', name: 'cols', type: 'textbox', value: '1', size: 10},
       
  1940 					{label: 'Rows', name: 'rows', type: 'textbox', value: '1', size: 10}
       
  1941 				],
       
  1942 				onsubmit: function() {
       
  1943 					var data = this.toJSON();
       
  1944 
       
  1945 					editor.undoManager.transact(function() {
       
  1946 						grid.merge(cell, data.cols, data.rows);
       
  1947 					});
       
  1948 				}
       
  1949 			});
       
  1950 		};
       
  1951 
       
  1952 		self.cell = function() {
       
  1953 			var dom = editor.dom, cellElm, data, classListCtrl, cells = [];
       
  1954 
       
  1955 			function onSubmitCellForm() {
       
  1956 				updateStyle(dom, this);
       
  1957 				data = Tools.extend(data, this.toJSON());
       
  1958 
       
  1959 				editor.undoManager.transact(function() {
       
  1960 					each(cells, function(cellElm) {
       
  1961 						editor.dom.setAttribs(cellElm, {
       
  1962 							scope: data.scope,
       
  1963 							style: data.style,
       
  1964 							'class': data['class']
       
  1965 						});
       
  1966 
       
  1967 						editor.dom.setStyles(cellElm, {
       
  1968 							width: addSizeSuffix(data.width),
       
  1969 							height: addSizeSuffix(data.height)
       
  1970 						});
       
  1971 
       
  1972 						// Switch cell type
       
  1973 						if (data.type && cellElm.nodeName.toLowerCase() != data.type) {
       
  1974 							cellElm = dom.rename(cellElm, data.type);
       
  1975 						}
       
  1976 
       
  1977 						// Apply/remove alignment
       
  1978 						unApplyAlign(cellElm);
       
  1979 						if (data.align) {
       
  1980 							editor.formatter.apply('align' + data.align, {}, cellElm);
       
  1981 						}
       
  1982 
       
  1983 						// Apply/remove vertical alignment
       
  1984 						unApplyVAlign(cellElm);
       
  1985 						if (data.valign) {
       
  1986 							editor.formatter.apply('valign' + data.valign, {}, cellElm);
       
  1987 						}
       
  1988 					});
       
  1989 
       
  1990 					editor.focus();
       
  1991 				});
       
  1992 			}
       
  1993 
       
  1994 			// Get selected cells or the current cell
       
  1995 			cells = editor.dom.select('td.mce-item-selected,th.mce-item-selected');
       
  1996 			cellElm = editor.dom.getParent(editor.selection.getStart(), 'td,th');
       
  1997 			if (!cells.length && cellElm) {
       
  1998 				cells.push(cellElm);
       
  1999 			}
       
  2000 
       
  2001 			cellElm = cellElm || cells[0];
       
  2002 
       
  2003 			if (!cellElm) {
       
  2004 				// If this element is null, return now to avoid crashing.
       
  2005 				return;
       
  2006 			}
       
  2007 
       
  2008 			data = {
       
  2009 				width: removePxSuffix(dom.getStyle(cellElm, 'width') || dom.getAttrib(cellElm, 'width')),
       
  2010 				height: removePxSuffix(dom.getStyle(cellElm, 'height') || dom.getAttrib(cellElm, 'height')),
       
  2011 				scope: dom.getAttrib(cellElm, 'scope'),
       
  2012 				'class': dom.getAttrib(cellElm, 'class')
       
  2013 			};
       
  2014 
       
  2015 			data.type = cellElm.nodeName.toLowerCase();
       
  2016 
       
  2017 			each('left center right'.split(' '), function(name) {
       
  2018 				if (editor.formatter.matchNode(cellElm, 'align' + name)) {
       
  2019 					data.align = name;
       
  2020 				}
       
  2021 			});
       
  2022 
       
  2023 			each('top middle bottom'.split(' '), function(name) {
       
  2024 				if (editor.formatter.matchNode(cellElm, 'valign' + name)) {
       
  2025 					data.valign = name;
       
  2026 				}
       
  2027 			});
       
  2028 
       
  2029 			if (editor.settings.table_cell_class_list) {
       
  2030 				classListCtrl = {
       
  2031 					name: 'class',
       
  2032 					type: 'listbox',
       
  2033 					label: 'Class',
       
  2034 					values: buildListItems(
       
  2035 						editor.settings.table_cell_class_list,
       
  2036 						function(item) {
       
  2037 							if (item.value) {
       
  2038 								item.textStyle = function() {
       
  2039 									return editor.formatter.getCssText({block: 'td', classes: [item.value]});
       
  2040 								};
       
  2041 							}
       
  2042 						}
       
  2043 					)
       
  2044 				};
       
  2045 			}
       
  2046 
       
  2047 			var generalCellForm = {
       
  2048 				type: 'form',
       
  2049 				layout: 'flex',
       
  2050 				direction: 'column',
       
  2051 				labelGapCalc: 'children',
       
  2052 				padding: 0,
       
  2053 				items: [
       
  2054 					{
       
  2055 						type: 'form',
       
  2056 						layout: 'grid',
       
  2057 						columns: 2,
       
  2058 						labelGapCalc: false,
       
  2059 						padding: 0,
       
  2060 						defaults: {
       
  2061 							type: 'textbox',
       
  2062 							maxWidth: 50
       
  2063 						},
       
  2064 						items: [
       
  2065 							{label: 'Width', name: 'width'},
       
  2066 							{label: 'Height', name: 'height'},
       
  2067 							{
       
  2068 								label: 'Cell type',
       
  2069 								name: 'type',
       
  2070 								type: 'listbox',
       
  2071 								text: 'None',
       
  2072 								minWidth: 90,
       
  2073 								maxWidth: null,
       
  2074 								values: [
       
  2075 									{text: 'Cell', value: 'td'},
       
  2076 									{text: 'Header cell', value: 'th'}
       
  2077 								]
       
  2078 							},
       
  2079 							{
       
  2080 								label: 'Scope',
       
  2081 								name: 'scope',
       
  2082 								type: 'listbox',
       
  2083 								text: 'None',
       
  2084 								minWidth: 90,
       
  2085 								maxWidth: null,
       
  2086 								values: [
       
  2087 									{text: 'None', value: ''},
       
  2088 									{text: 'Row', value: 'row'},
       
  2089 									{text: 'Column', value: 'col'},
       
  2090 									{text: 'Row group', value: 'rowgroup'},
       
  2091 									{text: 'Column group', value: 'colgroup'}
       
  2092 								]
       
  2093 							},
       
  2094 							{
       
  2095 								label: 'H Align',
       
  2096 								name: 'align',
       
  2097 								type: 'listbox',
       
  2098 								text: 'None',
       
  2099 								minWidth: 90,
       
  2100 								maxWidth: null,
       
  2101 								values: [
       
  2102 									{text: 'None', value: ''},
       
  2103 									{text: 'Left', value: 'left'},
       
  2104 									{text: 'Center', value: 'center'},
       
  2105 									{text: 'Right', value: 'right'}
       
  2106 								]
       
  2107 							},
       
  2108 							{
       
  2109 								label: 'V Align',
       
  2110 								name: 'valign',
       
  2111 								type: 'listbox',
       
  2112 								text: 'None',
       
  2113 								minWidth: 90,
       
  2114 								maxWidth: null,
       
  2115 								values: [
       
  2116 									{text: 'None', value: ''},
       
  2117 									{text: 'Top', value: 'top'},
       
  2118 									{text: 'Middle', value: 'middle'},
       
  2119 									{text: 'Bottom', value: 'bottom'}
       
  2120 								]
       
  2121 							}
       
  2122 						]
       
  2123 					},
       
  2124 
       
  2125 					classListCtrl
       
  2126 				]
       
  2127 			};
       
  2128 
       
  2129 			if (editor.settings.table_cell_advtab !== false) {
       
  2130 				appendStylesToData(dom, data, cellElm);
       
  2131 
       
  2132 				editor.windowManager.open({
       
  2133 					title: "Cell properties",
       
  2134 					bodyType: 'tabpanel',
       
  2135 					data: data,
       
  2136 					body: [
       
  2137 						{
       
  2138 							title: 'General',
       
  2139 							type: 'form',
       
  2140 							items: generalCellForm
       
  2141 						},
       
  2142 
       
  2143 						createStyleForm(dom)
       
  2144 					],
       
  2145 
       
  2146 					onsubmit: onSubmitCellForm
       
  2147 				});
       
  2148 			} else {
       
  2149 				editor.windowManager.open({
       
  2150 					title: "Cell properties",
       
  2151 					data: data,
       
  2152 					body: generalCellForm,
       
  2153 					onsubmit: onSubmitCellForm
       
  2154 				});
       
  2155 			}
       
  2156 		};
       
  2157 
       
  2158 		self.row = function() {
       
  2159 			var dom = editor.dom, tableElm, cellElm, rowElm, classListCtrl, data, rows = [], generalRowForm;
       
  2160 
       
  2161 			function onSubmitRowForm() {
       
  2162 				var tableElm, oldParentElm, parentElm;
       
  2163 
       
  2164 				updateStyle(dom, this);
       
  2165 				data = Tools.extend(data, this.toJSON());
       
  2166 
       
  2167 				editor.undoManager.transact(function() {
       
  2168 					var toType = data.type;
       
  2169 
       
  2170 					each(rows, function(rowElm) {
       
  2171 						editor.dom.setAttribs(rowElm, {
       
  2172 							scope: data.scope,
       
  2173 							style: data.style,
       
  2174 							'class': data['class']
       
  2175 						});
       
  2176 
       
  2177 						editor.dom.setStyles(rowElm, {
       
  2178 							height: addSizeSuffix(data.height)
       
  2179 						});
       
  2180 
       
  2181 						if (toType != rowElm.parentNode.nodeName.toLowerCase()) {
       
  2182 							tableElm = dom.getParent(rowElm, 'table');
       
  2183 
       
  2184 							oldParentElm = rowElm.parentNode;
       
  2185 							parentElm = dom.select(toType, tableElm)[0];
       
  2186 							if (!parentElm) {
       
  2187 								parentElm = dom.create(toType);
       
  2188 								if (tableElm.firstChild) {
       
  2189 									tableElm.insertBefore(parentElm, tableElm.firstChild);
       
  2190 								} else {
       
  2191 									tableElm.appendChild(parentElm);
       
  2192 								}
       
  2193 							}
       
  2194 
       
  2195 							parentElm.appendChild(rowElm);
       
  2196 
       
  2197 							if (!oldParentElm.hasChildNodes()) {
       
  2198 								dom.remove(oldParentElm);
       
  2199 							}
       
  2200 						}
       
  2201 
       
  2202 						// Apply/remove alignment
       
  2203 						unApplyAlign(rowElm);
       
  2204 						if (data.align) {
       
  2205 							editor.formatter.apply('align' + data.align, {}, rowElm);
       
  2206 						}
       
  2207 					});
       
  2208 
       
  2209 					editor.focus();
       
  2210 				});
       
  2211 			}
       
  2212 
       
  2213 			tableElm = editor.dom.getParent(editor.selection.getStart(), 'table');
       
  2214 			cellElm = editor.dom.getParent(editor.selection.getStart(), 'td,th');
       
  2215 
       
  2216 			each(tableElm.rows, function(row) {
       
  2217 				each(row.cells, function(cell) {
       
  2218 					if (dom.hasClass(cell, 'mce-item-selected') || cell == cellElm) {
       
  2219 						rows.push(row);
       
  2220 						return false;
       
  2221 					}
       
  2222 				});
       
  2223 			});
       
  2224 
       
  2225 			rowElm = rows[0];
       
  2226 			if (!rowElm) {
       
  2227 				// If this element is null, return now to avoid crashing.
       
  2228 				return;
       
  2229 			}
       
  2230 
       
  2231 			data = {
       
  2232 				height: removePxSuffix(dom.getStyle(rowElm, 'height') || dom.getAttrib(rowElm, 'height')),
       
  2233 				scope: dom.getAttrib(rowElm, 'scope'),
       
  2234 				'class': dom.getAttrib(rowElm, 'class')
       
  2235 			};
       
  2236 
       
  2237 			data.type = rowElm.parentNode.nodeName.toLowerCase();
       
  2238 
       
  2239 			each('left center right'.split(' '), function(name) {
       
  2240 				if (editor.formatter.matchNode(rowElm, 'align' + name)) {
       
  2241 					data.align = name;
       
  2242 				}
       
  2243 			});
       
  2244 
       
  2245 			if (editor.settings.table_row_class_list) {
       
  2246 				classListCtrl = {
       
  2247 					name: 'class',
       
  2248 					type: 'listbox',
       
  2249 					label: 'Class',
       
  2250 					values: buildListItems(
       
  2251 						editor.settings.table_row_class_list,
       
  2252 						function(item) {
       
  2253 							if (item.value) {
       
  2254 								item.textStyle = function() {
       
  2255 									return editor.formatter.getCssText({block: 'tr', classes: [item.value]});
       
  2256 								};
       
  2257 							}
       
  2258 						}
       
  2259 					)
       
  2260 				};
       
  2261 			}
       
  2262 
       
  2263 			generalRowForm = {
       
  2264 				type: 'form',
       
  2265 				columns: 2,
       
  2266 				padding: 0,
       
  2267 				defaults: {
       
  2268 					type: 'textbox'
       
  2269 				},
       
  2270 				items: [
       
  2271 					{
       
  2272 						type: 'listbox',
       
  2273 						name: 'type',
       
  2274 						label: 'Row type',
       
  2275 						text: 'None',
       
  2276 						maxWidth: null,
       
  2277 						values: [
       
  2278 							{text: 'Header', value: 'thead'},
       
  2279 							{text: 'Body', value: 'tbody'},
       
  2280 							{text: 'Footer', value: 'tfoot'}
       
  2281 						]
       
  2282 					},
       
  2283 					{
       
  2284 						type: 'listbox',
       
  2285 						name: 'align',
       
  2286 						label: 'Alignment',
       
  2287 						text: 'None',
       
  2288 						maxWidth: null,
       
  2289 						values: [
       
  2290 							{text: 'None', value: ''},
       
  2291 							{text: 'Left', value: 'left'},
       
  2292 							{text: 'Center', value: 'center'},
       
  2293 							{text: 'Right', value: 'right'}
       
  2294 						]
       
  2295 					},
       
  2296 					{label: 'Height', name: 'height'},
       
  2297 					classListCtrl
       
  2298 				]
       
  2299 			};
       
  2300 
       
  2301 			if (editor.settings.table_row_advtab !== false) {
       
  2302 				appendStylesToData(dom, data, rowElm);
       
  2303 
       
  2304 				editor.windowManager.open({
       
  2305 					title: "Row properties",
       
  2306 					data: data,
       
  2307 					bodyType: 'tabpanel',
       
  2308 					body: [
       
  2309 						{
       
  2310 							title: 'General',
       
  2311 							type: 'form',
       
  2312 							items: generalRowForm
       
  2313 						},
       
  2314 						createStyleForm(dom)
       
  2315 					],
       
  2316 
       
  2317 					onsubmit: onSubmitRowForm
       
  2318 				});
       
  2319 			} else {
       
  2320 				editor.windowManager.open({
       
  2321 					title: "Row properties",
       
  2322 					data: data,
       
  2323 					body: generalRowForm,
       
  2324 					onsubmit: onSubmitRowForm
       
  2325 				});
       
  2326 			}
       
  2327 		};
       
  2328 	};
       
  2329 });
       
  2330 
       
  2331 // Included from: js/tinymce/plugins/table/classes/Plugin.js
       
  2332 
       
  2333 /**
       
  2334  * Plugin.js
       
  2335  *
       
  2336  * Copyright, Moxiecode Systems AB
       
  2337  * Released under LGPL License.
       
  2338  *
       
  2339  * License: http://www.tinymce.com/license
       
  2340  * Contributing: http://www.tinymce.com/contributing
       
  2341  */
       
  2342 
       
  2343 /**
       
  2344  * This class contains all core logic for the table plugin.
       
  2345  *
       
  2346  * @class tinymce.tableplugin.Plugin
       
  2347  * @private
       
  2348  */
       
  2349 define("tinymce/tableplugin/Plugin", [
       
  2350 	"tinymce/tableplugin/TableGrid",
       
  2351 	"tinymce/tableplugin/Quirks",
       
  2352 	"tinymce/tableplugin/CellSelection",
       
  2353 	"tinymce/tableplugin/Dialogs",
       
  2354 	"tinymce/util/Tools",
       
  2355 	"tinymce/dom/TreeWalker",
       
  2356 	"tinymce/Env",
       
  2357 	"tinymce/PluginManager"
       
  2358 ], function(TableGrid, Quirks, CellSelection, Dialogs, Tools, TreeWalker, Env, PluginManager) {
       
  2359 	var each = Tools.each;
       
  2360 
       
  2361 	function Plugin(editor) {
       
  2362 		var clipboardRows, self = this, dialogs = new Dialogs(editor);
       
  2363 
       
  2364 		function cmd(command) {
       
  2365 			return function() {
       
  2366 				editor.execCommand(command);
       
  2367 			};
       
  2368 		}
       
  2369 
       
  2370 		function insertTable(cols, rows) {
       
  2371 			var y, x, html, tableElm;
       
  2372 
       
  2373 			html = '<table id="__mce"><tbody>';
       
  2374 
       
  2375 			for (y = 0; y < rows; y++) {
       
  2376 				html += '<tr>';
       
  2377 
       
  2378 				for (x = 0; x < cols; x++) {
       
  2379 					html += '<td>' + (Env.ie ? " " : '<br>') + '</td>';
       
  2380 				}
       
  2381 
       
  2382 				html += '</tr>';
       
  2383 			}
       
  2384 
       
  2385 			html += '</tbody></table>';
       
  2386 
       
  2387 			editor.undoManager.transact(function() {
       
  2388 				editor.insertContent(html);
       
  2389 
       
  2390 				tableElm = editor.dom.get('__mce');
       
  2391 				editor.dom.setAttrib(tableElm, 'id', null);
       
  2392 
       
  2393 				editor.dom.setAttribs(tableElm, editor.settings.table_default_attributes || {});
       
  2394 				editor.dom.setStyles(tableElm, editor.settings.table_default_styles || {});
       
  2395 			});
       
  2396 
       
  2397 			return tableElm;
       
  2398 		}
       
  2399 
       
  2400 		function handleDisabledState(ctrl, selector) {
       
  2401 			function bindStateListener() {
       
  2402 				ctrl.disabled(!editor.dom.getParent(editor.selection.getStart(), selector));
       
  2403 
       
  2404 				editor.selection.selectorChanged(selector, function(state) {
       
  2405 					ctrl.disabled(!state);
       
  2406 				});
       
  2407 			}
       
  2408 
       
  2409 			if (editor.initialized) {
       
  2410 				bindStateListener();
       
  2411 			} else {
       
  2412 				editor.on('init', bindStateListener);
       
  2413 			}
       
  2414 		}
       
  2415 
       
  2416 		function postRender() {
       
  2417 			/*jshint validthis:true*/
       
  2418 			handleDisabledState(this, 'table');
       
  2419 		}
       
  2420 
       
  2421 		function postRenderCell() {
       
  2422 			/*jshint validthis:true*/
       
  2423 			handleDisabledState(this, 'td,th');
       
  2424 		}
       
  2425 
       
  2426 		function generateTableGrid() {
       
  2427 			var html = '';
       
  2428 
       
  2429 			html = '<table role="grid" class="mce-grid mce-grid-border" aria-readonly="true">';
       
  2430 
       
  2431 			for (var y = 0; y < 10; y++) {
       
  2432 				html += '<tr>';
       
  2433 
       
  2434 				for (var x = 0; x < 10; x++) {
       
  2435 					html += '<td role="gridcell" tabindex="-1"><a id="mcegrid' + (y * 10 + x) + '" href="#" ' +
       
  2436 						'data-mce-x="' + x + '" data-mce-y="' + y + '"></a></td>';
       
  2437 				}
       
  2438 
       
  2439 				html += '</tr>';
       
  2440 			}
       
  2441 
       
  2442 			html += '</table>';
       
  2443 
       
  2444 			html += '<div class="mce-text-center" role="presentation">1 x 1</div>';
       
  2445 
       
  2446 			return html;
       
  2447 		}
       
  2448 
       
  2449 		function selectGrid(tx, ty, control) {
       
  2450 			var table = control.getEl().getElementsByTagName('table')[0];
       
  2451 			var x, y, focusCell, cell, active;
       
  2452 			var rtl = control.isRtl() || control.parent().rel == 'tl-tr';
       
  2453 
       
  2454 			table.nextSibling.innerHTML = (tx + 1) + ' x ' + (ty + 1);
       
  2455 
       
  2456 			if (rtl) {
       
  2457 				tx = 9 - tx;
       
  2458 			}
       
  2459 
       
  2460 			for (y = 0; y < 10; y++) {
       
  2461 				for (x = 0; x < 10; x++) {
       
  2462 					cell = table.rows[y].childNodes[x].firstChild;
       
  2463 					active = (rtl ? x >= tx : x <= tx) && y <= ty;
       
  2464 
       
  2465 					editor.dom.toggleClass(cell, 'mce-active', active);
       
  2466 
       
  2467 					if (active) {
       
  2468 						focusCell = cell;
       
  2469 					}
       
  2470 				}
       
  2471 			}
       
  2472 
       
  2473 			return focusCell.parentNode;
       
  2474 		}
       
  2475 
       
  2476 		if (editor.settings.table_grid === false) {
       
  2477 			editor.addMenuItem('inserttable', {
       
  2478 				text: 'Insert table',
       
  2479 				icon: 'table',
       
  2480 				context: 'table',
       
  2481 				onclick: dialogs.table
       
  2482 			});
       
  2483 		} else {
       
  2484 			editor.addMenuItem('inserttable', {
       
  2485 				text: 'Insert table',
       
  2486 				icon: 'table',
       
  2487 				context: 'table',
       
  2488 				ariaHideMenu: true,
       
  2489 				onclick: function(e) {
       
  2490 					if (e.aria) {
       
  2491 						this.parent().hideAll();
       
  2492 						e.stopImmediatePropagation();
       
  2493 						dialogs.table();
       
  2494 					}
       
  2495 				},
       
  2496 				onshow: function() {
       
  2497 					selectGrid(0, 0, this.menu.items()[0]);
       
  2498 				},
       
  2499 				onhide: function() {
       
  2500 					var elements = this.menu.items()[0].getEl().getElementsByTagName('a');
       
  2501 					editor.dom.removeClass(elements, 'mce-active');
       
  2502 					editor.dom.addClass(elements[0], 'mce-active');
       
  2503 				},
       
  2504 				menu: [
       
  2505 					{
       
  2506 						type: 'container',
       
  2507 						html: generateTableGrid(),
       
  2508 
       
  2509 						onPostRender: function() {
       
  2510 							this.lastX = this.lastY = 0;
       
  2511 						},
       
  2512 
       
  2513 						onmousemove: function(e) {
       
  2514 							var target = e.target, x, y;
       
  2515 
       
  2516 							if (target.tagName.toUpperCase() == 'A') {
       
  2517 								x = parseInt(target.getAttribute('data-mce-x'), 10);
       
  2518 								y = parseInt(target.getAttribute('data-mce-y'), 10);
       
  2519 
       
  2520 								if (this.isRtl() || this.parent().rel == 'tl-tr') {
       
  2521 									x = 9 - x;
       
  2522 								}
       
  2523 
       
  2524 								if (x !== this.lastX || y !== this.lastY) {
       
  2525 									selectGrid(x, y, e.control);
       
  2526 
       
  2527 									this.lastX = x;
       
  2528 									this.lastY = y;
       
  2529 								}
       
  2530 							}
       
  2531 						},
       
  2532 
       
  2533 						onclick: function(e) {
       
  2534 							var self = this;
       
  2535 
       
  2536 							if (e.target.tagName.toUpperCase() == 'A') {
       
  2537 								e.preventDefault();
       
  2538 								e.stopPropagation();
       
  2539 								self.parent().cancel();
       
  2540 
       
  2541 								editor.undoManager.transact(function() {
       
  2542 									insertTable(self.lastX + 1, self.lastY + 1);
       
  2543 								});
       
  2544 
       
  2545 								editor.addVisual();
       
  2546 							}
       
  2547 						}
       
  2548 					}
       
  2549 				]
       
  2550 			});
       
  2551 		}
       
  2552 
       
  2553 		editor.addMenuItem('tableprops', {
       
  2554 			text: 'Table properties',
       
  2555 			context: 'table',
       
  2556 			onPostRender: postRender,
       
  2557 			onclick: dialogs.tableProps
       
  2558 		});
       
  2559 
       
  2560 		editor.addMenuItem('deletetable', {
       
  2561 			text: 'Delete table',
       
  2562 			context: 'table',
       
  2563 			onPostRender: postRender,
       
  2564 			cmd: 'mceTableDelete'
       
  2565 		});
       
  2566 
       
  2567 		editor.addMenuItem('cell', {
       
  2568 			separator: 'before',
       
  2569 			text: 'Cell',
       
  2570 			context: 'table',
       
  2571 			menu: [
       
  2572 				{text: 'Cell properties', onclick: cmd('mceTableCellProps'), onPostRender: postRenderCell},
       
  2573 				{text: 'Merge cells', onclick: cmd('mceTableMergeCells'), onPostRender: postRenderCell},
       
  2574 				{text: 'Split cell', onclick: cmd('mceTableSplitCells'), onPostRender: postRenderCell}
       
  2575 			]
       
  2576 		});
       
  2577 
       
  2578 		editor.addMenuItem('row', {
       
  2579 			text: 'Row',
       
  2580 			context: 'table',
       
  2581 			menu: [
       
  2582 				{text: 'Insert row before', onclick: cmd('mceTableInsertRowBefore'), onPostRender: postRenderCell},
       
  2583 				{text: 'Insert row after', onclick: cmd('mceTableInsertRowAfter'), onPostRender: postRenderCell},
       
  2584 				{text: 'Delete row', onclick: cmd('mceTableDeleteRow'), onPostRender: postRenderCell},
       
  2585 				{text: 'Row properties', onclick: cmd('mceTableRowProps'), onPostRender: postRenderCell},
       
  2586 				{text: '-'},
       
  2587 				{text: 'Cut row', onclick: cmd('mceTableCutRow'), onPostRender: postRenderCell},
       
  2588 				{text: 'Copy row', onclick: cmd('mceTableCopyRow'), onPostRender: postRenderCell},
       
  2589 				{text: 'Paste row before', onclick: cmd('mceTablePasteRowBefore'), onPostRender: postRenderCell},
       
  2590 				{text: 'Paste row after', onclick: cmd('mceTablePasteRowAfter'), onPostRender: postRenderCell}
       
  2591 			]
       
  2592 		});
       
  2593 
       
  2594 		editor.addMenuItem('column', {
       
  2595 			text: 'Column',
       
  2596 			context: 'table',
       
  2597 			menu: [
       
  2598 				{text: 'Insert column before', onclick: cmd('mceTableInsertColBefore'), onPostRender: postRenderCell},
       
  2599 				{text: 'Insert column after', onclick: cmd('mceTableInsertColAfter'), onPostRender: postRenderCell},
       
  2600 				{text: 'Delete column', onclick: cmd('mceTableDeleteCol'), onPostRender: postRenderCell}
       
  2601 			]
       
  2602 		});
       
  2603 
       
  2604 		var menuItems = [];
       
  2605 		each("inserttable tableprops deletetable | cell row column".split(' '), function(name) {
       
  2606 			if (name == '|') {
       
  2607 				menuItems.push({text: '-'});
       
  2608 			} else {
       
  2609 				menuItems.push(editor.menuItems[name]);
       
  2610 			}
       
  2611 		});
       
  2612 
       
  2613 		editor.addButton("table", {
       
  2614 			type: "menubutton",
       
  2615 			title: "Table",
       
  2616 			menu: menuItems
       
  2617 		});
       
  2618 
       
  2619 		// Select whole table is a table border is clicked
       
  2620 		if (!Env.isIE) {
       
  2621 			editor.on('click', function(e) {
       
  2622 				e = e.target;
       
  2623 
       
  2624 				if (e.nodeName === 'TABLE') {
       
  2625 					editor.selection.select(e);
       
  2626 					editor.nodeChanged();
       
  2627 				}
       
  2628 			});
       
  2629 		}
       
  2630 
       
  2631 		self.quirks = new Quirks(editor);
       
  2632 
       
  2633 		editor.on('Init', function() {
       
  2634 			self.cellSelection = new CellSelection(editor);
       
  2635 		});
       
  2636 
       
  2637 		editor.on('PreInit', function() {
       
  2638 			// Remove internal data attributes
       
  2639 			editor.serializer.addAttributeFilter(
       
  2640 				'data-mce-cell-padding,data-mce-border,data-mce-border-color',
       
  2641 				function(nodes, name) {
       
  2642 
       
  2643 					var i = nodes.length;
       
  2644 
       
  2645 					while (i--) {
       
  2646 						nodes[i].attr(name, null);
       
  2647 					}
       
  2648 				});
       
  2649 		});
       
  2650 
       
  2651 		// Register action commands
       
  2652 		each({
       
  2653 			mceTableSplitCells: function(grid) {
       
  2654 				grid.split();
       
  2655 			},
       
  2656 
       
  2657 			mceTableMergeCells: function(grid) {
       
  2658 				var cell;
       
  2659 
       
  2660 				cell = editor.dom.getParent(editor.selection.getStart(), 'th,td');
       
  2661 
       
  2662 				if (!editor.dom.select('td.mce-item-selected,th.mce-item-selected').length) {
       
  2663 					dialogs.merge(grid, cell);
       
  2664 				} else {
       
  2665 					grid.merge();
       
  2666 				}
       
  2667 			},
       
  2668 
       
  2669 			mceTableInsertRowBefore: function(grid) {
       
  2670 				grid.insertRow(true);
       
  2671 			},
       
  2672 
       
  2673 			mceTableInsertRowAfter: function(grid) {
       
  2674 				grid.insertRow();
       
  2675 			},
       
  2676 
       
  2677 			mceTableInsertColBefore: function(grid) {
       
  2678 				grid.insertCol(true);
       
  2679 			},
       
  2680 
       
  2681 			mceTableInsertColAfter: function(grid) {
       
  2682 				grid.insertCol();
       
  2683 			},
       
  2684 
       
  2685 			mceTableDeleteCol: function(grid) {
       
  2686 				grid.deleteCols();
       
  2687 			},
       
  2688 
       
  2689 			mceTableDeleteRow: function(grid) {
       
  2690 				grid.deleteRows();
       
  2691 			},
       
  2692 
       
  2693 			mceTableCutRow: function(grid) {
       
  2694 				clipboardRows = grid.cutRows();
       
  2695 			},
       
  2696 
       
  2697 			mceTableCopyRow: function(grid) {
       
  2698 				clipboardRows = grid.copyRows();
       
  2699 			},
       
  2700 
       
  2701 			mceTablePasteRowBefore: function(grid) {
       
  2702 				grid.pasteRows(clipboardRows, true);
       
  2703 			},
       
  2704 
       
  2705 			mceTablePasteRowAfter: function(grid) {
       
  2706 				grid.pasteRows(clipboardRows);
       
  2707 			},
       
  2708 
       
  2709 			mceTableDelete: function(grid) {
       
  2710 				grid.deleteTable();
       
  2711 			}
       
  2712 		}, function(func, name) {
       
  2713 			editor.addCommand(name, function() {
       
  2714 				var grid = new TableGrid(editor);
       
  2715 
       
  2716 				if (grid) {
       
  2717 					func(grid);
       
  2718 					editor.execCommand('mceRepaint');
       
  2719 					self.cellSelection.clear();
       
  2720 				}
       
  2721 			});
       
  2722 		});
       
  2723 
       
  2724 		// Register dialog commands
       
  2725 		each({
       
  2726 			mceInsertTable: dialogs.table,
       
  2727 			mceTableProps: function() {
       
  2728 				dialogs.table(true);
       
  2729 			},
       
  2730 			mceTableRowProps: dialogs.row,
       
  2731 			mceTableCellProps: dialogs.cell
       
  2732 		}, function(func, name) {
       
  2733 			editor.addCommand(name, function(ui, val) {
       
  2734 				func(val);
       
  2735 			});
       
  2736 		});
       
  2737 
       
  2738 		// Enable tab key cell navigation
       
  2739 		if (editor.settings.table_tab_navigation !== false) {
       
  2740 			editor.on('keydown', function(e) {
       
  2741 				var cellElm, grid, delta;
       
  2742 
       
  2743 				if (e.keyCode == 9) {
       
  2744 					cellElm = editor.dom.getParent(editor.selection.getStart(), 'th,td');
       
  2745 
       
  2746 					if (cellElm) {
       
  2747 						e.preventDefault();
       
  2748 
       
  2749 						grid = new TableGrid(editor);
       
  2750 						delta = e.shiftKey ? -1 : 1;
       
  2751 
       
  2752 						editor.undoManager.transact(function() {
       
  2753 							if (!grid.moveRelIdx(cellElm, delta) && delta > 0) {
       
  2754 								grid.insertRow();
       
  2755 								grid.refresh();
       
  2756 								grid.moveRelIdx(cellElm, delta);
       
  2757 							}
       
  2758 						});
       
  2759 					}
       
  2760 				}
       
  2761 			});
       
  2762 		}
       
  2763 
       
  2764 		self.insertTable = insertTable;
       
  2765 	}
       
  2766 
       
  2767 	PluginManager.add('table', Plugin);
       
  2768 });
       
  2769 })(this);