Annotation of kupuMPIWG/silva/kupusilvatools.js, revision 1.1
1.1 ! dwinter 1: /*****************************************************************************
! 2: *
! 3: * Copyright (c) 2003-2005 Kupu Contributors. All rights reserved.
! 4: *
! 5: * This software is distributed under the terms of the Kupu
! 6: * License. See LICENSE.txt for license text. For a list of Kupu
! 7: * Contributors see CREDITS.txt.
! 8: *
! 9: *****************************************************************************/
! 10:
! 11: // $Id: kupusilvatools.js 14851 2005-07-21 11:39:15Z duncan $
! 12:
! 13: // a mapping from namespace to field names, here you can configure which
! 14: // metadata fields should be editable with the property editor (needs to
! 15: // be moved to somewhere in Silva or something?)
! 16: EDITABLE_METADATA = {
! 17: 'http://infrae.com/namespaces/metadata/silva-extra':
! 18: [['contactname', 'text', 0, 'Contact name'],
! 19: ['contactemail', 'text', 0, 'Contact email']
! 20: ],
! 21: 'http://infrae.com/namespaces/metadata/abstract':
! 22: [['author', 'text', 1, 'Presenting author'],
! 23: ['co_authors', 'textarea', 0, 'Co-author(s)']]
! 24: }
! 25:
! 26: function SilvaLinkTool() {
! 27: /* redefine the contextmenu elements */
! 28: };
! 29:
! 30: SilvaLinkTool.prototype = new LinkTool;
! 31:
! 32: SilvaLinkTool.prototype.createContextMenuElements = function(selNode, event) {
! 33: /* create the 'Create link' or 'Remove link' menu elements */
! 34: var ret = new Array();
! 35: var link = this.editor.getNearestParentOfType(selNode, 'a');
! 36: if (link) {
! 37: ret.push(new ContextMenuElement('Delete link', this.deleteLink, this));
! 38: } else {
! 39: ret.push(new ContextMenuElement('Create link', getLink, this));
! 40: };
! 41: return ret;
! 42: };
! 43:
! 44: function SilvaLinkToolBox(inputid, targetselectid, targetinputid, addbuttonid, updatebuttonid, delbuttonid, toolboxid, plainclass, activeclass) {
! 45: /* create and edit links */
! 46:
! 47: this.input = getFromSelector(inputid);
! 48: this.targetselect = getFromSelector(targetselectid);
! 49: this.targetinput = getFromSelector(targetinputid);
! 50: this.addbutton = getFromSelector(addbuttonid);
! 51: this.updatebutton = getFromSelector(updatebuttonid);
! 52: this.delbutton = getFromSelector(delbuttonid);
! 53: this.toolboxel = getFromSelector(toolboxid);
! 54: this.plainclass = plainclass;
! 55: this.activeclass = activeclass;
! 56: };
! 57:
! 58: SilvaLinkToolBox.prototype = new LinkToolBox;
! 59:
! 60: SilvaLinkToolBox.prototype.initialize = function(tool, editor) {
! 61: this.tool = tool;
! 62: this.editor = editor;
! 63: addEventHandler(this.targetselect, 'change', this.selectTargetHandler, this);
! 64: addEventHandler(this.targetinput, 'change', this.selectTargetHandler, this);
! 65: addEventHandler(this.addbutton, 'click', this.createLinkHandler, this);
! 66: addEventHandler(this.updatebutton, 'click', this.createLinkHandler, this);
! 67: addEventHandler(this.delbutton, 'click', this.tool.deleteLink, this);
! 68: this.targetinput.style.display = 'none';
! 69: this.editor.logMessage('Link tool initialized');
! 70: };
! 71:
! 72: SilvaLinkToolBox.prototype.selectTargetHandler = function(event) {
! 73: var select = this.targetselect;
! 74: var input = this.targetinput;
! 75:
! 76: var selvalue = select.options[select.selectedIndex].value;
! 77: if (selvalue != 'input') {
! 78: input.style.display = 'none';
! 79: } else {
! 80: input.style.display = 'inline';
! 81: };
! 82: };
! 83:
! 84: SilvaLinkToolBox.prototype.createLinkHandler = function(event) {
! 85: var url = this.input.value;
! 86: var target = this.targetselect.options[this.targetselect.selectedIndex].value;
! 87: if (target == 'input') {
! 88: target = this.targetinput.value;
! 89: };
! 90: this.tool.createLink(url, 'link', null, target);
! 91: };
! 92:
! 93: SilvaLinkToolBox.prototype.updateState = function(selNode, event) {
! 94: var currnode = selNode;
! 95: var link = false;
! 96: var href = '';
! 97: while (currnode) {
! 98: if (currnode.nodeName.toLowerCase() == 'a') {
! 99: href = currnode.getAttribute('href');
! 100: if (href) {
! 101: if (this.toolboxel) {
! 102: this.toolboxel.className = this.activeclass;
! 103: };
! 104: this.input.value = href;
! 105: var target = currnode.getAttribute('target');
! 106: if (!target) {
! 107: this.targetselect.selectedIndex = 0;
! 108: this.targetinput.style.display = 'none';
! 109: } else {
! 110: var target_found = false;
! 111: for (var i=0; i < this.targetselect.options.length; i++) {
! 112: var option = this.targetselect.options[i];
! 113: if (option.value == target) {
! 114: this.targetselect.selectedIndex = i;
! 115: target_found = true;
! 116: break;
! 117: };
! 118: };
! 119: if (target_found) {
! 120: this.targetinput.value = '';
! 121: this.targetinput.style.display = 'none';
! 122: } else {
! 123: // XXX this is pretty hard-coded...
! 124: this.targetselect.selectedIndex = this.targetselect.options.length - 1;
! 125: this.targetinput.value = target;
! 126: this.targetinput.style.display = 'inline';
! 127: };
! 128: };
! 129: this.addbutton.style.display = 'none';
! 130: this.updatebutton.style.display = 'inline';
! 131: this.delbutton.style.display = 'inline';
! 132: return;
! 133: };
! 134: };
! 135: currnode = currnode.parentNode;
! 136: };
! 137: this.targetselect.selectedIndex = 0;
! 138: this.targetinput.value = '';
! 139: this.targetinput.style.display = 'none';
! 140: this.updatebutton.style.display = 'none';
! 141: this.delbutton.style.display = 'none';
! 142: this.addbutton.style.display = 'inline';
! 143: if (this.toolboxel) {
! 144: this.toolboxel.className = this.plainclass;
! 145: };
! 146: this.input.value = '';
! 147: };
! 148:
! 149: function SilvaImageTool(editelid, urlinputid, targetselectid, targetinputid,
! 150: hireslinkradioid, linklinkradioid, linkinputid,
! 151: alignselectid, titleinputid, toolboxid, plainclass,
! 152: activeclass) {
! 153: /* Silva specific image tool */
! 154: this.editel = getFromSelector(editelid);
! 155: this.urlinput = getFromSelector(urlinputid);
! 156: this.targetselect = getFromSelector(targetselectid);
! 157: this.targetinput = getFromSelector(targetinputid);
! 158: this.hireslinkradio = getFromSelector(hireslinkradioid);
! 159: this.linklinkradio = getFromSelector(linklinkradioid);
! 160: this.linkinput = getFromSelector(linkinputid);
! 161: this.alignselect = getFromSelector(alignselectid);
! 162: this.titleinput = getFromSelector(titleinputid);
! 163: this.toolboxel = getFromSelector(toolboxid);
! 164: this.plainclass = plainclass;
! 165: this.activeclass = activeclass;
! 166: }
! 167:
! 168: SilvaImageTool.prototype = new ImageTool;
! 169:
! 170: SilvaImageTool.prototype.initialize = function(editor) {
! 171: this.editor = editor;
! 172: addEventHandler(this.targetselect, 'change', this.setTarget, this);
! 173: addEventHandler(this.targetselect, 'change', this.selectTargetHandler, this);
! 174: addEventHandler(this.targetinput, 'change', this.setTarget, this);
! 175: addEventHandler(this.urlinput, 'change', this.setSrc, this);
! 176: addEventHandler(this.hireslinkradio, 'click', this.setHires, this);
! 177: addEventHandler(this.linklinkradio, 'click', this.setNoHires, this);
! 178: addEventHandler(this.linkinput, 'keypress', this.setLink, this);
! 179: addEventHandler(this.linkinput, 'change', this.setLink, this);
! 180: addEventHandler(this.alignselect, 'change', this.setAlign, this);
! 181: addEventHandler(this.titleinput, 'change', this.setTitle, this);
! 182: this.targetinput.style.display = 'none';
! 183: this.editor.logMessage('Image tool initialized');
! 184: };
! 185:
! 186: SilvaImageTool.prototype.createContextMenuElements = function(selNode, event) {
! 187: return new Array(new ContextMenuElement('Create image', getImage, this));
! 188: };
! 189:
! 190: SilvaImageTool.prototype.selectTargetHandler = function(event) {
! 191: var select = this.targetselect;
! 192: var input = this.targetinput;
! 193:
! 194: var selvalue = select.options[select.selectedIndex].value;
! 195: if (selvalue != 'input') {
! 196: input.style.display = 'none';
! 197: } else {
! 198: input.style.display = 'inline';
! 199: };
! 200: };
! 201:
! 202: SilvaImageTool.prototype.updateState = function(selNode, event) {
! 203: var image = this.editor.getNearestParentOfType(selNode, 'img');
! 204: if (image) {
! 205: this.editel.style.display = 'block';
! 206: var src = image.getAttribute('src');
! 207: this.urlinput.value = src;
! 208: var target = image.getAttribute('target');
! 209: if (!target) {
! 210: this.targetselect.selectedIndex = 0;
! 211: this.targetinput.style.display = 'none';
! 212: } else {
! 213: var target_found = false;
! 214: for (var i=0; i < this.targetselect.options.length; i++) {
! 215: var option = this.targetselect.options[i];
! 216: if (option.value == target) {
! 217: this.targetselect.selectedIndex = i;
! 218: target_found = true;
! 219: break;
! 220: };
! 221: };
! 222: if (target_found) {
! 223: this.targetinput.value = '';
! 224: this.targetinput.style.display = 'none';
! 225: } else {
! 226: this.targetselect.selectedIndex = this.targetselect.options.length - 1;
! 227: this.targetinput.value = target;
! 228: this.targetinput.style.display = 'inline';
! 229: };
! 230: };
! 231: var hires = image.getAttribute('link_to_hires') == '1';
! 232: if (!hires) {
! 233: var link = image.getAttribute('link');
! 234: this.linklinkradio.checked = 'selected';
! 235: this.linkinput.value = link == null ? '' : link;
! 236: } else {
! 237: this.hireslinkradio.checked = 'checked';
! 238: this.linkinput.value = '';
! 239: };
! 240: if (this.toolboxel) {
! 241: this.toolboxel.className = this.activeclass;
! 242: };
! 243: var align = image.getAttribute('alignment');
! 244: if (!align) {
! 245: align = 'left';
! 246: };
! 247: var title = image.getAttribute('title');
! 248: if (!title) {
! 249: title = '';
! 250: };
! 251: this.titleinput.value = title;
! 252: selectSelectItem(this.alignselect, align);
! 253: } else {
! 254: this.editel.style.display = 'none';
! 255: this.urlinput.value = '';
! 256: this.titleinput.value = '';
! 257: if (this.toolboxel) {
! 258: this.toolboxel.className = this.plainclass;
! 259: };
! 260: this.targetselect.selectedIndex = 0;
! 261: this.targetinput.value = '';
! 262: this.targetinput.style.display = 'none';
! 263: };
! 264: };
! 265:
! 266: SilvaImageTool.prototype.setTarget = function() {
! 267: var target = this.targetselect.options[this.targetselect.selectedIndex].value;
! 268: if (target == 'input') {
! 269: target = this.targetinput.value;
! 270: };
! 271: var selNode = this.editor.getSelectedNode();
! 272: var image = this.editor.getNearestParentOfType(selNode, 'img');
! 273: if (!image) {
! 274: this.editor.logMessage('No image selected!', 1);
! 275: };
! 276: image.setAttribute('target', target);
! 277: };
! 278:
! 279: SilvaImageTool.prototype.setSrc = function() {
! 280: var selNode = this.editor.getSelectedNode();
! 281: var img = this.editor.getNearestParentOfType(selNode, 'img');
! 282: if (!img) {
! 283: this.editor.logMessage('Not inside an image!', 1);
! 284: };
! 285:
! 286: var src = this.urlinput.value;
! 287: img.setAttribute('src', src);
! 288: this.editor.logMessage('Image updated');
! 289: };
! 290:
! 291: SilvaImageTool.prototype.setHires = function() {
! 292: var selNode = this.editor.getSelectedNode();
! 293: var image = this.editor.getNearestParentOfType(selNode, 'img');
! 294: if (!image) {
! 295: this.editor.logMessage('No image selected!', 1);
! 296: return;
! 297: };
! 298: image.setAttribute('link_to_hires', '1');
! 299: image.removeAttribute('link');
! 300: this.linkinput.value = '';
! 301: };
! 302:
! 303: SilvaImageTool.prototype.setNoHires = function() {
! 304: var selNode = this.editor.getSelectedNode();
! 305: var image = this.editor.getNearestParentOfType(selNode, 'img');
! 306: if (!image) {
! 307: this.editor.logMessage('Not inside an image!', 1);
! 308: return;
! 309: };
! 310: var link = this.linkinput.value;
! 311: image.setAttribute('link_to_hires', '0');
! 312: image.setAttribute('link', link);
! 313: this.linklinkradio.setAttribute('selected', 'selected');
! 314: };
! 315:
! 316: SilvaImageTool.prototype.setLink = function() {
! 317: var link = this.linkinput.value;
! 318: var selNode = this.editor.getSelectedNode();
! 319: var image = this.editor.getNearestParentOfType(selNode, 'img');
! 320: if (!image) {
! 321: this.editor.logMessage('No image selected!', 1);
! 322: return;
! 323: };
! 324: image.setAttribute('link', link);
! 325: image.setAttribute('link_to_hires', '0');
! 326: };
! 327:
! 328: SilvaImageTool.prototype.setTitle = function() {
! 329: var selNode = this.editor.getSelectedNode();
! 330: var image = this.editor.getNearestParentOfType(selNode, 'img');
! 331: if (!image) {
! 332: this.editor.logMessage('No image selected!', 1);
! 333: return;
! 334: };
! 335: var title = this.titleinput.value;
! 336: image.setAttribute('title', title);
! 337: };
! 338:
! 339: SilvaImageTool.prototype.setAlign = function() {
! 340: var selNode = this.editor.getSelectedNode();
! 341: var image = this.editor.getNearestParentOfType(selNode, 'img');
! 342: if (!image) {
! 343: this.editor.logMessage('Not inside an image', 1);
! 344: return;
! 345: };
! 346: var align = this.alignselect.options[this.alignselect.selectedIndex].value;
! 347: image.setAttribute('alignment', align);
! 348: };
! 349:
! 350: function SilvaTableTool() {
! 351: /* Silva specific table functionality
! 352: overrides most of the table functionality, required because Silva requires
! 353: a completely different format for tables
! 354: */
! 355:
! 356: this.createTable = function(rows, cols, makeHeader, tableclass) {
! 357: /* add a Silvs specific table, with an (optional) header with colspan */
! 358: var doc = this.editor.getInnerDocument();
! 359:
! 360: var table = doc.createElement('table');
! 361: table.style.width = "100%";
! 362: table.className = tableclass;
! 363:
! 364: var tbody = doc.createElement('tbody');
! 365:
! 366: if (makeHeader) {
! 367: this._addRowHelper(doc, tbody, 'th', -1, cols);
! 368: }
! 369:
! 370: for (var i=0; i < rows; i++) {
! 371: this._addRowHelper(doc, tbody, 'td', -1, cols);
! 372: }
! 373:
! 374: table.appendChild(tbody);
! 375:
! 376: var iterator = new NodeIterator(table);
! 377: var currnode = null;
! 378: var contentcell = null;
! 379: while (currnode = iterator.next()) {
! 380: var nodename = currnode.nodeName.toLowerCase();
! 381: if (nodename == 'td' || nodename == 'th') {
! 382: contentcell = currnode;
! 383: break;
! 384: };
! 385: };
! 386:
! 387: var selection = this.editor.getSelection();
! 388: var docfrag = selection.cloneContents();
! 389: var setcursoratend = false;
! 390: if (contentcell && docfrag.hasChildNodes()) {
! 391: while (contentcell.hasChildNodes()) {
! 392: contentcell.removeChild(contentcell.firstChild);
! 393: };
! 394:
! 395: while (docfrag.hasChildNodes()) {
! 396: contentcell.appendChild(docfrag.firstChild);
! 397: setcursoratend = true;
! 398: };
! 399: };
! 400: this.editor.insertNodeAtSelection(table);
! 401:
! 402: this._setTableCellHandlers(table);
! 403:
! 404: this.editor.logMessage('Table added');
! 405: };
! 406:
! 407: this.addTableRow = function() {
! 408: /* add a table row or header */
! 409: var currnode = this.editor.getSelectedNode();
! 410: var doc = this.editor.getInnerDocument();
! 411: var tbody = this.editor.getNearestParentOfType(currnode, 'tbody');
! 412: if (!tbody) {
! 413: this.editor.logMessage('No table found!', 1);
! 414: return;
! 415: }
! 416: var cols = this._countCells(tbody);
! 417: var currrow = this.editor.getNearestParentOfType(currnode, 'tr');
! 418: if (!currrow) {
! 419: this.editor.logMessage('Not inside a row!', 1);
! 420: return;
! 421: };
! 422: var index = this._getRowIndex(currrow) + 1;
! 423: // should check what to add as well
! 424: this._addRowHelper(doc, tbody, 'td', index, cols);
! 425:
! 426: this.editor.logMessage('Table row added');
! 427: };
! 428:
! 429: this.delTableRow = function() {
! 430: /* delete a table row or header */
! 431: var currnode = this.editor.getSelectedNode();
! 432: var currtr = this.editor.getNearestParentOfType(currnode, 'tr');
! 433:
! 434: if (!currtr) {
! 435: this.editor.logMessage('Not inside a row!', 1);
! 436: return;
! 437: };
! 438:
! 439: currtr.parentNode.removeChild(currtr);
! 440:
! 441: this.editor.logMessage('Table row removed');
! 442: };
! 443:
! 444: this.addTableColumn = function() {
! 445: /* add a table column */
! 446: var currnode = this.editor.getSelectedNode();
! 447: var doc = this.editor.getInnerDocument();
! 448: var body = this.editor.getNearestParentOfType(currnode, 'tbody');
! 449: if (!body) {
! 450: this.editor.logMessage('Not inside a table!');
! 451: return;
! 452: };
! 453: var currcell = this.editor.getNearestParentOfType(currnode, 'td');
! 454: if (!currcell) {
! 455: var currcell = this.editor.getNearestParentOfType(currnode, 'th');
! 456: if (!currcell) {
! 457: this.editor.logMessage('Not inside a row!', 1);
! 458: return;
! 459: } else {
! 460: var index = -1;
! 461: };
! 462: } else {
! 463: var index = this._getColIndex(currcell) + 1;
! 464: };
! 465: var numcells = this._countCells(body);
! 466: this._addColHelper(doc, body, index, numcells);
! 467:
! 468: this.editor.logMessage('Column added');
! 469: };
! 470:
! 471: this.delTableColumn = function() {
! 472: /* delete a column */
! 473: var currnode = this.editor.getSelectedNode();
! 474: var body = this.editor.getNearestParentOfType(currnode, 'tbody');
! 475: if (!body) {
! 476: this.editor.logMessage('Not inside a table body!', 1);
! 477: return;
! 478: }
! 479: var currcell = this.editor.getNearestParentOfType(currnode, 'td');
! 480: if (!currcell) {
! 481: currcell = this.editor.getNearestParentOfType(currnode, 'th');
! 482: if (!currcell) {
! 483: this.editor.logMessage('Not inside a cell!');
! 484: return;
! 485: };
! 486: var index = -1;
! 487: } else {
! 488: var index = this._getColIndex(currcell);
! 489: };
! 490:
! 491: this._delColHelper(body, index);
! 492:
! 493: this.editor.logMessage('Column deleted');
! 494: };
! 495:
! 496: this.setColumnWidths = function(widths) {
! 497: /* sets relative column widths */
! 498: var selNode = this.editor.getSelectedNode();
! 499: var table = this.editor.getNearestParentOfType(selNode, 'table');
! 500:
! 501: // first remove all current width settings from the table
! 502: var iterator = new NodeIterator(table);
! 503: var currnode = null;
! 504: while (currnode = iterator.next()) {
! 505: if (currnode.nodeName.toLowerCase() == 'td') {
! 506: if (currnode.getAttribute('width')) {
! 507: currnode.removeAttribute('width');
! 508: } else if (currnode.style.width) {
! 509: delete currnode.style.width;
! 510: };
! 511: };
! 512: };
! 513:
! 514: var silva_column_info = new Array();
! 515: widths = widths.split(',');
! 516: for (var i=0; i < widths.length; i++) {
! 517: widths[i] = widths[i].strip();
! 518: silva_column_info.push('C:' + widths[i]);
! 519: widths[i] = parseInt(widths[i]);
! 520: };
! 521: silva_column_info = silva_column_info.join(' ');
! 522: table.setAttribute('silva_column_info', silva_column_info);
! 523:
! 524: // now convert the relative widths to percentages
! 525: // first find the first row containing cells
! 526: var totalunits = 0;
! 527: for (var i=0; i < widths.length; i++) {
! 528: totalunits += widths[i];
! 529: };
! 530: var iterator = new NodeIterator(table);
! 531: var currnode = null;
! 532: var row = null;
! 533: while (currnode = iterator.next()) {
! 534: if (currnode.nodeName.toLowerCase() == 'td') {
! 535: row = currnode.parentNode;
! 536: break;
! 537: };
! 538: };
! 539: var iterator = new NodeIterator(row);
! 540: var percent_per_unit = 100.0 / totalunits;
! 541: var currcell = null;
! 542: for (var i=0; i < widths.length; i++) {
! 543: while (currcell = iterator.next()) {
! 544: if (currcell.nodeName.toLowerCase() == 'td') {
! 545: currcell.setAttribute('width', '' + (widths[i] * percent_per_unit) + '%');
! 546: break;
! 547: };
! 548: };
! 549: };
! 550: };
! 551:
! 552: this.getColumnWidths = function(table) {
! 553: var silvacolinfo = table.getAttribute('silva_column_info');
! 554: var widths = new Array();
! 555: if (!silvacolinfo) {
! 556: var body = null;
! 557: var iterator = new NodeIterator(table);
! 558: var body = iterator.next();
! 559: while (body.nodeName.toLowerCase() != 'tbody') {
! 560: body = iterator.next();
! 561: };
! 562: var numcols = this._countCells(body);
! 563: for (var i=0; i < numcols; i++) {
! 564: widths.push(1);
! 565: };
! 566: } else {
! 567: silvacolinfo = silvacolinfo.split(' ');
! 568: for (var i=0; i < silvacolinfo.length; i++) {
! 569: var pair = silvacolinfo[i].split(':');
! 570: widths.push(parseInt(pair[1]));
! 571: };
! 572: widths = this._factorWidths(widths);
! 573: };
! 574: return widths;
! 575: };
! 576:
! 577: this._factorWidths = function(widths) {
! 578: var highest = 0;
! 579: for (var i=0; i < widths.length; i++) {
! 580: if (widths[i] > highest) {
! 581: highest = widths[i];
! 582: };
! 583: };
! 584: var factor = 1;
! 585: for (var i=0; i < highest; i++) {
! 586: var testnum = highest - i;
! 587: var isfactor = true;
! 588: for (var j=0; j < widths.length; j++) {
! 589: if (widths[j] % testnum != 0) {
! 590: isfactor = false;
! 591: break;
! 592: };
! 593: };
! 594: if (isfactor) {
! 595: factor = testnum;
! 596: break;
! 597: };
! 598: };
! 599: if (factor > 1) {
! 600: for (var i=0; i < widths.length; i++) {
! 601: widths[i] = widths[i] / factor;
! 602: };
! 603: };
! 604: return widths;
! 605: };
! 606:
! 607: this._addRowHelper = function(doc, body, celltype, index, numcells) {
! 608: /* actually adds a row to the table */
! 609: var row = doc.createElement('tr');
! 610:
! 611: // fill the row with cells
! 612: if (celltype == 'td') {
! 613: for (var i=0; i < numcells; i++) {
! 614: var cell = doc.createElement(celltype);
! 615: var nbsp = doc.createTextNode("\u00a0");
! 616: cell.appendChild(nbsp);
! 617: row.appendChild(cell);
! 618: }
! 619: } else if (celltype == 'th') {
! 620: var cell = doc.createElement(celltype);
! 621: cell.setAttribute('colSpan', numcells);
! 622: var nbsp = doc.createTextNode("\u00a0");
! 623: cell.appendChild(nbsp);
! 624: row.appendChild(cell);
! 625: }
! 626:
! 627: // now append it to the tbody
! 628: var rows = this._getAllRows(body);
! 629: if (index == -1 || index >= rows.length) {
! 630: body.appendChild(row);
! 631: } else {
! 632: var nextrow = rows[index];
! 633: body.insertBefore(row, nextrow);
! 634: }
! 635:
! 636: return row;
! 637: };
! 638:
! 639: this._addColHelper = function(doc, body, index, numcells) {
! 640: /* actually adds a column to a table */
! 641: var rows = this._getAllRows(body);
! 642: for (var i=0; i < rows.length; i++) {
! 643: var row = rows[i];
! 644: var cols = this._getAllColumns(row);
! 645: var col = cols[0];
! 646: if (col.nodeName.toLowerCase() == 'th') {
! 647: var colspan = col.getAttribute('colSpan');
! 648: if (colspan) {
! 649: colspan = parseInt(colspan);
! 650: } else {
! 651: colspan = 1;
! 652: }
! 653: col.setAttribute('colSpan', colspan + 1);
! 654: } else {
! 655: var cell = doc.createElement('td');
! 656: var nbsp = doc.createTextNode('\u00a0');
! 657: cell.appendChild(nbsp);
! 658: if (index == -1 || index >= rows.length) {
! 659: row.appendChild(cell);
! 660: } else {
! 661: row.insertBefore(cell, cols[index]);
! 662: };
! 663: };
! 664: };
! 665: };
! 666:
! 667: this._delColHelper = function(body, index) {
! 668: /* actually delete all cells in a column */
! 669: var rows = this._getAllRows(body);
! 670: for (var i=0; i < rows.length; i++) {
! 671: var row = rows[i];
! 672: var cols = this._getAllColumns(row);
! 673: if (cols[0].nodeName.toLowerCase() == 'th') {
! 674: // is a table header, so reduce colspan
! 675: var th = cols[0];
! 676: var colspan = th.getAttribute('colSpan');
! 677: if (!colspan || colspan == '1') {
! 678: body.removeChild(row);
! 679: } else {
! 680: colspan = parseInt(colspan);
! 681: th.setAttribute('colSpan', colspan - 1);
! 682: };
! 683: } else {
! 684: // is a table cell row, remove one
! 685: if (index > -1) {
! 686: row.removeChild(cols[index]);
! 687: } else {
! 688: row.removeChild(cols[cols.length - 1]);
! 689: }
! 690: }
! 691: };
! 692: };
! 693:
! 694: this._getRowIndex = function(row) {
! 695: /* get the current rowindex */
! 696: var rowindex = 0;
! 697: var prevrow = row.previousSibling;
! 698: while (prevrow) {
! 699: if (prevrow.nodeName.toLowerCase() == 'tr') {
! 700: rowindex++;
! 701: };
! 702: prevrow = prevrow.previousSibling;
! 703: };
! 704: return rowindex;
! 705: };
! 706:
! 707: this._countCells = function(body) {
! 708: /* get the current column index */
! 709: var numcols = 0;
! 710: var cols = this._getAllColumns(this._getAllRows(body)[0]);
! 711: for (var i=0; i < cols.length; i++) {
! 712: var node = cols[i];
! 713: if (node.nodeName.toLowerCase() == 'th') {
! 714: var colspan = node.getAttribute('colSpan');
! 715: if (colspan) {
! 716: colspan = parseInt(colspan);
! 717: } else {
! 718: colspan = 1;
! 719: };
! 720: numcols += colspan;
! 721: } else {
! 722: numcols++;
! 723: };
! 724: };
! 725: return numcols;
! 726: };
! 727:
! 728: this._getAllRows = function(body) {
! 729: /* returns an Array of all available rows */
! 730: var rows = new Array();
! 731: for (var i=0; i < body.childNodes.length; i++) {
! 732: var node = body.childNodes[i];
! 733: if (node.nodeName.toLowerCase() == 'tr') {
! 734: rows.push(node);
! 735: };
! 736: };
! 737: return rows;
! 738: };
! 739:
! 740: this._getAllColumns = function(row) {
! 741: /* returns an Array of all columns in a row */
! 742: var cols = new Array();
! 743: for (var i=0; i < row.childNodes.length; i++) {
! 744: var node = row.childNodes[i];
! 745: if (node.nodeName.toLowerCase() == 'td' ||
! 746: node.nodeName.toLowerCase() == 'th') {
! 747: cols.push(node);
! 748: };
! 749: };
! 750: return cols;
! 751: };
! 752: }
! 753:
! 754: SilvaTableTool.prototype = new TableTool;
! 755:
! 756: function SilvaTableToolBox(addtabledivid, edittabledivid, newrowsinputid,
! 757: newcolsinputid, makeheaderinputid, classselectid, alignselectid, widthinputid,
! 758: addtablebuttonid, addrowbuttonid, delrowbuttonid, addcolbuttonid, delcolbuttonid,
! 759: fixbuttonid, delbuttonid, toolboxid, plainclass, activeclass) {
! 760: /* Silva specific table functionality
! 761: overrides most of the table functionality, required because Silva requires
! 762: a completely different format for tables
! 763: */
! 764:
! 765: this.addtablediv = getFromSelector(addtabledivid);
! 766: this.edittablediv = getFromSelector(edittabledivid);
! 767: this.newrowsinput = getFromSelector(newrowsinputid);
! 768: this.newcolsinput = getFromSelector(newcolsinputid);
! 769: this.makeheaderinput = getFromSelector(makeheaderinputid);
! 770: this.classselect = getFromSelector(classselectid);
! 771: this.alignselect = getFromSelector(alignselectid);
! 772: this.widthinput = getFromSelector(widthinputid);
! 773: this.addtablebutton = getFromSelector(addtablebuttonid);
! 774: this.addrowbutton = getFromSelector(addrowbuttonid);
! 775: this.delrowbutton = getFromSelector(delrowbuttonid);
! 776: this.addcolbutton = getFromSelector(addcolbuttonid);
! 777: this.delcolbutton = getFromSelector(delcolbuttonid);
! 778: this.fixbutton = getFromSelector(fixbuttonid);
! 779: this.delbutton = getFromSelector(delbuttonid);
! 780: this.toolboxel = getFromSelector(toolboxid);
! 781: this.plainclass = plainclass;
! 782: this.activeclass = activeclass;
! 783:
! 784: this.initialize = function(tool, editor) {
! 785: /* attach the event handlers */
! 786: this.tool = tool;
! 787: this.editor = editor;
! 788: addEventHandler(this.addtablebutton, "click", this.addTable, this);
! 789: addEventHandler(this.addrowbutton, "click", this.tool.addTableRow, this.tool);
! 790: addEventHandler(this.delrowbutton, "click", this.tool.delTableRow, this.tool);
! 791: addEventHandler(this.addcolbutton, "click", this.tool.addTableColumn, this.tool);
! 792: addEventHandler(this.delcolbutton, "click", this.tool.delTableColumn, this.tool);
! 793: addEventHandler(this.fixbutton, "click", this.fixTable, this);
! 794: addEventHandler(this.delbutton, "click", this.tool.delTable, this);
! 795: addEventHandler(this.alignselect, "change", this.setColumnAlign, this);
! 796: addEventHandler(this.classselect, "change", this.setTableClass, this);
! 797: addEventHandler(this.widthinput, "change", this.setColumnWidths, this);
! 798: this.addtablediv.style.display = "block";
! 799: this.edittablediv.style.display = "none";
! 800: this.editor.logMessage('Table tool initialized');
! 801: };
! 802:
! 803: this.updateState = function(selNode) {
! 804: /* update the state (add/edit) and update the pulldowns (if required) */
! 805: var table = this.editor.getNearestParentOfType(selNode, 'table');
! 806: if (table) {
! 807: this.addtablediv.style.display = "none";
! 808: this.edittablediv.style.display = "block";
! 809: var td = this.editor.getNearestParentOfType(selNode, 'td');
! 810: if (!td) {
! 811: td = this.editor.getNearestParentOfType(selNode, 'th');
! 812: this.widthinput.value = '';
! 813: } else {
! 814: this.widthinput.value = this.tool.getColumnWidths(table);
! 815: };
! 816: if (td) {
! 817: var align = td.getAttribute('align');
! 818: if (this.editor.config.use_css) {
! 819: align = td.style.textAlign;
! 820: };
! 821: selectSelectItem(this.alignselect, align);
! 822: };
! 823: selectSelectItem(this.classselect, table.className);
! 824: if (this.toolboxel) {
! 825: this.toolboxel.className = this.activeclass;
! 826: };
! 827: } else {
! 828: this.edittablediv.style.display = "none";
! 829: this.addtablediv.style.display = "block";
! 830: this.alignselect.selectedIndex = 0;
! 831: this.classselect.selectedIndex = 0;
! 832: if (this.toolboxel) {
! 833: this.toolboxel.className = this.plainclass;
! 834: };
! 835: };
! 836: };
! 837:
! 838: this.addTable = function() {
! 839: /* add a Silvs specific table, with an (optional) header with colspan */
! 840: var rows = parseInt(this.newrowsinput.value);
! 841: var cols = parseInt(this.newcolsinput.value);
! 842: var makeHeader = this.makeheaderinput.checked;
! 843: var classchooser = getFromSelector("kupu-table-classchooser-add");
! 844: var tableclass = this.classselect.options[this.classselect.selectedIndex].value;
! 845: this.tool.createTable(rows, cols, makeHeader, tableclass);
! 846: };
! 847:
! 848: this.setTableClass = function() {
! 849: var cls = this.classselect.options[this.classselect.selectedIndex].value;
! 850: this.tool.setTableClass(cls);
! 851: };
! 852:
! 853: this.setColumnWidths = function() {
! 854: var widths = this.widthinput.value;
! 855: this.tool.setColumnWidths(widths);
! 856: };
! 857:
! 858: this.fixTable = function(event) {
! 859: /* fix the table so it is Silva (and this tool) compliant */
! 860: // since this can be quite a nasty creature we can't just use the
! 861: // helper methods
! 862:
! 863: // first we create a new tbody element
! 864: var currnode = this.editor.getSelectedNode();
! 865: var table = this.editor.getNearestParentOfType(currnode, 'TABLE');
! 866: if (!table) {
! 867: this.editor.logMessage('Not inside a table!');
! 868: return;
! 869: };
! 870: var doc = this.editor.getInnerDocument();
! 871: var tbody = doc.createElement('tbody');
! 872:
! 873: var allowed_classes = new Array('plain', 'grid', 'list', 'listing', 'data');
! 874: if (!allowed_classes.contains(table.getAttribute('class'))) {
! 875: table.setAttribute('class', 'plain');
! 876: };
! 877:
! 878: table.setAttribute('cellpadding', '0');
! 879: table.setAttribute('cellspacing', '0');
! 880:
! 881: // now get all the rows of the table, the rows can either be
! 882: // direct descendants of the table or inside a 'tbody', 'thead'
! 883: // or 'tfoot' element
! 884: var rows = new Array();
! 885: var parents = new Array('thead', 'tbody', 'tfoot');
! 886: for (var i=0; i < table.childNodes.length; i++) {
! 887: var node = table.childNodes[i];
! 888: if (node.nodeName.toLowerCase() == 'tr') {
! 889: rows.push(node);
! 890: } else if (parents.contains(node.nodeName.toLowerCase())) {
! 891: for (var j=0; j < node.childNodes.length; j++) {
! 892: var inode = node.childNodes[j];
! 893: if (inode.nodeName.toLowerCase() == 'tr') {
! 894: rows.push(inode);
! 895: };
! 896: };
! 897: };
! 898: };
! 899:
! 900: // now find out how many cells our rows should have
! 901: var numcols = 0;
! 902: for (var i=0; i < rows.length; i++) {
! 903: var row = rows[i];
! 904: var currnumcols = 0;
! 905: for (var j=0; j < row.childNodes.length; j++) {
! 906: var node = row.childNodes[j];
! 907: if (node.nodeName.toLowerCase() == 'td' ||
! 908: node.nodeName.toLowerCase() == 'th') {
! 909: var colspan = 1;
! 910: if (node.getAttribute('colSpan')) {
! 911: colspan = parseInt(node.getAttribute('colSpan'));
! 912: };
! 913: currnumcols += colspan;
! 914: };
! 915: };
! 916: if (currnumcols > numcols) {
! 917: numcols = currnumcols;
! 918: };
! 919: };
! 920:
! 921: // now walk through all rows to clean them up
! 922: for (var i=0; i < rows.length; i++) {
! 923: var row = rows[i];
! 924: var newrow = doc.createElement('tr');
! 925: var currcolnum = 0;
! 926: var inhead = -1;
! 927: while (row.childNodes.length > 0) {
! 928: var node = row.childNodes[0];
! 929: if (node.nodeName.toLowerCase() == 'td') {
! 930: if (inhead == -1) {
! 931: inhead = 0;
! 932: node.setAttribute('colSpan', '1');
! 933: };
! 934: } else if (node.nodeName.toLowerCase() == 'th') {
! 935: if (inhead == -1) {
! 936: inhead = 1;
! 937: newrow.appendChild(node);
! 938: node.setAttribute('colSpan', '1');
! 939: node.setAttribute('rowSpan', '1');
! 940: continue;
! 941: } else if (inhead == 0) {
! 942: var td = doc.createElement('td');
! 943: while (node.childNodes.length) {
! 944: td.appendChild(node.childNodes[0]);
! 945: };
! 946: row.removeChild(node);
! 947: node = td;
! 948: };
! 949: } else {
! 950: row.removeChild(node);
! 951: continue;
! 952: };
! 953: node.setAttribute('rowspan', '1');
! 954: if (inhead) {
! 955: while (node.childNodes.length) {
! 956: newrow.childNodes[0].appendChild(node.childNodes[0]);
! 957: };
! 958: var colspan = node.getAttribute('colSpan');
! 959: if (colspan) {
! 960: colspan = parseInt(colspan);
! 961: } else {
! 962: colspan = 1;
! 963: }
! 964: var current_colspan = parseInt(newrow.childNodes[0].getAttribute('colSpan'));
! 965: newrow.childNodes[0].setAttribute('colSpan', (current_colspan + colspan).toString());
! 966: row.removeChild(node);
! 967: } else {
! 968: node.setAttribute('colSpan', 1);
! 969: node.setAttribute('rowSpan', 1);
! 970: newrow.appendChild(node);
! 971: };
! 972: };
! 973: if (newrow.childNodes.length) {
! 974: tbody.appendChild(newrow);
! 975: };
! 976: };
! 977:
! 978: // now make sure all rows have the correct length
! 979: for (var i=0; i < tbody.childNodes.length; i++) {
! 980: var row = tbody.childNodes[i];
! 981: if (row.childNodes.length && row.childNodes[0].nodeName.toLowerCase() == 'th') {
! 982: row.childNodes[0].setAttribute('colSpan', numcols);
! 983: } else {
! 984: while (row.childNodes.length < numcols) {
! 985: var td = doc.createElement('td');
! 986: var nbsp = doc.createTextNode('\u00a0');
! 987: td.appendChild(nbsp);
! 988: row.appendChild(td);
! 989: };
! 990: };
! 991: };
! 992:
! 993: // now remove all the old stuff from the table and add the new tbody
! 994: var tlength = table.childNodes.length;
! 995: for (var i=0; i < tlength; i++) {
! 996: table.removeChild(table.childNodes[0]);
! 997: };
! 998: table.appendChild(tbody);
! 999:
! 1000: this.editor.getDocument().getWindow().focus();
! 1001:
! 1002: this.editor.logMessage('Table cleaned up');
! 1003: };
! 1004:
! 1005: this._fixAllTables = function() {
! 1006: /* fix all the tables in the document at once */
! 1007: return;
! 1008: var tables = this.editor.getInnerDocument().getElementsByTagName('table');
! 1009: for (var i=0; i < tables.length; i++) {
! 1010: this.fixTable(tables[i]);
! 1011: };
! 1012: };
! 1013: }
! 1014:
! 1015: SilvaTableToolBox.prototype = new TableToolBox;
! 1016:
! 1017: function SilvaIndexTool(inputid, addbuttonid, updatebuttonid, deletebuttonid, toolboxid, plainclass, activeclass) {
! 1018: /* a tool to manage index items (named anchors) for Silva */
! 1019: this.input = getFromSelector(inputid);
! 1020: this.addbutton = getFromSelector(addbuttonid);
! 1021: this.updatebutton = getFromSelector(updatebuttonid);
! 1022: this.deletebutton = getFromSelector(deletebuttonid);
! 1023: this.toolboxel = getFromSelector(toolboxid);
! 1024: this.plainclass = plainclass;
! 1025: this.activeclass = activeclass;
! 1026:
! 1027: this.initialize = function(editor) {
! 1028: /* attach the event handlers */
! 1029: this.editor = editor;
! 1030: addEventHandler(this.input, 'blur', this.updateIndex, this);
! 1031: addEventHandler(this.addbutton, 'click', this.addIndex, this);
! 1032: addEventHandler(this.updatebutton, 'click', this.updateIndex, this);
! 1033: addEventHandler(this.deletebutton, 'click', this.deleteIndex, this);
! 1034: if (this.editor.getBrowserName() == 'IE') {
! 1035: // need to catch some additional events for IE
! 1036: addEventHandler(editor.getInnerDocument(), 'keyup', this.handleKeyPressOnIndex, this);
! 1037: addEventHandler(editor.getInnerDocument(), 'keydown', this.handleKeyPressOnIndex, this);
! 1038: };
! 1039: addEventHandler(editor.getInnerDocument(), 'keypress', this.handleKeyPressOnIndex, this);
! 1040: this.updatebutton.style.display = 'none';
! 1041: this.deletebutton.style.display = 'none';
! 1042: };
! 1043:
! 1044: this.addIndex = function(event) {
! 1045: /* create an index */
! 1046: var name = this.input.value;
! 1047: var currnode = this.editor.getSelectedNode();
! 1048: var indexel = this.editor.getNearestParentOfType(currnode, 'A');
! 1049:
! 1050: if (indexel && indexel.getAttribute('href')) {
! 1051: this.editor.logMessage('Can not add index items in anchors');
! 1052: return;
! 1053: };
! 1054:
! 1055: if (!indexel) {
! 1056: var doc = this.editor.getDocument();
! 1057: if (!name) {
! 1058: var selection = this.editor.getSelection();
! 1059: var cloned = selection.cloneContents();
! 1060: var iterator = new NodeIterator(cloned);
! 1061: var name = '';
! 1062: var currnode = null;
! 1063: while (currnode = iterator.next()) {
! 1064: if (currnode.nodeValue) {
! 1065: name += currnode.nodeValue;
! 1066: };
! 1067: };
! 1068: if (name) {
! 1069: this.input.value = name;
! 1070: };
! 1071: };
! 1072: var docel = doc.getDocument();
! 1073: indexel = docel.createElement('a');
! 1074: var text = docel.createTextNode('[' + name + ']');
! 1075: indexel.appendChild(text);
! 1076: indexel = this.editor.insertNodeAtSelection(indexel, true);
! 1077: indexel.className = 'index';
! 1078: };
! 1079:
! 1080: indexel.setAttribute('name', name);
! 1081: var sel = this.editor.getSelection();
! 1082: sel.collapse(true);
! 1083: this.editor.logMessage('Index added');
! 1084: };
! 1085:
! 1086: this.updateIndex = function(event) {
! 1087: /* update an existing index */
! 1088: var currnode = this.editor.getSelectedNode();
! 1089: var indexel = this.editor.getNearestParentOfType(currnode, 'A');
! 1090: if (!indexel) {
! 1091: return;
! 1092: };
! 1093:
! 1094: if (indexel && indexel.getAttribute('href')) {
! 1095: this.editor.logMessage('Can not add an index element inside a link!');
! 1096: return;
! 1097: };
! 1098:
! 1099: var name = this.input.value;
! 1100: indexel.setAttribute('name', name);
! 1101: while (indexel.hasChildNodes()) {
! 1102: indexel.removeChild(indexel.firstChild);
! 1103: };
! 1104: var text = this.editor.getInnerDocument().createTextNode('[' + name + ']')
! 1105: indexel.appendChild(text);
! 1106: this.editor.logMessage('Index modified');
! 1107: };
! 1108:
! 1109: this.deleteIndex = function() {
! 1110: var selNode = this.editor.getSelectedNode();
! 1111: var a = this.editor.getNearestParentOfType(selNode, 'a');
! 1112: if (!a || a.getAttribute('href')) {
! 1113: this.editor.logMessage('Not inside an index element!');
! 1114: return;
! 1115: };
! 1116: a.parentNode.removeChild(a);
! 1117: this.editor.logMessage('Index element removed');
! 1118: };
! 1119:
! 1120: this.handleKeyPressOnIndex = function(event) {
! 1121: var selNode = this.editor.getSelectedNode();
! 1122: var a = this.editor.getNearestParentOfType(selNode, 'a');
! 1123: if (!a || a.getAttribute('href')) {
! 1124: return;
! 1125: };
! 1126: var keyCode = event.keyCode;
! 1127: if (keyCode == 8 || keyCode == 46) {
! 1128: a.parentNode.removeChild(a);
! 1129: } else if (keyCode == 9 || keyCode == 39) {
! 1130: var next = a.nextSibling;
! 1131: while (next && next.nodeName.toLowerCase() == 'br') {
! 1132: next = next.nextSibling;
! 1133: };
! 1134: if (!next) {
! 1135: var doc = this.editor.getInnerDocument();
! 1136: next = doc.createTextNode('\xa0');
! 1137: a.parentNode.appendChild(next);
! 1138: };
! 1139: var selection = this.editor.getSelection();
! 1140: // XXX I fear I'm working around bugs here... because of a bug in
! 1141: // selection.moveStart() I can't use the same codepath in IE as in Moz
! 1142: if (this.editor.getBrowserName() == 'IE') {
! 1143: selection.selectNodeContents(a);
! 1144: // XXX are we depending on a bug here? shouldn't we move the
! 1145: // selection one place to get out of the anchor? it works,
! 1146: // but seems wrong...
! 1147: selection.collapse(true);
! 1148: } else {
! 1149: selection.selectNodeContents(next);
! 1150: selection.collapse();
! 1151: var selection = this.editor.getSelection();
! 1152: };
! 1153: this.editor.updateState();
! 1154: };
! 1155: if (event.preventDefault) {
! 1156: event.preventDefault();
! 1157: } else {
! 1158: event.returnValue = false;
! 1159: };
! 1160: return false;
! 1161: };
! 1162:
! 1163: this.updateState = function(selNode) {
! 1164: var indexel = this.editor.getNearestParentOfType(selNode, 'A');
! 1165: if (indexel && !indexel.getAttribute('href')) {
! 1166: if (this.toolboxel) {
! 1167: this.toolboxel.className = this.activeclass;
! 1168: };
! 1169: this.input.value = indexel.getAttribute('name');
! 1170: this.addbutton.style.display = 'none';
! 1171: this.updatebutton.style.display = 'inline';
! 1172: this.deletebutton.style.display = 'inline';
! 1173: } else {
! 1174: if (this.toolboxel) {
! 1175: this.toolboxel.className = this.plainclass;
! 1176: };
! 1177: this.input.value = '';
! 1178: this.updatebutton.style.display = 'none';
! 1179: this.deletebutton.style.display = 'none';
! 1180: this.addbutton.style.display = 'inline';
! 1181: };
! 1182: };
! 1183:
! 1184: this.createContextMenuElements = function(selNode, event) {
! 1185: var indexel = this.editor.getNearestParentOfType(selNode, 'A');
! 1186: if (indexel && !indexel.getAttribute('href')) {
! 1187: return new Array(new ContextMenuElement('Delete index', this.deleteIndex, this));
! 1188: } else {
! 1189: return new Array();
! 1190: };
! 1191: };
! 1192: };
! 1193:
! 1194: SilvaIndexTool.prototype = new KupuTool;
! 1195:
! 1196: function SilvaTocTool(depthselectid, addbuttonid, delbuttonid, toolboxid, plainclass, activeclass) {
! 1197: this.depthselect = getFromSelector(depthselectid);
! 1198: this.addbutton = getFromSelector(addbuttonid);
! 1199: this.delbutton = getFromSelector(delbuttonid);
! 1200: this.toolbox = getFromSelector(toolboxid);
! 1201: this.plainclass = plainclass;
! 1202: this.activeclass = activeclass;
! 1203: this._inside_toc = false;
! 1204:
! 1205: this.initialize = function(editor) {
! 1206: this.editor = editor;
! 1207: addEventHandler(this.addbutton, 'click', this.addOrUpdateToc, this);
! 1208: addEventHandler(this.depthselect, 'change', this.updateToc, this);
! 1209: addEventHandler(this.delbutton, 'click', this.deleteToc, this);
! 1210: addEventHandler(editor.getInnerDocument(), 'keypress', this.handleKeyPressOnToc, this);
! 1211: if (this.editor.getBrowserName() == 'IE') {
! 1212: addEventHandler(editor.getInnerDocument(), 'keydown', this.handleKeyPressOnToc, this);
! 1213: addEventHandler(editor.getInnerDocument(), 'keyup', this.handleKeyPressOnToc, this);
! 1214: };
! 1215: };
! 1216:
! 1217: this.handleKeyPressOnToc = function(event) {
! 1218: if (!this._inside_toc) {
! 1219: return;
! 1220: };
! 1221: var keyCode = event.keyCode;
! 1222: if (keyCode == 8 || keyCode == 46) {
! 1223: var selNode = this.editor.getSelectedNode();
! 1224: var toc = this.getNearestToc(selNode);
! 1225: toc.parentNode.removeChild(toc);
! 1226: };
! 1227: if (keyCode == 13 || keyCode == 9 || keyCode == 39) {
! 1228: var selNode = this.editor.getSelectedNode();
! 1229: var toc = this.getNearestToc(selNode);
! 1230: var doc = this.editor.getInnerDocument();
! 1231: var selection = this.editor.getSelection();
! 1232: if (toc.nextSibling) {
! 1233: var sibling = toc.nextSibling;
! 1234: selection.selectNodeContents(toc.nextSibling);
! 1235: selection.collapse();
! 1236: } else {
! 1237: var parent = toc.parentNode;
! 1238: var p = doc.createElement('p');
! 1239: parent.appendChild(p);
! 1240: var text = doc.createTextNode('\xa0');
! 1241: p.appendChild(text);
! 1242: selection.selectNodeContents(p);
! 1243: };
! 1244: this._inside_toc = false;
! 1245: };
! 1246: if (event.preventDefault) {
! 1247: event.preventDefault();
! 1248: } else {
! 1249: event.returnValue = false;
! 1250: };
! 1251: };
! 1252:
! 1253: this.updateState = function(selNode, event) {
! 1254: var toc = this.getNearestToc(selNode);
! 1255: if (toc) {
! 1256: var depth = toc.getAttribute('toc_depth');
! 1257: selectSelectItem(this.depthselect, depth);
! 1258: this.addbutton.style.display = 'none';
! 1259: this.delbutton.style.display = 'inline';
! 1260: this._inside_toc = true;
! 1261: if (this.toolbox) {
! 1262: this.toolbox.className = this.activeclass;
! 1263: };
! 1264: } else {
! 1265: this.depthselect.selectedIndex = 0;
! 1266: this.delbutton.style.display = 'none';
! 1267: this.addbutton.style.display = 'inline';
! 1268: this._inside_toc = false;
! 1269: if (this.toolbox) {
! 1270: this.toolbox.className = this.plainclass;
! 1271: };
! 1272: };
! 1273: };
! 1274:
! 1275: this.addOrUpdateToc = function(event, depth) {
! 1276: var selNode = this.editor.getSelectedNode();
! 1277: var depth = depth ? depth : this.depthselect.options[this.depthselect.selectedIndex].value;
! 1278: var toc = this.getNearestToc(selNode);
! 1279: var doc = this.editor.getInnerDocument();
! 1280: var toctext = this.getTocText(depth);
! 1281: if (toc) {
! 1282: // there's already a toc, just update the depth
! 1283: toc.setAttribute('toc_depth', depth);
! 1284: while (toc.hasChildNodes()) {
! 1285: toc.removeChild(toc.firstChild);
! 1286: };
! 1287: toc.appendChild(doc.createTextNode(toctext));
! 1288: } else {
! 1289: // create a new toc
! 1290: var div = doc.createElement('div');
! 1291: div.setAttribute('toc_depth', depth);
! 1292: div.setAttribute('is_toc', 1);
! 1293: div.className = 'toc';
! 1294: var text = doc.createTextNode(toctext);
! 1295: div.appendChild(text);
! 1296: this.editor.insertNodeAtSelection(div);
! 1297: };
! 1298: };
! 1299:
! 1300: this.createDefaultToc = function() {
! 1301: // XXX nasty workaround, entering null as the event...
! 1302: this.addOrUpdateToc(null, '-1');
! 1303: };
! 1304:
! 1305: this.updateToc = function() {
! 1306: var selNode = this.editor.getSelectedNode();
! 1307: var toc = this.getNearestToc(selNode);
! 1308: if (toc) {
! 1309: var depth = this.depthselect.options[this.depthselect.selectedIndex].value;
! 1310: var toctext = this.getTocText(depth);
! 1311: toc.setAttribute('toc_depth', depth);
! 1312: while (toc.hasChildNodes()) {
! 1313: toc.removeChild(toc.firstChild);
! 1314: };
! 1315: doc = this.editor.getInnerDocument();
! 1316: toc.appendChild(doc.createTextNode(toctext));
! 1317: };
! 1318: };
! 1319:
! 1320: this.deleteToc = function() {
! 1321: var selNode = this.editor.getSelectedNode();
! 1322: var toc = this.getNearestToc(selNode);
! 1323: if (!toc) {
! 1324: this.editor.logMessage('Not inside a toc!', 1);
! 1325: return;
! 1326: };
! 1327: toc.parentNode.removeChild(toc);
! 1328: };
! 1329:
! 1330: this.getNearestToc = function(selNode) {
! 1331: var currnode = selNode;
! 1332: while (currnode) {
! 1333: if (currnode.nodeName.toLowerCase() == 'div' &&
! 1334: currnode.getAttribute('is_toc')) {
! 1335: return currnode;
! 1336: };
! 1337: currnode = currnode.parentNode;
! 1338: };
! 1339: return false;
! 1340: };
! 1341:
! 1342: this.createContextMenuElements = function(selNode, event) {
! 1343: /* create the 'Delete TOC' menu elements */
! 1344: var ret = new Array();
! 1345: if (this.getNearestToc(selNode)) {
! 1346: ret.push(new ContextMenuElement('Delete TOC', this.deleteToc, this));
! 1347: } else {
! 1348: ret.push(new ContextMenuElement('Create TOC', this.createDefaultToc, this));
! 1349: };
! 1350: return ret;
! 1351: };
! 1352:
! 1353: this.getTocText = function(depth) {
! 1354: var toctext = 'Table of Contents ';
! 1355: switch (depth) {
! 1356: case '-1':
! 1357: toctext += '(unlimited levels)';
! 1358: break;
! 1359: case '1':
! 1360: toctext += '(1 level)';
! 1361: break;
! 1362: default:
! 1363: toctext += '(' + depth + ' levels)';
! 1364: break;
! 1365: };
! 1366: return toctext;
! 1367: };
! 1368: };
! 1369:
! 1370: SilvaTocTool.prototype = new KupuTool;
! 1371:
! 1372: function SilvaAbbrTool(abbrradioid, acronymradioid, radiocontainerid, titleinputid,
! 1373: addbuttonid, updatebuttonid, delbuttonid,
! 1374: toolboxid, plainclass, activeclass) {
! 1375: /* tool to manage citation elements */
! 1376: this.abbrradio = getFromSelector(abbrradioid);
! 1377: this.acronymradio = getFromSelector(acronymradioid);
! 1378: this.radiocontainer = getFromSelector(radiocontainerid);
! 1379: this.titleinput = getFromSelector(titleinputid);
! 1380: this.addbutton = getFromSelector(addbuttonid);
! 1381: this.updatebutton = getFromSelector(updatebuttonid);
! 1382: this.delbutton = getFromSelector(delbuttonid);
! 1383: this.toolbox = getFromSelector(toolboxid);
! 1384: this.plainclass = plainclass;
! 1385: this.activeclass = activeclass;
! 1386:
! 1387: this.initialize = function(editor) {
! 1388: this.editor = editor;
! 1389: addEventHandler(this.addbutton, 'click', this.addElement, this);
! 1390: addEventHandler(this.updatebutton, 'click', this.updateElement, this);
! 1391: addEventHandler(this.delbutton, 'click', this.deleteElement, this);
! 1392:
! 1393: this.updatebutton.style.display = 'none';
! 1394: this.delbutton.style.display = 'none';
! 1395: };
! 1396:
! 1397: this.updateState = function(selNode, event) {
! 1398: var element = this.getNearestAbbrAcronym(selNode);
! 1399: if (element) {
! 1400: this.addbutton.style.display = 'none';
! 1401: this.updatebutton.style.display = 'inline';
! 1402: this.delbutton.style.display = 'inline';
! 1403: this.titleinput.value = element.getAttribute('title');
! 1404: this.radiocontainer.style.display = 'none';
! 1405: if (this.toolbox) {
! 1406: this.toolbox.className = this.activeclass;
! 1407: };
! 1408: } else {
! 1409: this.addbutton.style.display = 'inline';
! 1410: this.updatebutton.style.display = 'none';
! 1411: this.delbutton.style.display = 'none';
! 1412: this.titleinput.value = '';
! 1413: if (this.editor.getBrowserName() == 'IE' || this.radiocontainer.nodeName.toLowerCase() != 'tr') {
! 1414: this.radiocontainer.style.display = 'block';
! 1415: } else {
! 1416: this.radiocontainer.style.display = 'table-row';
! 1417: };
! 1418: if (this.toolbox) {
! 1419: this.toolbox.className = this.plainclass;
! 1420: };
! 1421: };
! 1422: };
! 1423:
! 1424: this.getNearestAbbrAcronym = function(selNode) {
! 1425: var current = selNode;
! 1426: while (current && current.nodeType != 9) {
! 1427: if (current.nodeType == 1) {
! 1428: var nodeName = current.nodeName.toLowerCase();
! 1429: if (nodeName == 'abbr' || nodeName == 'acronym') {
! 1430: return current;
! 1431: };
! 1432: };
! 1433: current = current.parentNode;
! 1434: };
! 1435: };
! 1436:
! 1437: this.addElement = function() {
! 1438: var type = this.abbrradio.checked ? 'abbr' : 'acronym';
! 1439: var doc = this.editor.getInnerDocument();
! 1440: var selNode = this.editor.getSelectedNode();
! 1441: if (this.getNearestAbbrAcronym(selNode)) {
! 1442: this.editor.logMessage('Can not nest abbr and acronym elements');
! 1443: return;
! 1444: };
! 1445: var element = doc.createElement(type);
! 1446: element.setAttribute('title', this.titleinput.value);
! 1447:
! 1448: var selection = this.editor.getSelection();
! 1449: var docfrag = selection.cloneContents();
! 1450: var placecursoratend = false;
! 1451: if (docfrag.hasChildNodes()) {
! 1452: for (var i=0; i < docfrag.childNodes.length; i++) {
! 1453: element.appendChild(docfrag.childNodes[i]);
! 1454: };
! 1455: placecursoratend = true;
! 1456: } else {
! 1457: var text = doc.createTextNode('\xa0');
! 1458: element.appendChild(text);
! 1459: };
! 1460: this.editor.insertNodeAtSelection(element, 1);
! 1461: var selection = this.editor.getSelection();
! 1462: selection.collapse(placecursoratend);
! 1463: this.editor.getDocument().getWindow().focus();
! 1464: var selNode = selection.getSelectedNode();
! 1465: this.editor.updateState(selNode);
! 1466: this.editor.logMessage('Element ' + type + ' added');
! 1467: };
! 1468:
! 1469: this.updateElement = function() {
! 1470: var selNode = this.editor.getSelectedNode();
! 1471: var element = this.getNearestAbbrAcronym(selNode);
! 1472: if (!element) {
! 1473: this.editor.logMessage('Not inside an abbr or acronym element!', 1);
! 1474: return;
! 1475: };
! 1476: var title = this.titleinput.value;
! 1477: element.setAttribute('title', title);
! 1478: this.editor.logMessage('Updated ' + element.nodeName.toLowerCase() + ' element');
! 1479: };
! 1480:
! 1481: this.deleteElement = function() {
! 1482: var selNode = this.editor.getSelectedNode();
! 1483: var element = this.getNearestAbbrAcronym(selNode);
! 1484: if (!element) {
! 1485: this.editor.logMessage('Not inside an abbr or acronym element!', 1);
! 1486: return;
! 1487: };
! 1488: element.parentNode.removeChild(element);
! 1489: this.editor.logMessage('Deleted ' + element.nodeName.toLowerCase() + ' deleted');
! 1490: };
! 1491: };
! 1492:
! 1493: SilvaAbbrTool.prototype = new KupuTool;
! 1494:
! 1495: function SilvaCitationTool(authorinputid, sourceinputid, addbuttonid, updatebuttonid, delbuttonid,
! 1496: toolboxid, plainclass, activeclass) {
! 1497: /* tool to manage citation elements */
! 1498: this.authorinput = getFromSelector(authorinputid);
! 1499: this.sourceinput = getFromSelector(sourceinputid);
! 1500: this.addbutton = getFromSelector(addbuttonid);
! 1501: this.updatebutton = getFromSelector(updatebuttonid);
! 1502: this.delbutton = getFromSelector(delbuttonid);
! 1503: this.toolbox = getFromSelector(toolboxid);
! 1504: this.plainclass = plainclass;
! 1505: this.activeclass = activeclass;
! 1506: this._inside_citation = false;
! 1507:
! 1508: this.initialize = function(editor) {
! 1509: this.editor = editor;
! 1510: addEventHandler(this.addbutton, 'click', this.addCitation, this);
! 1511: addEventHandler(this.updatebutton, 'click', this.updateCitation, this);
! 1512: addEventHandler(this.delbutton, 'click', this.deleteCitation, this);
! 1513: if (editor.getBrowserName() == 'IE') {
! 1514: addEventHandler(editor.getInnerDocument(), 'keyup', this.cancelEnterPress, this);
! 1515: addEventHandler(editor.getInnerDocument(), 'keydown', this.handleKeyPressOnCitation, this);
! 1516: } else {
! 1517: addEventHandler(editor.getInnerDocument(), 'keypress', this.handleKeyPressOnCitation, this);
! 1518: };
! 1519:
! 1520: this.updatebutton.style.display = 'none';
! 1521: this.delbutton.style.display = 'none';
! 1522: };
! 1523:
! 1524: this.cancelEnterPress = function(event) {
! 1525: if (!this._inside_citation || (event.keyCode != 13 && event.keyCode != 9)) {
! 1526: return;
! 1527: };
! 1528: if (event.preventDefault) {
! 1529: event.preventDefault();
! 1530: } else {
! 1531: event.returnValue = false;
! 1532: };
! 1533: };
! 1534:
! 1535: this.handleKeyPressOnCitation = function(event) {
! 1536: if (!this._inside_citation) {
! 1537: return;
! 1538: };
! 1539: var keyCode = event.keyCode;
! 1540: var citation = this.getNearestCitation(this.editor.getSelectedNode());
! 1541: var doc = this.editor.getInnerDocument();
! 1542: var selection = this.editor.getSelection();
! 1543: if (keyCode == 13 && this.editor.getBrowserName() == 'IE') {
! 1544: var br = doc.createElement('br');
! 1545: var currnode = selection.getSelectedNode();
! 1546: selection.replaceWithNode(br);
! 1547: selection.selectNodeContents(br);
! 1548: selection.collapse(true);
! 1549: event.returnValue = false;
! 1550: } else if (keyCode == 9) {
! 1551: var next = citation.nextSibling;
! 1552: if (!next) {
! 1553: next = doc.createElement('p');
! 1554: next.appendChild(doc.createTextNode('\xa0'));
! 1555: citation.parentNode.appendChild(next);
! 1556: };
! 1557: selection.selectNodeContents(next);
! 1558: selection.collapse();
! 1559: if (event.preventDefault) {
! 1560: event.preventDefault();
! 1561: };
! 1562: event.returnValue = false;
! 1563: this._inside_citation = false;
! 1564: };
! 1565: };
! 1566:
! 1567: this.updateState = function(selNode, event) {
! 1568: var citation = this.getNearestCitation(selNode);
! 1569: if (citation) {
! 1570: this.addbutton.style.display = 'none';
! 1571: this.updatebutton.style.display = 'inline';
! 1572: this.delbutton.style.display = 'inline';
! 1573: this.authorinput.value = citation.getAttribute('author');
! 1574: this.sourceinput.value = citation.getAttribute('source');
! 1575: this._inside_citation = true;
! 1576: if (this.toolbox) {
! 1577: this.toolbox.className = this.activeclass;
! 1578: };
! 1579: } else {
! 1580: this.addbutton.style.display = 'inline';
! 1581: this.updatebutton.style.display = 'none';
! 1582: this.delbutton.style.display = 'none';
! 1583: this.authorinput.value = '';
! 1584: this.sourceinput.value = '';
! 1585: this._inside_citation = false;
! 1586: if (this.toolbox) {
! 1587: this.toolbox.className = this.plainclass;
! 1588: };
! 1589: };
! 1590: };
! 1591:
! 1592: this.addCitation = function() {
! 1593: var selNode = this.editor.getSelectedNode();
! 1594: var citation = this.getNearestCitation(selNode);
! 1595: if (citation) {
! 1596: this.editor.logMessage('Nested citations are not allowed!');
! 1597: return;
! 1598: };
! 1599: var author = this.authorinput.value;
! 1600: var source = this.sourceinput.value;
! 1601: var doc = this.editor.getInnerDocument();
! 1602: var div = doc.createElement('div');
! 1603: div.className = 'citation';
! 1604: div.setAttribute('author', author);
! 1605: div.setAttribute('source', source);
! 1606: div.setAttribute('is_citation', '1');
! 1607: var selection = this.editor.getSelection();
! 1608: var docfrag = selection.cloneContents();
! 1609: var placecursoratend = false;
! 1610: if (docfrag.hasChildNodes()) {
! 1611: for (var i=0; i < docfrag.childNodes.length; i++) {
! 1612: div.appendChild(docfrag.childNodes[i]);
! 1613: };
! 1614: placecursoratend = true;
! 1615: } else {
! 1616: var text = doc.createTextNode('\xa0');
! 1617: div.appendChild(text);
! 1618: };
! 1619: this.editor.insertNodeAtSelection(div, 1);
! 1620: var selection = this.editor.getSelection();
! 1621: selection.collapse(placecursoratend);
! 1622: this.editor.getDocument().getWindow().focus();
! 1623: var selNode = selection.getSelectedNode();
! 1624: this.editor.updateState(selNode);
! 1625: };
! 1626:
! 1627: this.updateCitation = function() {
! 1628: var selNode = this.editor.getSelectedNode();
! 1629: var citation = this.getNearestCitation(selNode);
! 1630: if (!citation) {
! 1631: this.editor.logMessage('Not inside a citation element!');
! 1632: return;
! 1633: };
! 1634: citation.setAttribute('author', this.authorinput.value);
! 1635: citation.setAttribute('source', this.sourceinput.value);
! 1636: };
! 1637:
! 1638: this.deleteCitation = function() {
! 1639: var selNode = this.editor.getSelectedNode();
! 1640: var citation = this.getNearestCitation(selNode);
! 1641: if (!citation) {
! 1642: this.editor.logMessage('Not inside citation element!');
! 1643: return;
! 1644: };
! 1645: citation.parentNode.removeChild(citation);
! 1646: };
! 1647:
! 1648: this.getNearestCitation = function(selNode) {
! 1649: var currnode = selNode;
! 1650: while (currnode) {
! 1651: if (currnode.nodeName.toLowerCase() == 'div' &&
! 1652: currnode.getAttribute('is_citation')) {
! 1653: return currnode;
! 1654: };
! 1655: currnode = currnode.parentNode;
! 1656: };
! 1657: return false;
! 1658: };
! 1659:
! 1660: this.createContextMenuElements = function(selNode, event) {
! 1661: /* create the 'Delete citation' menu elements */
! 1662: var ret = new Array();
! 1663: if (this.getNearestCitation(selNode)) {
! 1664: ret.push(new ContextMenuElement('Delete cite', this.deleteCitation, this));
! 1665: };
! 1666: return ret;
! 1667: };
! 1668: };
! 1669:
! 1670: SilvaCitationTool.prototype = new KupuTool;
! 1671:
! 1672: function SilvaExternalSourceTool(idselectid, formcontainerid, addbuttonid, cancelbuttonid,
! 1673: updatebuttonid, delbuttonid, toolboxid, plainclass, activeclass) {
! 1674: this.idselect = getFromSelector(idselectid);
! 1675: this.formcontainer = getFromSelector(formcontainerid);
! 1676: this.addbutton = getFromSelector(addbuttonid);
! 1677: this.cancelbutton = getFromSelector(cancelbuttonid);
! 1678: this.updatebutton = getFromSelector(updatebuttonid);
! 1679: this.delbutton = getFromSelector(delbuttonid);
! 1680: this.toolbox = getFromSelector(toolboxid);
! 1681: this.plainclass = plainclass;
! 1682: this.activeclass = activeclass;
! 1683:
! 1684: this._editing = false;
! 1685: this._url = null;
! 1686: this._id = null;
! 1687: this._form = null;
! 1688: this._insideExternalSource = false;
! 1689:
! 1690: // store the base url, this will be prepended to the id to form the url to
! 1691: // get the codesource from (Zope's acquisition will make sure it ends up on
! 1692: // the right object)
! 1693: var urlparts = document.location.toString().split('/')
! 1694: this._baseurl = urlparts.slice(0, urlparts.length - 2).join('/');
! 1695:
! 1696: this.initialize = function(editor) {
! 1697: this.editor = editor;
! 1698: addEventHandler(this.addbutton, 'click', this.startExternalSourceAddEdit, this);
! 1699: addEventHandler(this.cancelbutton, 'click', this.resetTool, this);
! 1700: addEventHandler(this.updatebutton, 'click', this.startExternalSourceAddEdit, this);
! 1701: addEventHandler(this.delbutton, 'click', this.delExternalSource, this);
! 1702: addEventHandler(editor.getInnerDocument(), 'keypress', this.handleKeyPressOnExternalSource, this);
! 1703: if (this.editor.getBrowserName() == 'IE') {
! 1704: addEventHandler(editor.getInnerDocument(), 'keydown', this.handleKeyPressOnExternalSource, this);
! 1705: addEventHandler(editor.getInnerDocument(), 'keyup', this.handleKeyPressOnExternalSource, this);
! 1706: };
! 1707:
! 1708: // search for a special serialized identifier of the current document
! 1709: // which is used to send to the ExternalSource element when sending
! 1710: // requests so the ExternalSources know their context
! 1711: this.docref = null;
! 1712: var metas = this.editor.getInnerDocument().getElementsByTagName('meta');
! 1713: for (var i=0; i < metas.length; i++) {
! 1714: var meta = metas[i];
! 1715: if (meta.getAttribute('name') == 'docref') {
! 1716: this.docref = meta.getAttribute('content');
! 1717: };
! 1718: };
! 1719:
! 1720: this.updatebutton.style.display = 'none';
! 1721: this.delbutton.style.display = 'none';
! 1722: this.cancelbutton.style.display = 'none';
! 1723: };
! 1724:
! 1725: this.updateState = function(selNode) {
! 1726: var extsource = this.getNearestExternalSource(selNode);
! 1727: if (extsource) {
! 1728: this._insideExternalSource = true;
! 1729: selectSelectItem(this.idselect, extsource.getAttribute('source_id'));
! 1730: this.addbutton.style.display = 'none';
! 1731: this.cancelbutton.style.display = 'none';
! 1732: this.updatebutton.style.display = 'inline';
! 1733: this.delbutton.style.display = 'inline';
! 1734: this.startExternalSourceUpdate(extsource);
! 1735: if (this.toolbox) {
! 1736: this.toolbox.className = this.activeclass;
! 1737: };
! 1738: } else {
! 1739: this._insideExternalSource = false;
! 1740: this.resetTool();
! 1741: if (this.toolbox) {
! 1742: this.toolbox.className = this.plainclass;
! 1743: };
! 1744: };
! 1745: };
! 1746:
! 1747: this.handleKeyPressOnExternalSource = function(event) {
! 1748: if (!this._insideExternalSource) {
! 1749: return;
! 1750: };
! 1751: var keyCode = event.keyCode;
! 1752: var selNode = this.editor.getSelectedNode();
! 1753: var div = this.getNearestExternalSource(selNode);
! 1754: var doc = this.editor.getInnerDocument();
! 1755: if (keyCode == 13 || keyCode == 9 || keyCode == 39) {
! 1756: if (div.nextSibling) {
! 1757: var selection = this.editor.getSelection();
! 1758: selection.selectNodeContents(div.nextSibling);
! 1759: selection.collapse();
! 1760: } else {
! 1761: var p = doc.createElement('p');
! 1762: var nbsp = doc.createTextNode('\xa0');
! 1763: p.appendChild(nbsp);
! 1764: div.parentNode.appendChild(p);
! 1765: var selection = this.editor.getSelection();
! 1766: selection.selectNodeContents(p);
! 1767: selection.collapse();
! 1768: };
! 1769: this._insideExternalSource = false;
! 1770: } else if (keyCode == 8) {
! 1771: var selectnode = div.nextSibling;
! 1772: if (!selectnode) {
! 1773: selectnode = doc.createElement('p');
! 1774: selectnode.appendChild(doc.createTextNode('\xa0'));
! 1775: doc.appendChild(selectnode);
! 1776: };
! 1777: var selection = this.editor.getSelection();
! 1778: selection.selectNodeContents(selectnode);
! 1779: div.parentNode.removeChild(div);
! 1780: selection.collapse();
! 1781: };
! 1782: if (event.preventDefault) {
! 1783: event.preventDefault();
! 1784: } else {
! 1785: event.returnValue = false;
! 1786: };
! 1787: };
! 1788:
! 1789: this.getUrlAndContinue = function(id, handler) {
! 1790: if (id == this._id) {
! 1791: // return cached
! 1792: handler.call(this, this._url);
! 1793: return;
! 1794: };
! 1795: var request = new getXMLHttpRequest();
! 1796: request.open('GET',
! 1797: this._baseurl + '/edit/get_extsource_url?id=' + id, true);
! 1798: var callback = new ContextFixer(function() {
! 1799: if (request.readyState == 4) {
! 1800: var url = request.responseText;
! 1801: this._id = id;
! 1802: this._url = url;
! 1803: handler.call(this, url);
! 1804: };
! 1805: }, this);
! 1806: request.onreadystatechange = callback.execute;
! 1807: request.send('');
! 1808: };
! 1809:
! 1810: this.startExternalSourceAddEdit = function() {
! 1811: // get the appropriate form and display it
! 1812: if (!this._editing) {
! 1813: var id = this.idselect.options[this.idselect.selectedIndex].value;
! 1814: this.getUrlAndContinue(id, this._continueStartExternalSourceEdit);
! 1815: } else {
! 1816: // validate the data and take further actions
! 1817: var formdata = this._gatherFormData();
! 1818: var doc = window.document;
! 1819: var request = new XMLHttpRequest();
! 1820: request.open('POST', this._url + '/validate_form_to_request', true);
! 1821: var callback = new ContextFixer(this._addExternalSourceIfValidated, request, this);
! 1822: request.onreadystatechange = callback.execute;
! 1823: request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
! 1824: request.send(formdata);
! 1825: };
! 1826: };
! 1827:
! 1828: this._continueStartExternalSourceEdit = function(url) {
! 1829: url = url + '/get_rendered_form_for_editor?docref=' + this.docref;
! 1830: var request = new XMLHttpRequest();
! 1831: request.open('GET', url, true);
! 1832: var callback = new ContextFixer(this._addFormToTool, request, this);
! 1833: request.onreadystatechange = callback.execute;
! 1834: request.send(null);
! 1835: while (this.formcontainer.hasChildNodes()) {
! 1836: this.formcontainer.removeChild(this.formcontainer.firstChild);
! 1837: };
! 1838: var text = document.createTextNode('Loading...');
! 1839: this.formcontainer.appendChild(text);
! 1840: this.updatebutton.style.display = 'none';
! 1841: this.cancelbutton.style.display = 'inline';
! 1842: this.addbutton.style.display = 'inline';
! 1843: this._editing = true;
! 1844: };
! 1845:
! 1846: this.startExternalSourceUpdate = function(extsource) {
! 1847: var id = extsource.getAttribute('source_id');
! 1848: this.getUrlAndContinue(id, this._continueStartExternalSourceUpdate);
! 1849: };
! 1850:
! 1851: this._continueStartExternalSourceUpdate = function(url) {
! 1852: url = url + '/get_rendered_form_for_editor';
! 1853: var formdata = this._gatherFormDataFromElement();
! 1854: formdata += '&docref=' + this.docref;
! 1855: var request = new XMLHttpRequest();
! 1856: request.open('POST', url, true);
! 1857: request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
! 1858: var callback = new ContextFixer(this._addFormToTool, request, this);
! 1859: request.onreadystatechange = callback.execute;
! 1860: request.send(formdata);
! 1861: this._editing = true;
! 1862: while (this.formcontainer.hasChildNodes()) {
! 1863: this.formcontainer.removeChild(this.formcontainer.firstChild);
! 1864: };
! 1865: var text = document.createTextNode('Loading...');
! 1866: this.formcontainer.appendChild(text);
! 1867: };
! 1868:
! 1869: this._addFormToTool = function(object) {
! 1870: if (this.readyState == 4) {
! 1871: while (object.formcontainer.hasChildNodes()) {
! 1872: object.formcontainer.removeChild(object.formcontainer.firstChild);
! 1873: };
! 1874: // XXX Somehow appending the XML to the form using DOM doesn't
! 1875: // work correctly, it looks like the elements aren't HTMLElements
! 1876: // but XML elements, don't know how to fix now so I'll use string
! 1877: // insertion for now, needless to say it should be changed to DOM
! 1878: // manipulation asap...
! 1879: // XXX why is this.responseXML.documentElement.xml sometimes 'undefined'?
! 1880: object.formcontainer.innerHTML = this.responseText;
! 1881: object.idselect.style.display = 'none';
! 1882: // the formcontainer will contain a table with a form
! 1883: var form = null;
! 1884: var iterator = new NodeIterator(object.formcontainer);
! 1885: while (form == null) {
! 1886: var next = iterator.next();
! 1887: if (next.nodeName.toLowerCase() == 'form') {
! 1888: form = next;
! 1889: };
! 1890: };
! 1891: object._form = form;
! 1892: };
! 1893: };
! 1894:
! 1895: this._addExternalSourceIfValidated = function(object) {
! 1896: if (this.readyState == 4) {
! 1897: if (this.status == '200') {
! 1898: // success, add the external source element to the document
! 1899: var selNode = object.editor.getSelectedNode();
! 1900: var currsource = object.getNearestExternalSource(selNode);
! 1901: var doc = object.editor.getInnerDocument();
! 1902:
! 1903: var extsource = doc.createElement('div');
! 1904: extsource.setAttribute('source_id', object._id);
! 1905: var header = doc.createElement('h4');
! 1906: extsource.appendChild(header);
! 1907: extsource.className = 'externalsource';
! 1908: var metatype = 'Silva Code Source'; // a default just in case
! 1909: for (var i=0; i < this.responseXML.documentElement.childNodes.length; i++) {
! 1910: var child = this.responseXML.documentElement.childNodes[i];
! 1911: if (child.nodeName.toLowerCase() == 'parameter') {
! 1912: var key = child.getAttribute('key');
! 1913: var value = '';
! 1914: for (var j=0; j < child.childNodes.length; j++) {
! 1915: value += child.childNodes[j].nodeValue;
! 1916: };
! 1917: if (key == 'metatype') {
! 1918: metatype = value;
! 1919: continue;
! 1920: };
! 1921: extsource.setAttribute(key, value);
! 1922: var textel = doc.createTextNode('Key: ' + key + ', value: ' + value.toString());
! 1923: extsource.appendChild(textel);
! 1924: extsource.appendChild(doc.createElement('br'));
! 1925: };
! 1926: };
! 1927: var htext = doc.createTextNode(metatype + ' \xab' + object._id + '\xbb');
! 1928: header.insertBefore(htext, header.firstChild);
! 1929: extsource.appendChild(doc.createElement('br'));
! 1930: if (!currsource) {
! 1931: object.editor.insertNodeAtSelection(extsource);
! 1932: } else {
! 1933: currsource.parentNode.replaceChild(extsource, currsource);
! 1934: var selection = object.editor.getSelection();
! 1935: selection.selectNodeContents(extsource);
! 1936: selection.collapse(true);
! 1937: };
! 1938: object.resetTool();
! 1939: object.editor.updateState();
! 1940: } else if (this.status == '400') {
! 1941: // failure, provide some feedback and return to the form
! 1942: alert('Form could not be validated, error message: ' + this.responseText);
! 1943: } else {
! 1944: alert('POST failed with unhandled status ' + this.status);
! 1945: throw('Error handling POST, server returned ' + this.status + ' HTTP status code');
! 1946: };
! 1947: };
! 1948: };
! 1949:
! 1950: this.delExternalSource = function() {
! 1951: var selNode = this.editor.getSelectedNode();
! 1952: var source = this.getNearestExternalSource(selNode);
! 1953: if (!source) {
! 1954: this.editor.logMessage('Not inside external source!', 1);
! 1955: return;
! 1956: };
! 1957: var nextsibling = source.nextSibling;
! 1958: source.parentNode.removeChild(source);
! 1959: if (nextsibling) {
! 1960: var selection = this.editor.getSelection();
! 1961: selection.selectNodeContents(nextsibling);
! 1962: selection.collapse();
! 1963: };
! 1964: };
! 1965:
! 1966: this.resetTool = function() {
! 1967: while (this.formcontainer.hasChildNodes()) {
! 1968: this.formcontainer.removeChild(this.formcontainer.firstChild);
! 1969: };
! 1970: this.idselect.style.display = 'inline';
! 1971: this.addbutton.style.display = 'inline';
! 1972: this.cancelbutton.style.display = 'none';
! 1973: this.updatebutton.style.display = 'none';
! 1974: this.delbutton.style.display = 'none';
! 1975: //this.editor.updateState();
! 1976: this._editing = false;
! 1977: };
! 1978:
! 1979: this._gatherFormData = function() {
! 1980: /* walks through the form and creates a POST body */
! 1981: // XXX we may want to turn this into a helper function, since it's
! 1982: // quite useful outside of this object I reckon
! 1983: var form = this._form;
! 1984: if (!form) {
! 1985: this.editor.logMessage('Not currently editing');
! 1986: return;
! 1987: };
! 1988: // first place all data into a dict, convert to a string later on
! 1989: var data = {};
! 1990: for (var i=0; i < form.elements.length; i++) {
! 1991: var child = form.elements[i];
! 1992: var elname = child.nodeName.toLowerCase();
! 1993: if (elname == 'input') {
! 1994: var name = child.getAttribute('name');
! 1995: var type = child.getAttribute('type');
! 1996: if (!type || type == 'text' || type == 'hidden' || type == 'password') {
! 1997: data[name] = child.value;
! 1998: } else if (type == 'checkbox' || type == 'radio') {
! 1999: if (child.checked) {
! 2000: if (data[name]) {
! 2001: if (typeof data[name] == typeof('')) {
! 2002: var value = new Array(data[name]);
! 2003: value.push(child.value);
! 2004: data[name] = value;
! 2005: } else {
! 2006: data[name].push(child.value);
! 2007: };
! 2008: } else {
! 2009: data[name] = child.value;
! 2010: };
! 2011: };
! 2012: };
! 2013: } else if (elname == 'textarea') {
! 2014: data[child.getAttribute('name')] = child.value;
! 2015: } else if (elname == 'select') {
! 2016: var name = child.getAttribute('name');
! 2017: var multiple = child.getAttribute('multiple');
! 2018: if (!multiple) {
! 2019: data[name] = child.options[child.selectedIndex].value;
! 2020: } else {
! 2021: var value = new Array();
! 2022: for (var i=0; i < child.options.length; i++) {
! 2023: if (child.options[i].checked) {
! 2024: value.push(options[i].value);
! 2025: };
! 2026: if (value.length > 1) {
! 2027: data[name] = value;
! 2028: } else if (value.length) {
! 2029: data[name] = value[0];
! 2030: };
! 2031: };
! 2032: };
! 2033: };
! 2034: };
! 2035:
! 2036: // now we should turn it into a query string
! 2037: var ret = new Array();
! 2038: for (var key in data) {
! 2039: var value = data[key];
! 2040: // XXX does IE5 support encodeURIComponent?
! 2041: ret.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
! 2042: };
! 2043:
! 2044: return ret.join("&");
! 2045: };
! 2046:
! 2047: this._gatherFormDataFromElement = function() {
! 2048: var selNode = this.editor.getSelectedNode();
! 2049: var source = this.getNearestExternalSource(selNode);
! 2050: if (!source) {
! 2051: return '';
! 2052: };
! 2053: var ret = new Array();
! 2054: for (var i=0; i < source.attributes.length; i++) {
! 2055: var attr = source.attributes[i];
! 2056: var name = attr.nodeName;
! 2057: var value = attr.nodeValue;
! 2058: if (name != 'class' && name != 'source_id' && name != 'id') {
! 2059: ret.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
! 2060: };
! 2061: };
! 2062: return ret.join('&');
! 2063: };
! 2064:
! 2065: this.getNearestExternalSource = function(selNode) {
! 2066:
! 2067: var currnode = selNode;
! 2068: while (currnode) {
! 2069: if (currnode.nodeName.toLowerCase() == 'div' && currnode.className == 'externalsource') {
! 2070: return currnode;
! 2071: };
! 2072: currnode = currnode.parentNode;
! 2073: };
! 2074: };
! 2075: };
! 2076:
! 2077: SilvaExternalSourceTool.prototype = new KupuTool;
! 2078:
! 2079: function SilvaKupuUI(textstyleselectid) {
! 2080: this.tsselect = getFromSelector(textstyleselectid);
! 2081:
! 2082: this.updateState = function(selNode) {
! 2083: /* set the text-style pulldown */
! 2084:
! 2085: // first get the nearest style
! 2086: var styles = {}; // use an object here so we can use the 'in' operator later on
! 2087: for (var i=0; i < this.tsselect.options.length; i++) {
! 2088: // XXX we should cache this
! 2089: styles[this.tsselect.options[i].value] = i;
! 2090: }
! 2091:
! 2092: // search the list of nodes like in the original one, break if we encounter a match,
! 2093: // this method does some more than the original one since it can handle commands in
! 2094: // the form of '<style>|<classname>' next to the plain '<style>' commands
! 2095: var currnode = selNode;
! 2096: var index = -1;
! 2097: while (index==-1 && currnode) {
! 2098: var nodename = currnode.nodeName.toLowerCase();
! 2099: for (var style in styles) {
! 2100: if (style.indexOf('|') < 0) {
! 2101: // simple command
! 2102: if (nodename == style.toLowerCase() && !currnode.className) {
! 2103: index = styles[style];
! 2104: break;
! 2105: };
! 2106: } else {
! 2107: // command + classname
! 2108: var tuple = style.split('|');
! 2109: if (nodename == tuple[0].toLowerCase() && currnode.className == tuple[1]) {
! 2110: index = styles[style];
! 2111: break;
! 2112: };
! 2113: };
! 2114: };
! 2115: currnode = currnode.parentNode;
! 2116: }
! 2117: this.tsselect.selectedIndex = Math.max(index,0);
! 2118: };
! 2119:
! 2120: this.setTextStyle = function(style) {
! 2121: /* parse the argument into a type and classname part
! 2122:
! 2123: generate a block element accordingly
! 2124: */
! 2125: // XXX somehow this method always gets called twice... I would
! 2126: // really like to know why, but can't find it right now and don't
! 2127: // have time for a full investigation, so fiddle-fixed it this
! 2128: // way. Needless to say this needs some investigation at some point...
! 2129: if (this._cancel_update) {
! 2130: this._cancel_update = false;
! 2131: return;
! 2132: };
! 2133:
! 2134: var classname = "";
! 2135: var eltype = style;
! 2136: if (style.indexOf('|') > -1) {
! 2137: style = style.split('|');
! 2138: eltype = style[0];
! 2139: classname = style[1];
! 2140: };
! 2141:
! 2142: var command = eltype;
! 2143: // first create the element, then find it and set the classname
! 2144: if (this.editor.getBrowserName() == 'IE') {
! 2145: command = '<' + eltype + '>';
! 2146: };
! 2147: this.editor.getDocument().execCommand('formatblock', command);
! 2148:
! 2149: // now get a reference to the element just added
! 2150: var selNode = this.editor.getSelectedNode();
! 2151: var el = this.editor.getNearestParentOfType(selNode, eltype);
! 2152:
! 2153: // now set the classname
! 2154: if (classname) {
! 2155: el.className = classname;
! 2156: el.setAttribute('silva_type', classname);
! 2157: };
! 2158: this._cancel_update = true;
! 2159: this.editor.updateState();
! 2160: this.editor.getDocument().getWindow().focus();
! 2161: };
! 2162: };
! 2163:
! 2164: SilvaKupuUI.prototype = new KupuUI;
! 2165:
! 2166: function SilvaPropertyTool(tablerowid) {
! 2167: /* a simple tool to edit metadata fields
! 2168:
! 2169: the fields' contents are stored in Silva's metadata sets
! 2170: */
! 2171: this.tablerow = document.getElementById(tablerowid);
! 2172: this.table = this.tablerow.parentNode;
! 2173: while (!this.table.nodeName.toLowerCase() == 'table') {
! 2174: this.table = this.table.parentNode;
! 2175: };
! 2176: // remove current content from the fields
! 2177: var tds = this.tablerow.getElementsByTagName('td');
! 2178: for (var i=0; i < tds.length; i++) {
! 2179: while (tds[i].hasChildNodes()) {
! 2180: tds[i].removeChild(tds[i].childNodes[0]);
! 2181: };
! 2182: };
! 2183: };
! 2184:
! 2185: SilvaPropertyTool.prototype = new KupuTool;
! 2186:
! 2187: SilvaPropertyTool.prototype.initialize = function(editor) {
! 2188: this.editor = editor;
! 2189:
! 2190: // walk through all metadata fields and expose them to the user
! 2191: var metas = this.editor.getInnerDocument().getElementsByTagName('meta');
! 2192: for (var i=0; i < metas.length; i++) {
! 2193: var meta = metas[i];
! 2194: var name = meta.getAttribute('name');
! 2195: if (!name) {
! 2196: // http-equiv type
! 2197: continue;
! 2198: };
! 2199: var rowcopy = this.tablerow.cloneNode(true);
! 2200: var tag = this.parseFormElIntoRow(meta, rowcopy);
! 2201: if (tag) {
! 2202: this.tablerow.parentNode.appendChild(tag);
! 2203: };
! 2204: };
! 2205: // throw away the original row: we don't need it anymore...
! 2206: this.tablerow.parentNode.removeChild(this.tablerow);
! 2207: };
! 2208:
! 2209: SilvaPropertyTool.prototype.parseFormElIntoRow = function(metatag, tablerow) {
! 2210: /* render a field in the properties tool according to a metadata tag
! 2211:
! 2212: returns some false value if the meta tag should not be editable
! 2213: */
! 2214: var scheme = metatag.getAttribute('scheme');
! 2215: if (!scheme || !(scheme in EDITABLE_METADATA)) {
! 2216: return;
! 2217: };
! 2218: var name = metatag.getAttribute('name');
! 2219: var namespace = metatag.getAttribute('scheme');
! 2220: var nametypes = EDITABLE_METADATA[scheme];
! 2221: var type = 'text';
! 2222: var mandatory = false;
! 2223: var namefound = false;
! 2224: var fieldtitle = '';
! 2225: for (var i=0; i < nametypes.length; i++) {
! 2226: var nametype = nametypes[i];
! 2227: var elname = nametype[0];
! 2228: var type = nametype[1];
! 2229: var mandatory = nametype[2];
! 2230: var fieldtitle = nametype[3];
! 2231: if (elname == name) {
! 2232: namefound = true;
! 2233: break;
! 2234: };
! 2235: };
! 2236: if (!namefound) {
! 2237: return;
! 2238: };
! 2239:
! 2240: var titlefield = document.createElement('span');
! 2241: var title = document.createTextNode(fieldtitle);
! 2242: titlefield.appendChild(title);
! 2243: tablerow.getElementsByTagName('td')[0].appendChild(titlefield);
! 2244: titlefield.className = 'metadata-field';
! 2245:
! 2246: var input = null;
! 2247: var value = metatag.getAttribute('content');
! 2248: var parentvalue = metatag.getAttribute('parentcontent');
! 2249: if (type == 'text') {
! 2250: input = document.createElement('input');
! 2251: input.value = value;
! 2252: input.setAttribute('type', 'text');
! 2253: } else if (type == 'textarea') {
! 2254: input = document.createElement('textarea');
! 2255: var content = document.createTextNode(value);
! 2256: input.appendChild(content);
! 2257: };
! 2258: input.setAttribute('name', name);
! 2259: input.setAttribute('namespace', namespace);
! 2260: input.className = 'metadata-input';
! 2261: if (mandatory) {
! 2262: input.setAttribute('mandatory', 'true');
! 2263: };
! 2264: var td = tablerow.getElementsByTagName('td')[1]
! 2265: td.appendChild(input);
! 2266: if (parentvalue && parentvalue != '') {
! 2267: td.appendChild(document.createElement('br'));
! 2268: td.appendChild(document.createTextNode('acquired value:'));
! 2269: td.appendChild(document.createElement('br'));
! 2270: td.appendChild(document.createTextNode(parentvalue));
! 2271: };
! 2272:
! 2273: return tablerow;
! 2274: };
! 2275:
! 2276: SilvaPropertyTool.prototype.beforeSave = function() {
! 2277: /* save the metadata to the document */
! 2278: var doc = this.editor.getInnerDocument();
! 2279: var inputs = this.table.getElementsByTagName('input');
! 2280: var textareas = this.table.getElementsByTagName('textarea');
! 2281: var errors = [];
! 2282: var okay = [];
! 2283: for (var i=0; i < inputs.length; i++) {
! 2284: var input = inputs[i];
! 2285: if (!input.getAttribute('type') == 'text' || !input.getAttribute('namespace')) {
! 2286: continue;
! 2287: };
! 2288: var name = input.getAttribute('name');
! 2289: var scheme = input.getAttribute('namespace');
! 2290: var value = input.value;
! 2291: if (input.getAttribute('mandatory') && value.strip() == '') {
! 2292: errors.push(name);
! 2293: continue;
! 2294: };
! 2295: okay.push([name, scheme, value]);
! 2296: };
! 2297: for (var i=0; i < textareas.length; i++) {
! 2298: var textarea = textareas[i];
! 2299: var name = textarea.getAttribute('name');
! 2300: var scheme = textarea.getAttribute('namespace');
! 2301: var value = textarea.value;
! 2302: if (textarea.getAttribute('mandatory') && value.strip() == '') {
! 2303: errors.push(name);
! 2304: continue;
! 2305: };
! 2306: okay.push([name, scheme, value]);
! 2307: };
! 2308: if (errors.length) {
! 2309: throw('Error: fields ' + errors.join(', ') + ' are required but not filled in');
! 2310: };
! 2311: for (var i=0; i < okay.length; i++) {
! 2312: this._addMetaTag(doc, okay[i][0], okay[i][1], okay[i][2]);
! 2313: };
! 2314: };
! 2315:
! 2316: SilvaPropertyTool.prototype._addMetaTag = function(doc, name, scheme, value, parentvalue) {
! 2317: var head = doc.getElementsByTagName('head')[0];
! 2318: if (!head) {
! 2319: throw('The editable document *must* have a <head> element!');
! 2320: };
! 2321: // first find and delete the old one
! 2322: // XXX if only we'd have XPath...
! 2323: var metas = doc.getElementsByTagName('meta');
! 2324: for (var i=0; i < metas.length; i++) {
! 2325: var meta = metas[i];
! 2326: if (meta.getAttribute('name') == name &&
! 2327: meta.getAttribute('scheme') == scheme) {
! 2328: meta.parentNode.removeChild(meta);
! 2329: };
! 2330: };
! 2331: var tag = doc.createElement('meta');
! 2332: tag.setAttribute('name', name);
! 2333: tag.setAttribute('scheme', scheme);
! 2334: tag.setAttribute('content', value);
! 2335:
! 2336: head.appendChild(tag);
! 2337: };
! 2338:
! 2339: function SilvaCharactersTool(charselectid) {
! 2340: /* a tool to add non-standard characters */
! 2341: this._charselect = document.getElementById(charselectid);
! 2342: };
! 2343:
! 2344: SilvaCharactersTool.prototype = new KupuTool;
! 2345:
! 2346: SilvaCharactersTool.prototype.initialize = function(editor) {
! 2347: this.editor = editor;
! 2348: addEventHandler(this._charselect, 'change', this.addCharacter, this);
! 2349: var chars = this.editor.config.nonstandard_chars.split(' ');
! 2350: for (var i=0; i < chars.length; i++) {
! 2351: var option = document.createElement('option');
! 2352: option.value = chars[i];
! 2353: var text = document.createTextNode(chars[i]);
! 2354: option.appendChild(text);
! 2355: this._charselect.appendChild(option);
! 2356: };
! 2357: };
! 2358:
! 2359: SilvaCharactersTool.prototype.addCharacter = function() {
! 2360: var select = this._charselect;
! 2361: var c = select.options[select.selectedIndex].value;
! 2362: if (!c.strip()) {
! 2363: return;
! 2364: };
! 2365: var selection = this.editor.getSelection();
! 2366: var textnode = this.editor.getInnerDocument().createTextNode(c);
! 2367: var span = this.editor.getInnerDocument().createElement('span');
! 2368: span.appendChild(textnode);
! 2369: selection.replaceWithNode(span);
! 2370: var selection = this.editor.getSelection();
! 2371: selection.selectNodeContents(span);
! 2372: selection.moveEnd(1);
! 2373: selection.collapse(true);
! 2374: this.editor.logMessage('Character ' + c + ' inserted');
! 2375: this.editor.getDocument().getWindow().focus();
! 2376: select.selectedIndex = 0;
! 2377: };
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>