Subversion Repositories Sites.tela-botanica.org

Rev

Rev 609 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
420 florian 1
/**
2
 * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
3
 *
4
 * @author Moxiecode
5
 * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
6
 */
7
 
8
/* Import plugin specific language pack */
9
tinyMCE.importPluginLanguagePack('table');
10
 
11
var TinyMCE_TablePlugin = {
12
	getInfo : function() {
13
		return {
14
			longname : 'Tables',
15
			author : 'Moxiecode Systems AB',
16
			authorurl : 'http://tinymce.moxiecode.com',
17
			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/table',
18
			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
19
		};
20
	},
21
 
22
	initInstance : function(inst) {
23
		if (tinyMCE.isGecko) {
24
			var doc = inst.getDoc();
25
			tinyMCE.addEvent(doc, "mouseup", TinyMCE_TablePlugin._mouseDownHandler);
26
		}
27
 
28
		inst.tableRowClipboard = null;
29
	},
30
 
31
	/**
32
	 * Returns the HTML contents of the table control.
33
	 */
34
	getControlHTML : function(control_name) {
35
		var controls = new Array(
36
			['table', 'table.gif', 'lang_table_desc', 'mceInsertTable', true],
37
			['delete_table', 'table_delete.gif', 'lang_table_del', 'mceTableDelete'],
38
			['delete_col', 'table_delete_col.gif', 'lang_table_delete_col_desc', 'mceTableDeleteCol'],
39
			['delete_row', 'table_delete_row.gif', 'lang_table_delete_row_desc', 'mceTableDeleteRow'],
40
			['col_after', 'table_insert_col_after.gif', 'lang_table_col_after_desc', 'mceTableInsertColAfter'],
41
			['col_before', 'table_insert_col_before.gif', 'lang_table_col_before_desc', 'mceTableInsertColBefore'],
42
			['row_after', 'table_insert_row_after.gif', 'lang_table_row_after_desc', 'mceTableInsertRowAfter'],
43
			['row_before', 'table_insert_row_before.gif', 'lang_table_row_before_desc', 'mceTableInsertRowBefore'],
44
			['row_props', 'table_row_props.gif', 'lang_table_row_desc', 'mceTableRowProps', true],
45
			['cell_props', 'table_cell_props.gif', 'lang_table_cell_desc', 'mceTableCellProps', true],
46
			['split_cells', 'table_split_cells.gif', 'lang_table_split_cells_desc', 'mceTableSplitCells', true],
47
			['merge_cells', 'table_merge_cells.gif', 'lang_table_merge_cells_desc', 'mceTableMergeCells', true]);
48
 
49
		// Render table control
50
		for (var i=0; i<controls.length; i++) {
51
			var but = controls[i];
52
			var cmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + but[3] + '\', ' + (but.length > 4 ? but[4] : false) + (but.length > 5 ? ', \'' + but[5] + '\'' : '') + ');return false;';
53
 
54
			if (but[0] == control_name)
55
				return tinyMCE.getButtonHTML(control_name, but[2], '{$pluginurl}/images/'+ but[1], but[3], (but.length > 4 ? but[4] : false));
56
		}
57
 
58
		// Special tablecontrols
59
		if (control_name == "tablecontrols") {
60
			var html = "";
61
 
62
			html += tinyMCE.getControlHTML("table");
63
			html += tinyMCE.getControlHTML("separator");
64
			html += tinyMCE.getControlHTML("row_props");
65
			html += tinyMCE.getControlHTML("cell_props");
66
			html += tinyMCE.getControlHTML("separator");
67
			html += tinyMCE.getControlHTML("row_before");
68
			html += tinyMCE.getControlHTML("row_after");
69
			html += tinyMCE.getControlHTML("delete_row");
70
			html += tinyMCE.getControlHTML("separator");
71
			html += tinyMCE.getControlHTML("col_before");
72
			html += tinyMCE.getControlHTML("col_after");
73
			html += tinyMCE.getControlHTML("delete_col");
74
			html += tinyMCE.getControlHTML("separator");
75
			html += tinyMCE.getControlHTML("split_cells");
76
			html += tinyMCE.getControlHTML("merge_cells");
77
 
78
			return html;
79
		}
80
 
81
		return "";
82
	},
83
 
84
	/**
85
	 * Executes the table commands.
86
	 */
87
	execCommand : function(editor_id, element, command, user_interface, value) {
88
		// Is table command
89
		switch (command) {
90
			case "mceInsertTable":
91
			case "mceTableRowProps":
92
			case "mceTableCellProps":
93
			case "mceTableSplitCells":
94
			case "mceTableMergeCells":
95
			case "mceTableInsertRowBefore":
96
			case "mceTableInsertRowAfter":
97
			case "mceTableDeleteRow":
98
			case "mceTableInsertColBefore":
99
			case "mceTableInsertColAfter":
100
			case "mceTableDeleteCol":
101
			case "mceTableCutRow":
102
			case "mceTableCopyRow":
103
			case "mceTablePasteRowBefore":
104
			case "mceTablePasteRowAfter":
105
			case "mceTableDelete":
106
				var inst = tinyMCE.getInstanceById(editor_id);
107
 
108
				inst.execCommand('mceBeginUndoLevel');
109
				TinyMCE_TablePlugin._doExecCommand(editor_id, element, command, user_interface, value);
110
				inst.execCommand('mceEndUndoLevel');
111
 
112
				return true;
113
		}
114
 
115
		// Pass to next handler in chain
116
		return false;
117
	},
118
 
119
	handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {
120
		var colspan = "1", rowspan = "1", tdElm;
121
 
122
		var inst = tinyMCE.getInstanceById(editor_id);
123
 
124
		// Reset table controls
125
		tinyMCE.switchClass(editor_id + '_table', 'mceButtonNormal');
126
		tinyMCE.switchClass(editor_id + '_delete_table', 'mceButtonDisabled');
127
		tinyMCE.switchClass(editor_id + '_row_props', 'mceButtonDisabled');
128
		tinyMCE.switchClass(editor_id + '_cell_props', 'mceButtonDisabled');
129
		tinyMCE.switchClass(editor_id + '_row_before', 'mceButtonDisabled');
130
		tinyMCE.switchClass(editor_id + '_row_after', 'mceButtonDisabled');
131
		tinyMCE.switchClass(editor_id + '_delete_row', 'mceButtonDisabled');
132
		tinyMCE.switchClass(editor_id + '_col_before', 'mceButtonDisabled');
133
		tinyMCE.switchClass(editor_id + '_col_after', 'mceButtonDisabled');
134
		tinyMCE.switchClass(editor_id + '_delete_col', 'mceButtonDisabled');
135
		tinyMCE.switchClass(editor_id + '_split_cells', 'mceButtonDisabled');
136
		tinyMCE.switchClass(editor_id + '_merge_cells', 'mceButtonDisabled');
137
 
138
		// Within a td element
139
		if (tdElm = tinyMCE.getParentElement(node, "td,th")) {
140
			tinyMCE.switchClass(editor_id + '_cell_props', 'mceButtonSelected');
141
			tinyMCE.switchClass(editor_id + '_delete_table', 'mceButtonNormal');
142
			tinyMCE.switchClass(editor_id + '_row_before', 'mceButtonNormal');
143
			tinyMCE.switchClass(editor_id + '_row_after', 'mceButtonNormal');
144
			tinyMCE.switchClass(editor_id + '_delete_row', 'mceButtonNormal');
145
			tinyMCE.switchClass(editor_id + '_col_before', 'mceButtonNormal');
146
			tinyMCE.switchClass(editor_id + '_col_after', 'mceButtonNormal');
147
			tinyMCE.switchClass(editor_id + '_delete_col', 'mceButtonNormal');
148
 
149
			colspan = tinyMCE.getAttrib(tdElm, "colspan");
150
			rowspan = tinyMCE.getAttrib(tdElm, "rowspan");
151
 
152
			colspan = colspan == "" ? "1" : colspan;
153
			rowspan = rowspan == "" ? "1" : rowspan;
154
 
155
			if (colspan != "1" || rowspan != "1")
156
				tinyMCE.switchClass(editor_id + '_split_cells', 'mceButtonNormal');
157
		}
158
 
159
		// Within a tr element
160
		if (tinyMCE.getParentElement(node, "tr"))
161
			tinyMCE.switchClass(editor_id + '_row_props', 'mceButtonSelected');
162
 
163
		// Within table
164
		if (tinyMCE.getParentElement(node, "table")) {
165
			tinyMCE.switchClass(editor_id + '_table', 'mceButtonSelected');
166
			tinyMCE.switchClass(editor_id + '_merge_cells', 'mceButtonNormal');
167
		}
168
	},
169
 
170
	// Private plugin internal methods
171
 
172
	_mouseDownHandler : function(e) {
173
		var elm = tinyMCE.isMSIE ? event.srcElement : e.target;
174
		var focusElm = tinyMCE.selectedInstance.getFocusElement();
175
 
176
		// If press on special Mozilla create TD/TR thingie
177
		if (elm.nodeName == "BODY" && (focusElm.nodeName == "TD" || focusElm.nodeName == "TH" || (focusElm.parentNode && focusElm.parentNode.nodeName == "TD") ||(focusElm.parentNode && focusElm.parentNode.nodeName == "TH") )) {
178
			window.setTimeout(function() {
179
				var tableElm = tinyMCE.getParentElement(focusElm, "table");
180
				tinyMCE.handleVisualAid(tableElm, true, tinyMCE.settings['visual'], tinyMCE.selectedInstance);
181
			}, 10);
182
		}
183
	},
184
 
185
	/**
186
	 * Executes the table commands.
187
	 */
188
	_doExecCommand : function(editor_id, element, command, user_interface, value) {
189
		var inst = tinyMCE.getInstanceById(editor_id);
190
		var focusElm = inst.getFocusElement();
191
		var trElm = tinyMCE.getParentElement(focusElm, "tr");
192
		var tdElm = tinyMCE.getParentElement(focusElm, "td,th");
193
		var tableElm = tinyMCE.getParentElement(focusElm, "table");
194
		var doc = inst.contentWindow.document;
195
		var tableBorder = tableElm ? tableElm.getAttribute("border") : "";
196
 
197
		// Get first TD if no TD found
198
		if (trElm && tdElm == null)
199
			tdElm = trElm.cells[0];
200
 
201
		// ------- Inner functions ---------
202
		function inArray(ar, v) {
203
			for (var i=0; i<ar.length; i++) {
204
				// Is array
205
				if (ar[i].length > 0 && inArray(ar[i], v))
206
					return true;
207
 
208
				// Found value
209
				if (ar[i] == v)
210
					return true;
211
			}
212
 
213
			return false;
214
		}
215
 
216
		function makeTD() {
217
			var newTD = doc.createElement("td");
218
			newTD.innerHTML = "&nbsp;";
219
		}
220
 
221
		function getColRowSpan(td) {
222
			var colspan = tinyMCE.getAttrib(td, "colspan");
223
			var rowspan = tinyMCE.getAttrib(td, "rowspan");
224
 
225
			colspan = colspan == "" ? 1 : parseInt(colspan);
226
			rowspan = rowspan == "" ? 1 : parseInt(rowspan);
227
 
228
			return {colspan : colspan, rowspan : rowspan};
229
		}
230
 
231
		function getCellPos(grid, td) {
232
			var x, y;
233
 
234
			for (y=0; y<grid.length; y++) {
235
				for (x=0; x<grid[y].length; x++) {
236
					if (grid[y][x] == td)
237
						return {cellindex : x, rowindex : y};
238
				}
239
			}
240
 
241
			return null;
242
		}
243
 
244
		function getCell(grid, row, col) {
245
			if (grid[row] && grid[row][col])
246
				return grid[row][col];
247
 
248
			return null;
249
		}
250
 
251
		function getTableGrid(table) {
252
			var grid = new Array(), rows = table.rows, x, y, td, sd, xstart, x2, y2;
253
 
254
			for (y=0; y<rows.length; y++) {
255
				for (x=0; x<rows[y].cells.length; x++) {
256
					td = rows[y].cells[x];
257
					sd = getColRowSpan(td);
258
 
259
					// All ready filled
260
					for (xstart = x; grid[y] && grid[y][xstart]; xstart++) ;
261
 
262
					// Fill box
263
					for (y2=y; y2<y+sd['rowspan']; y2++) {
264
						if (!grid[y2])
265
							grid[y2] = new Array();
266
 
267
						for (x2=xstart; x2<xstart+sd['colspan']; x2++)
268
							grid[y2][x2] = td;
269
					}
270
				}
271
			}
272
 
273
			return grid;
274
		}
275
 
276
		function trimRow(table, tr, td, new_tr) {
277
			var grid = getTableGrid(table), cpos = getCellPos(grid, td);
278
			var cells, lastElm;
279
 
280
			// Time to crop away some
281
			if (new_tr.cells.length != tr.childNodes.length) {
282
				cells = tr.childNodes;
283
				lastElm = null;
284
 
285
				for (var x=0; td = getCell(grid, cpos.rowindex, x); x++) {
286
					var remove = true;
287
					var sd = getColRowSpan(td);
288
 
289
					// Remove due to rowspan
290
					if (inArray(cells, td)) {
291
						new_tr.childNodes[x]._delete = true;
292
					} else if ((lastElm == null || td != lastElm) && sd.colspan > 1) { // Remove due to colspan
293
						for (var i=x; i<x+td.colSpan; i++)
294
							new_tr.childNodes[i]._delete = true;
295
					}
296
 
297
					if ((lastElm == null || td != lastElm) && sd.rowspan > 1)
298
						td.rowSpan = sd.rowspan + 1;
299
 
300
					lastElm = td;
301
				}
302
 
303
				deleteMarked(tableElm);
304
			}
305
		}
306
 
307
		function prevElm(node, name) {
308
			while ((node = node.previousSibling) != null) {
309
				if (node.nodeName == name)
310
					return node;
311
			}
312
 
313
			return null;
314
		}
315
 
316
		function nextElm(node, names) {
317
			var namesAr = names.split(',');
318
 
319
			while ((node = node.nextSibling) != null) {
320
				for (var i=0; i<namesAr.length; i++) {
321
					if (node.nodeName.toLowerCase() == namesAr[i].toLowerCase() )
322
						return node;
323
				}
324
			}
325
 
326
			return null;
327
		}
328
 
329
		function deleteMarked(tbl) {
330
			if (tbl.rows == 0)
331
				return;
332
 
333
			var tr = tbl.rows[0];
334
			do {
335
				var next = nextElm(tr, "TR");
336
 
337
				// Delete row
338
				if (tr._delete) {
339
					tr.parentNode.removeChild(tr);
340
					continue;
341
				}
342
 
343
				// Delete cells
344
				var td = tr.cells[0];
345
				if (td.cells > 1) {
346
					do {
347
						var nexttd = nextElm(td, "TD,TH");
348
 
349
						if (td._delete)
350
							td.parentNode.removeChild(td);
351
					} while ((td = nexttd) != null);
352
				}
353
			} while ((tr = next) != null);
354
		}
355
 
356
		function addRows(td_elm, tr_elm, rowspan) {
357
			// Add rows
358
			td_elm.rowSpan = 1;
359
			var trNext = nextElm(tr_elm, "TR");
360
			for (var i=1; i<rowspan && trNext; i++) {
361
				var newTD = doc.createElement("td");
362
				newTD.innerHTML = "&nbsp;";
363
 
364
				if (tinyMCE.isMSIE)
365
					trNext.insertBefore(newTD, trNext.cells(td_elm.cellIndex));
366
				else
367
					trNext.insertBefore(newTD, trNext.cells[td_elm.cellIndex]);
368
 
369
				trNext = nextElm(trNext, "TR");
370
			}
371
		}
372
 
373
		function copyRow(doc, table, tr) {
374
			var grid = getTableGrid(table);
375
			var newTR = tr.cloneNode(false);
376
			var cpos = getCellPos(grid, tr.cells[0]);
377
			var lastCell = null;
378
			var tableBorder = tinyMCE.getAttrib(table, "border");
379
			var tdElm = null;
380
 
381
			for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
382
				var newTD = null;
383
 
384
				if (lastCell != tdElm) {
385
					for (var i=0; i<tr.cells.length; i++) {
386
						if (tdElm == tr.cells[i]) {
387
							newTD = tdElm.cloneNode(true);
388
							break;
389
						}
390
					}
391
				}
392
 
393
				if (newTD == null) {
394
					newTD = doc.createElement("td");
395
					newTD.innerHTML = "&nbsp;";
396
				}
397
 
398
				// Reset col/row span
399
				newTD.colSpan = 1;
400
				newTD.rowSpan = 1;
401
 
402
				newTR.appendChild(newTD);
403
 
404
				lastCell = tdElm;
405
			}
406
 
407
			return newTR;
408
		}
409
 
410
		// ---- Commands -----
411
 
412
		// Handle commands
413
		switch (command) {
414
			case "mceTableRowProps":
415
				if (trElm == null)
416
					return true;
417
 
418
				if (user_interface) {
419
					// Setup template
420
					var template = new Array();
421
 
422
					template['file'] = '../../plugins/table/row.htm';
423
					template['width'] = 380;
424
					template['height'] = 295;
425
 
426
					// Language specific width and height addons
427
					template['width'] += tinyMCE.getLang('lang_table_rowprops_delta_width', 0);
428
					template['height'] += tinyMCE.getLang('lang_table_rowprops_delta_height', 0);
429
 
430
					// Open window
431
					tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes"});
432
				}
433
 
434
				return true;
435
 
436
			case "mceTableCellProps":
437
				if (tdElm == null)
438
					return true;
439
 
440
				if (user_interface) {
441
					// Setup template
442
					var template = new Array();
443
 
444
					template['file'] = '../../plugins/table/cell.htm';
445
					template['width'] = 380;
446
					template['height'] = 295;
447
 
448
					// Language specific width and height addons
449
					template['width'] += tinyMCE.getLang('lang_table_cellprops_delta_width', 0);
450
					template['height'] += tinyMCE.getLang('lang_table_cellprops_delta_height', 0);
451
 
452
					// Open window
453
					tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes"});
454
				}
455
 
456
				return true;
457
 
458
			case "mceInsertTable":
459
				if (user_interface) {
460
					// Setup template
461
					var template = new Array();
462
 
463
					template['file'] = '../../plugins/table/table.htm';
464
					template['width'] = 380;
465
					template['height'] = 295;
466
 
467
					// Language specific width and height addons
468
					template['width'] += tinyMCE.getLang('lang_table_table_delta_width', 0);
469
					template['height'] += tinyMCE.getLang('lang_table_table_delta_height', 0);
470
 
471
					// Open window
472
					tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes", action : value});
473
				}
474
 
475
				return true;
476
 
477
			case "mceTableDelete":
478
				var table = tinyMCE.getParentElement(inst.getFocusElement(), "table");
479
				if (table) {
480
					table.parentNode.removeChild(table);
481
					inst.repaint();
482
				}
483
				return true;
484
 
485
			case "mceTableSplitCells":
486
			case "mceTableMergeCells":
487
			case "mceTableInsertRowBefore":
488
			case "mceTableInsertRowAfter":
489
			case "mceTableDeleteRow":
490
			case "mceTableInsertColBefore":
491
			case "mceTableInsertColAfter":
492
			case "mceTableDeleteCol":
493
			case "mceTableCutRow":
494
			case "mceTableCopyRow":
495
			case "mceTablePasteRowBefore":
496
			case "mceTablePasteRowAfter":
497
				// No table just return (invalid command)
498
				if (!tableElm)
499
					return true;
500
 
501
				// Table has a tbody use that reference
502
				// Changed logic by ApTest 2005.07.12 (www.aptest.com)
503
				// Now lookk at the focused element and take its parentNode.  That will be a tbody or a table.
504
				if (trElm && tableElm != trElm.parentNode)
505
					tableElm = trElm.parentNode;
506
 
507
				if (tableElm && trElm) {
508
					switch (command) {
509
						case "mceTableCutRow":
510
							if (!trElm || !tdElm)
511
								return true;
512
 
513
							inst.tableRowClipboard = copyRow(doc, tableElm, trElm);
514
							inst.execCommand("mceTableDeleteRow");
515
							break;
516
 
517
						case "mceTableCopyRow":
518
							if (!trElm || !tdElm)
519
								return true;
520
 
521
							inst.tableRowClipboard = copyRow(doc, tableElm, trElm);
522
							break;
523
 
524
						case "mceTablePasteRowBefore":
525
							if (!trElm || !tdElm)
526
								return true;
527
 
528
							var newTR = inst.tableRowClipboard.cloneNode(true);
529
 
530
							var prevTR = prevElm(trElm, "TR");
531
							if (prevTR != null)
532
								trimRow(tableElm, prevTR, prevTR.cells[0], newTR);
533
 
534
							trElm.parentNode.insertBefore(newTR, trElm);
535
							break;
536
 
537
						case "mceTablePasteRowAfter":
538
							if (!trElm || !tdElm)
539
								return true;
540
 
541
							var nextTR = nextElm(trElm, "TR");
542
							var newTR = inst.tableRowClipboard.cloneNode(true);
543
 
544
							trimRow(tableElm, trElm, tdElm, newTR);
545
 
546
							if (nextTR == null)
547
								trElm.parentNode.appendChild(newTR);
548
							else
549
								nextTR.parentNode.insertBefore(newTR, nextTR);
550
 
551
							break;
552
 
553
						case "mceTableInsertRowBefore":
554
							if (!trElm || !tdElm)
555
								return true;
556
 
557
							var grid = getTableGrid(tableElm);
558
							var cpos = getCellPos(grid, tdElm);
559
							var newTR = doc.createElement("tr");
560
							var lastTDElm = null;
561
 
562
							cpos.rowindex--;
563
							if (cpos.rowindex < 0)
564
								cpos.rowindex = 0;
565
 
566
							// Create cells
567
							for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
568
								if (tdElm != lastTDElm) {
569
									var sd = getColRowSpan(tdElm);
570
 
571
									if (sd['rowspan'] == 1) {
572
										var newTD = doc.createElement("td");
573
 
574
										newTD.innerHTML = "&nbsp;";
575
										newTD.colSpan = tdElm.colSpan;
576
 
577
										newTR.appendChild(newTD);
578
									} else
579
										tdElm.rowSpan = sd['rowspan'] + 1;
580
 
581
									lastTDElm = tdElm;
582
								}
583
							}
584
 
585
							trElm.parentNode.insertBefore(newTR, trElm);
586
 
587
							grid = getTableGrid(tableElm);
588
							inst.selection.selectNode(getCell(grid, cpos.rowindex + 1, cpos.cellindex), tinyMCE.isGecko, true); // Only collape on gecko
589
						break;
590
 
591
						case "mceTableInsertRowAfter":
592
							if (!trElm || !tdElm)
593
								return true;
594
 
595
							var grid = getTableGrid(tableElm);
596
							var cpos = getCellPos(grid, tdElm);
597
							var newTR = doc.createElement("tr");
598
							var lastTDElm = null;
599
 
600
							// Create cells
601
							for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
602
								if (tdElm != lastTDElm) {
603
									var sd = getColRowSpan(tdElm);
604
 
605
									if (sd['rowspan'] == 1) {
606
										var newTD = doc.createElement("td");
607
 
608
										newTD.innerHTML = "&nbsp;";
609
										newTD.colSpan = tdElm.colSpan;
610
 
611
										newTR.appendChild(newTD);
612
									} else
613
										tdElm.rowSpan = sd['rowspan'] + 1;
614
 
615
									lastTDElm = tdElm;
616
								}
617
							}
618
 
619
							if (newTR.hasChildNodes()) {
620
								var nextTR = nextElm(trElm, "TR");
621
								if (nextTR)
622
									nextTR.parentNode.insertBefore(newTR, nextTR);
623
								else
624
									tableElm.appendChild(newTR);
625
							}
626
 
627
							grid = getTableGrid(tableElm);
628
							inst.selection.selectNode(getCell(grid, cpos.rowindex, cpos.cellindex), tinyMCE.isGecko, true); // Only collape on gecko
629
						break;
630
 
631
						case "mceTableDeleteRow":
632
							if (!trElm || !tdElm)
633
								return true;
634
 
635
							var grid = getTableGrid(tableElm);
636
							var cpos = getCellPos(grid, tdElm);
637
 
638
							// Only one row, remove whole table
639
							if (grid.length == 1) {
640
								tableElm = tinyMCE.getParentElement(tableElm, "table"); // Look for table instead of tbody
641
								tableElm.parentNode.removeChild(tableElm);
642
								return true;
643
							}
644
 
645
							// Move down row spanned cells
646
							var cells = trElm.cells;
647
							var nextTR = nextElm(trElm, "TR");
648
							for (var x=0; x<cells.length; x++) {
649
								if (cells[x].rowSpan > 1) {
650
									var newTD = cells[x].cloneNode(true);
651
									var sd = getColRowSpan(cells[x]);
652
 
653
									newTD.rowSpan = sd.rowspan - 1;
654
 
655
									var nextTD = nextTR.cells[x];
656
 
657
									if (nextTD == null)
658
										nextTR.appendChild(newTD);
659
									else
660
										nextTR.insertBefore(newTD, nextTD);
661
								}
662
							}
663
 
664
							// Delete cells
665
							var lastTDElm = null;
666
							for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
667
								if (tdElm != lastTDElm) {
668
									var sd = getColRowSpan(tdElm);
669
 
670
									if (sd.rowspan > 1) {
671
										tdElm.rowSpan = sd.rowspan - 1;
672
									} else {
673
										trElm = tdElm.parentNode;
674
 
675
										if (trElm.parentNode)
676
											trElm._delete = true;
677
									}
678
 
679
									lastTDElm = tdElm;
680
								}
681
							}
682
 
683
							deleteMarked(tableElm);
684
 
685
							cpos.rowindex--;
686
							if (cpos.rowindex < 0)
687
								cpos.rowindex = 0;
688
 
689
							// Recalculate grid and select
690
							grid = getTableGrid(tableElm);
691
							inst.selection.selectNode(getCell(grid, cpos.rowindex, 0), tinyMCE.isGecko, true); // Only collape on gecko
692
						break;
693
 
694
						case "mceTableInsertColBefore":
695
							if (!trElm || !tdElm)
696
								return true;
697
 
698
							var grid = getTableGrid(tableElm);
699
							var cpos = getCellPos(grid, tdElm);
700
							var lastTDElm = null;
701
 
702
							for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {
703
								if (tdElm != lastTDElm) {
704
									var sd = getColRowSpan(tdElm);
705
 
706
									if (sd['colspan'] == 1) {
707
										var newTD = doc.createElement(tdElm.nodeName);
708
 
709
										newTD.innerHTML = "&nbsp;";
710
										newTD.rowSpan = tdElm.rowSpan;
711
 
712
										tdElm.parentNode.insertBefore(newTD, tdElm);
713
									} else
714
										tdElm.colSpan++;
715
 
716
									lastTDElm = tdElm;
717
								}
718
							}
719
 
720
							grid = getTableGrid(tableElm);
721
							inst.selection.selectNode(getCell(grid, cpos.rowindex, cpos.cellindex + 1), tinyMCE.isGecko, true); // Only collape on gecko
722
						break;
723
 
724
						case "mceTableInsertColAfter":
725
							if (!trElm || !tdElm)
726
								return true;
727
 
728
							var grid = getTableGrid(tableElm);
729
							var cpos = getCellPos(grid, tdElm);
730
							var lastTDElm = null;
731
 
732
							for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {
733
								if (tdElm != lastTDElm) {
734
									var sd = getColRowSpan(tdElm);
735
 
736
									if (sd['colspan'] == 1) {
737
										var newTD = doc.createElement(tdElm.nodeName);
738
 
739
										newTD.innerHTML = "&nbsp;";
740
										newTD.rowSpan = tdElm.rowSpan;
741
 
742
										var nextTD = nextElm(tdElm, "TD,TH");
743
										if (nextTD == null)
744
											tdElm.parentNode.appendChild(newTD);
745
										else
746
											nextTD.parentNode.insertBefore(newTD, nextTD);
747
									} else
748
										tdElm.colSpan++;
749
 
750
									lastTDElm = tdElm;
751
								}
752
							}
753
 
754
							grid = getTableGrid(tableElm);
755
							inst.selection.selectNode(getCell(grid, cpos.rowindex, cpos.cellindex), tinyMCE.isGecko, true); // Only collape on gecko
756
						break;
757
 
758
						case "mceTableDeleteCol":
759
							if (!trElm || !tdElm)
760
								return true;
761
 
762
							var grid = getTableGrid(tableElm);
763
							var cpos = getCellPos(grid, tdElm);
764
							var lastTDElm = null;
765
 
766
							// Only one col, remove whole table
767
							if (grid.length > 1 && grid[0].length <= 1) {
768
								tableElm = tinyMCE.getParentElement(tableElm, "table"); // Look for table instead of tbody
769
								tableElm.parentNode.removeChild(tableElm);
770
								return true;
771
							}
772
 
773
							// Delete cells
774
							for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {
775
								if (tdElm != lastTDElm) {
776
									var sd = getColRowSpan(tdElm);
777
 
778
									if (sd['colspan'] > 1)
779
										tdElm.colSpan = sd['colspan'] - 1;
780
									else {
781
										if (tdElm.parentNode)
782
											tdElm.parentNode.removeChild(tdElm);
783
									}
784
 
785
									lastTDElm = tdElm;
786
								}
787
							}
788
 
789
							cpos.cellindex--;
790
							if (cpos.cellindex < 0)
791
								cpos.cellindex = 0;
792
 
793
							// Recalculate grid and select
794
							grid = getTableGrid(tableElm);
795
							inst.selection.selectNode(getCell(grid, cpos.rowindex, 0), tinyMCE.isGecko, true); // Only collape on gecko
796
						break;
797
 
798
					case "mceTableSplitCells":
799
						if (!trElm || !tdElm)
800
							return true;
801
 
802
						var spandata = getColRowSpan(tdElm);
803
 
804
						var colspan = spandata["colspan"];
805
						var rowspan = spandata["rowspan"];
806
 
807
						// Needs splitting
808
						if (colspan > 1 || rowspan > 1) {
809
							// Generate cols
810
							tdElm.colSpan = 1;
811
							for (var i=1; i<colspan; i++) {
812
								var newTD = doc.createElement("td");
813
 
814
								newTD.innerHTML = "&nbsp;";
815
 
816
								trElm.insertBefore(newTD, nextElm(tdElm, "TD,TH"));
817
 
818
								if (rowspan > 1)
819
									addRows(newTD, trElm, rowspan);
820
							}
821
 
822
							addRows(tdElm, trElm, rowspan);
823
						}
824
 
825
						// Apply visual aids
826
						tableElm = tinyMCE.getParentElement(inst.getFocusElement(), "table");
827
						break;
828
 
829
					case "mceTableMergeCells":
830
						var rows = new Array();
831
						var sel = inst.getSel();
832
						var grid = getTableGrid(tableElm);
833
 
834
						if (tinyMCE.isMSIE || sel.rangeCount == 1) {
835
							if (user_interface) {
836
								// Setup template
837
								var template = new Array();
838
								var sp = getColRowSpan(tdElm);
839
 
840
								template['file'] = '../../plugins/table/merge_cells.htm';
841
								template['width'] = 250;
842
								template['height'] = 105 + (tinyMCE.isNS7 ? 25 : 0);
843
 
844
								// Language specific width and height addons
845
								template['width'] += tinyMCE.getLang('lang_table_merge_cells_delta_width', 0);
846
								template['height'] += tinyMCE.getLang('lang_table_merge_cells_delta_height', 0);
847
 
848
								// Open window
849
								tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes", action : "update", numcols : sp.colspan, numrows : sp.rowspan});
850
 
851
								return true;
852
							} else {
853
								var numRows = parseInt(value['numrows']);
854
								var numCols = parseInt(value['numcols']);
855
								var cpos = getCellPos(grid, tdElm);
856
 
857
								if (("" + numRows) == "NaN")
858
									numRows = 1;
859
 
860
								if (("" + numCols) == "NaN")
861
									numCols = 1;
862
 
863
								// Get rows and cells
864
								var tRows = tableElm.rows;
865
								for (var y=cpos.rowindex; y<grid.length; y++) {
866
									var rowCells = new Array();
867
 
868
									for (var x=cpos.cellindex; x<grid[y].length; x++) {
869
										var td = getCell(grid, y, x);
870
 
871
										if (td && !inArray(rows, td) && !inArray(rowCells, td)) {
872
											var cp = getCellPos(grid, td);
873
 
874
											// Within range
875
											if (cp.cellindex < cpos.cellindex+numCols && cp.rowindex < cpos.rowindex+numRows)
876
												rowCells[rowCells.length] = td;
877
										}
878
									}
879
 
880
									if (rowCells.length > 0)
881
										rows[rows.length] = rowCells;
882
								}
883
 
884
								//return true;
885
							}
886
						} else {
887
							var cells = new Array();
888
							var sel = inst.getSel();
889
							var lastTR = null;
890
							var curRow = null;
891
							var x1 = -1, y1 = -1, x2, y2;
892
 
893
							// Only one cell selected, whats the point?
894
							if (sel.rangeCount < 2)
895
								return true;
896
 
897
							// Get all selected cells
898
							for (var i=0; i<sel.rangeCount; i++) {
899
								var rng = sel.getRangeAt(i);
900
								var tdElm = rng.startContainer.childNodes[rng.startOffset];
901
 
902
								if (!tdElm)
903
									break;
904
 
905
								if (tdElm.nodeName == "TD")
906
									cells[cells.length] = tdElm;
907
							}
908
 
909
							// Get rows and cells
910
							var tRows = tableElm.rows;
911
							for (var y=0; y<tRows.length; y++) {
912
								var rowCells = new Array();
913
 
914
								for (var x=0; x<tRows[y].cells.length; x++) {
915
									var td = tRows[y].cells[x];
916
 
917
									for (var i=0; i<cells.length; i++) {
918
										if (td == cells[i]) {
919
											rowCells[rowCells.length] = td;
920
										}
921
									}
922
								}
923
 
924
								if (rowCells.length > 0)
925
									rows[rows.length] = rowCells;
926
							}
927
 
928
							// Find selected cells in grid and box
929
							var curRow = new Array();
930
							var lastTR = null;
931
							for (var y=0; y<grid.length; y++) {
932
								for (var x=0; x<grid[y].length; x++) {
933
									grid[y][x]._selected = false;
934
 
935
									for (var i=0; i<cells.length; i++) {
936
										if (grid[y][x] == cells[i]) {
937
											// Get start pos
938
											if (x1 == -1) {
939
												x1 = x;
940
												y1 = y;
941
											}
942
 
943
											// Get end pos
944
											x2 = x;
945
											y2 = y;
946
 
947
											grid[y][x]._selected = true;
948
										}
949
									}
950
								}
951
							}
952
 
953
							// Is there gaps, if so deny
954
							for (var y=y1; y<=y2; y++) {
955
								for (var x=x1; x<=x2; x++) {
956
									if (!grid[y][x]._selected) {
957
										alert("Invalid selection for merge.");
958
										return true;
959
									}
960
								}
961
							}
962
						}
963
 
964
						// Validate selection and get total rowspan and colspan
965
						var rowSpan = 1, colSpan = 1;
966
 
967
						// Validate horizontal and get total colspan
968
						var lastRowSpan = -1;
969
						for (var y=0; y<rows.length; y++) {
970
							var rowColSpan = 0;
971
 
972
							for (var x=0; x<rows[y].length; x++) {
973
								var sd = getColRowSpan(rows[y][x]);
974
 
975
								rowColSpan += sd['colspan'];
976
 
977
								if (lastRowSpan != -1 && sd['rowspan'] != lastRowSpan) {
978
									alert("Invalid selection for merge.");
979
									return true;
980
								}
981
 
982
								lastRowSpan = sd['rowspan'];
983
							}
984
 
985
							if (rowColSpan > colSpan)
986
								colSpan = rowColSpan;
987
 
988
							lastRowSpan = -1;
989
						}
990
 
991
						// Validate vertical and get total rowspan
992
						var lastColSpan = -1;
993
						for (var x=0; x<rows[0].length; x++) {
994
							var colRowSpan = 0;
995
 
996
							for (var y=0; y<rows.length; y++) {
997
								var sd = getColRowSpan(rows[y][x]);
998
 
999
								colRowSpan += sd['rowspan'];
1000
 
1001
								if (lastColSpan != -1 && sd['colspan'] != lastColSpan) {
1002
									alert("Invalid selection for merge.");
1003
									return true;
1004
								}
1005
 
1006
								lastColSpan = sd['colspan'];
1007
							}
1008
 
1009
							if (colRowSpan > rowSpan)
1010
								rowSpan = colRowSpan;
1011
 
1012
							lastColSpan = -1;
1013
						}
1014
 
1015
						// Setup td
1016
						tdElm = rows[0][0];
1017
						tdElm.rowSpan = rowSpan;
1018
						tdElm.colSpan = colSpan;
1019
 
1020
						// Merge cells
1021
						for (var y=0; y<rows.length; y++) {
1022
							for (var x=0; x<rows[y].length; x++) {
1023
								var html = rows[y][x].innerHTML;
1024
								var chk = tinyMCE.regexpReplace(html, "[ \t\r\n]", "");
1025
 
1026
								if (chk != "<br/>" && chk != "<br>" && chk != "&nbsp;" && (x+y > 0))
1027
									tdElm.innerHTML += html;
1028
 
1029
								// Not current cell
1030
								if (rows[y][x] != tdElm && !rows[y][x]._deleted) {
1031
									var cpos = getCellPos(grid, rows[y][x]);
1032
									var tr = rows[y][x].parentNode;
1033
 
1034
									tr.removeChild(rows[y][x]);
1035
									rows[y][x]._deleted = true;
1036
 
1037
									// Empty TR, remove it
1038
									if (!tr.hasChildNodes()) {
1039
										tr.parentNode.removeChild(tr);
1040
 
1041
										var lastCell = null;
1042
										for (var x=0; cellElm = getCell(grid, cpos.rowindex, x); x++) {
1043
											if (cellElm != lastCell && cellElm.rowSpan > 1)
1044
												cellElm.rowSpan--;
1045
 
1046
											lastCell = cellElm;
1047
										}
1048
 
1049
										if (tdElm.rowSpan > 1)
1050
											tdElm.rowSpan--;
1051
									}
1052
								}
1053
							}
1054
						}
1055
 
1056
						break;
1057
					}
1058
 
1059
					tableElm = tinyMCE.getParentElement(inst.getFocusElement(), "table");
1060
					tinyMCE.handleVisualAid(tableElm, true, tinyMCE.settings['visual'], tinyMCE.selectedInstance);
1061
					tinyMCE.triggerNodeChange();
1062
					inst.repaint();
1063
				}
1064
 
1065
			return true;
1066
		}
1067
 
1068
		// Pass to next handler in chain
1069
		return false;
1070
	}
1071
};
1072
 
1073
tinyMCE.addPlugin("table", TinyMCE_TablePlugin);