17116c689f281591cccd2919ff9317eed86f2bb1
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / htmlarea / plugins / TableOperations / table-operations.js
1 /***************************************************************
2 * Copyright notice
3 *
4 * (c) 2002 interactivetools.com, inc. Authored by Mihai Bazon, sponsored by http://www.bloki.com.
5 * (c) 2005 Xinha, http://xinha.gogo.co.nz/ for the original toggle borders function.
6 * (c) 2004-2008 Stanislas Rolland <stanislas.rolland(arobas)fructifor.ca>
7 * All rights reserved
8 *
9 * This script is part of the TYPO3 project. The TYPO3 project is
10 * free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * The GNU General Public License can be found at
16 * http://www.gnu.org/copyleft/gpl.html.
17 * A copy is found in the textfile GPL.txt and important notices to the license
18 * from the author is found in LICENSE.txt distributed with these scripts.
19 *
20 *
21 * This script is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * This script is a modified version of a script published under the htmlArea License.
27 * A copy of the htmlArea License may be found in the textfile HTMLAREA_LICENSE.txt.
28 *
29 * This copyright notice MUST APPEAR in all copies of the script!
30 ***************************************************************/
31 /*
32 * Table Operations Plugin for TYPO3 htmlArea RTE
33 *
34 * TYPO3 SVN ID: $Id$
35 */
36 TableOperations = HTMLArea.Plugin.extend({
37
38 constructor : function(editor, pluginName) {
39 this.base(editor, pluginName);
40 },
41
42 /*
43 * This function gets called by the class constructor
44 */
45 configurePlugin : function (editor) {
46
47 this.buttonsConfiguration = this.editorConfiguration.buttons;
48
49 /*
50 * Registering plugin "About" information
51 */
52 var pluginInformation = {
53 version : "3.7",
54 developer : "Mihai Bazon & Stanislas Rolland",
55 developerUrl : "http://www.fructifor.ca/",
56 copyrightOwner : "Mihai Bazon & Stanislas Rolland",
57 sponsor : "Zapatec Inc. & Fructifor Inc.",
58 sponsorUrl : "http://www.fructifor.ca/",
59 license : "GPL"
60 };
61 this.registerPluginInformation(pluginInformation);
62
63 /*
64 * Registering the buttons
65 */
66 var hideToggleBorders = this.editorConfiguration.hideTableOperationsInToolbar && !(this.buttonsConfiguration.toggleborders && this.buttonsConfiguration.toggleborders.keepInToolbar);
67 var buttonList = this.buttonList;
68 for (var i = 0, n = buttonList.length; i < n; ++i) {
69 var button = buttonList[i];
70 buttonId = (button[0] === "InsertTable") ? button[0] : ("TO-" + button[0]);
71 var buttonConfiguration = {
72 id : buttonId,
73 tooltip : this.localize((buttonId === "InsertTable") ? "Insert Table" : buttonId),
74 action : "onButtonPress",
75 hotKey : (this.buttonsConfiguration[button[2]] ? this.buttonsConfiguration[button[2]].hotKey : null),
76 context : button[1],
77 hide : ((buttonId == "TO-toggle-borders") ? hideToggleBorders : ((button[0] === "InsertTable") ? false : this.editorConfiguration.hideTableOperationsInToolbar))
78 };
79 this.registerButton(buttonConfiguration);
80 }
81
82 return true;
83 },
84
85 /*
86 * The list of buttons added by this plugin
87 */
88 buttonList : [
89 ["InsertTable", null, "table"],
90 ["toggle-borders", null, "toggleborders"],
91 ["table-prop", "table", "tableproperties"],
92 ["row-prop", "tr", "rowproperties"],
93 ["row-insert-above", "tr", "rowinsertabove"],
94 ["row-insert-under", "tr", "rowinsertunder"],
95 ["row-delete", "tr", "rowdelete"],
96 ["row-split", "td,th[rowSpan!=1]", "rowsplit"],
97 ["col-insert-before", "td,th", "columninsertbefore"],
98 ["col-insert-after", "td,th", "columninsertafter"],
99 ["col-delete", "td,th", "columndelete"],
100 ["col-split", "td,th[colSpan!=1]", "columnsplit"],
101 ["cell-prop", "td,th", "cellproperties"],
102 ["cell-insert-before", "td,th", "cellinsertbefore"],
103 ["cell-insert-after", "td,th", "cellinsertafter"],
104 ["cell-delete", "td,th", "celldelete"],
105 ["cell-merge", "tr", "cellmerge"],
106 ["cell-split", "td,th[colSpan!=1,rowSpan!=1]", "cellsplit"]
107 ],
108
109 /************************
110 * UTILITIES
111 ************************/
112 /*
113 * Retrieve the closest element having the specified tagName in the list of
114 * ancestors of the current selection/caret.
115 */
116 getClosest : function (tagName) {
117 var editor = this.editor;
118 var ancestors = editor.getAllAncestors();
119 var ret = null;
120 tagName = ("" + tagName).toLowerCase();
121 for (var i=0; i < ancestors.length; ++i) {
122 var el = ancestors[i];
123 if (el.tagName.toLowerCase() == tagName) {
124 ret = el;
125 break;
126 }
127 }
128 return ret;
129 },
130
131 /*
132 * Open the table properties dialog.
133 */
134 dialogTableProperties : function () {
135 // retrieve existing values
136 var table = this.getClosest("table");
137 var tablePropertiesInitFunctRef = TableOperations.tablePropertiesInit(table);
138 var tablePropertiesUpdateFunctRef = TableOperations.tablePropertiesUpdate(table);
139 var dialog = new PopupWin(this.editor, this.localize("Table Properties"), tablePropertiesUpdateFunctRef, tablePropertiesInitFunctRef, 570, 600);
140 },
141
142 /*
143 * Open the row/cell properties dialog.
144 * This function requires the file PopupWin to be loaded.
145 */
146 dialogRowCellProperties : function (cell) {
147 // retrieve existing values
148 if (cell) {
149 var element = this.getClosest("td");
150 if (!element) var element = this.getClosest("th");
151 } else {
152 var element = this.getClosest("tr");
153 }
154 if(element) {
155 var rowCellPropertiesInitFunctRef = TableOperations.rowCellPropertiesInit(element, cell);
156 var rowCellPropertiesUpdateFunctRef = TableOperations.rowCellPropertiesUpdate(element);
157 var dialog = new PopupWin(this.editor, this.localize(cell ? "Cell Properties" : "Row Properties"), rowCellPropertiesUpdateFunctRef, rowCellPropertiesInitFunctRef, 700, 425);
158 }
159 },
160
161 /*
162 * This function gets called when a Table Operations button was pressed.
163 *
164 * @param object editor: the editor instance
165 * @param string id: the button id or the key
166 *
167 * @return boolean false if action is completed
168 */
169 onButtonPress : function (editor, id, target) {
170 // Could be a button or its hotkey
171 var buttonId = this.translateHotKey(id);
172 buttonId = buttonId ? buttonId : id;
173
174 var mozbr = HTMLArea.is_gecko ? "<br />" : "";
175 var tableParts = ["tfoot", "thead", "tbody"];
176 var tablePartsIndex = { tfoot : 0, thead : 1, tbody : 2 };
177
178 // helper function that clears the content in a table row
179 function clearRow(tr) {
180 var tds = tr.getElementsByTagName("td");
181 for (var i = tds.length; --i >= 0;) {
182 var td = tds[i];
183 td.rowSpan = 1;
184 td.innerHTML = mozbr;
185 }
186 var tds = tr.getElementsByTagName("th");
187 for (var i = tds.length; --i >= 0;) {
188 var td = tds[i];
189 td.rowSpan = 1;
190 td.innerHTML = mozbr;
191 }
192 };
193
194 function splitRow(td) {
195 var n = parseInt("" + td.rowSpan);
196 var colSpan = td.colSpan;
197 var tagName = td.tagName.toLowerCase();
198 td.rowSpan = 1;
199 var tr = td.parentNode;
200 var sectionRowIndex = tr.sectionRowIndex;
201 var rows = tr.parentNode.rows;
202 var index = td.cellIndex;
203 while (--n > 0) {
204 tr = rows[++sectionRowIndex];
205 // Last row
206 if (!tr) tr = td.parentNode.parentNode.appendChild(editor._doc.createElement("tr"));
207 var otd = editor._doc.createElement(tagName);
208 otd.colSpan = colSpan;
209 otd.innerHTML = mozbr;
210 tr.insertBefore(otd, tr.cells[index]);
211 }
212 };
213
214 function splitCol(td) {
215 var nc = parseInt("" + td.colSpan);
216 var tagName = td.tagName.toLowerCase();
217 td.colSpan = 1;
218 var tr = td.parentNode;
219 var ref = td.nextSibling;
220 while (--nc > 0) {
221 var otd = editor._doc.createElement(tagName);
222 otd.rowSpan = td.rowSpan;
223 otd.innerHTML = mozbr;
224 tr.insertBefore(otd, ref);
225 }
226 };
227
228 function splitCell(td) {
229 var nc = parseInt("" + td.colSpan);
230 splitCol(td);
231 var cells = td.parentNode.cells;
232 var index = td.cellIndex;
233 while (nc-- > 0) {
234 splitRow(cells[index++]);
235 }
236 };
237
238 function selectNextNode(el) {
239 var node = el.nextSibling;
240 while (node && node.nodeType != 1) {
241 node = node.nextSibling;
242 }
243 if (!node) {
244 node = el.previousSibling;
245 while (node && node.nodeType != 1) {
246 node = node.previousSibling;
247 }
248 }
249 if (!node) node = el.parentNode;
250 editor.selectNodeContents(node);
251 };
252
253 function getSelectedCells(sel) {
254 var cell, range, i = 0, cells = [];
255 try {
256 while (range = sel.getRangeAt(i++)) {
257 cell = range.startContainer.childNodes[range.startOffset];
258 while (!/^(td|th|body)$/.test(cell.tagName.toLowerCase())) cell = cell.parentNode;
259 if (/^(td|th)$/.test(cell.tagName.toLowerCase())) cells.push(cell);
260 }
261 } catch(e) {
262 /* finished walking through selection */
263 }
264 return cells;
265 };
266
267 function deleteEmptyTable(table) {
268 var lastPart = true;
269 for (var j = tableParts.length; --j >= 0;) {
270 var tablePart = table.getElementsByTagName(tableParts[j])[0];
271 if (tablePart) lastPart = false;
272 }
273 if (lastPart) {
274 selectNextNode(table);
275 table.parentNode.removeChild(table);
276 }
277 };
278
279 switch (buttonId) {
280 // ROWS
281 case "TO-row-insert-above":
282 case "TO-row-insert-under":
283 var tr = this.getClosest("tr");
284 if (!tr) break;
285 var otr = tr.cloneNode(true);
286 clearRow(otr);
287 otr = tr.parentNode.insertBefore(otr, (/under/.test(buttonId) ? tr.nextSibling : tr));
288 this.editor.selectNodeContents(otr.firstChild, true);
289 break;
290 case "TO-row-delete":
291 var tr = this.getClosest("tr");
292 if (!tr) break;
293 var part = tr.parentNode;
294 var table = part.parentNode;
295 if(part.rows.length == 1) { // this the last row, delete the whole table part
296 selectNextNode(part);
297 table.removeChild(part);
298 deleteEmptyTable(table);
299 } else {
300 // set the caret first to a position that doesn't disappear.
301 selectNextNode(tr);
302 part.removeChild(tr);
303 }
304 editor.forceRedraw();
305 editor.focusEditor();
306 editor.updateToolbar();
307 break;
308 case "TO-row-split":
309 var cell = this.getClosest("td");
310 if (!cell) var cell = this.getClosest("th");
311 if (!cell) break;
312 var sel = editor._getSelection();
313 if (HTMLArea.is_gecko && !sel.isCollapsed && !HTMLArea.is_safari && !HTMLArea.is_opera) {
314 var cells = getSelectedCells(sel);
315 for (i = 0; i < cells.length; ++i) splitRow(cells[i]);
316 } else {
317 splitRow(cell);
318 }
319 editor.forceRedraw();
320 editor.updateToolbar();
321 break;
322
323 // COLUMNS
324 case "TO-col-insert-before":
325 case "TO-col-insert-after":
326 var cell = this.getClosest("td");
327 if (!cell) var cell = this.getClosest("th");
328 if (!cell) break;
329 var index = cell.cellIndex;
330 var table = cell.parentNode.parentNode.parentNode;
331 for (var j = tableParts.length; --j >= 0;) {
332 var tablePart = table.getElementsByTagName(tableParts[j])[0];
333 if (tablePart) {
334 var rows = tablePart.rows;
335 for (var i = rows.length; --i >= 0;) {
336 var tr = rows[i];
337 var ref = tr.cells[index + (/after/.test(buttonId) ? 1 : 0)];
338 if (!ref) {
339 var otd = editor._doc.createElement(tr.lastChild.tagName.toLowerCase());
340 otd.innerHTML = mozbr;
341 tr.appendChild(otd);
342 } else {
343 var otd = editor._doc.createElement(ref.tagName.toLowerCase());
344 otd.innerHTML = mozbr;
345 tr.insertBefore(otd, ref);
346 }
347 }
348 }
349 }
350 editor.focusEditor();
351 break;
352 case "TO-col-split":
353 var cell = this.getClosest("td");
354 if (!cell) var cell = this.getClosest("th");
355 if (!cell) break;
356 var sel = editor._getSelection();
357 if (HTMLArea.is_gecko && !sel.isCollapsed && !HTMLArea.is_safari && !HTMLArea.is_opera) {
358 var cells = getSelectedCells(sel);
359 for (i = 0; i < cells.length; ++i) splitCol(cells[i]);
360 } else {
361 splitCol(cell);
362 }
363 editor.forceRedraw();
364 editor.updateToolbar();
365 break;
366 case "TO-col-delete":
367 var cell = this.getClosest("td");
368 if (!cell) var cell = this.getClosest("th");
369 if (!cell) break;
370 var index = cell.cellIndex;
371 var part = cell.parentNode.parentNode;
372 var table = part.parentNode;
373 var lastPart = true;
374 for (var j = tableParts.length; --j >= 0;) {
375 var tablePart = table.getElementsByTagName(tableParts[j])[0];
376 if (tablePart) {
377 var rows = tablePart.rows;
378 var lastColumn = true;
379 for (var i = rows.length; --i >= 0;) {
380 if(rows[i].cells.length > 1) lastColumn = false;
381 }
382 if (lastColumn) {
383 // this is the last column, delete the whole tablepart
384 // set the caret first to a position that doesn't disappear
385 selectNextNode(tablePart);
386 table.removeChild(tablePart);
387 } else {
388 // set the caret first to a position that doesn't disappear
389 if (part == tablePart) selectNextNode(cell);
390 for (var i = rows.length; --i >= 0;) {
391 if(rows[i].cells[index]) rows[i].removeChild(rows[i].cells[index]);
392 }
393 lastPart = false;
394 }
395 }
396 }
397 if (lastPart) {
398 // the last table section was deleted: delete the whole table
399 // set the caret first to a position that doesn't disappear
400 selectNextNode(table);
401 table.parentNode.removeChild(table);
402 }
403 editor.forceRedraw();
404 editor.focusEditor();
405 editor.updateToolbar();
406 break;
407
408 // CELLS
409 case "TO-cell-split":
410 var cell = this.getClosest("td");
411 if (!cell) var cell = this.getClosest("th");
412 if (!cell) break;
413 var sel = editor._getSelection();
414 if (HTMLArea.is_gecko && !sel.isCollapsed && !HTMLArea.is_safari && !HTMLArea.is_opera) {
415 var cells = getSelectedCells(sel);
416 for (i = 0; i < cells.length; ++i) splitCell(cells[i]);
417 } else {
418 splitCell(cell);
419 }
420 editor.forceRedraw();
421 editor.updateToolbar();
422 break;
423 case "TO-cell-insert-before":
424 case "TO-cell-insert-after":
425 var cell = this.getClosest("td");
426 if (!cell) var cell = this.getClosest("th");
427 if (!cell) break;
428 var tr = cell.parentNode;
429 var otd = editor._doc.createElement(cell.tagName.toLowerCase());
430 otd.innerHTML = mozbr;
431 tr.insertBefore(otd, (/after/.test(buttonId) ? cell.nextSibling : cell));
432 editor.forceRedraw();
433 editor.focusEditor();
434 break;
435 case "TO-cell-delete":
436 var cell = this.getClosest("td");
437 if (!cell) var cell = this.getClosest("th");
438 if (!cell) break;
439 var row = cell.parentNode;
440 if(row.cells.length == 1) { // this is the only cell in the row, delete the row
441 var part = row.parentNode;
442 var table = part.parentNode;
443 if (part.rows.length == 1) { // this the last row, delete the whole table part
444 selectNextNode(part);
445 table.removeChild(part);
446 deleteEmptyTable(table);
447 } else {
448 selectNextNode(row);
449 part.removeChild(row);
450 }
451 } else {
452 // set the caret first to a position that doesn't disappear
453 selectNextNode(cell);
454 row.removeChild(cell);
455 }
456 editor.forceRedraw();
457 editor.focusEditor();
458 editor.updateToolbar();
459 break;
460 case "TO-cell-merge":
461 var sel = editor._getSelection();
462 var range, i = 0;
463 var rows = new Array();
464 for (var k = tableParts.length; --k >= 0;) rows[k] = [];
465 var row = null;
466 var cells = null;
467 if (HTMLArea.is_gecko && !HTMLArea.is_safari && !HTMLArea.is_opera) {
468 try {
469 while (range = sel.getRangeAt(i++)) {
470 var td = range.startContainer.childNodes[range.startOffset];
471 if (td.parentNode != row) {
472 (cells) && rows[tablePartsIndex[row.parentNode.tagName.toLowerCase()]].push(cells);
473 row = td.parentNode;
474 cells = [];
475 }
476 cells.push(td);
477 }
478 } catch(e) {
479 /* finished walking through selection */
480 }
481 rows[tablePartsIndex[row.parentNode.tagName.toLowerCase()]].push(cells);
482 } else {
483 // Internet Explorer, Safari and Opera
484 var cell = this.getClosest("td");
485 if (!cell) var cell = this.getClosest("th");
486 if (!cell) {
487 alert(this.localize("Please click into some cell"));
488 break;
489 }
490 var tr = cell.parentElement;
491 var no_cols = prompt(this.localize("How many columns would you like to merge?"), 2);
492 if (!no_cols) break;
493 var no_rows = prompt(this.localize("How many rows would you like to merge?"), 2);
494 if (!no_rows) break;
495 var cell_index = cell.cellIndex;
496 while (no_rows-- > 0) {
497 td = tr.cells[cell_index];
498 cells = [td];
499 for (var i = 1; i < no_cols; ++i) {
500 td = td.nextSibling;
501 if (!td) break;
502 cells.push(td);
503 }
504 rows[tablePartsIndex[tr.parentNode.tagName.toLowerCase()]].push(cells);
505 tr = tr.nextSibling;
506 if (!tr) break;
507 }
508 }
509 for (var k = tableParts.length; --k >= 0;) {
510 var cellHTML = "";
511 for (var i = 0; i < rows[k].length; ++i) {
512 // i && (cellHTML += "<br />");
513 var cells = rows[k][i];
514 if(!cells) continue;
515 for (var j=0; j < cells.length; ++j) {
516 // j && (cellHTML += "&nbsp;");
517 var cell = cells[j];
518 cellHTML += cell.innerHTML;
519 if(i || j) {
520 if(cell.parentNode.cells.length == 1) cell.parentNode.parentNode.removeChild(cell.parentNode);
521 else cell.parentNode.removeChild(cell);
522 }
523 }
524 }
525 try {
526 var td = rows[k][0][0];
527 td.innerHTML = cellHTML;
528 td.rowSpan = rows[k].length;
529 td.colSpan = rows[k][0].length;
530 editor.selectNodeContents(td);
531 } catch(e) { }
532 }
533
534 editor.forceRedraw();
535 editor.focusEditor();
536 break;
537
538 // CREATION AND PROPERTIES
539 case "InsertTable":
540 this.dialogInsertTable();
541 break;
542 case "TO-table-prop":
543 this.dialogTableProperties();
544 break;
545 case "TO-row-prop":
546 this.dialogRowCellProperties(false);
547 break;
548 case "TO-cell-prop":
549 this.dialogRowCellProperties(true);
550 break;
551 case "TO-toggle-borders":
552 this.toggleBorders();
553 break;
554 default:
555 alert("Button [" + buttonId + "] not yet implemented");
556 }
557 },
558
559 /*
560 * Open insert table request
561 */
562 dialogInsertTable : function () {
563 this.dialog = this.openDialog("InsertTable", this.makeUrlFromPopupName("insert_table"), "insertTable", null, {width:520, height:230});
564 return false;
565 },
566
567 /*
568 * Get the insert table action function
569 */
570 insertTable : function(param) {
571 var editor = this.editor;
572 if (!param) return false;
573 var doc = editor._doc;
574 var table = doc.createElement("table");
575 for (var field in param) {
576 if (param.hasOwnProperty(field)) {
577 var value = param[field];
578 if (value) {
579 switch (field) {
580 case "f_width" :
581 if(value != "") {
582 table.style.width = parseInt(value) + param["f_unit"];
583 break;
584 }
585 case "f_align" :
586 table.style.textAlign = value;
587 break;
588 case "f_border" :
589 if(value != "") {
590 table.style.borderWidth = parseInt(value)+"px";
591 table.style.borderStyle = "solid";
592 }
593 break;
594 case "f_spacing" :
595 if(value != "") {
596 table.cellSpacing = parseInt(value);
597 break;
598 }
599 case "f_padding" :
600 if(value != "") {
601 table.cellPadding = parseInt(value);
602 break;
603 }
604 case "f_float" :
605 if (HTMLArea.is_ie) {
606 table.style.styleFloat = ((value != "not set") ? value : "");
607 } else {
608 table.style.cssFloat = ((value != "not set") ? value : "");
609 }
610 break;
611 }
612 }
613 }
614 }
615 var cellwidth = 0;
616 if(param.f_fixed) cellwidth = Math.floor(100 / parseInt(param.f_cols));
617 var tbody = doc.createElement("tbody");
618 table.appendChild(tbody);
619 for (var i = param["f_rows"]; i > 0; i--) {
620 var tr = doc.createElement("tr");
621 tbody.appendChild(tr);
622 for (var j = param["f_cols"]; j > 0; j--) {
623 var td = doc.createElement("td");
624 if (cellwidth) td.style.width = cellwidth + "%";
625 if (HTMLArea.is_opera) { td.innerHTML = '&nbsp;'; }
626 tr.appendChild(td);
627 }
628 }
629 editor.focusEditor();
630 editor.insertNodeAtSelection(table);
631 if (this.buttonsConfiguration.toggleborders && this.buttonsConfiguration.toggleborders.setOnTableCreation) {
632 this.toggleBorders();
633 }
634 return true;
635 },
636
637 toggleBorders : function () {
638 var tables = this.editor._doc.getElementsByTagName("table");
639 if (tables.length != 0) {
640 this.editor.borders = true;
641 for (var ix=0; ix < tables.length; ix++) this.editor.borders = this.editor.borders && /htmlarea-showtableborders/.test(tables[ix].className);
642 for (ix=0; ix < tables.length; ix++) {
643 if (!this.editor.borders) HTMLArea._addClass(tables[ix],'htmlarea-showtableborders');
644 else HTMLArea._removeClass(tables[ix],'htmlarea-showtableborders');
645 }
646 }
647 // The only way to get Firefox to show these borders...
648 if (HTMLArea.is_gecko && !HTMLArea.is_safari && !HTMLArea.is_opera) this.editor.setMode("wysiwyg");
649 }
650 });
651
652 /*
653 * Set the language file for the plugin
654 */
655 TableOperations.I18N = TableOperations_langArray;
656
657 /*
658 * Initialize the table properties dialog
659 */
660 TableOperations.tablePropertiesInit = function(table) {
661 return (function (dialog) {
662 var doc = dialog.doc;
663 var content = dialog.content;
664 var i18n = TableOperations.I18N;
665 TableOperations.buildTitle(doc, i18n, content, "Table Properties");
666 TableOperations.buildDescriptionFieldset(doc, table, i18n, content);
667 var obj = dialog.editor.config.customSelects.BlockStyle ? dialog.editor.plugins.BlockStyle.instance : dialog.editor.config.customSelects["DynamicCSS-class"];
668 if (obj && (obj.loaded || obj.cssLoaded)) TableOperations.buildStylingFieldset(doc, table, i18n, content, obj.cssArray);
669 if (!dialog.editor.config.disableLayoutFieldsetInTableOperations) TableOperations.buildLayoutFieldset(doc, table, i18n, content);
670 if (!dialog.editor.config.disableAlignmentFieldsetInTableOperations) TableOperations.buildAlignmentFieldset(doc, table, i18n, content, "floating");
671 if (!dialog.editor.config.disableSpacingFieldsetInTableOperations) TableOperations.buildSpacingFieldset(doc, table, i18n, content);
672 if (!dialog.editor.config.disableBordersFieldsetInTableOperations) TableOperations.buildBordersFieldset(dialog.dialogWindow, doc, dialog.editor, table, i18n, content);
673 if (!dialog.editor.config.disableColorFieldsetInTableOperations) TableOperations.buildColorsFieldset(dialog.dialogWindow, doc, dialog.editor, table, i18n, content);
674 dialog.modal = true;
675 dialog.addButtons("ok", "cancel");
676 dialog.showAtElement();
677 });
678 };
679
680 /*
681 * Update the table properties and close the dialog
682 */
683 TableOperations.tablePropertiesUpdate = function(table) {
684 return (function (dialog,params) {
685 dialog.editor.focusEditor();
686 TableOperations.processStyle(params, table);
687 table.removeAttribute("border");
688 for (var i in params) {
689 var val = params[i];
690 switch (i) {
691 case "f_caption":
692 if (/\S/.test(val)) {
693 // contains non white-space characters
694 var caption = table.getElementsByTagName("caption")[0];
695 if (!caption) {
696 caption = dialog.editor._doc.createElement("caption");
697 table.insertBefore(caption, table.firstChild);
698 }
699 caption.innerHTML = val;
700 } else {
701 // search for caption and delete it if found
702 var caption = table.getElementsByTagName("caption")[0];
703 if (caption) caption.parentNode.removeChild(caption);
704 }
705 break;
706 case "f_summary":
707 table.summary = val;
708 break;
709 case "f_width":
710 table.style.width = ("" + val) + params.f_unit;
711 break;
712 case "f_align":
713 table.align = val;
714 break;
715 case "f_spacing":
716 table.cellSpacing = val;
717 break;
718 case "f_padding":
719 table.cellPadding = val;
720 break;
721 case "f_frames":
722 table.frame = (val != "not set") ? val : "";
723 break;
724 case "f_rules":
725 if (val != "not set") table.rules = val;
726 else table.removeAttribute("rules");
727 break;
728 case "f_class":
729 case "f_class_tbody":
730 case "f_class_thead":
731 case "f_class_tfoot":
732 var tpart = table;
733 if (i.length > 7) tpart = table.getElementsByTagName(i.substring(8,13))[0];
734 var cls = tpart.className.trim().split(" ");
735 for (var j = cls.length;j > 0;) {
736 if (!HTMLArea.reservedClassNames.test(cls[--j])) HTMLArea._removeClass(tpart,cls[j]);
737 }
738 if (val != 'none') HTMLArea._addClass(tpart,val);
739 break;
740 }
741 }
742 dialog.editor.focusEditor();
743 dialog.editor.updateToolbar();
744 });
745 };
746
747 /*
748 * Initialize the row/cell properties dialog
749 */
750 TableOperations.rowCellPropertiesInit = function(element,cell) {
751 return (function (dialog) {
752 var doc = dialog.doc;
753 var content = dialog.content;
754 var i18n = TableOperations.I18N;
755 TableOperations.buildTitle(doc, i18n, content, (cell ? "Cell Properties" : "Row Properties"));
756 if (cell) TableOperations.buildCellTypeFieldset(dialog.dialogWindow, doc, dialog.editor, element, i18n, content);
757 else TableOperations.buildRowGroupFieldset(dialog.dialogWindow, doc, dialog.editor, element, i18n, content);
758 var obj = dialog.editor.config.customSelects.BlockStyle ? dialog.editor.plugins.BlockStyle.instance : dialog.editor.config.customSelects["DynamicCSS-class"];
759 if (obj && (obj.loaded || obj.cssLoaded)) TableOperations.buildStylingFieldset(doc, element, i18n, content, obj.cssArray);
760 else TableOperations.insertSpace(doc, content);
761 if (!dialog.editor.config.disableLayoutFieldsetInTableOperations) TableOperations.buildLayoutFieldset(doc, element, i18n, content, "floating");
762 if (!dialog.editor.config.disableAlignmentFieldsetInTableOperations) TableOperations.buildAlignmentFieldset(doc, element, i18n, content);
763 if (!dialog.editor.config.disableBordersFieldsetInTableOperations) TableOperations.buildBordersFieldset(dialog.dialogWindow, doc, dialog.editor, element, i18n, content);
764 if (!dialog.editor.config.disableColorFieldsetInTableOperations) TableOperations.buildColorsFieldset(dialog.dialogWindow, doc, dialog.editor, element, i18n, content);
765 dialog.modal = true;
766 dialog.addButtons("ok", "cancel");
767 dialog.showAtElement();
768 });
769 };
770
771 /*
772 * Update the row/cell properties and close the dialog
773 */
774 TableOperations.rowCellPropertiesUpdate = function(element) {
775 return (function (dialog,params) {
776 dialog.editor.focusEditor();
777 TableOperations.processStyle(params, element);
778 var convertCellType = false;
779 for (var i in params) {
780 var val = params[i];
781 switch (i) {
782 case "f_scope":
783 if (val != "not set") element.scope = val;
784 else element.removeAttribute('scope');
785 break;
786 case "f_cell_type":
787 // Set all cell attributes before cloning it with a new tag
788 if (val != element.tagName.toLowerCase()) {
789 var newCellType = val;
790 convertCellType = true;
791 }
792 break;
793 case "f_rowgroup":
794 var section = element.parentNode;
795 var tagName = section.tagName.toLowerCase();
796 if (val != tagName) {
797 var table = section.parentNode;
798 var newSection = table.getElementsByTagName(val)[0];
799 if (!newSection) var newSection = table.insertBefore(dialog.editor._doc.createElement(val), table.getElementsByTagName("tbody")[0]);
800 if (tagName == "thead" && val == "tbody") var newElement = newSection.insertBefore(element, newSection.firstChild);
801 else var newElement = newSection.appendChild(element);
802 if (!section.hasChildNodes()) table.removeChild(section);
803 }
804 break;
805 case "f_char":
806 element.ch = val;
807 break;
808 case "f_class":
809 var cls = element.className.trim().split(" ");
810 for (var j = cls.length;j > 0;) {
811 if (!HTMLArea.reservedClassNames.test(cls[--j])) HTMLArea._removeClass(element,cls[j]);
812 }
813 if (val != 'none') HTMLArea._addClass(element,val);
814 break;
815 }
816 }
817 if (convertCellType) {
818 var newCell = dialog.editor._doc.createElement(newCellType), p = element.parentNode, a, attrName, name;
819 var attrs = element.attributes;
820 for (var i = attrs.length; --i >= 0 ;) {
821 a = attrs.item(i);
822 attrName = a.nodeName;
823 name = attrName.toLowerCase();
824 // IE5.5 reports wrong values. For this reason we extract the values directly from the root node.
825 if (typeof(element[attrName]) != "undefined" && name != "style" && !/^on/.test(name)) {
826 if (element[attrName]) newCell.setAttribute(attrName, element[attrName]);
827 } else {
828 if (a.nodeValue) newCell.setAttribute(attrName, a.nodeValue);
829 }
830 }
831 // In IE, the above fails to update the classname and style attributes.
832 if (HTMLArea.is_ie) {
833 if (element.style.cssText) newCell.style.cssText = element.style.cssText;
834 if (element.className) {
835 newCell.setAttribute("className", element.className);
836 } else {
837 newCell.className = element.className;
838 newCell.removeAttribute("className");
839 }
840 }
841 while (element.firstChild) newCell.appendChild(element.firstChild);
842 p.insertBefore(newCell, element);
843 p.removeChild(element);
844 dialog.editor.selectNodeContents(newCell, false);
845 }
846 dialog.editor.updateToolbar();
847 });
848 };
849
850 TableOperations.getLength = function(value) {
851 var len = parseInt(value);
852 if (isNaN(len)) len = "";
853 return len;
854 };
855
856 // Applies the style found in "params" to the given element.
857 TableOperations.processStyle = function(params,element) {
858 var style = element.style;
859 for (var i in params) {
860 var val = params[i];
861 switch (i) {
862 case "f_st_backgroundColor":
863 style.backgroundColor = val;
864 break;
865 case "f_st_color":
866 style.color = val;
867 break;
868 case "f_st_backgroundImage":
869 if (/\S/.test(val)) {
870 style.backgroundImage = "url(" + val + ")";
871 } else {
872 style.backgroundImage = "";
873 }
874 break;
875 case "f_st_borderWidth":
876 if (/\S/.test(val)) {
877 style.borderWidth = val + "px";
878 } else {
879 style.borderWidth = "";
880 }
881 if (params["f_st_borderStyle"] == "none") style.borderWidth = "0px";
882 if (params["f_st_borderStyle"] == "not set") style.borderWidth = "";
883 break;
884 case "f_st_borderStyle":
885 style.borderStyle = (val != "not set") ? val : "";
886 break;
887 case "f_st_borderColor":
888 style.borderColor = val;
889 break;
890 case "f_st_borderCollapse":
891 style.borderCollapse = val ? "collapse" : "";
892 break;
893 case "f_st_width":
894 if (/\S/.test(val)) {
895 style.width = val + params["f_st_widthUnit"];
896 } else {
897 style.width = "";
898 }
899 break;
900 case "f_st_height":
901 if (/\S/.test(val)) {
902 style.height = val + params["f_st_heightUnit"];
903 } else {
904 style.height = "";
905 }
906 break;
907 case "f_st_textAlign":
908 if (val == "character") {
909 var ch = params["f_st_textAlignChar"];
910 if (ch == '"') {
911 ch = '\\"';
912 }
913 style.textAlign = '"' + ch + '"';
914 } else {
915 style.textAlign = (val != "not set") ? val : "";
916 }
917 break;
918 case "f_st_vertAlign":
919 style.verticalAlign = (val != "not set") ? val : "";
920 break;
921 case "f_st_float":
922 if (HTMLArea.is_ie) {
923 style.styleFloat = (val != "not set") ? val : "";
924 } else {
925 style.cssFloat = (val != "not set") ? val : "";
926 }
927 break;
928 // case "f_st_margin":
929 // style.margin = val + "px";
930 // break;
931 // case "f_st_padding":
932 // style.padding = val + "px";
933 // break;
934 }
935 }
936 };
937
938 // Returns an HTML element for a widget that allows color selection. That is,
939 // a button that contains the given color, if any, and when pressed will popup
940 // the sooner-or-later-to-be-rewritten select_color.html dialog allowing user
941 // to select some color. If a color is selected, an input field with the name
942 // "f_st_"+name will be updated with the color value in #123456 format.
943 TableOperations.createColorButton = function(w, doc, editor, color, name) {
944 if (!color) {
945 color = "";
946 } else if (!/#/.test(color)) {
947 color = HTMLArea._colorToRgb(color);
948 }
949
950 var df = doc.createElement("span");
951 var field = doc.createElement("input");
952 field.type = "hidden";
953 df.appendChild(field);
954 field.name = "f_st_" + name;
955 field.id = "f_st_" + name;
956 field.value = color;
957 var button = doc.createElement("span");
958 button.className = "buttonColor";
959 df.appendChild(button);
960 var span = doc.createElement("span");
961 span.className = "chooser";
962 span.style.backgroundColor = color;
963 button.appendChild(span);
964 button.onmouseover = function() { if (!this.disabled) this.className += " buttonColor-hilite"; };
965 button.onmouseout = function() { if (!this.disabled) this.className = "buttonColor"; };
966 span.onclick = function() {
967 if (this.parentNode.disabled) return false;
968 var typo3ColorPlugin = editor.plugins.TYPO3Color;
969 if (typo3ColorPlugin) {
970 typo3ColorPlugin.instance.dialogSelectColor("color", span, field, w);
971 } else {
972 editor._popupDialog("select_color.html", function(color) {
973 if (color) {
974 span.style.backgroundColor = "#" + color;
975 field.value = "#" + color;
976 }
977 }, color, 200, 182, w);
978 }
979 };
980 var span2 = doc.createElement("span");
981 span2.innerHTML = "&#x00d7;";
982 span2.className = "nocolor";
983 span2.title = TableOperations.I18N["Unset color"];
984 button.appendChild(span2);
985 span2.onmouseover = function() { if (!this.parentNode.disabled) this.className += " nocolor-hilite"; };
986 span2.onmouseout = function() { if (!this.parentNode.disabled) this.className = "nocolor"; };
987 span2.onclick = function() {
988 span.style.backgroundColor = "";
989 field.value = "";
990 };
991 return df;
992 };
993 TableOperations.buildTitle = function(doc,i18n,content,title) {
994 var div = doc.createElement("div");
995 div.className = "title";
996 div.innerHTML = i18n[title];
997 content.appendChild(div);
998 doc.title = i18n[title];
999 };
1000 TableOperations.buildDescriptionFieldset = function(doc,el,i18n,content) {
1001 var fieldset = doc.createElement("fieldset");
1002 TableOperations.insertLegend(doc, i18n, fieldset, "Description");
1003 TableOperations.insertSpace(doc, fieldset);
1004 var f_caption = "";
1005 var capel = el.getElementsByTagName("caption")[0];
1006 if (capel) f_caption = capel.innerHTML;
1007 TableOperations.buildInput(doc, el, i18n, fieldset, "f_caption", "Caption:", "Description of the nature of the table", "", "", f_caption, "fr", "value", "");
1008 TableOperations.insertSpace(doc, fieldset);
1009 TableOperations.buildInput(doc, el, i18n, fieldset, "f_summary", "Summary:", "Summary of the table purpose and structure", "", "", el.summary, "fr", "value", "");
1010 TableOperations.insertSpace(doc, fieldset);
1011 content.appendChild(fieldset);
1012 };
1013 TableOperations.buildRowGroupFieldset = function(w,doc,editor,el,i18n,content) {
1014 var fieldset = doc.createElement("fieldset");
1015 TableOperations.insertLegend(doc, i18n, fieldset, "Row group");
1016 TableOperations.insertSpace(doc, fieldset);
1017 selected = el.parentNode.tagName.toLowerCase();
1018 var selectScope = TableOperations.buildSelectField(doc, el, i18n, fieldset, "f_rowgroup", "Row group:", "fr", "", "Table section", ["Table body", "Table header", "Table footer"], ["tbody", "thead", "tfoot"], new RegExp((selected ? selected : "tbody"), "i"));
1019 TableOperations.insertSpace(doc, fieldset);
1020 content.appendChild(fieldset);
1021 };
1022 TableOperations.buildCellTypeFieldset = function(w,doc,editor,el,i18n,content) {
1023 var fieldset = doc.createElement("fieldset");
1024 TableOperations.insertLegend(doc, i18n, fieldset, "Cell Type and Scope");
1025 TableOperations.insertSpace(doc, fieldset);
1026 var ul = doc.createElement("ul");
1027 fieldset.appendChild(ul);
1028 var li = doc.createElement("li");
1029 ul.appendChild(li);
1030 var selectType = TableOperations.buildSelectField(doc, el, i18n, li, "f_cell_type", "Type of cell", "fr", "", "Specifies the type of cell", ["Normal", "Header"], ["td", "th"], new RegExp(el.tagName.toLowerCase(), "i"));
1031 selectType.onchange = function() { TableOperations.setStyleOptions(doc, editor, el, i18n, this); };
1032 var li = doc.createElement("li");
1033 ul.appendChild(li);
1034 selected = el.scope.toLowerCase();
1035 (selected.match(/([^\s]*)\s/)) && (selected = RegExp.$1);
1036 var selectScope = TableOperations.buildSelectField(doc, el, i18n, li, "f_scope", "Scope", "fr", "", "Scope of header cell", ["Not set", "scope_row", "scope_column", "scope_rowgroup"], ["not set", "row", "col", "rowgroup"], new RegExp((selected ? selected : "not set"), "i"));
1037 TableOperations.insertSpace(doc, fieldset);
1038 content.appendChild(fieldset);
1039 };
1040 TableOperations.getCssLabelsClasses = function(cssArray,i18n,tagName,selectedIn) {
1041 var cssLabels = new Array();
1042 var cssClasses = new Array();
1043 cssLabels[0] = i18n["Default"];
1044 cssClasses[0] = "none";
1045 var selected = selectedIn;
1046 var cls = selected.split(" ");
1047 var nonReservedClassName = false;
1048 for (var ia = cls.length; ia > 0;) {
1049 if(!HTMLArea.reservedClassNames.test(cls[--ia])) {
1050 selected = cls[ia];
1051 nonReservedClassName = true;
1052 break;
1053 }
1054 }
1055 var found = false, i = 1, cssClass;
1056 if(cssArray[tagName]) {
1057 for(cssClass in cssArray[tagName]){
1058 if(cssClass != "none") {
1059 cssLabels[i] = cssArray[tagName][cssClass];
1060 cssClasses[i] = cssClass;
1061 if(cssClass == selected) found = true;
1062 i++;
1063 } else {
1064 cssLabels[0] = cssArray[tagName][cssClass];
1065 }
1066 }
1067 }
1068 if(cssArray['all']){
1069 for(cssClass in cssArray['all']){
1070 cssLabels[i] = cssArray['all'][cssClass];
1071 cssClasses[i] = cssClass;
1072 if(cssClass == selected) found = true;
1073 i++;
1074 }
1075 }
1076 if(selected && nonReservedClassName && !found) {
1077 cssLabels[i] = i18n["Undefined"];
1078 cssClasses[i] = selected;
1079 }
1080 return [cssLabels, cssClasses, selected];
1081 };
1082 TableOperations.setStyleOptions = function(doc,editor,el,i18n,typeSelect) {
1083 var tagName = typeSelect.value;
1084 var select = doc.getElementById("f_class");
1085 if (!select) return false;
1086 var obj = dialog.editor.config.customSelects.BlockStyle ? dialog.editor.plugins.BlockStyle.instance : dialog.editor.config.customSelects["DynamicCSS-class"];
1087 if (obj && (obj.loaded || obj.cssLoaded)) var cssArray = obj.cssArray;
1088 else return false;
1089 var cssLabelsClasses = TableOperations.getCssLabelsClasses(cssArray,i18n,tagName,el.className);
1090 var options = cssLabelsClasses[0];
1091 var values = cssLabelsClasses[1];
1092 var selected = cssLabelsClasses[2];
1093 var selectedReg = new RegExp((selected ? selected : "none"), "i");
1094 while(select.options.length>0) select.options[select.length-1] = null;
1095 select.selectedIndex = 0;
1096 var option;
1097 for (var i = 0; i < options.length; ++i) {
1098 option = doc.createElement("option");
1099 select.appendChild(option);
1100 option.value = values[i];
1101 option.appendChild(doc.createTextNode(options[i]));
1102 option.selected = selectedReg.test(values[i]);
1103 }
1104 if(select.options.length>1) select.disabled = false;
1105 else select.disabled = true;
1106 };
1107 TableOperations.buildStylingFieldset = function(doc,el,i18n,content,cssArray) {
1108 var tagName = el.tagName.toLowerCase();
1109 var table = (tagName == "table");
1110 var cssLabelsClasses = TableOperations.getCssLabelsClasses(cssArray,i18n,tagName,el.className);
1111 var cssLabels = cssLabelsClasses[0];
1112 var cssClasses = cssLabelsClasses[1];
1113 var selected = cssLabelsClasses[2];
1114 var fieldset = doc.createElement("fieldset");
1115 TableOperations.insertLegend(doc, i18n, fieldset, "CSS Style");
1116 TableOperations.insertSpace(doc, fieldset);
1117 var ul = doc.createElement("ul");
1118 ul.className = "floating";
1119 fieldset.appendChild(ul);
1120 var li = doc.createElement("li");
1121 ul.appendChild(li);
1122 TableOperations.buildSelectField(doc, el, i18n, li, "f_class", (table ? "Table class:" : "Class:"), "fr", "", (table ? "Table class selector" : "Class selector"), cssLabels, cssClasses, new RegExp((selected ? selected : "none"), "i"), "", false);
1123 if (table) {
1124 var tbody = el.getElementsByTagName("tbody")[0];
1125 if (tbody) {
1126 var li = doc.createElement("li");
1127 ul.appendChild(li);
1128 cssLabelsClasses = TableOperations.getCssLabelsClasses(cssArray, i18n, "tbody", tbody.className);
1129 cssLabels = cssLabelsClasses[0];
1130 cssClasses = cssLabelsClasses[1];
1131 selected = cssLabelsClasses[2];
1132 TableOperations.buildSelectField(doc, el, i18n, li, "f_class_tbody", "Table body class:", "fr", "", "Table body class selector", cssLabels, cssClasses, new RegExp((selected ? selected : "none"), "i"), "", false);
1133 }
1134 ul = null;
1135 var thead = el.getElementsByTagName("thead")[0];
1136 if (thead) {
1137 var ul = doc.createElement("ul");
1138 fieldset.appendChild(ul);
1139 var li = doc.createElement("li");
1140 ul.appendChild(li);
1141 cssLabelsClasses = TableOperations.getCssLabelsClasses(cssArray, i18n, "thead", thead.className);
1142 cssLabels = cssLabelsClasses[0];
1143 cssClasses = cssLabelsClasses[1];
1144 selected = cssLabelsClasses[2];
1145 TableOperations.buildSelectField(doc, el, i18n, li, "f_class_thead", "Table header class:", "fr", "", "Table header class selector", cssLabels, cssClasses, new RegExp((selected ? selected : "none"), "i"), "", false);
1146 }
1147 var tfoot = el.getElementsByTagName("tfoot")[0];
1148 if (tfoot) {
1149 if (!ul) {
1150 var ul = doc.createElement("ul");
1151 fieldset.appendChild(ul);
1152 }
1153 var li = doc.createElement("li");
1154 ul.appendChild(li);
1155 cssLabelsClasses = TableOperations.getCssLabelsClasses(cssArray, i18n, "tfoot", tfoot.className);
1156 cssLabels = cssLabelsClasses[0];
1157 cssClasses = cssLabelsClasses[1];
1158 selected = cssLabelsClasses[2];
1159 TableOperations.buildSelectField(doc, el, i18n, li, "f_class_tfoot", "Table footer class:", "fr", "", "Table footer class selector", cssLabels, cssClasses, new RegExp((selected ? selected : "none"), "i"), "", false);
1160 }
1161 }
1162 TableOperations.insertSpace(doc, fieldset);
1163 content.appendChild(fieldset);
1164 };
1165 TableOperations.buildLayoutFieldset = function(doc,el,i18n,content,fieldsetClass) {
1166 var select, selected;
1167 var fieldset = doc.createElement("fieldset");
1168 if(fieldsetClass) fieldset.className = fieldsetClass;
1169 TableOperations.insertLegend(doc, i18n, fieldset, "Layout");
1170 var f_st_width = TableOperations.getLength(el.style.width);
1171 var f_st_height = TableOperations.getLength(el.style.height);
1172 var selectedWidthUnit = /%/.test(el.style.width) ? '%' : (/px/.test(el.style.width) ? 'px' : 'em');
1173 var selectedHeightUnit = /%/.test(el.style.height) ? '%' : (/px/.test(el.style.height) ? 'px' : 'em');
1174 var tag = el.tagName.toLowerCase();
1175 var ul = doc.createElement("ul");
1176 fieldset.appendChild(ul);
1177 switch(tag) {
1178 case "table" :
1179 var li = doc.createElement("li");
1180 ul.appendChild(li);
1181 TableOperations.buildInput(doc, el, i18n, li, "f_st_width", "Width:", "Table width", "", "5", f_st_width, "fr");
1182 select = TableOperations.buildSelectField(doc, el, i18n, li, "f_st_widthUnit", "", "", "", "Width unit", ["percent", "pixels", "em"], ["%", "px", "em"], new RegExp((f_st_width ? selectedWidthUnit : "%"), "i"));
1183 var li = doc.createElement("li");
1184 ul.appendChild(li);
1185 TableOperations.buildInput(doc, el, i18n, li, "f_st_height", "Height:", "Table height", "", "5", f_st_height, "fr");
1186 select = TableOperations.buildSelectField(doc, el, i18n, li, "f_st_heightUnit", "", "", "", "Height unit", ["percent", "pixels", "em"], ["%", "px", "em"], new RegExp((f_st_height ? selectedHeightUnit : "%"), "i"));
1187 selected = (HTMLArea._is_ie) ? el.style.styleFloat : el.style.cssFloat;
1188 select = TableOperations.buildSelectField(doc, el, i18n, li, "f_st_float", "Float:", "", "", "Specifies where the table should float", ["Not set", "Non-floating", "Left", "Right"], ["not set", "none", "left", "right"], new RegExp((selected ? selected : "not set"), "i"));
1189 break;
1190 case "tr" :
1191 var li = doc.createElement("li");
1192 ul.appendChild(li);
1193 TableOperations.buildInput(doc, el, i18n, li, "f_st_width", "Width:", "Row width", "", "5", f_st_width, "fr");
1194 select = TableOperations.buildSelectField(doc, el, i18n, li, "f_st_widthUnit", "", "", "", "Width unit", ["percent", "pixels", "em"], ["%", "px", "em"], new RegExp((f_st_width ? selectedWidthUnit : "%"), "i"));
1195 var li = doc.createElement("li");
1196 ul.appendChild(li);
1197 TableOperations.buildInput(doc, el, i18n, li, "f_st_height", "Height:", "Row height", "", "5", f_st_height, "fr");
1198 select = TableOperations.buildSelectField(doc, el, i18n, li, "f_st_heightUnit", "", "", "", "Height unit", ["percent", "pixels", "em"], ["%", "px", "em"], new RegExp((f_st_height ? selectedHeightUnit : "%"), "i"));
1199 break;
1200 case "td" :
1201 case "th" :
1202 var li = doc.createElement("li");
1203 ul.appendChild(li);
1204 TableOperations.buildInput(doc, el, i18n, li, "f_st_width", "Width:", "Cell width", "", "5", f_st_width, "fr");
1205 select = TableOperations.buildSelectField(doc, el, i18n, li, "f_st_widthUnit", "", "", "", "Width unit", ["percent", "pixels", "em"], ["%", "px", "em"], new RegExp((f_st_width ? selectedWidthUnit : "%"), "i"));
1206 var li = doc.createElement("li");
1207 ul.appendChild(li);
1208 TableOperations.buildInput(doc, el, i18n, li, "f_st_height", "Height:", "Cell height", "", "5", f_st_height, "fr");
1209 select = TableOperations.buildSelectField(doc, el, i18n, li, "f_st_heightUnit", "", "", "", "Height unit", ["percent", "pixels", "em"], ["%", "px", "em"], new RegExp((f_st_height ? selectedHeightUnit : "%"), "i"));
1210 }
1211 content.appendChild(fieldset);
1212 };
1213 TableOperations.buildAlignmentFieldset = function(doc,el,i18n,content,fieldsetClass) {
1214 var select;
1215 var tag = el.tagName.toLowerCase();
1216 var fieldset = doc.createElement("fieldset");
1217 if(fieldsetClass) fieldset.className = fieldsetClass;
1218 TableOperations.insertLegend(doc, i18n, fieldset, "Alignment");
1219 var options = ["Not set", "Left", "Center", "Right", "Justify"];
1220 var values = ["not set", "left", "center", "right", "justify"];
1221 var selected = el.style.textAlign;
1222 (selected.match(/([^\s]*)\s/)) && (selected = RegExp.$1);
1223 /*
1224 if (tag == "td") {
1225 options.push("Character");
1226 values.push("character");
1227 if(f_st_textAlign.charAt(0) == '"') {
1228 var splitArray = f_st_textAlign.split('"');
1229 var f_st_textAlignChar = splitArray[0];
1230 f_st_textAlign = "character";
1231 }
1232 }
1233 */
1234 var ul = doc.createElement("ul");
1235 fieldset.appendChild(ul);
1236 var li = doc.createElement("li");
1237 ul.appendChild(li);
1238 select = TableOperations.buildSelectField(doc, el, i18n, li, "f_st_textAlign", "Text alignment:", "fl", "", "Horizontal alignment of text within cell", options, values, new RegExp((selected ? selected : "not set"), "i"));
1239 /*
1240 if (tag == "td") {
1241 var characterFields = [];
1242 TableOperations.buildInput(doc, el, i18n, fieldset, "f_st_textAlignChar", "", "Align on this character", "", "1", f_st_textAlignChar, "", "floating", "", characterFields);
1243 function setCharVisibility(value) {
1244 for (var i = 0; i < characterFields.length; ++i) {
1245 var characterFieldElement = characterFields[i];
1246 characterFieldElement.style.visibility = value ? "visible" : "hidden";
1247 if (value && (characterFieldElement.tagName.toLowerCase() == "input" )) {
1248 characterFieldElement.focus();
1249 characterFieldElement.select();
1250 }
1251 }
1252 };
1253 select.onchange = function() { setCharVisibility(this.value == "character"); };
1254 setCharVisibility(select.value == "character");
1255 }
1256 */
1257 var li = doc.createElement("li");
1258 ul.appendChild(li);
1259 selected = el.style.verticalAlign;
1260 (selected.match(/([^\s]*)\s/)) && (selected = RegExp.$1);
1261 select = TableOperations.buildSelectField(doc, el, i18n, li, "f_st_vertAlign", "Vertical alignment:", "fl", "", "Vertical alignment of content within cell", ["Not set", "Top", "Middle", "Bottom", "Baseline"], ["not set", "top", "middle", "bottom", "baseline"], new RegExp((selected ? selected : "not set"), "i"));
1262 content.appendChild(fieldset);
1263 };
1264 TableOperations.buildSpacingFieldset = function(doc,el,i18n,content) {
1265 var fieldset = doc.createElement("fieldset");
1266 TableOperations.insertLegend(doc, i18n, fieldset, "Spacing and padding");
1267 var ul = doc.createElement("ul");
1268 fieldset.appendChild(ul);
1269 var li = doc.createElement("li");
1270 ul.appendChild(li);
1271 TableOperations.buildInput(doc, el, i18n, li, "f_spacing", "Cell spacing:", "Space between adjacent cells", "pixels", "5", el.cellSpacing, "fr", "", "postlabel");
1272 var li = doc.createElement("li");
1273 ul.appendChild(li);
1274 TableOperations.buildInput(doc, el, i18n, li, "f_padding", "Cell padding:", "Space between content and border in cell", "pixels", "5", el.cellPadding, "fr", "", "postlabel");
1275 content.appendChild(fieldset);
1276 };
1277 TableOperations.buildBordersFieldset = function(w,doc,editor,el,i18n,content,fieldsetClass) {
1278 var select;
1279 var selected;
1280 var borderFields = [];
1281 function setBorderFieldsVisibility(value) {
1282 for (var i = 0; i < borderFields.length; ++i) {
1283 var borderFieldElement = borderFields[i];
1284 borderFieldElement.style.visibility = value ? "hidden" : "visible";
1285 if (!value && (borderFieldElement.tagName.toLowerCase() == "input")) {
1286 borderFieldElement.focus();
1287 borderFieldElement.select();
1288 }
1289 }
1290 };
1291 var fieldset = doc.createElement("fieldset");
1292 fieldset.className = fieldsetClass;
1293 TableOperations.insertLegend(doc, i18n, fieldset, "Frame and borders");
1294 TableOperations.insertSpace(doc, fieldset);
1295 // Gecko reports "solid solid solid solid" for "border-style: solid".
1296 // That is, "top right bottom left" -- we only consider the first value.
1297 selected = el.style.borderStyle;
1298 (selected.match(/([^\s]*)\s/)) && (selected = RegExp.$1);
1299 selectBorderStyle = TableOperations.buildSelectField(doc, el, i18n, fieldset, "f_st_borderStyle", "Border style:", "fr", "floating", "Border style", ["Not set", "No border", "Dotted", "Dashed", "Solid", "Double", "Groove", "Ridge", "Inset", "Outset"], ["not set", "none", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset"], new RegExp((selected ? selected : "not set"), "i"));
1300 selectBorderStyle.onchange = function() { setBorderFieldsVisibility(this.value == "none"); };
1301 TableOperations.buildInput(doc, el, i18n, fieldset, "f_st_borderWidth", "Border width:", "Border width", "pixels", "5", TableOperations.getLength(el.style.borderWidth), "fr", "floating", "postlabel", borderFields);
1302 TableOperations.insertSpace(doc, fieldset, borderFields);
1303
1304 if (el.tagName.toLowerCase() == "table") {
1305 TableOperations.buildColorField(w, doc, editor, el, i18n, fieldset, "", "Color:", "fr", "colorButton", el.style.borderColor, "borderColor", borderFields);
1306 var label = doc.createElement("label");
1307 label.className = "fl-borderCollapse";
1308 label.htmlFor = "f_st_borderCollapse";
1309 label.innerHTML = i18n["Collapsed borders"];
1310 fieldset.appendChild(label);
1311 borderFields.push(label);
1312 var input = doc.createElement("input");
1313 input.className = "checkbox";
1314 input.type = "checkbox";
1315 input.name = "f_st_borderCollapse";
1316 input.id = "f_st_borderCollapse";
1317 input.defaultChecked = /collapse/i.test(el.style.borderCollapse);
1318 input.checked = input.defaultChecked;
1319 fieldset.appendChild(input);
1320 borderFields.push(input);
1321 TableOperations.insertSpace(doc, fieldset, borderFields);
1322 select = TableOperations.buildSelectField(doc, el, i18n, fieldset, "f_frames", "Frames:", "fr", "floating", "Specifies which sides should have a border", ["Not set", "No sides", "The top side only", "The bottom side only", "The top and bottom sides only", "The right and left sides only", "The left-hand side only", "The right-hand side only", "All four sides"], ["not set", "void", "above", "below", "hsides", "vsides", "lhs", "rhs", "box"], new RegExp((el.frame ? el.frame : "not set"), "i"), borderFields);
1323 TableOperations.insertSpace(doc, fieldset, borderFields);
1324 select = TableOperations.buildSelectField(doc, el, i18n, fieldset, "f_rules", "Rules:", "fr", "floating", "Specifies where rules should be displayed", ["Not set", "No rules", "Rules will appear between rows only", "Rules will appear between columns only", "Rules will appear between all rows and columns"], ["not set", "none", "rows", "cols", "all"], new RegExp((el.rules ? el.rules : "not set"), "i"), borderFields);
1325 } else {
1326 TableOperations.insertSpace(doc, fieldset, borderFields);
1327 TableOperations.buildColorField(w, doc, editor, el, i18n, fieldset, "", "Color:", "fr", "colorButton", el.style.borderColor, "borderColor", borderFields);
1328 }
1329 setBorderFieldsVisibility(selectBorderStyle.value == "none");
1330 TableOperations.insertSpace(doc, fieldset);
1331 content.appendChild(fieldset);
1332 };
1333 TableOperations.buildColorsFieldset = function(w,doc,editor,el,i18n,content) {
1334 var fieldset = doc.createElement("fieldset");
1335 TableOperations.insertLegend(doc, i18n, fieldset, "Background and colors");
1336 var ul = doc.createElement("ul");
1337 fieldset.appendChild(ul);
1338 var li = doc.createElement("li");
1339 ul.appendChild(li);
1340 TableOperations.buildColorField(w, doc, editor, el, i18n, li, "", "FG Color:", "fr", "colorButtonNoFloat", el.style.color, "color");
1341 var li = doc.createElement("li");
1342 ul.appendChild(li);
1343 TableOperations.buildColorField(w, doc, editor, el, i18n, li, "", "Background:", "fr", "colorButtonNoFloat", el.style.backgroundColor, "backgroundColor");
1344 var url;
1345 if (el.style.backgroundImage.match(/url\(\s*(.*?)\s*\)/)) url = RegExp.$1;
1346 TableOperations.buildInput(doc, el, i18n, li, "f_st_backgroundImage", "Image URL:", "URL of the background image", "", "", url, "", "shorter-value");
1347 content.appendChild(fieldset);
1348 };
1349 TableOperations.insertLegend = function(doc,i18n, fieldset,legend) {
1350 var legendNode = doc.createElement("legend");
1351 legendNode.innerHTML = i18n[legend];
1352 fieldset.appendChild(legendNode);
1353 };
1354 TableOperations.insertSpace = function(doc,fieldset,fields) {
1355 var space = doc.createElement("div");
1356 space.className = "space";
1357 fieldset.appendChild(space);
1358 if(fields) fields.push(space);
1359 };
1360 TableOperations.buildInput = function(doc,el,i18n,fieldset,fieldName,fieldLabel,fieldTitle,postLabel,fieldSize,fieldValue,labelClass,inputClass,postClass,fields) {
1361 var label;
1362 // Field label
1363 if(fieldLabel) {
1364 label = doc.createElement("label");
1365 if(labelClass) label.className = labelClass;
1366 label.innerHTML = i18n[fieldLabel];
1367 label.htmlFor = fieldName;
1368 fieldset.appendChild(label);
1369 if(fields) fields.push(label);
1370 }
1371 // Input field
1372 var input = doc.createElement("input");
1373 input.type = "text";
1374 input.id = fieldName;
1375 input.name = fieldName;
1376 if(inputClass) input.className = inputClass;
1377 if(fieldTitle) input.title = i18n[fieldTitle];
1378 if(fieldSize) input.size = fieldSize;
1379 if(fieldValue) input.value = fieldValue;
1380 fieldset.appendChild(input);
1381 if(fields) fields.push(input);
1382 // Field post label
1383 if(postLabel) {
1384 label = doc.createElement("span");
1385 if(postClass) label.className = postClass;
1386 label.innerHTML = i18n[postLabel];
1387 fieldset.appendChild(label);
1388 if(fields) fields.push(label);
1389 }
1390 };
1391 TableOperations.buildSelectField = function(doc,el,i18n,fieldset,fieldName,fieldLabel,labelClass,selectClass,fieldTitle,options,values,selected,fields,translateOptions) {
1392 if(typeof(translateOptions) == "undefined") var translateOptions = true;
1393 // Field Label
1394 if(fieldLabel) {
1395 var label = doc.createElement("label");
1396 if(labelClass) label.className = labelClass;
1397 label.innerHTML = i18n[fieldLabel];
1398 label.htmlFor = fieldName;
1399 fieldset.appendChild(label);
1400 if(fields) fields.push(label);
1401 }
1402 // Text Alignment Select Box
1403 var select = doc.createElement("select");
1404 if (selectClass) select.className = selectClass;
1405 select.id = fieldName;
1406 select.name = fieldName;
1407 select.title= i18n[fieldTitle];
1408 select.selectedIndex = 0;
1409 var option;
1410 for (var i = 0; i < options.length; ++i) {
1411 option = doc.createElement("option");
1412 select.appendChild(option);
1413 option.value = values[i];
1414 if(translateOptions) option.appendChild(doc.createTextNode(i18n[options[i]]));
1415 else option.appendChild(doc.createTextNode(options[i]));
1416 option.selected = selected.test(option.value);
1417 }
1418 if (select.options.length>1) select.disabled = false;
1419 else select.disabled = true;
1420 fieldset.appendChild(select);
1421 if(fields) fields.push(select);
1422 return select;
1423 };
1424 TableOperations.buildColorField = function(w,doc,editor,el,i18n,fieldset,fieldName,fieldLabel,labelClass, buttonClass, fieldValue,fieldType,fields) {
1425 // Field Label
1426 if(fieldLabel) {
1427 var label = doc.createElement("label");
1428 if(labelClass) label.className = labelClass;
1429 label.innerHTML = i18n[fieldLabel];
1430 fieldset.appendChild(label);
1431 if(fields) fields.push(label);
1432 }
1433 var colorButton = TableOperations.createColorButton(w, doc, editor, fieldValue, fieldType);
1434 colorButton.className = buttonClass;
1435 fieldset.appendChild(colorButton);
1436 if(fields) fields.push(colorButton);
1437 };