source: trunk/phpgwapi/js/htmlarea/plugins/TableOperations/table-operations.js @ 2

Revision 2, 34.7 KB checked in by niltonneto, 17 years ago (diff)

Removida todas as tags usadas pelo CVS ($Id, $Source).
Primeira versão no CVS externo.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
Line 
1// Table Operations Plugin for HTMLArea-3.0
2// Implementation by Mihai Bazon.  Sponsored by http://www.bloki.com
3//
4// htmlArea v3.0 - Copyright (c) 2002 interactivetools.com, inc.
5// This notice MUST stay intact for use (see license.txt).
6//
7// A free WYSIWYG editor replacement for <textarea> fields.
8// For full source code and docs, visit http://www.interactivetools.com/
9//
10// Version 3.0 developed by Mihai Bazon for InteractiveTools.
11//   http://dynarch.com/mishoo
12//
13
14// Object that will encapsulate all the table operations provided by
15// HTMLArea-3.0 (except "insert table" which is included in the main file)
16function TableOperations(editor) {
17        this.editor = editor;
18
19        var cfg = editor.config;
20        var tt = TableOperations.I18N;
21        var bl = TableOperations.btnList;
22        var self = this;
23
24        // register the toolbar buttons provided by this plugin
25        var toolbar = ["linebreak"];
26        for (var i in bl) {
27                var btn = bl[i];
28                if (!btn) {
29                        toolbar.push("separator");
30                } else {
31                        var id = "TO-" + btn[0];
32                        cfg.registerButton(id, tt[id], editor.imgURL(btn[0] + ".gif", "TableOperations"), false,
33                                           function(editor, id) {
34                                                   // dispatch button press event
35                                                   self.buttonPress(editor, id);
36                                           }, btn[1]);
37                        toolbar.push(id);
38                }
39        }
40
41        // add a new line in the toolbar
42        cfg.toolbar.push(toolbar);
43};
44
45TableOperations._pluginInfo = {
46        name          : "TableOperations",
47        version       : "1.0",
48        developer     : "Mihai Bazon",
49        developer_url : "http://dynarch.com/mishoo/",
50        c_owner       : "Mihai Bazon",
51        sponsor       : "Zapatec Inc.",
52        sponsor_url   : "http://www.bloki.com",
53        license       : "htmlArea"
54};
55
56/************************
57 * UTILITIES
58 ************************/
59
60// retrieves the closest element having the specified tagName in the list of
61// ancestors of the current selection/caret.
62TableOperations.prototype.getClosest = function(tagName) {
63        var editor = this.editor;
64        var ancestors = editor.getAllAncestors();
65        var ret = null;
66        tagName = ("" + tagName).toLowerCase();
67        for (var i in ancestors) {
68                var el = ancestors[i];
69                if (el.tagName.toLowerCase() == tagName) {
70                        ret = el;
71                        break;
72                }
73        }
74        return ret;
75};
76
77// this function requires the file PopupDiv/PopupWin to be loaded from browser
78TableOperations.prototype.dialogTableProperties = function() {
79        var i18n = TableOperations.I18N;
80        // retrieve existing values
81        var table = this.getClosest("table");
82        // this.editor.selectNodeContents(table);
83        // this.editor.updateToolbar();
84
85        var dialog = new PopupWin(this.editor, i18n["Table Properties"], function(dialog, params) {
86                TableOperations.processStyle(params, table);
87                for (var i in params) {
88                        var val = params[i];
89                        switch (i) {
90                            case "f_caption":
91                                if (/\S/.test(val)) {
92                                        // contains non white-space characters
93                                        var caption = table.getElementsByTagName("caption")[0];
94                                        if (!caption) {
95                                                caption = dialog.editor._doc.createElement("caption");
96                                                table.insertBefore(caption, table.firstChild);
97                                        }
98                                        caption.innerHTML = val;
99                                } else {
100                                        // search for caption and delete it if found
101                                        var caption = table.getElementsByTagName("caption")[0];
102                                        if (caption) {
103                                                caption.parentNode.removeChild(caption);
104                                        }
105                                }
106                                break;
107                            case "f_summary":
108                                table.summary = val;
109                                break;
110                            case "f_width":
111                                table.style.width = ("" + val) + params.f_unit;
112                                break;
113                            case "f_align":
114                                table.align = val;
115                                break;
116                            case "f_spacing":
117                                table.cellSpacing = val;
118                                break;
119                            case "f_padding":
120                                table.cellPadding = val;
121                                break;
122                            case "f_borders":
123                                table.border = val;
124                                break;
125                            case "f_frames":
126                                table.frame = val;
127                                break;
128                            case "f_rules":
129                                table.rules = val;
130                                break;
131                        }
132                }
133                // various workarounds to refresh the table display (Gecko,
134                // what's going on?! do not disappoint me!)
135                dialog.editor.forceRedraw();
136                dialog.editor.focusEditor();
137                dialog.editor.updateToolbar();
138                var save_collapse = table.style.borderCollapse;
139                table.style.borderCollapse = "collapse";
140                table.style.borderCollapse = "separate";
141                table.style.borderCollapse = save_collapse;
142        },
143
144        // this function gets called when the dialog needs to be initialized
145        function (dialog) {
146
147                var f_caption = "";
148                var capel = table.getElementsByTagName("caption")[0];
149                if (capel) {
150                        f_caption = capel.innerHTML;
151                }
152                var f_summary = table.summary;
153                var f_width = parseInt(table.style.width);
154                isNaN(f_width) && (f_width = "");
155                var f_unit = /%/.test(table.style.width) ? 'percent' : 'pixels';
156                var f_align = table.align;
157                var f_spacing = table.cellSpacing;
158                var f_padding = table.cellPadding;
159                var f_borders = table.border;
160                var f_frames = table.frame;
161                var f_rules = table.rules;
162
163                function selected(val) {
164                        return val ? " selected" : "";
165                };
166
167                // dialog contents
168                dialog.content.style.width = "400px";
169                dialog.content.innerHTML = " \
170<div class='title'\
171 style='background: url(" + dialog.baseURL + dialog.editor.imgURL("table-prop.gif", "TableOperations") + ") #fff 98% 50% no-repeat'>" + i18n["Table Properties"] + "\
172</div> \
173<table style='width:100%'> \
174  <tr> \
175    <td> \
176      <fieldset><legend>" + i18n["Description"] + "</legend> \
177       <table style='width:100%'> \
178        <tr> \
179          <td class='label'>" + i18n["Caption"] + ":</td> \
180          <td class='value'><input type='text' name='f_caption' value='" + f_caption + "'/></td> \
181        </tr><tr> \
182          <td class='label'>" + i18n["Summary"] + ":</td> \
183          <td class='value'><input type='text' name='f_summary' value='" + f_summary + "'/></td> \
184        </tr> \
185       </table> \
186      </fieldset> \
187    </td> \
188  </tr> \
189  <tr><td id='--HA-layout'></td></tr> \
190  <tr> \
191    <td> \
192      <fieldset><legend>" + i18n["Spacing and padding"] + "</legend> \
193       <table style='width:100%'> \
194"+//        <tr> \
195//           <td class='label'>" + i18n["Width"] + ":</td> \
196//           <td><input type='text' name='f_width' value='" + f_width + "' size='5' /> \
197//             <select name='f_unit'> \
198//               <option value='%'" + selected(f_unit == "percent") + ">" + i18n["percent"] + "</option> \
199//               <option value='px'" + selected(f_unit == "pixels") + ">" + i18n["pixels"] + "</option> \
200//             </select> &nbsp;&nbsp;" + i18n["Align"] + ": \
201//             <select name='f_align'> \
202//               <option value='left'" + selected(f_align == "left") + ">" + i18n["Left"] + "</option> \
203//               <option value='center'" + selected(f_align == "center") + ">" + i18n["Center"] + "</option> \
204//               <option value='right'" + selected(f_align == "right") + ">" + i18n["Right"] + "</option> \
205//             </select> \
206//           </td> \
207//         </tr> \
208"        <tr> \
209          <td class='label'>" + i18n["Spacing"] + ":</td> \
210          <td><input type='text' name='f_spacing' size='5' value='" + f_spacing + "' /> &nbsp;" + i18n["Padding"] + ":\
211            <input type='text' name='f_padding' size='5' value='" + f_padding + "' /> &nbsp;&nbsp;" + i18n["pixels"] + "\
212          </td> \
213        </tr> \
214       </table> \
215      </fieldset> \
216    </td> \
217  </tr> \
218  <tr> \
219    <td> \
220      <fieldset><legend>Frame and borders</legend> \
221        <table width='100%'> \
222          <tr> \
223            <td class='label'>" + i18n["Borders"] + ":</td> \
224            <td><input name='f_borders' type='text' size='5' value='" + f_borders + "' /> &nbsp;&nbsp;" + i18n["pixels"] + "</td> \
225          </tr> \
226          <tr> \
227            <td class='label'>" + i18n["Frames"] + ":</td> \
228            <td> \
229              <select name='f_frames'> \
230                <option value='void'" + selected(f_frames == "void") + ">" + i18n["No sides"] + "</option> \
231                <option value='above'" + selected(f_frames == "above") + ">" + i18n["The top side only"] + "</option> \
232                <option value='below'" + selected(f_frames == "below") + ">" + i18n["The bottom side only"] + "</option> \
233                <option value='hsides'" + selected(f_frames == "hsides") + ">" + i18n["The top and bottom sides only"] + "</option> \
234                <option value='vsides'" + selected(f_frames == "vsides") + ">" + i18n["The right and left sides only"] + "</option> \
235                <option value='lhs'" + selected(f_frames == "lhs") + ">" + i18n["The left-hand side only"] + "</option> \
236                <option value='rhs'" + selected(f_frames == "rhs") + ">" + i18n["The right-hand side only"] + "</option> \
237                <option value='box'" + selected(f_frames == "box") + ">" + i18n["All four sides"] + "</option> \
238              </select> \
239            </td> \
240          </tr> \
241          <tr> \
242            <td class='label'>" + i18n["Rules"] + ":</td> \
243            <td> \
244              <select name='f_rules'> \
245                <option value='none'" + selected(f_rules == "none") + ">" + i18n["No rules"] + "</option> \
246                <option value='rows'" + selected(f_rules == "rows") + ">" + i18n["Rules will appear between rows only"] + "</option> \
247                <option value='cols'" + selected(f_rules == "cols") + ">" + i18n["Rules will appear between columns only"] + "</option> \
248                <option value='all'" + selected(f_rules == "all") + ">" + i18n["Rules will appear between all rows and columns"] + "</option> \
249              </select> \
250            </td> \
251          </tr> \
252        </table> \
253      </fieldset> \
254    </td> \
255  </tr> \
256  <tr> \
257    <td id='--HA-style'></td> \
258  </tr> \
259</table> \
260";
261                var st_prop = TableOperations.createStyleFieldset(dialog.doc, dialog.editor, table);
262                var p = dialog.doc.getElementById("--HA-style");
263                p.appendChild(st_prop);
264                var st_layout = TableOperations.createStyleLayoutFieldset(dialog.doc, dialog.editor, table);
265                p = dialog.doc.getElementById("--HA-layout");
266                p.appendChild(st_layout);
267                dialog.modal = true;
268                dialog.addButtons("ok", "cancel");
269                dialog.showAtElement(dialog.editor._iframe, "c");
270        });
271};
272
273// this function requires the file PopupDiv/PopupWin to be loaded from browser
274TableOperations.prototype.dialogRowCellProperties = function(cell) {
275        var i18n = TableOperations.I18N;
276        // retrieve existing values
277        var element = this.getClosest(cell ? "td" : "tr");
278        var table = this.getClosest("table");
279        // this.editor.selectNodeContents(element);
280        // this.editor.updateToolbar();
281
282        var dialog = new PopupWin(this.editor, i18n[cell ? "Cell Properties" : "Row Properties"], function(dialog, params) {
283                TableOperations.processStyle(params, element);
284                for (var i in params) {
285                        var val = params[i];
286                        switch (i) {
287                            case "f_align":
288                                element.align = val;
289                                break;
290                            case "f_char":
291                                element.ch = val;
292                                break;
293                            case "f_valign":
294                                element.vAlign = val;
295                                break;
296                        }
297                }
298                // various workarounds to refresh the table display (Gecko,
299                // what's going on?! do not disappoint me!)
300                dialog.editor.forceRedraw();
301                dialog.editor.focusEditor();
302                dialog.editor.updateToolbar();
303                var save_collapse = table.style.borderCollapse;
304                table.style.borderCollapse = "collapse";
305                table.style.borderCollapse = "separate";
306                table.style.borderCollapse = save_collapse;
307        },
308
309        // this function gets called when the dialog needs to be initialized
310        function (dialog) {
311
312                var f_align = element.align;
313                var f_valign = element.vAlign;
314                var f_char = element.ch;
315
316                function selected(val) {
317                        return val ? " selected" : "";
318                };
319
320                // dialog contents
321                dialog.content.style.width = "400px";
322                dialog.content.innerHTML = " \
323<div class='title'\
324 style='background: url(" + dialog.baseURL + dialog.editor.imgURL(cell ? "cell-prop.gif" : "row-prop.gif", "TableOperations") + ") #fff 98% 50% no-repeat'>" + i18n[cell ? "Cell Properties" : "Row Properties"] + "</div> \
325<table style='width:100%'> \
326  <tr> \
327    <td id='--HA-layout'> \
328"+//      <fieldset><legend>" + i18n["Layout"] + "</legend> \
329//        <table style='width:100%'> \
330//         <tr> \
331//           <td class='label'>" + i18n["Align"] + ":</td> \
332//           <td> \
333//             <select name='f_align'> \
334//               <option value='left'" + selected(f_align == "left") + ">" + i18n["Left"] + "</option> \
335//               <option value='center'" + selected(f_align == "center") + ">" + i18n["Center"] + "</option> \
336//               <option value='right'" + selected(f_align == "right") + ">" + i18n["Right"] + "</option> \
337//               <option value='char'" + selected(f_align == "char") + ">" + i18n["Char"] + "</option> \
338//             </select> \
339//             &nbsp;&nbsp;" + i18n["Char"] + ": \
340//             <input type='text' style='font-family: monospace; text-align: center' name='f_char' size='1' value='" + f_char + "' /> \
341//           </td> \
342//         </tr><tr> \
343//           <td class='label'>" + i18n["Vertical align"] + ":</td> \
344//           <td> \
345//             <select name='f_valign'> \
346//               <option value='top'" + selected(f_valign == "top") + ">" + i18n["Top"] + "</option> \
347//               <option value='middle'" + selected(f_valign == "middle") + ">" + i18n["Middle"] + "</option> \
348//               <option value='bottom'" + selected(f_valign == "bottom") + ">" + i18n["Bottom"] + "</option> \
349//               <option value='baseline'" + selected(f_valign == "baseline") + ">" + i18n["Baseline"] + "</option> \
350//             </select> \
351//           </td> \
352//         </tr> \
353//        </table> \
354//       </fieldset> \
355"    </td> \
356  </tr> \
357  <tr> \
358    <td id='--HA-style'></td> \
359  </tr> \
360</table> \
361";
362                var st_prop = TableOperations.createStyleFieldset(dialog.doc, dialog.editor, element);
363                var p = dialog.doc.getElementById("--HA-style");
364                p.appendChild(st_prop);
365                var st_layout = TableOperations.createStyleLayoutFieldset(dialog.doc, dialog.editor, element);
366                p = dialog.doc.getElementById("--HA-layout");
367                p.appendChild(st_layout);
368                dialog.modal = true;
369                dialog.addButtons("ok", "cancel");
370                dialog.showAtElement(dialog.editor._iframe, "c");
371        });
372};
373
374// this function gets called when some button from the TableOperations toolbar
375// was pressed.
376TableOperations.prototype.buttonPress = function(editor, button_id) {
377        this.editor = editor;
378        var mozbr = HTMLArea.is_gecko ? "<br />" : "";
379        var i18n = TableOperations.I18N;
380
381        // helper function that clears the content in a table row
382        function clearRow(tr) {
383                var tds = tr.getElementsByTagName("td");
384                for (var i = tds.length; --i >= 0;) {
385                        var td = tds[i];
386                        td.rowSpan = 1;
387                        td.innerHTML = mozbr;
388                }
389        };
390
391        function splitRow(td) {
392                var n = parseInt("" + td.rowSpan);
393                var nc = parseInt("" + td.colSpan);
394                td.rowSpan = 1;
395                tr = td.parentNode;
396                var itr = tr.rowIndex;
397                var trs = tr.parentNode.rows;
398                var index = td.cellIndex;
399                while (--n > 0) {
400                        tr = trs[++itr];
401                        var otd = editor._doc.createElement("td");
402                        otd.colSpan = td.colSpan;
403                        otd.innerHTML = mozbr;
404                        tr.insertBefore(otd, tr.cells[index]);
405                }
406                editor.forceRedraw();
407                editor.updateToolbar();
408        };
409
410        function splitCol(td) {
411                var nc = parseInt("" + td.colSpan);
412                td.colSpan = 1;
413                tr = td.parentNode;
414                var ref = td.nextSibling;
415                while (--nc > 0) {
416                        var otd = editor._doc.createElement("td");
417                        otd.rowSpan = td.rowSpan;
418                        otd.innerHTML = mozbr;
419                        tr.insertBefore(otd, ref);
420                }
421                editor.forceRedraw();
422                editor.updateToolbar();
423        };
424
425        function splitCell(td) {
426                var nc = parseInt("" + td.colSpan);
427                splitCol(td);
428                var items = td.parentNode.cells;
429                var index = td.cellIndex;
430                while (nc-- > 0) {
431                        splitRow(items[index++]);
432                }
433        };
434
435        function selectNextNode(el) {
436                var node = el.nextSibling;
437                while (node && node.nodeType != 1) {
438                        node = node.nextSibling;
439                }
440                if (!node) {
441                        node = el.previousSibling;
442                        while (node && node.nodeType != 1) {
443                                node = node.previousSibling;
444                        }
445                }
446                if (!node) {
447                        node = el.parentNode;
448                }
449                editor.selectNodeContents(node);
450        };
451
452        switch (button_id) {
453                // ROWS
454
455            case "TO-row-insert-above":
456            case "TO-row-insert-under":
457                var tr = this.getClosest("tr");
458                if (!tr) {
459                        break;
460                }
461                var otr = tr.cloneNode(true);
462                clearRow(otr);
463                tr.parentNode.insertBefore(otr, /under/.test(button_id) ? tr.nextSibling : tr);
464                editor.forceRedraw();
465                editor.focusEditor();
466                break;
467            case "TO-row-delete":
468                var tr = this.getClosest("tr");
469                if (!tr) {
470                        break;
471                }
472                var par = tr.parentNode;
473                if (par.rows.length == 1) {
474                        alert(i18n["not-del-last-row"]);
475                        break;
476                }
477                // set the caret first to a position that doesn't
478                // disappear.
479                selectNextNode(tr);
480                par.removeChild(tr);
481                editor.forceRedraw();
482                editor.focusEditor();
483                editor.updateToolbar();
484                break;
485            case "TO-row-split":
486                var td = this.getClosest("td");
487                if (!td) {
488                        break;
489                }
490                splitRow(td);
491                break;
492
493                // COLUMNS
494
495            case "TO-col-insert-before":
496            case "TO-col-insert-after":
497                var td = this.getClosest("td");
498                if (!td) {
499                        break;
500                }
501                var rows = td.parentNode.parentNode.rows;
502                var index = td.cellIndex;
503                for (var i = rows.length; --i >= 0;) {
504                        var tr = rows[i];
505                        var ref = tr.cells[index + (/after/.test(button_id) ? 1 : 0)];
506                        var otd = editor._doc.createElement("td");
507                        otd.innerHTML = mozbr;
508                        tr.insertBefore(otd, ref);
509                }
510                editor.focusEditor();
511                break;
512            case "TO-col-split":
513                var td = this.getClosest("td");
514                if (!td) {
515                        break;
516                }
517                splitCol(td);
518                break;
519            case "TO-col-delete":
520                var td = this.getClosest("td");
521                if (!td) {
522                        break;
523                }
524                var index = td.cellIndex;
525                if (td.parentNode.cells.length == 1) {
526                        alert(i18n["not-del-last-col"]);
527                        break;
528                }
529                // set the caret first to a position that doesn't disappear
530                selectNextNode(td);
531                var rows = td.parentNode.parentNode.rows;
532                for (var i = rows.length; --i >= 0;) {
533                        var tr = rows[i];
534                        tr.removeChild(tr.cells[index]);
535                }
536                editor.forceRedraw();
537                editor.focusEditor();
538                editor.updateToolbar();
539                break;
540
541                // CELLS
542
543            case "TO-cell-split":
544                var td = this.getClosest("td");
545                if (!td) {
546                        break;
547                }
548                splitCell(td);
549                break;
550            case "TO-cell-insert-before":
551            case "TO-cell-insert-after":
552                var td = this.getClosest("td");
553                if (!td) {
554                        break;
555                }
556                var tr = td.parentNode;
557                var otd = editor._doc.createElement("td");
558                otd.innerHTML = mozbr;
559                tr.insertBefore(otd, /after/.test(button_id) ? td.nextSibling : td);
560                editor.forceRedraw();
561                editor.focusEditor();
562                break;
563            case "TO-cell-delete":
564                var td = this.getClosest("td");
565                if (!td) {
566                        break;
567                }
568                if (td.parentNode.cells.length == 1) {
569                        alert(i18n["not-del-last-cell"]);
570                        break;
571                }
572                // set the caret first to a position that doesn't disappear
573                selectNextNode(td);
574                td.parentNode.removeChild(td);
575                editor.forceRedraw();
576                editor.updateToolbar();
577                break;
578            case "TO-cell-merge":
579                // !! FIXME: Mozilla specific !!
580                var sel = editor._getSelection();
581                var range, i = 0;
582                var rows = [];
583                var row = null;
584                var cells = null;
585                if (!HTMLArea.is_ie) {
586                        try {
587                                while (range = sel.getRangeAt(i++)) {
588                                        var td = range.startContainer.childNodes[range.startOffset];
589                                        if (td.parentNode != row) {
590                                                row = td.parentNode;
591                                                (cells) && rows.push(cells);
592                                                cells = [];
593                                        }
594                                        cells.push(td);
595                                }
596                        } catch(e) {/* finished walking through selection */}
597                        rows.push(cells);
598                } else {
599                        // Internet Explorer "browser"
600                        var td = this.getClosest("td");
601                        if (!td) {
602                                alert(i18n["Please click into some cell"]);
603                                break;
604                        }
605                        var tr = td.parentElement;
606                        var no_cols = prompt(i18n["How many columns would you like to merge?"], 2);
607                        if (!no_cols) {
608                                // cancelled
609                                break;
610                        }
611                        var no_rows = prompt(i18n["How many rows would you like to merge?"], 2);
612                        if (!no_rows) {
613                                // cancelled
614                                break;
615                        }
616                        var cell_index = td.cellIndex;
617                        while (no_rows-- > 0) {
618                                td = tr.cells[cell_index];
619                                cells = [td];
620                                for (var i = 1; i < no_cols; ++i) {
621                                        td = td.nextSibling;
622                                        if (!td) {
623                                                break;
624                                        }
625                                        cells.push(td);
626                                }
627                                rows.push(cells);
628                                tr = tr.nextSibling;
629                                if (!tr) {
630                                        break;
631                                }
632                        }
633                }
634                var HTML = "";
635                for (i = 0; i < rows.length; ++i) {
636                        // i && (HTML += "<br />");
637                        var cells = rows[i];
638                        for (var j = 0; j < cells.length; ++j) {
639                                // j && (HTML += "&nbsp;");
640                                var cell = cells[j];
641                                HTML += cell.innerHTML;
642                                (i || j) && (cell.parentNode.removeChild(cell));
643                        }
644                }
645                var td = rows[0][0];
646                td.innerHTML = HTML;
647                td.rowSpan = rows.length;
648                td.colSpan = rows[0].length;
649                editor.selectNodeContents(td);
650                editor.forceRedraw();
651                editor.focusEditor();
652                break;
653
654                // PROPERTIES
655
656            case "TO-table-prop":
657                this.dialogTableProperties();
658                break;
659
660            case "TO-row-prop":
661                this.dialogRowCellProperties(false);
662                break;
663
664            case "TO-cell-prop":
665                this.dialogRowCellProperties(true);
666                break;
667
668            default:
669                alert("Button [" + button_id + "] not yet implemented");
670        }
671};
672
673// the list of buttons added by this plugin
674TableOperations.btnList = [
675        // table properties button
676        ["table-prop",       "table"],
677        null,                   // separator
678
679        // ROWS
680        ["row-prop",         "tr"],
681        ["row-insert-above", "tr"],
682        ["row-insert-under", "tr"],
683        ["row-delete",       "tr"],
684        ["row-split",        "td[rowSpan!=1]"],
685        null,
686
687        // COLS
688        ["col-insert-before", "td"],
689        ["col-insert-after",  "td"],
690        ["col-delete",        "td"],
691        ["col-split",         "td[colSpan!=1]"],
692        null,
693
694        // CELLS
695        ["cell-prop",          "td"],
696        ["cell-insert-before", "td"],
697        ["cell-insert-after",  "td"],
698        ["cell-delete",        "td"],
699        ["cell-merge",         "tr"],
700        ["cell-split",         "td[colSpan!=1,rowSpan!=1]"]
701        ];
702
703
704
705//// GENERIC CODE [style of any element; this should be moved into a separate
706//// file as it'll be very useful]
707//// BEGIN GENERIC CODE -----------------------------------------------------
708
709TableOperations.getLength = function(value) {
710        var len = parseInt(value);
711        if (isNaN(len)) {
712                len = "";
713        }
714        return len;
715};
716
717// Applies the style found in "params" to the given element.
718TableOperations.processStyle = function(params, element) {
719        var style = element.style;
720        for (var i in params) {
721                var val = params[i];
722                switch (i) {
723                    case "f_st_backgroundColor":
724                        style.backgroundColor = val;
725                        break;
726                    case "f_st_color":
727                        style.color = val;
728                        break;
729                    case "f_st_backgroundImage":
730                        if (/\S/.test(val)) {
731                                style.backgroundImage = "url(" + val + ")";
732                        } else {
733                                style.backgroundImage = "none";
734                        }
735                        break;
736                    case "f_st_borderWidth":
737                        style.borderWidth = val;
738                        break;
739                    case "f_st_borderStyle":
740                        style.borderStyle = val;
741                        break;
742                    case "f_st_borderColor":
743                        style.borderColor = val;
744                        break;
745                    case "f_st_borderCollapse":
746                        style.borderCollapse = val ? "collapse" : "";
747                        break;
748                    case "f_st_width":
749                        if (/\S/.test(val)) {
750                                style.width = val + params["f_st_widthUnit"];
751                        } else {
752                                style.width = "";
753                        }
754                        break;
755                    case "f_st_height":
756                        if (/\S/.test(val)) {
757                                style.height = val + params["f_st_heightUnit"];
758                        } else {
759                                style.height = "";
760                        }
761                        break;
762                    case "f_st_textAlign":
763                        if (val == "char") {
764                                var ch = params["f_st_textAlignChar"];
765                                if (ch == '"') {
766                                        ch = '\\"';
767                                }
768                                style.textAlign = '"' + ch + '"';
769                        } else {
770                                style.textAlign = val;
771                        }
772                        break;
773                    case "f_st_verticalAlign":
774                        style.verticalAlign = val;
775                        break;
776                    case "f_st_float":
777                        style.cssFloat = val;
778                        break;
779//                  case "f_st_margin":
780//                      style.margin = val + "px";
781//                      break;
782//                  case "f_st_padding":
783//                      style.padding = val + "px";
784//                      break;
785                }
786        }
787};
788
789// Returns an HTML element for a widget that allows color selection.  That is,
790// a button that contains the given color, if any, and when pressed will popup
791// the sooner-or-later-to-be-rewritten select_color.html dialog allowing user
792// to select some color.  If a color is selected, an input field with the name
793// "f_st_"+name will be updated with the color value in #123456 format.
794TableOperations.createColorButton = function(doc, editor, color, name) {
795        if (!color) {
796                color = "";
797        } else if (!/#/.test(color)) {
798                color = HTMLArea._colorToRgb(color);
799        }
800
801        var df = doc.createElement("span");
802        var field = doc.createElement("input");
803        field.type = "hidden";
804        df.appendChild(field);
805        field.name = "f_st_" + name;
806        field.value = color;
807        var button = doc.createElement("span");
808        button.className = "buttonColor";
809        df.appendChild(button);
810        var span = doc.createElement("span");
811        span.className = "chooser";
812        // span.innerHTML = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
813        span.style.backgroundColor = color;
814        button.appendChild(span);
815        button.onmouseover = function() { if (!this.disabled) { this.className += " buttonColor-hilite"; }};
816        button.onmouseout = function() { if (!this.disabled) { this.className = "buttonColor"; }};
817        span.onclick = function() {
818                if (this.parentNode.disabled) {
819                        return false;
820                }
821                editor._popupDialog("select_color.html", function(color) {
822                        if (color) {
823                                span.style.backgroundColor = "#" + color;
824                                field.value = "#" + color;
825                        }
826                }, color);
827        };
828        var span2 = doc.createElement("span");
829        span2.innerHTML = "&#x00d7;";
830        span2.className = "nocolor";
831        span2.title = TableOperations.I18N["Unset color"];
832        button.appendChild(span2);
833        span2.onmouseover = function() { if (!this.parentNode.disabled) { this.className += " nocolor-hilite"; }};
834        span2.onmouseout = function() { if (!this.parentNode.disabled) { this.className = "nocolor"; }};
835        span2.onclick = function() {
836                span.style.backgroundColor = "";
837                field.value = "";
838        };
839        return df;
840};
841
842TableOperations.createStyleLayoutFieldset = function(doc, editor, el) {
843        var i18n = TableOperations.I18N;
844        var fieldset = doc.createElement("fieldset");
845        var legend = doc.createElement("legend");
846        fieldset.appendChild(legend);
847        legend.innerHTML = i18n["Layout"];
848        var table = doc.createElement("table");
849        fieldset.appendChild(table);
850        table.style.width = "100%";
851        var tbody = doc.createElement("tbody");
852        table.appendChild(tbody);
853
854        var tagname = el.tagName.toLowerCase();
855        var tr, td, input, select, option, options, i;
856
857        if (tagname != "td" && tagname != "tr" && tagname != "th") {
858                tr = doc.createElement("tr");
859                tbody.appendChild(tr);
860                td = doc.createElement("td");
861                td.className = "label";
862                tr.appendChild(td);
863                td.innerHTML = i18n["Float"] + ":";
864                td = doc.createElement("td");
865                tr.appendChild(td);
866                select = doc.createElement("select");
867                td.appendChild(select);
868                select.name = "f_st_float";
869                options = ["None", "Left", "Right"];
870                for (i in options) {
871                        var Val = options[i];
872                        var val = options[i].toLowerCase();
873                        option = doc.createElement("option");
874                        option.innerHTML = i18n[Val];
875                        option.value = val;
876                        option.selected = (("" + el.style.cssFloat).toLowerCase() == val);
877                        select.appendChild(option);
878                }
879        }
880
881        tr = doc.createElement("tr");
882        tbody.appendChild(tr);
883        td = doc.createElement("td");
884        td.className = "label";
885        tr.appendChild(td);
886        td.innerHTML = i18n["Width"] + ":";
887        td = doc.createElement("td");
888        tr.appendChild(td);
889        input = doc.createElement("input");
890        input.type = "text";
891        input.value = TableOperations.getLength(el.style.width);
892        input.size = "5";
893        input.name = "f_st_width";
894        input.style.marginRight = "0.5em";
895        td.appendChild(input);
896        select = doc.createElement("select");
897        select.name = "f_st_widthUnit";
898        option = doc.createElement("option");
899        option.innerHTML = i18n["percent"];
900        option.value = "%";
901        option.selected = /%/.test(el.style.width);
902        select.appendChild(option);
903        option = doc.createElement("option");
904        option.innerHTML = i18n["pixels"];
905        option.value = "px";
906        option.selected = /px/.test(el.style.width);
907        select.appendChild(option);
908        td.appendChild(select);
909
910        select.style.marginRight = "0.5em";
911        td.appendChild(doc.createTextNode(i18n["Text align"] + ":"));
912        select = doc.createElement("select");
913        select.style.marginLeft = select.style.marginRight = "0.5em";
914        td.appendChild(select);
915        select.name = "f_st_textAlign";
916        options = ["Left", "Center", "Right", "Justify"];
917        if (tagname == "td") {
918                options.push("Char");
919        }
920        input = doc.createElement("input");
921        input.name = "f_st_textAlignChar";
922        input.size = "1";
923        input.style.fontFamily = "monospace";
924        td.appendChild(input);
925        for (i in options) {
926                var Val = options[i];
927                var val = Val.toLowerCase();
928                option = doc.createElement("option");
929                option.value = val;
930                option.innerHTML = i18n[Val];
931                option.selected = (el.style.textAlign.toLowerCase() == val);
932                select.appendChild(option);
933        }
934        function setCharVisibility(value) {
935                input.style.visibility = value ? "visible" : "hidden";
936                if (value) {
937                        input.focus();
938                        input.select();
939                }
940        };
941        select.onchange = function() { setCharVisibility(this.value == "char"); };
942        setCharVisibility(select.value == "char");
943
944        tr = doc.createElement("tr");
945        tbody.appendChild(tr);
946        td = doc.createElement("td");
947        td.className = "label";
948        tr.appendChild(td);
949        td.innerHTML = i18n["Height"] + ":";
950        td = doc.createElement("td");
951        tr.appendChild(td);
952        input = doc.createElement("input");
953        input.type = "text";
954        input.value = TableOperations.getLength(el.style.height);
955        input.size = "5";
956        input.name = "f_st_height";
957        input.style.marginRight = "0.5em";
958        td.appendChild(input);
959        select = doc.createElement("select");
960        select.name = "f_st_heightUnit";
961        option = doc.createElement("option");
962        option.innerHTML = i18n["percent"];
963        option.value = "%";
964        option.selected = /%/.test(el.style.height);
965        select.appendChild(option);
966        option = doc.createElement("option");
967        option.innerHTML = i18n["pixels"];
968        option.value = "px";
969        option.selected = /px/.test(el.style.height);
970        select.appendChild(option);
971        td.appendChild(select);
972
973        select.style.marginRight = "0.5em";
974        td.appendChild(doc.createTextNode(i18n["Vertical align"] + ":"));
975        select = doc.createElement("select");
976        select.name = "f_st_verticalAlign";
977        select.style.marginLeft = "0.5em";
978        td.appendChild(select);
979        options = ["Top", "Middle", "Bottom", "Baseline"];
980        for (i in options) {
981                var Val = options[i];
982                var val = Val.toLowerCase();
983                option = doc.createElement("option");
984                option.value = val;
985                option.innerHTML = i18n[Val];
986                option.selected = (el.style.verticalAlign.toLowerCase() == val);
987                select.appendChild(option);
988        }
989
990        return fieldset;
991};
992
993// Returns an HTML element containing the style attributes for the given
994// element.  This can be easily embedded into any dialog; the functionality is
995// also provided.
996TableOperations.createStyleFieldset = function(doc, editor, el) {
997        var i18n = TableOperations.I18N;
998        var fieldset = doc.createElement("fieldset");
999        var legend = doc.createElement("legend");
1000        fieldset.appendChild(legend);
1001        legend.innerHTML = i18n["CSS Style"];
1002        var table = doc.createElement("table");
1003        fieldset.appendChild(table);
1004        table.style.width = "100%";
1005        var tbody = doc.createElement("tbody");
1006        table.appendChild(tbody);
1007
1008        var tr, td, input, select, option, options, i;
1009
1010        tr = doc.createElement("tr");
1011        tbody.appendChild(tr);
1012        td = doc.createElement("td");
1013        tr.appendChild(td);
1014        td.className = "label";
1015        td.innerHTML = i18n["Background"] + ":";
1016        td = doc.createElement("td");
1017        tr.appendChild(td);
1018        var df = TableOperations.createColorButton(doc, editor, el.style.backgroundColor, "backgroundColor");
1019        df.firstChild.nextSibling.style.marginRight = "0.5em";
1020        td.appendChild(df);
1021        td.appendChild(doc.createTextNode(i18n["Image URL"] + ": "));
1022        input = doc.createElement("input");
1023        input.type = "text";
1024        input.name = "f_st_backgroundImage";
1025        if (el.style.backgroundImage.match(/url\(\s*(.*?)\s*\)/)) {
1026                input.value = RegExp.$1;
1027        }
1028        // input.style.width = "100%";
1029        td.appendChild(input);
1030
1031        tr = doc.createElement("tr");
1032        tbody.appendChild(tr);
1033        td = doc.createElement("td");
1034        tr.appendChild(td);
1035        td.className = "label";
1036        td.innerHTML = i18n["FG Color"] + ":";
1037        td = doc.createElement("td");
1038        tr.appendChild(td);
1039        td.appendChild(TableOperations.createColorButton(doc, editor, el.style.color, "color"));
1040
1041        // for better alignment we include an invisible field.
1042        input = doc.createElement("input");
1043        input.style.visibility = "hidden";
1044        input.type = "text";
1045        td.appendChild(input);
1046
1047        tr = doc.createElement("tr");
1048        tbody.appendChild(tr);
1049        td = doc.createElement("td");
1050        tr.appendChild(td);
1051        td.className = "label";
1052        td.innerHTML = i18n["Border"] + ":";
1053        td = doc.createElement("td");
1054        tr.appendChild(td);
1055
1056        var colorButton = TableOperations.createColorButton(doc, editor, el.style.borderColor, "borderColor");
1057        var btn = colorButton.firstChild.nextSibling;
1058        td.appendChild(colorButton);
1059        // borderFields.push(btn);
1060        btn.style.marginRight = "0.5em";
1061
1062        select = doc.createElement("select");
1063        var borderFields = [];
1064        td.appendChild(select);
1065        select.name = "f_st_borderStyle";
1066        options = ["none", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset"];
1067        var currentBorderStyle = el.style.borderStyle;
1068        // Gecko reports "solid solid solid solid" for "border-style: solid".
1069        // That is, "top right bottom left" -- we only consider the first
1070        // value.
1071        (currentBorderStyle.match(/([^\s]*)\s/)) && (currentBorderStyle = RegExp.$1);
1072        for (i in options) {
1073                var val = options[i];
1074                option = doc.createElement("option");
1075                option.value = val;
1076                option.innerHTML = val;
1077                (val == currentBorderStyle) && (option.selected = true);
1078                select.appendChild(option);
1079        }
1080        select.style.marginRight = "0.5em";
1081        function setBorderFieldsStatus(value) {
1082                for (i in borderFields) {
1083                        var el = borderFields[i];
1084                        el.style.visibility = value ? "hidden" : "visible";
1085                        if (!value && (el.tagName.toLowerCase() == "input")) {
1086                                el.focus();
1087                                el.select();
1088                        }
1089                }
1090        };
1091        select.onchange = function() { setBorderFieldsStatus(this.value == "none"); };
1092
1093        input = doc.createElement("input");
1094        borderFields.push(input);
1095        input.type = "text";
1096        input.name = "f_st_borderWidth";
1097        input.value = TableOperations.getLength(el.style.borderWidth);
1098        input.size = "5";
1099        td.appendChild(input);
1100        input.style.marginRight = "0.5em";
1101        var span = doc.createElement("span");
1102        span.innerHTML = i18n["pixels"];
1103        td.appendChild(span);
1104        borderFields.push(span);
1105
1106        setBorderFieldsStatus(select.value == "none");
1107
1108        if (el.tagName.toLowerCase() == "table") {
1109                // the border-collapse style is only for tables
1110                tr = doc.createElement("tr");
1111                tbody.appendChild(tr);
1112                td = doc.createElement("td");
1113                td.className = "label";
1114                tr.appendChild(td);
1115                input = doc.createElement("input");
1116                input.type = "checkbox";
1117                input.name = "f_st_borderCollapse";
1118                input.id = "f_st_borderCollapse";
1119                var val = (/collapse/i.test(el.style.borderCollapse));
1120                input.checked = val ? 1 : 0;
1121                td.appendChild(input);
1122
1123                td = doc.createElement("td");
1124                tr.appendChild(td);
1125                var label = doc.createElement("label");
1126                label.htmlFor = "f_st_borderCollapse";
1127                label.innerHTML = i18n["Collapsed borders"];
1128                td.appendChild(label);
1129        }
1130
1131//      tr = doc.createElement("tr");
1132//      tbody.appendChild(tr);
1133//      td = doc.createElement("td");
1134//      td.className = "label";
1135//      tr.appendChild(td);
1136//      td.innerHTML = i18n["Margin"] + ":";
1137//      td = doc.createElement("td");
1138//      tr.appendChild(td);
1139//      input = doc.createElement("input");
1140//      input.type = "text";
1141//      input.size = "5";
1142//      input.name = "f_st_margin";
1143//      td.appendChild(input);
1144//      input.style.marginRight = "0.5em";
1145//      td.appendChild(doc.createTextNode(i18n["Padding"] + ":"));
1146
1147//      input = doc.createElement("input");
1148//      input.type = "text";
1149//      input.size = "5";
1150//      input.name = "f_st_padding";
1151//      td.appendChild(input);
1152//      input.style.marginLeft = "0.5em";
1153//      input.style.marginRight = "0.5em";
1154//      td.appendChild(doc.createTextNode(i18n["pixels"]));
1155
1156        return fieldset;
1157};
1158
1159//// END GENERIC CODE -------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.