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