src/pyams_skin/resources/js/ext/tinymce/dev/plugins/table/classes/Dialogs.js
changeset 69 a361355b55c7
equal deleted inserted replaced
68:fd8fb93e1b6a 69:a361355b55c7
       
     1 /**
       
     2  * Dialogs.js
       
     3  *
       
     4  * Copyright, Moxiecode Systems AB
       
     5  * Released under LGPL License.
       
     6  *
       
     7  * License: http://www.tinymce.com/license
       
     8  * Contributing: http://www.tinymce.com/contributing
       
     9  */
       
    10 
       
    11 /*eslint dot-notation:0*/
       
    12 
       
    13 /**
       
    14  * ...
       
    15  *
       
    16  * @class tinymce.tableplugin.Dialogs
       
    17  * @private
       
    18  */
       
    19 define("tinymce/tableplugin/Dialogs", [
       
    20 	"tinymce/util/Tools",
       
    21 	"tinymce/Env"
       
    22 ], function(Tools, Env) {
       
    23 	var each = Tools.each;
       
    24 
       
    25 	return function(editor) {
       
    26 		var self = this;
       
    27 
       
    28 		function createColorPickAction() {
       
    29 			var colorPickerCallback = editor.settings.color_picker_callback;
       
    30 
       
    31 			if (colorPickerCallback) {
       
    32 				return function() {
       
    33 					var self = this;
       
    34 
       
    35 					colorPickerCallback.call(
       
    36 						editor,
       
    37 						function(value) {
       
    38 							self.value(value).fire('change');
       
    39 						},
       
    40 						self.value()
       
    41 					);
       
    42 				};
       
    43 			}
       
    44 		}
       
    45 
       
    46 		function createStyleForm(dom) {
       
    47 			return {
       
    48 				title: 'Advanced',
       
    49 				type: 'form',
       
    50 				defaults: {
       
    51 					onchange: function() {
       
    52 						updateStyle(dom, this.parents().reverse()[0], this.name() == "style");
       
    53 					}
       
    54 				},
       
    55 				items: [
       
    56 					{
       
    57 						label: 'Style',
       
    58 						name: 'style',
       
    59 						type: 'textbox'
       
    60 					},
       
    61 
       
    62 					{
       
    63 						type: 'form',
       
    64 						padding: 0,
       
    65 						formItemDefaults: {
       
    66 							layout: 'grid',
       
    67 							alignH: ['start', 'right']
       
    68 						},
       
    69 						defaults: {
       
    70 							size: 7
       
    71 						},
       
    72 						items: [
       
    73 							{
       
    74 								label: 'Border color',
       
    75 								type: 'colorbox',
       
    76 								name: 'borderColor',
       
    77 								onaction: createColorPickAction()
       
    78 							},
       
    79 
       
    80 							{
       
    81 								label: 'Background color',
       
    82 								type: 'colorbox',
       
    83 								name: 'backgroundColor',
       
    84 								onaction: createColorPickAction()
       
    85 							}
       
    86 						]
       
    87 					}
       
    88 				]
       
    89 			};
       
    90 		}
       
    91 
       
    92 		function removePxSuffix(size) {
       
    93 			return size ? size.replace(/px$/, '') : "";
       
    94 		}
       
    95 
       
    96 		function addSizeSuffix(size) {
       
    97 			if (/^[0-9]+$/.test(size)) {
       
    98 				size += "px";
       
    99 			}
       
   100 
       
   101 			return size;
       
   102 		}
       
   103 
       
   104 		function unApplyAlign(elm) {
       
   105 			each('left center right'.split(' '), function(name) {
       
   106 				editor.formatter.remove('align' + name, {}, elm);
       
   107 			});
       
   108 		}
       
   109 
       
   110 		function unApplyVAlign(elm) {
       
   111 			each('top middle bottom'.split(' '), function(name) {
       
   112 				editor.formatter.remove('valign' + name, {}, elm);
       
   113 			});
       
   114 		}
       
   115 
       
   116 		function buildListItems(inputList, itemCallback, startItems) {
       
   117 			function appendItems(values, output) {
       
   118 				output = output || [];
       
   119 
       
   120 				Tools.each(values, function(item) {
       
   121 					var menuItem = {text: item.text || item.title};
       
   122 
       
   123 					if (item.menu) {
       
   124 						menuItem.menu = appendItems(item.menu);
       
   125 					} else {
       
   126 						menuItem.value = item.value;
       
   127 
       
   128 						if (itemCallback) {
       
   129 							itemCallback(menuItem);
       
   130 						}
       
   131 					}
       
   132 
       
   133 					output.push(menuItem);
       
   134 				});
       
   135 
       
   136 				return output;
       
   137 			}
       
   138 
       
   139 			return appendItems(inputList, startItems || []);
       
   140 		}
       
   141 
       
   142 		function updateStyle(dom, win, isStyleCtrl) {
       
   143 			var data = win.toJSON();
       
   144 			var css = dom.parseStyle(data.style);
       
   145 
       
   146 			if (isStyleCtrl) {
       
   147 				win.find('#borderColor').value(css["border-color"] || '')[0].fire('change');
       
   148 				win.find('#backgroundColor').value(css["background-color"] || '')[0].fire('change');
       
   149 			} else {
       
   150 				css["border-color"] = data.borderColor;
       
   151 				css["background-color"] = data.backgroundColor;
       
   152 			}
       
   153 
       
   154 			win.find('#style').value(dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
       
   155 		}
       
   156 
       
   157 		function appendStylesToData(dom, data, elm) {
       
   158 			var css = dom.parseStyle(dom.getAttrib(elm, 'style'));
       
   159 
       
   160 			if (css["border-color"]) {
       
   161 				data.borderColor = css["border-color"];
       
   162 			}
       
   163 
       
   164 			if (css["background-color"]) {
       
   165 				data.backgroundColor = css["background-color"];
       
   166 			}
       
   167 
       
   168 			data.style = dom.serializeStyle(css);
       
   169 		}
       
   170 
       
   171 		function mergeStyles(dom, elm, styles) {
       
   172 			var css = dom.parseStyle(dom.getAttrib(elm, 'style'));
       
   173 
       
   174 			each(styles, function(style) {
       
   175 				css[style.name] = style.value;
       
   176 			});
       
   177 
       
   178 			dom.setAttrib(elm, 'style', dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
       
   179 		}
       
   180 
       
   181 		self.tableProps = function() {
       
   182 			self.table(true);
       
   183 		};
       
   184 
       
   185 		self.table = function(isProps) {
       
   186 			var dom = editor.dom, tableElm, colsCtrl, rowsCtrl, classListCtrl, data = {}, generalTableForm, stylesToMerge;
       
   187 
       
   188 			function onSubmitTableForm() {
       
   189 
       
   190 				//Explore the layers of the table till we find the first layer of tds or ths
       
   191 				function styleTDTH (elm, name, value) {
       
   192 					if (elm.tagName === "TD" || elm.tagName === "TH") {
       
   193 						dom.setStyle(elm, name, value);
       
   194 					} else {
       
   195 						if (elm.children) {
       
   196 							for (var i = 0; i < elm.children.length; i++) {
       
   197 								styleTDTH(elm.children[i], name, value);
       
   198 							}
       
   199 						}
       
   200 					}
       
   201 				}
       
   202 
       
   203 				var captionElm;
       
   204 
       
   205 				updateStyle(dom, this);
       
   206 				data = Tools.extend(data, this.toJSON());
       
   207 
       
   208 				if (data["class"] === false) {
       
   209 					delete data["class"];
       
   210 				}
       
   211 
       
   212 				editor.undoManager.transact(function() {
       
   213 					if (!tableElm) {
       
   214 						tableElm = editor.plugins.table.insertTable(data.cols || 1, data.rows || 1);
       
   215 					}
       
   216 
       
   217 					editor.dom.setAttribs(tableElm, {
       
   218 						style: data.style,
       
   219 						'class': data['class']
       
   220 					});
       
   221 
       
   222 					if (editor.settings.table_style_by_css) {
       
   223 						stylesToMerge = [];
       
   224 						stylesToMerge.push({name: 'border', value: data.border});
       
   225 						stylesToMerge.push({name: 'border-spacing', value: addSizeSuffix(data.cellspacing)});
       
   226 						mergeStyles(dom, tableElm, stylesToMerge);
       
   227 						dom.setAttribs(tableElm, {
       
   228 							'data-mce-border-color': data.borderColor,
       
   229 							'data-mce-cell-padding': data.cellpadding,
       
   230 							'data-mce-border': data.border
       
   231 						});
       
   232 						if (tableElm.children) {
       
   233 							for (var i = 0; i < tableElm.children.length; i++) {
       
   234 								styleTDTH(tableElm.children[i], 'border', data.border);
       
   235 								styleTDTH(tableElm.children[i], 'padding', addSizeSuffix(data.cellpadding));
       
   236 							}
       
   237 						}
       
   238 					} else {
       
   239 						editor.dom.setAttribs(tableElm, {
       
   240 							border: data.border,
       
   241 							cellpadding: data.cellpadding,
       
   242 							cellspacing: data.cellspacing
       
   243 						});
       
   244 					}
       
   245 
       
   246 					if (dom.getAttrib(tableElm, 'width') && !editor.settings.table_style_by_css) {
       
   247 						dom.setAttrib(tableElm, 'width', removePxSuffix(data.width));
       
   248 					} else {
       
   249 						dom.setStyle(tableElm, 'width', addSizeSuffix(data.width));
       
   250 					}
       
   251 
       
   252 					dom.setStyle(tableElm, 'height', addSizeSuffix(data.height));
       
   253 
       
   254 					// Toggle caption on/off
       
   255 					captionElm = dom.select('caption', tableElm)[0];
       
   256 
       
   257 					if (captionElm && !data.caption) {
       
   258 						dom.remove(captionElm);
       
   259 					}
       
   260 
       
   261 					if (!captionElm && data.caption) {
       
   262 						captionElm = dom.create('caption');
       
   263 						captionElm.innerHTML = !Env.ie ? '<br data-mce-bogus="1"/>' : '\u00a0';
       
   264 						tableElm.insertBefore(captionElm, tableElm.firstChild);
       
   265 					}
       
   266 					unApplyAlign(tableElm);
       
   267 					if (data.align) {
       
   268 						editor.formatter.apply('align' + data.align, {}, tableElm);
       
   269 					}
       
   270 
       
   271 					editor.focus();
       
   272 					editor.addVisual();
       
   273 				});
       
   274 			}
       
   275 
       
   276 			function getTDTHOverallStyle (elm, name) {
       
   277 				var cells = editor.dom.select("td,th", elm), firstChildStyle;
       
   278 
       
   279 				function checkChildren(firstChildStyle, elms) {
       
   280 
       
   281 					for (var i = 0; i < elms.length; i++) {
       
   282 						var currentStyle = dom.getStyle(elms[i], name);
       
   283 						if (typeof firstChildStyle === "undefined") {
       
   284 							firstChildStyle = currentStyle;
       
   285 						}
       
   286 						if (firstChildStyle != currentStyle) {
       
   287 							return "";
       
   288 						}
       
   289 					}
       
   290 
       
   291 					return firstChildStyle;
       
   292 
       
   293 				}
       
   294 
       
   295 				firstChildStyle = checkChildren(firstChildStyle, cells);
       
   296 
       
   297 				return firstChildStyle;
       
   298 			}
       
   299 
       
   300 			if (isProps === true) {
       
   301 				tableElm = dom.getParent(editor.selection.getStart(), 'table');
       
   302 
       
   303 				if (tableElm) {
       
   304 					data = {
       
   305 						width: removePxSuffix(dom.getStyle(tableElm, 'width') || dom.getAttrib(tableElm, 'width')),
       
   306 						height: removePxSuffix(dom.getStyle(tableElm, 'height') || dom.getAttrib(tableElm, 'height')),
       
   307 						cellspacing: removePxSuffix(dom.getStyle(tableElm, 'border-spacing') ||
       
   308 							dom.getAttrib(tableElm, 'cellspacing')),
       
   309 						cellpadding: dom.getAttrib(tableElm, 'data-mce-cell-padding') || dom.getAttrib(tableElm, 'cellpadding') ||
       
   310 							getTDTHOverallStyle(tableElm, 'padding'),
       
   311 						border: dom.getAttrib(tableElm, 'data-mce-border') || dom.getAttrib(tableElm, 'border') ||
       
   312 							getTDTHOverallStyle(tableElm, 'border'),
       
   313 						borderColor: dom.getAttrib(tableElm, 'data-mce-border-color'),
       
   314 						caption: !!dom.select('caption', tableElm)[0],
       
   315 						'class': dom.getAttrib(tableElm, 'class')
       
   316 					};
       
   317 
       
   318 					each('left center right'.split(' '), function(name) {
       
   319 						if (editor.formatter.matchNode(tableElm, 'align' + name)) {
       
   320 							data.align = name;
       
   321 						}
       
   322 					});
       
   323 				}
       
   324 			} else {
       
   325 				colsCtrl = {label: 'Cols', name: 'cols'};
       
   326 				rowsCtrl = {label: 'Rows', name: 'rows'};
       
   327 			}
       
   328 
       
   329 			if (editor.settings.table_class_list) {
       
   330 				if (data["class"]) {
       
   331 					data["class"] = data["class"].replace(/\s*mce\-item\-table\s*/g, '');
       
   332 				}
       
   333 
       
   334 				classListCtrl = {
       
   335 					name: 'class',
       
   336 					type: 'listbox',
       
   337 					label: 'Class',
       
   338 					values: buildListItems(
       
   339 						editor.settings.table_class_list,
       
   340 						function(item) {
       
   341 							if (item.value) {
       
   342 								item.textStyle = function() {
       
   343 									return editor.formatter.getCssText({block: 'table', classes: [item.value]});
       
   344 								};
       
   345 							}
       
   346 						}
       
   347 					)
       
   348 				};
       
   349 			}
       
   350 
       
   351 			generalTableForm = {
       
   352 				type: 'form',
       
   353 				layout: 'flex',
       
   354 				direction: 'column',
       
   355 				labelGapCalc: 'children',
       
   356 				padding: 0,
       
   357 				items: [
       
   358 					{
       
   359 						type: 'form',
       
   360 						labelGapCalc: false,
       
   361 						padding: 0,
       
   362 						layout: 'grid',
       
   363 						columns: 2,
       
   364 						defaults: {
       
   365 							type: 'textbox',
       
   366 							maxWidth: 50
       
   367 						},
       
   368 						items: (editor.settings.table_appearance_options !== false) ? [
       
   369 							colsCtrl,
       
   370 							rowsCtrl,
       
   371 							{label: 'Width', name: 'width'},
       
   372 							{label: 'Height', name: 'height'},
       
   373 							{label: 'Cell spacing', name: 'cellspacing'},
       
   374 							{label: 'Cell padding', name: 'cellpadding'},
       
   375 							{label: 'Border', name: 'border'},
       
   376 							{label: 'Caption', name: 'caption', type: 'checkbox'}
       
   377 						] : [
       
   378 							colsCtrl,
       
   379 							rowsCtrl,
       
   380 							{label: 'Width', name: 'width'},
       
   381 							{label: 'Height', name: 'height'}
       
   382 						]
       
   383 					},
       
   384 
       
   385 					{
       
   386 						label: 'Alignment',
       
   387 						name: 'align',
       
   388 						type: 'listbox',
       
   389 						text: 'None',
       
   390 						values: [
       
   391 							{text: 'None', value: ''},
       
   392 							{text: 'Left', value: 'left'},
       
   393 							{text: 'Center', value: 'center'},
       
   394 							{text: 'Right', value: 'right'}
       
   395 						]
       
   396 					},
       
   397 
       
   398 					classListCtrl
       
   399 				]
       
   400 			};
       
   401 
       
   402 			if (editor.settings.table_advtab !== false) {
       
   403 				appendStylesToData(dom, data, tableElm);
       
   404 
       
   405 				editor.windowManager.open({
       
   406 					title: "Table properties",
       
   407 					data: data,
       
   408 					bodyType: 'tabpanel',
       
   409 					body: [
       
   410 						{
       
   411 							title: 'General',
       
   412 							type: 'form',
       
   413 							items: generalTableForm
       
   414 						},
       
   415 						createStyleForm(dom)
       
   416 					],
       
   417 
       
   418 					onsubmit: onSubmitTableForm
       
   419 				});
       
   420 			} else {
       
   421 				editor.windowManager.open({
       
   422 					title: "Table properties",
       
   423 					data: data,
       
   424 					body: generalTableForm,
       
   425 					onsubmit: onSubmitTableForm
       
   426 				});
       
   427 			}
       
   428 		};
       
   429 
       
   430 		self.merge = function(grid, cell) {
       
   431 			editor.windowManager.open({
       
   432 				title: "Merge cells",
       
   433 				body: [
       
   434 					{label: 'Cols', name: 'cols', type: 'textbox', value: '1', size: 10},
       
   435 					{label: 'Rows', name: 'rows', type: 'textbox', value: '1', size: 10}
       
   436 				],
       
   437 				onsubmit: function() {
       
   438 					var data = this.toJSON();
       
   439 
       
   440 					editor.undoManager.transact(function() {
       
   441 						grid.merge(cell, data.cols, data.rows);
       
   442 					});
       
   443 				}
       
   444 			});
       
   445 		};
       
   446 
       
   447 		self.cell = function() {
       
   448 			var dom = editor.dom, cellElm, data, classListCtrl, cells = [];
       
   449 
       
   450 			function onSubmitCellForm() {
       
   451 				updateStyle(dom, this);
       
   452 				data = Tools.extend(data, this.toJSON());
       
   453 
       
   454 				editor.undoManager.transact(function() {
       
   455 					each(cells, function(cellElm) {
       
   456 						editor.dom.setAttribs(cellElm, {
       
   457 							scope: data.scope,
       
   458 							style: data.style,
       
   459 							'class': data['class']
       
   460 						});
       
   461 
       
   462 						editor.dom.setStyles(cellElm, {
       
   463 							width: addSizeSuffix(data.width),
       
   464 							height: addSizeSuffix(data.height)
       
   465 						});
       
   466 
       
   467 						// Switch cell type
       
   468 						if (data.type && cellElm.nodeName.toLowerCase() != data.type) {
       
   469 							cellElm = dom.rename(cellElm, data.type);
       
   470 						}
       
   471 
       
   472 						// Apply/remove alignment
       
   473 						unApplyAlign(cellElm);
       
   474 						if (data.align) {
       
   475 							editor.formatter.apply('align' + data.align, {}, cellElm);
       
   476 						}
       
   477 
       
   478 						// Apply/remove vertical alignment
       
   479 						unApplyVAlign(cellElm);
       
   480 						if (data.valign) {
       
   481 							editor.formatter.apply('valign' + data.valign, {}, cellElm);
       
   482 						}
       
   483 					});
       
   484 
       
   485 					editor.focus();
       
   486 				});
       
   487 			}
       
   488 
       
   489 			// Get selected cells or the current cell
       
   490 			cells = editor.dom.select('td.mce-item-selected,th.mce-item-selected');
       
   491 			cellElm = editor.dom.getParent(editor.selection.getStart(), 'td,th');
       
   492 			if (!cells.length && cellElm) {
       
   493 				cells.push(cellElm);
       
   494 			}
       
   495 
       
   496 			cellElm = cellElm || cells[0];
       
   497 
       
   498 			if (!cellElm) {
       
   499 				// If this element is null, return now to avoid crashing.
       
   500 				return;
       
   501 			}
       
   502 
       
   503 			data = {
       
   504 				width: removePxSuffix(dom.getStyle(cellElm, 'width') || dom.getAttrib(cellElm, 'width')),
       
   505 				height: removePxSuffix(dom.getStyle(cellElm, 'height') || dom.getAttrib(cellElm, 'height')),
       
   506 				scope: dom.getAttrib(cellElm, 'scope'),
       
   507 				'class': dom.getAttrib(cellElm, 'class')
       
   508 			};
       
   509 
       
   510 			data.type = cellElm.nodeName.toLowerCase();
       
   511 
       
   512 			each('left center right'.split(' '), function(name) {
       
   513 				if (editor.formatter.matchNode(cellElm, 'align' + name)) {
       
   514 					data.align = name;
       
   515 				}
       
   516 			});
       
   517 
       
   518 			each('top middle bottom'.split(' '), function(name) {
       
   519 				if (editor.formatter.matchNode(cellElm, 'valign' + name)) {
       
   520 					data.valign = name;
       
   521 				}
       
   522 			});
       
   523 
       
   524 			if (editor.settings.table_cell_class_list) {
       
   525 				classListCtrl = {
       
   526 					name: 'class',
       
   527 					type: 'listbox',
       
   528 					label: 'Class',
       
   529 					values: buildListItems(
       
   530 						editor.settings.table_cell_class_list,
       
   531 						function(item) {
       
   532 							if (item.value) {
       
   533 								item.textStyle = function() {
       
   534 									return editor.formatter.getCssText({block: 'td', classes: [item.value]});
       
   535 								};
       
   536 							}
       
   537 						}
       
   538 					)
       
   539 				};
       
   540 			}
       
   541 
       
   542 			var generalCellForm = {
       
   543 				type: 'form',
       
   544 				layout: 'flex',
       
   545 				direction: 'column',
       
   546 				labelGapCalc: 'children',
       
   547 				padding: 0,
       
   548 				items: [
       
   549 					{
       
   550 						type: 'form',
       
   551 						layout: 'grid',
       
   552 						columns: 2,
       
   553 						labelGapCalc: false,
       
   554 						padding: 0,
       
   555 						defaults: {
       
   556 							type: 'textbox',
       
   557 							maxWidth: 50
       
   558 						},
       
   559 						items: [
       
   560 							{label: 'Width', name: 'width'},
       
   561 							{label: 'Height', name: 'height'},
       
   562 							{
       
   563 								label: 'Cell type',
       
   564 								name: 'type',
       
   565 								type: 'listbox',
       
   566 								text: 'None',
       
   567 								minWidth: 90,
       
   568 								maxWidth: null,
       
   569 								values: [
       
   570 									{text: 'Cell', value: 'td'},
       
   571 									{text: 'Header cell', value: 'th'}
       
   572 								]
       
   573 							},
       
   574 							{
       
   575 								label: 'Scope',
       
   576 								name: 'scope',
       
   577 								type: 'listbox',
       
   578 								text: 'None',
       
   579 								minWidth: 90,
       
   580 								maxWidth: null,
       
   581 								values: [
       
   582 									{text: 'None', value: ''},
       
   583 									{text: 'Row', value: 'row'},
       
   584 									{text: 'Column', value: 'col'},
       
   585 									{text: 'Row group', value: 'rowgroup'},
       
   586 									{text: 'Column group', value: 'colgroup'}
       
   587 								]
       
   588 							},
       
   589 							{
       
   590 								label: 'H Align',
       
   591 								name: 'align',
       
   592 								type: 'listbox',
       
   593 								text: 'None',
       
   594 								minWidth: 90,
       
   595 								maxWidth: null,
       
   596 								values: [
       
   597 									{text: 'None', value: ''},
       
   598 									{text: 'Left', value: 'left'},
       
   599 									{text: 'Center', value: 'center'},
       
   600 									{text: 'Right', value: 'right'}
       
   601 								]
       
   602 							},
       
   603 							{
       
   604 								label: 'V Align',
       
   605 								name: 'valign',
       
   606 								type: 'listbox',
       
   607 								text: 'None',
       
   608 								minWidth: 90,
       
   609 								maxWidth: null,
       
   610 								values: [
       
   611 									{text: 'None', value: ''},
       
   612 									{text: 'Top', value: 'top'},
       
   613 									{text: 'Middle', value: 'middle'},
       
   614 									{text: 'Bottom', value: 'bottom'}
       
   615 								]
       
   616 							}
       
   617 						]
       
   618 					},
       
   619 
       
   620 					classListCtrl
       
   621 				]
       
   622 			};
       
   623 
       
   624 			if (editor.settings.table_cell_advtab !== false) {
       
   625 				appendStylesToData(dom, data, cellElm);
       
   626 
       
   627 				editor.windowManager.open({
       
   628 					title: "Cell properties",
       
   629 					bodyType: 'tabpanel',
       
   630 					data: data,
       
   631 					body: [
       
   632 						{
       
   633 							title: 'General',
       
   634 							type: 'form',
       
   635 							items: generalCellForm
       
   636 						},
       
   637 
       
   638 						createStyleForm(dom)
       
   639 					],
       
   640 
       
   641 					onsubmit: onSubmitCellForm
       
   642 				});
       
   643 			} else {
       
   644 				editor.windowManager.open({
       
   645 					title: "Cell properties",
       
   646 					data: data,
       
   647 					body: generalCellForm,
       
   648 					onsubmit: onSubmitCellForm
       
   649 				});
       
   650 			}
       
   651 		};
       
   652 
       
   653 		self.row = function() {
       
   654 			var dom = editor.dom, tableElm, cellElm, rowElm, classListCtrl, data, rows = [], generalRowForm;
       
   655 
       
   656 			function onSubmitRowForm() {
       
   657 				var tableElm, oldParentElm, parentElm;
       
   658 
       
   659 				updateStyle(dom, this);
       
   660 				data = Tools.extend(data, this.toJSON());
       
   661 
       
   662 				editor.undoManager.transact(function() {
       
   663 					var toType = data.type;
       
   664 
       
   665 					each(rows, function(rowElm) {
       
   666 						editor.dom.setAttribs(rowElm, {
       
   667 							scope: data.scope,
       
   668 							style: data.style,
       
   669 							'class': data['class']
       
   670 						});
       
   671 
       
   672 						editor.dom.setStyles(rowElm, {
       
   673 							height: addSizeSuffix(data.height)
       
   674 						});
       
   675 
       
   676 						if (toType != rowElm.parentNode.nodeName.toLowerCase()) {
       
   677 							tableElm = dom.getParent(rowElm, 'table');
       
   678 
       
   679 							oldParentElm = rowElm.parentNode;
       
   680 							parentElm = dom.select(toType, tableElm)[0];
       
   681 							if (!parentElm) {
       
   682 								parentElm = dom.create(toType);
       
   683 								if (tableElm.firstChild) {
       
   684 									tableElm.insertBefore(parentElm, tableElm.firstChild);
       
   685 								} else {
       
   686 									tableElm.appendChild(parentElm);
       
   687 								}
       
   688 							}
       
   689 
       
   690 							parentElm.appendChild(rowElm);
       
   691 
       
   692 							if (!oldParentElm.hasChildNodes()) {
       
   693 								dom.remove(oldParentElm);
       
   694 							}
       
   695 						}
       
   696 
       
   697 						// Apply/remove alignment
       
   698 						unApplyAlign(rowElm);
       
   699 						if (data.align) {
       
   700 							editor.formatter.apply('align' + data.align, {}, rowElm);
       
   701 						}
       
   702 					});
       
   703 
       
   704 					editor.focus();
       
   705 				});
       
   706 			}
       
   707 
       
   708 			tableElm = editor.dom.getParent(editor.selection.getStart(), 'table');
       
   709 			cellElm = editor.dom.getParent(editor.selection.getStart(), 'td,th');
       
   710 
       
   711 			each(tableElm.rows, function(row) {
       
   712 				each(row.cells, function(cell) {
       
   713 					if (dom.hasClass(cell, 'mce-item-selected') || cell == cellElm) {
       
   714 						rows.push(row);
       
   715 						return false;
       
   716 					}
       
   717 				});
       
   718 			});
       
   719 
       
   720 			rowElm = rows[0];
       
   721 			if (!rowElm) {
       
   722 				// If this element is null, return now to avoid crashing.
       
   723 				return;
       
   724 			}
       
   725 
       
   726 			data = {
       
   727 				height: removePxSuffix(dom.getStyle(rowElm, 'height') || dom.getAttrib(rowElm, 'height')),
       
   728 				scope: dom.getAttrib(rowElm, 'scope'),
       
   729 				'class': dom.getAttrib(rowElm, 'class')
       
   730 			};
       
   731 
       
   732 			data.type = rowElm.parentNode.nodeName.toLowerCase();
       
   733 
       
   734 			each('left center right'.split(' '), function(name) {
       
   735 				if (editor.formatter.matchNode(rowElm, 'align' + name)) {
       
   736 					data.align = name;
       
   737 				}
       
   738 			});
       
   739 
       
   740 			if (editor.settings.table_row_class_list) {
       
   741 				classListCtrl = {
       
   742 					name: 'class',
       
   743 					type: 'listbox',
       
   744 					label: 'Class',
       
   745 					values: buildListItems(
       
   746 						editor.settings.table_row_class_list,
       
   747 						function(item) {
       
   748 							if (item.value) {
       
   749 								item.textStyle = function() {
       
   750 									return editor.formatter.getCssText({block: 'tr', classes: [item.value]});
       
   751 								};
       
   752 							}
       
   753 						}
       
   754 					)
       
   755 				};
       
   756 			}
       
   757 
       
   758 			generalRowForm = {
       
   759 				type: 'form',
       
   760 				columns: 2,
       
   761 				padding: 0,
       
   762 				defaults: {
       
   763 					type: 'textbox'
       
   764 				},
       
   765 				items: [
       
   766 					{
       
   767 						type: 'listbox',
       
   768 						name: 'type',
       
   769 						label: 'Row type',
       
   770 						text: 'None',
       
   771 						maxWidth: null,
       
   772 						values: [
       
   773 							{text: 'Header', value: 'thead'},
       
   774 							{text: 'Body', value: 'tbody'},
       
   775 							{text: 'Footer', value: 'tfoot'}
       
   776 						]
       
   777 					},
       
   778 					{
       
   779 						type: 'listbox',
       
   780 						name: 'align',
       
   781 						label: 'Alignment',
       
   782 						text: 'None',
       
   783 						maxWidth: null,
       
   784 						values: [
       
   785 							{text: 'None', value: ''},
       
   786 							{text: 'Left', value: 'left'},
       
   787 							{text: 'Center', value: 'center'},
       
   788 							{text: 'Right', value: 'right'}
       
   789 						]
       
   790 					},
       
   791 					{label: 'Height', name: 'height'},
       
   792 					classListCtrl
       
   793 				]
       
   794 			};
       
   795 
       
   796 			if (editor.settings.table_row_advtab !== false) {
       
   797 				appendStylesToData(dom, data, rowElm);
       
   798 
       
   799 				editor.windowManager.open({
       
   800 					title: "Row properties",
       
   801 					data: data,
       
   802 					bodyType: 'tabpanel',
       
   803 					body: [
       
   804 						{
       
   805 							title: 'General',
       
   806 							type: 'form',
       
   807 							items: generalRowForm
       
   808 						},
       
   809 						createStyleForm(dom)
       
   810 					],
       
   811 
       
   812 					onsubmit: onSubmitRowForm
       
   813 				});
       
   814 			} else {
       
   815 				editor.windowManager.open({
       
   816 					title: "Row properties",
       
   817 					data: data,
       
   818 					body: generalRowForm,
       
   819 					onsubmit: onSubmitRowForm
       
   820 				});
       
   821 			}
       
   822 		};
       
   823 	};
       
   824 });