Annotation of kupuMPIWG/common/kupubasetools.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: // table auskommentiert dirk wintergruen 2005-08-30
! 12: // $Id: kupubasetools.js 14575 2005-07-12 20:18:12Z duncan $
! 13:
! 14:
! 15: //----------------------------------------------------------------------------
! 16: //
! 17: // Toolboxes
! 18: //
! 19: // These are addons for Kupu, simple plugins that implement a certain
! 20: // interface to provide functionality and control view aspects.
! 21: //
! 22: //----------------------------------------------------------------------------
! 23:
! 24: //----------------------------------------------------------------------------
! 25: // Superclasses
! 26: //----------------------------------------------------------------------------
! 27:
! 28: function KupuTool() {
! 29: /* Superclass (or actually more of an interface) for tools
! 30:
! 31: Tools must implement at least an initialize method and an
! 32: updateState method, and can implement other methods to add
! 33: certain extra functionality (e.g. createContextMenuElements).
! 34: */
! 35:
! 36: this.toolboxes = {};
! 37:
! 38: // methods
! 39: this.initialize = function(editor) {
! 40: /* Initialize the tool.
! 41:
! 42: Obviously this can be overriden but it will do
! 43: for the most simple cases
! 44: */
! 45: this.editor = editor;
! 46: };
! 47:
! 48: this.registerToolBox = function(id, toolbox) {
! 49: /* register a ui box
! 50:
! 51: Note that this needs to be called *after* the tool has been
! 52: registered to the KupuEditor
! 53: */
! 54: this.toolboxes[id] = toolbox;
! 55: toolbox.initialize(this, this.editor);
! 56: };
! 57:
! 58: this.updateState = function(selNode, event) {
! 59: /* Is called when user moves cursor to other element
! 60:
! 61: Calls the updateState for all toolboxes and may want perform
! 62: some actions itself
! 63: */
! 64: for (id in this.toolboxes) {
! 65: this.toolboxes[id].updateState(selNode, event);
! 66: };
! 67: };
! 68:
! 69: this.enable = function() {
! 70: // Called when the tool is enabled after a form is dismissed.
! 71: }
! 72:
! 73: this.disable = function() {
! 74: // Called when the tool is disabled (e.g. for a modal form)
! 75: }
! 76: // private methods
! 77: addEventHandler = addEventHandler;
! 78:
! 79: this._selectSelectItem = function(select, item) {
! 80: this.editor.logMessage(_('Deprecation warning: KupuTool._selectSelectItem'));
! 81: };
! 82: this._fixTabIndex = function(element) {
! 83: var tabIndex = this.editor.getDocument().getEditable().tabIndex-1;
! 84: if (tabIndex && !element.tabIndex) {
! 85: element.tabIndex = tabIndex;
! 86: }
! 87: }
! 88: }
! 89:
! 90: function KupuToolBox() {
! 91: /* Superclass for a user-interface object that controls a tool */
! 92:
! 93: this.initialize = function(tool, editor) {
! 94: /* store a reference to the tool and the editor */
! 95: this.tool = tool;
! 96: this.editor = editor;
! 97: };
! 98:
! 99: this.updateState = function(selNode, event) {
! 100: /* update the toolbox according to the current iframe's situation */
! 101: };
! 102:
! 103: this._selectSelectItem = function(select, item) {
! 104: this.editor.logMessage(_('Deprecation warning: KupuToolBox._selectSelectItem'));
! 105: };
! 106: };
! 107:
! 108: function NoContextMenu(object) {
! 109: /* Decorator for a tool to suppress the context menu */
! 110: object.createContextMenuElements = function(selNode, event) {
! 111: return [];
! 112: }
! 113: return object;
! 114: }
! 115:
! 116: // Helper function for enabling/disabling tools
! 117: function KupuButtonDisable(button) {
! 118: button = button || this.button;
! 119: button.disabled = "disabled";
! 120: button.className += ' disabled';
! 121: }
! 122: function KupuButtonEnable(button) {
! 123: button = button || this.button;
! 124: button.disabled = "";
! 125: button.className = button.className.replace(/ *\bdisabled\b/g, '');
! 126: }
! 127:
! 128:
! 129: //----------------------------------------------------------------------------
! 130: // Implementations
! 131: //----------------------------------------------------------------------------
! 132:
! 133: function KupuButton(buttonid, commandfunc, tool) {
! 134: /* Base prototype for kupu button tools */
! 135: this.buttonid = buttonid;
! 136: this.button = getFromSelector(buttonid);
! 137: this.commandfunc = commandfunc;
! 138: this.tool = tool;
! 139:
! 140: this.initialize = function(editor) {
! 141: this.editor = editor;
! 142: this._fixTabIndex(this.button);
! 143: addEventHandler(this.button, 'click', this.execCommand, this);
! 144: };
! 145:
! 146: this.execCommand = function() {
! 147: /* exec this button's command */
! 148: this.commandfunc(this, this.editor, this.tool);
! 149: };
! 150:
! 151: this.updateState = function(selNode, event) {
! 152: /* override this in subclasses to determine whether a button should
! 153: look 'pressed in' or not
! 154: */
! 155: };
! 156: this.disable = KupuButtonDisable;
! 157: this.enable = KupuButtonEnable;
! 158: };
! 159:
! 160: KupuButton.prototype = new KupuTool;
! 161: function KupuStateButton(buttonid, commandfunc, checkfunc, offclass, onclass) {
! 162: /* A button that can have two states (e.g. pressed and
! 163: not-pressed) based on CSS classes */
! 164: this.buttonid = buttonid;
! 165: this.button = getFromSelector(buttonid);
! 166: this.commandfunc = commandfunc;
! 167: this.checkfunc = checkfunc;
! 168: this.offclass = offclass;
! 169: this.onclass = onclass;
! 170: this.pressed = false;
! 171:
! 172: this.execCommand = function() {
! 173: /* exec this button's command */
! 174: this.button.className = (this.pressed ? this.offclass : this.onclass);
! 175: this.pressed = !this.pressed;
! 176: this.editor.focusDocument();
! 177: this.commandfunc(this, this.editor);
! 178: };
! 179:
! 180: this.updateState = function(selNode, event) {
! 181: /* check if we need to be clicked or unclicked, and update accordingly
! 182:
! 183: if the state of the button should be changed, we set the class
! 184: */
! 185: var currclass = this.button.className;
! 186: var newclass = null;
! 187: if (this.checkfunc(selNode, this, this.editor, event)) {
! 188: newclass = this.onclass;
! 189: this.pressed = true;
! 190: } else {
! 191: newclass = this.offclass;
! 192: this.pressed = false;
! 193: };
! 194: if (currclass != newclass) {
! 195: this.button.className = newclass;
! 196: };
! 197: };
! 198: };
! 199:
! 200: KupuStateButton.prototype = new KupuButton;
! 201:
! 202: /* Same as the state button, but the focusDocument call is delayed.
! 203: * Mozilla&Firefox have a bug on windows which can cause a crash if you
! 204: * change CSS positioning styles on an element which has focus.
! 205: */
! 206: function KupuLateFocusStateButton(buttonid, commandfunc, checkfunc, offclass, onclass) {
! 207: KupuStateButton.apply(this, [buttonid, commandfunc, checkfunc, offclass, onclass]);
! 208: this.execCommand = function() {
! 209: /* exec this button's command */
! 210: this.button.className = (this.pressed ? this.offclass : this.onclass);
! 211: this.pressed = !this.pressed;
! 212: this.commandfunc(this, this.editor);
! 213: this.editor.focusDocument();
! 214: };
! 215: }
! 216: KupuLateFocusStateButton.prototype = new KupuStateButton;
! 217:
! 218: function KupuRemoveElementButton(buttonid, element_name, cssclass) {
! 219: /* A button specialized in removing elements in the current node
! 220: context. Typical usages include removing links, images, etc. */
! 221: this.button = getFromSelector(buttonid);
! 222: this.onclass = 'invisible';
! 223: this.offclass = cssclass;
! 224: this.pressed = false;
! 225:
! 226: this.commandfunc = function(button, editor) {
! 227: editor.removeNearestParentOfType(editor.getSelectedNode(), element_name);
! 228: };
! 229:
! 230: this.checkfunc = function(currnode, button, editor, event) {
! 231: var element = editor.getNearestParentOfType(currnode, element_name);
! 232: return (element ? false : true);
! 233: };
! 234: };
! 235:
! 236: KupuRemoveElementButton.prototype = new KupuStateButton;
! 237:
! 238: function KupuUI(textstyleselectid) {
! 239: /* View
! 240:
! 241: This is the main view, which controls most of the toolbar buttons.
! 242: Even though this is probably never going to be removed from the view,
! 243: it was easier to implement this as a plain tool (plugin) as well.
! 244: */
! 245:
! 246: // attributes
! 247: this.tsselect = getFromSelector(textstyleselectid);
! 248:
! 249: this.initialize = function(editor) {
! 250: /* initialize the ui like tools */
! 251: this.editor = editor;
! 252: this._fixTabIndex(this.tsselect);
! 253: this._selectevent = addEventHandler(this.tsselect, 'change', this.setTextStyleHandler, this);
! 254: };
! 255:
! 256: this.setTextStyleHandler = function(event) {
! 257: this.setTextStyle(this.tsselect.options[this.tsselect.selectedIndex].value);
! 258: };
! 259:
! 260: // event handlers
! 261: this.basicButtonHandler = function(action) {
! 262: /* event handler for basic actions (toolbar buttons) */
! 263: this.editor.execCommand(action);
! 264: this.editor.updateState();
! 265: };
! 266:
! 267: this.saveButtonHandler = function() {
! 268: /* handler for the save button */
! 269: this.editor.saveDocument();
! 270: };
! 271:
! 272: this.saveAndExitButtonHandler = function(redirect_url) {
! 273: /* save the document and, if successful, redirect */
! 274: this.editor.saveDocument(redirect_url);
! 275: };
! 276:
! 277: this.cutButtonHandler = function() {
! 278: try {
! 279: this.editor.execCommand('Cut');
! 280: } catch (e) {
! 281: if (this.editor.getBrowserName() == 'Mozilla') {
! 282: alert(_('Cutting from JavaScript is disabled on your Mozilla due to security settings. For more information, read http://www.mozilla.org/editor/midasdemo/securityprefs.html'));
! 283: } else {
! 284: throw e;
! 285: };
! 286: };
! 287: this.editor.updateState();
! 288: };
! 289:
! 290: this.copyButtonHandler = function() {
! 291: try {
! 292: this.editor.execCommand('Copy');
! 293: } catch (e) {
! 294: if (this.editor.getBrowserName() == 'Mozilla') {
! 295: alert(_('Copying from JavaScript is disabled on your Mozilla due to security settings. For more information, read http://www.mozilla.org/editor/midasdemo/securityprefs.html'));
! 296: } else {
! 297: throw e;
! 298: };
! 299: };
! 300: this.editor.updateState();
! 301: };
! 302:
! 303: this.pasteButtonHandler = function() {
! 304: try {
! 305: this.editor.execCommand('Paste');
! 306: } catch (e) {
! 307: if (this.editor.getBrowserName() == 'Mozilla') {
! 308: alert(_('Pasting from JavaScript is disabled on your Mozilla due to security settings. For more information, read http://www.mozilla.org/editor/midasdemo/securityprefs.html'));
! 309: } else {
! 310: throw e;
! 311: };
! 312: };
! 313: this.editor.updateState();
! 314: };
! 315:
! 316: this.setTextStyle = function(style) {
! 317: /* method for the text style pulldown
! 318:
! 319: parse the argument into a type and classname part if it contains
! 320: a pipe symbol (|), generate a block element
! 321: */
! 322: var classname = "";
! 323: var eltype = style;
! 324: if (style.indexOf('|') > -1) {
! 325: style = style.split('|');
! 326: eltype = style[0];
! 327: classname = style[1];
! 328: };
! 329:
! 330: var command = eltype;
! 331: // first create the element, then find it and set the classname
! 332: if (this.editor.getBrowserName() == 'IE') {
! 333: command = '<' + eltype + '>';
! 334: };
! 335: this.editor.getDocument().execCommand('formatblock', command);
! 336:
! 337: // now get a reference to the element just added
! 338: var selNode = this.editor.getSelectedNode();
! 339: var el = this.editor.getNearestParentOfType(selNode, eltype);
! 340:
! 341: // now set the classname
! 342: if (classname) {
! 343: el.className = classname;
! 344: };
! 345: this.editor.updateState();
! 346: };
! 347:
! 348: this.updateState = function(selNode) {
! 349: /* set the text-style pulldown */
! 350:
! 351: // first get the nearest style
! 352: var styles = {}; // use an object here so we can use the 'in' operator later on
! 353: for (var i=0; i < this.tsselect.options.length; i++) {
! 354: // XXX we should cache this
! 355: styles[this.tsselect.options[i].value.toUpperCase()] = i;
! 356: }
! 357:
! 358: var currnode = selNode;
! 359: var index = 0;
! 360: while (currnode) {
! 361: if (currnode.nodeName.toUpperCase() in styles) {
! 362: index = styles[currnode.nodeName.toUpperCase()];
! 363: break
! 364: }
! 365: currnode = currnode.parentNode;
! 366: }
! 367:
! 368: this.tsselect.selectedIndex = index;
! 369: };
! 370:
! 371: this.createContextMenuElements = function(selNode, event) {
! 372: var ret = new Array();
! 373: ret.push(new ContextMenuElement(_('Cut'),
! 374: this.cutButtonHandler, this));
! 375: ret.push(new ContextMenuElement(_('Copy'),
! 376: this.copyButtonHandler, this));
! 377: ret.push(new ContextMenuElement(_('Paste'),
! 378: this.pasteButtonHandler, this));
! 379: return ret;
! 380: };
! 381: this.disable = function() {
! 382: this.tsselect.disabled = "disabled";
! 383: }
! 384: this.enable = function() {
! 385: this.tsselect.disabled = "";
! 386: }
! 387: }
! 388:
! 389: KupuUI.prototype = new KupuTool;
! 390:
! 391: // function ColorchooserTool(fgcolorbuttonid, hlcolorbuttonid, colorchooserid) {
! 392: // /* the colorchooser */
! 393:
! 394: // this.fgcolorbutton = getFromSelector(fgcolorbuttonid);
! 395: // this.hlcolorbutton = getFromSelector(hlcolorbuttonid);
! 396: // this.ccwindow = getFromSelector(colorchooserid);
! 397: // this.command = null;
! 398:
! 399: // this.initialize = function(editor) {
! 400: // /* attach the event handlers */
! 401: // this.editor = editor;
! 402:
! 403: // this.createColorchooser(this.ccwindow);
! 404:
! 405: // addEventHandler(this.fgcolorbutton, "click", this.openFgColorChooser, this);
! 406: // addEventHandler(this.hlcolorbutton, "click", this.openHlColorChooser, this);
! 407: // addEventHandler(this.ccwindow, "click", this.chooseColor, this);
! 408:
! 409: // this.hide();
! 410:
! 411: // this.editor.logMessage(_('Colorchooser tool initialized'));
! 412: // };
! 413:
! 414: // this.updateState = function(selNode) {
! 415: // /* update state of the colorchooser */
! 416: // this.hide();
! 417: // };
! 418:
! 419: // this.openFgColorChooser = function() {
! 420: // /* event handler for opening the colorchooser */
! 421: // this.command = "forecolor";
! 422: // this.show();
! 423: // };
! 424:
! 425: // this.openHlColorChooser = function() {
! 426: // /* event handler for closing the colorchooser */
! 427: // if (this.editor.getBrowserName() == "IE") {
! 428: // this.command = "backcolor";
! 429: // } else {
! 430: // this.command = "hilitecolor";
! 431: // }
! 432: // this.show();
! 433: // };
! 434:
! 435: // this.chooseColor = function(event) {
! 436: // /* event handler for choosing the color */
! 437: // var target = _SARISSA_IS_MOZ ? event.target : event.srcElement;
! 438: // var cell = this.editor.getNearestParentOfType(target, 'td');
! 439: // this.editor.execCommand(this.command, cell.getAttribute('bgColor'));
! 440: // this.hide();
! 441:
! 442: // this.editor.logMessage(_('Color chosen'));
! 443: // };
! 444:
! 445: // this.show = function(command) {
! 446: // /* show the colorchooser */
! 447: // this.ccwindow.style.display = "block";
! 448: // };
! 449:
! 450: // this.hide = function() {
! 451: // /* hide the colorchooser */
! 452: // this.command = null;
! 453: // this.ccwindow.style.display = "none";
! 454: // };
! 455:
! 456: // this.createColorchooser = function(table) {
! 457: // /* create the colorchooser table */
! 458:
! 459: // var chunks = new Array('00', '33', '66', '99', 'CC', 'FF');
! 460: // table.setAttribute('id', 'kupu-colorchooser-table');
! 461: // table.style.borderWidth = '2px';
! 462: // table.style.borderStyle = 'solid';
! 463: // table.style.position = 'absolute';
! 464: // table.style.cursor = 'default';
! 465: // table.style.display = 'none';
! 466:
! 467: // var tbody = document.createElement('tbody');
! 468:
! 469: // for (var i=0; i < 6; i++) {
! 470: // var tr = document.createElement('tr');
! 471: // var r = chunks[i];
! 472: // for (var j=0; j < 6; j++) {
! 473: // var g = chunks[j];
! 474: // for (var k=0; k < 6; k++) {
! 475: // var b = chunks[k];
! 476: // var color = '#' + r + g + b;
! 477: // var td = document.createElement('td');
! 478: // td.setAttribute('bgColor', color);
! 479: // td.style.backgroundColor = color;
! 480: // td.style.borderWidth = '1px';
! 481: // td.style.borderStyle = 'solid';
! 482: // td.style.fontSize = '1px';
! 483: // td.style.width = '10px';
! 484: // td.style.height = '10px';
! 485: // var text = document.createTextNode('\u00a0');
! 486: // td.appendChild(text);
! 487: // tr.appendChild(td);
! 488: // }
! 489: // }
! 490: // tbody.appendChild(tr);
! 491: // }
! 492: // table.appendChild(tbody);
! 493:
! 494: // return table;
! 495: // };
! 496: // this.enable = function() {
! 497: // KupuButtonEnable(this.fgcolorbutton);
! 498: // KupuButtonEnable(this.hlcolorbutton);
! 499: // }
! 500: // this.disable = function() {
! 501: // KupuButtonDisable(this.fgcolorbutton);
! 502: // KupuButtonDisable(this.hlcolorbutton);
! 503: // }
! 504: // }
! 505:
! 506: // ColorchooserTool.prototype = new KupuTool;
! 507:
! 508: function PropertyTool(titlefieldid, descfieldid) {
! 509: /* The property tool */
! 510:
! 511: this.titlefield = getFromSelector(titlefieldid);
! 512: this.descfield = getFromSelector(descfieldid);
! 513:
! 514: this.initialize = function(editor) {
! 515: /* attach the event handlers and set the initial values */
! 516: this.editor = editor;
! 517: addEventHandler(this.titlefield, "change", this.updateProperties, this);
! 518: addEventHandler(this.descfield, "change", this.updateProperties, this);
! 519:
! 520: // set the fields
! 521: var heads = this.editor.getInnerDocument().getElementsByTagName('head');
! 522: if (!heads[0]) {
! 523: this.editor.logMessage(_('No head in document!'), 1);
! 524: } else {
! 525: var head = heads[0];
! 526: var titles = head.getElementsByTagName('title');
! 527: if (titles.length) {
! 528: this.titlefield.value = titles[0].text;
! 529: }
! 530: var metas = head.getElementsByTagName('meta');
! 531: if (metas.length) {
! 532: for (var i=0; i < metas.length; i++) {
! 533: var meta = metas[i];
! 534: if (meta.getAttribute('name') &&
! 535: meta.getAttribute('name').toLowerCase() ==
! 536: 'description') {
! 537: this.descfield.value = meta.getAttribute('content');
! 538: break;
! 539: }
! 540: }
! 541: }
! 542: }
! 543:
! 544: this.editor.logMessage(_('Property tool initialized'));
! 545: };
! 546:
! 547: this.updateProperties = function() {
! 548: /* event handler for updating the properties form */
! 549: var doc = this.editor.getInnerDocument();
! 550: var heads = doc.getElementsByTagName('HEAD');
! 551: if (!heads) {
! 552: this.editor.logMessage(_('No head in document!'), 1);
! 553: return;
! 554: }
! 555:
! 556: var head = heads[0];
! 557:
! 558: // set the title
! 559: var titles = head.getElementsByTagName('title');
! 560: if (!titles) {
! 561: var title = doc.createElement('title');
! 562: var text = doc.createTextNode(this.titlefield.value);
! 563: title.appendChild(text);
! 564: head.appendChild(title);
! 565: } else {
! 566: var title = titles[0];
! 567: // IE6 title has no children, and refuses appendChild.
! 568: // Delete and recreate the title.
! 569: if (title.childNodes.length == 0) {
! 570: title.removeNode(true);
! 571: title = doc.createElement('title');
! 572: title.innerText = this.titlefield.value;
! 573: head.appendChild(title);
! 574: } else {
! 575: title.childNodes[0].nodeValue = this.titlefield.value;
! 576: }
! 577: }
! 578: document.title = this.titlefield.value;
! 579:
! 580: // let's just fulfill the usecase, not think about more properties
! 581: // set the description
! 582: var metas = doc.getElementsByTagName('meta');
! 583: var descset = 0;
! 584: for (var i=0; i < metas.length; i++) {
! 585: var meta = metas[i];
! 586: if (meta.getAttribute('name') &&
! 587: meta.getAttribute('name').toLowerCase() == 'description') {
! 588: meta.setAttribute('content', this.descfield.value);
! 589: }
! 590: }
! 591:
! 592: if (!descset) {
! 593: var meta = doc.createElement('meta');
! 594: meta.setAttribute('name', 'description');
! 595: meta.setAttribute('content', this.descfield.value);
! 596: head.appendChild(meta);
! 597: }
! 598:
! 599: this.editor.logMessage(_('Properties modified'));
! 600: };
! 601: }
! 602:
! 603: PropertyTool.prototype = new KupuTool;
! 604:
! 605: function LinkTool() {
! 606: /* Add and update hyperlinks */
! 607:
! 608: this.initialize = function(editor) {
! 609: this.editor = editor;
! 610: this.editor.logMessage(_('Link tool initialized'));
! 611: };
! 612:
! 613: this.createLinkHandler = function(event) {
! 614: /* create a link according to a url entered in a popup */
! 615: var linkWindow = openPopup('kupupopups/link.html', 300, 200);
! 616: linkWindow.linktool = this;
! 617: linkWindow.focus();
! 618: };
! 619:
! 620: this.updateLink = function (linkel, url, type, name, target, title) {
! 621: if (type && type == 'anchor') {
! 622: linkel.removeAttribute('href');
! 623: linkel.setAttribute('name', name);
! 624: } else {
! 625: linkel.href = url;
! 626: if (linkel.innerHTML == "") {
! 627: var doc = this.editor.getInnerDocument();
! 628: linkel.appendChild(doc.createTextNode(title || url));
! 629: }
! 630: if (title) {
! 631: linkel.title = title;
! 632: } else {
! 633: linkel.removeAttribute('title');
! 634: }
! 635: if (target && target != '') {
! 636: linkel.setAttribute('target', target);
! 637: }
! 638: else {
! 639: linkel.removeAttribute('target');
! 640: };
! 641: linkel.style.color = this.linkcolor;
! 642: };
! 643: };
! 644:
! 645: this.formatSelectedLink = function(url, type, name, target, title) {
! 646: var currnode = this.editor.getSelectedNode();
! 647:
! 648: // selection inside link
! 649: var linkel = this.editor.getNearestParentOfType(currnode, 'A');
! 650: if (linkel) {
! 651: this.updateLink(linkel, url, type, name, target, title);
! 652: return true;
! 653: }
! 654:
! 655: if (currnode.nodeType!=1) return false;
! 656:
! 657: // selection contains links
! 658: var linkelements = currnode.getElementsByTagName('A');
! 659: var selection = this.editor.getSelection();
! 660: var containsLink = false;
! 661: for (var i = 0; i < linkelements.length; i++) {
! 662: linkel = linkelements[i];
! 663: if (selection.containsNode(linkel)) {
! 664: this.updateLink(linkel, url, type, name, target, title);
! 665: containsLink = true;
! 666: }
! 667: };
! 668: return containsLink;
! 669: }
! 670:
! 671: // Can create a link in the following circumstances:
! 672: // The selection is inside a link:
! 673: // just update the link attributes.
! 674: // The selection contains links:
! 675: // update the attributes of the contained links
! 676: // No links inside or outside the selection:
! 677: // create a link around the selection
! 678: // No selection:
! 679: // insert a link containing the title
! 680: //
! 681: // the order of the arguments is a bit odd here because of backward
! 682: // compatibility
! 683: this.createLink = function(url, type, name, target, title) {
! 684: if (!this.formatSelectedLink(url, type, name, target, title)) {
! 685: // No links inside or outside.
! 686: this.editor.execCommand("CreateLink", url);
! 687: if (!this.formatSelectedLink(url, type, name, target, title)) {
! 688: // Insert link with no text selected, insert the title
! 689: // or URI instead.
! 690: var doc = this.editor.getInnerDocument();
! 691: linkel = doc.createElement("a");
! 692: linkel.setAttribute('href', url);
! 693: linkel.setAttribute('class', 'generated');
! 694: this.editor.getSelection().replaceWithNode(linkel, true);
! 695: this.updateLink(linkel, url, type, name, target, title);
! 696: };
! 697: }
! 698: this.editor.logMessage(_('Link added'));
! 699: this.editor.updateState();
! 700: };
! 701:
! 702: this.deleteLink = function() {
! 703: /* delete the current link */
! 704: var currnode = this.editor.getSelectedNode();
! 705: var linkel = this.editor.getNearestParentOfType(currnode, 'a');
! 706: if (!linkel) {
! 707: this.editor.logMessage(_('Not inside link'));
! 708: return;
! 709: };
! 710: while (linkel.childNodes.length) {
! 711: linkel.parentNode.insertBefore(linkel.childNodes[0], linkel);
! 712: };
! 713: linkel.parentNode.removeChild(linkel);
! 714:
! 715: this.editor.logMessage(_('Link removed'));
! 716: this.editor.updateState();
! 717: };
! 718:
! 719: this.createContextMenuElements = function(selNode, event) {
! 720: /* create the 'Create link' or 'Remove link' menu elements */
! 721: var ret = new Array();
! 722: var link = this.editor.getNearestParentOfType(selNode, 'a');
! 723: if (link) {
! 724: ret.push(new ContextMenuElement(_('Delete link'), this.deleteLink, this));
! 725: } else {
! 726: ret.push(new ContextMenuElement(_('Create link'), this.createLinkHandler, this));
! 727: };
! 728: return ret;
! 729: };
! 730: }
! 731:
! 732: LinkTool.prototype = new KupuTool;
! 733:
! 734: function LinkToolBox(inputid, buttonid, toolboxid, plainclass, activeclass) {
! 735: /* create and edit links */
! 736:
! 737: this.input = getFromSelector(inputid);
! 738: this.button = getFromSelector(buttonid);
! 739: this.toolboxel = getFromSelector(toolboxid);
! 740: this.plainclass = plainclass;
! 741: this.activeclass = activeclass;
! 742:
! 743: this.initialize = function(tool, editor) {
! 744: /* attach the event handlers */
! 745: this.tool = tool;
! 746: this.editor = editor;
! 747: addEventHandler(this.input, "blur", this.updateLink, this);
! 748: addEventHandler(this.button, "click", this.addLink, this);
! 749: };
! 750:
! 751: this.updateState = function(selNode) {
! 752: /* if we're inside a link, update the input, else empty it */
! 753: var linkel = this.editor.getNearestParentOfType(selNode, 'a');
! 754: if (linkel) {
! 755: // check first before setting a class for backward compatibility
! 756: if (this.toolboxel) {
! 757: this.toolboxel.className = this.activeclass;
! 758: };
! 759: this.input.value = linkel.getAttribute('href');
! 760: } else {
! 761: // check first before setting a class for backward compatibility
! 762: if (this.toolboxel) {
! 763: this.toolboxel.className = this.plainclass;
! 764: };
! 765: this.input.value = '';
! 766: }
! 767: };
! 768:
! 769: this.addLink = function(event) {
! 770: /* add a link */
! 771: var url = this.input.value;
! 772: this.tool.createLink(url);
! 773: };
! 774:
! 775: this.updateLink = function() {
! 776: /* update the current link */
! 777: var currnode = this.editor.getSelectedNode();
! 778: var linkel = this.editor.getNearestParentOfType(currnode, 'A');
! 779: if (!linkel) {
! 780: return;
! 781: }
! 782:
! 783: var url = this.input.value;
! 784: linkel.setAttribute('href', url);
! 785:
! 786: this.editor.logMessage(_('Link modified'));
! 787: };
! 788: };
! 789:
! 790: LinkToolBox.prototype = new LinkToolBox;
! 791:
! 792: function ImageTool() {
! 793: /* Image tool to add images */
! 794:
! 795: this.initialize = function(editor) {
! 796: /* attach the event handlers */
! 797: this.editor = editor;
! 798: this.editor.logMessage(_('Image tool initialized'));
! 799: };
! 800:
! 801: this.createImageHandler = function(event) {
! 802: /* create an image according to a url entered in a popup */
! 803: var imageWindow = openPopup('kupupopups/image.html', 300, 200);
! 804: imageWindow.imagetool = this;
! 805: imageWindow.focus();
! 806: };
! 807:
! 808: this.createImage = function(url, alttext, imgclass) {
! 809: /* create an image */
! 810: var img = this.editor.getInnerDocument().createElement('img');
! 811: img.src = url;
! 812: img.removeAttribute('height');
! 813: img.removeAttribute('width');
! 814: if (alttext) {
! 815: img.alt = alttext;
! 816: };
! 817: if (imgclass) {
! 818: img.className = imgclass;
! 819: };
! 820: img = this.editor.insertNodeAtSelection(img, 1);
! 821: this.editor.logMessage(_('Image inserted'));
! 822: this.editor.updateState();
! 823: return img;
! 824: };
! 825:
! 826: this.setImageClass = function(imgclass) {
! 827: /* set the class of the selected image */
! 828: var currnode = this.editor.getSelectedNode();
! 829: var currimg = this.editor.getNearestParentOfType(currnode, 'IMG');
! 830: if (currimg) {
! 831: currimg.className = imgclass;
! 832: };
! 833: };
! 834:
! 835: this.createContextMenuElements = function(selNode, event) {
! 836: return new Array(new ContextMenuElement(_('Create image'), this.createImageHandler, this));
! 837: };
! 838: }
! 839:
! 840: ImageTool.prototype = new KupuTool;
! 841:
! 842: function ImageToolBox(inputfieldid, insertbuttonid, classselectid, toolboxid, plainclass, activeclass) {
! 843: /* toolbox for adding images */
! 844:
! 845: this.inputfield = getFromSelector(inputfieldid);
! 846: this.insertbutton = getFromSelector(insertbuttonid);
! 847: this.classselect = getFromSelector(classselectid);
! 848: this.toolboxel = getFromSelector(toolboxid);
! 849: this.plainclass = plainclass;
! 850: this.activeclass = activeclass;
! 851:
! 852: this.initialize = function(tool, editor) {
! 853: this.tool = tool;
! 854: this.editor = editor;
! 855: addEventHandler(this.classselect, "change", this.setImageClass, this);
! 856: addEventHandler(this.insertbutton, "click", this.addImage, this);
! 857: };
! 858:
! 859: this.updateState = function(selNode, event) {
! 860: /* update the state of the toolbox element */
! 861: var imageel = this.editor.getNearestParentOfType(selNode, 'img');
! 862: if (imageel) {
! 863: // check first before setting a class for backward compatibility
! 864: if (this.toolboxel) {
! 865: this.toolboxel.className = this.activeclass;
! 866: this.inputfield.value = imageel.getAttribute('src');
! 867: var imgclass = imageel.className ? imageel.className : 'image-inline';
! 868: selectSelectItem(this.classselect, imgclass);
! 869: };
! 870: } else {
! 871: if (this.toolboxel) {
! 872: this.toolboxel.className = this.plainclass;
! 873: };
! 874: };
! 875: };
! 876:
! 877: this.addImage = function() {
! 878: /* add an image */
! 879: var url = this.inputfield.value;
! 880: var sel_class = this.classselect.options[this.classselect.selectedIndex].value;
! 881: this.tool.createImage(url, null, sel_class);
! 882: this.editor.focusDocument();
! 883: };
! 884:
! 885: this.setImageClass = function() {
! 886: /* set the class for the current image */
! 887: var sel_class = this.classselect.options[this.classselect.selectedIndex].value;
! 888: this.tool.setImageClass(sel_class);
! 889: this.editor.focusDocument();
! 890: };
! 891: };
! 892:
! 893: ImageToolBox.prototype = new KupuToolBox;
! 894:
! 895: // function TableTool() {
! 896: // /* The table tool */
! 897:
! 898: // // XXX There are some awfully long methods in here!!
! 899: // this.createContextMenuElements = function(selNode, event) {
! 900: // var table = this.editor.getNearestParentOfType(selNode, 'table');
! 901: // if (!table) {
! 902: // ret = new Array();
! 903: // var el = new ContextMenuElement(_('Add table'), this.addPlainTable, this);
! 904: // ret.push(el);
! 905: // return ret;
! 906: // } else {
! 907: // var ret = new Array();
! 908: // ret.push(new ContextMenuElement(_('Add row'), this.addTableRow, this));
! 909: // ret.push(new ContextMenuElement(_('Delete row'), this.delTableRow, this));
! 910: // ret.push(new ContextMenuElement(_('Add column'), this.addTableColumn, this));
! 911: // ret.push(new ContextMenuElement(_('Delete column'), this.delTableColumn, this));
! 912: // ret.push(new ContextMenuElement(_('Delete Table'), this.delTable, this));
! 913: // return ret;
! 914: // };
! 915: // };
! 916:
! 917: // this.addPlainTable = function() {
! 918: // /* event handler for the context menu */
! 919: // this.createTable(2, 3, 1, 'plain');
! 920: // };
! 921:
! 922: // this.createTable = function(rows, cols, makeHeader, tableclass) {
! 923: // /* add a table */
! 924: // if (rows < 1 || rows > 99 || cols < 1 || cols > 99) {
! 925: // this.editor.logMessage(_('Invalid table size'), 1);
! 926: // return;
! 927: // };
! 928:
! 929: // var doc = this.editor.getInnerDocument();
! 930:
! 931: // table = doc.createElement("table");
! 932: // table.className = tableclass;
! 933:
! 934: // // If the user wants a row of headings, make them
! 935: // if (makeHeader) {
! 936: // var tr = doc.createElement("tr");
! 937: // var thead = doc.createElement("thead");
! 938: // for (i=0; i < cols; i++) {
! 939: // var th = doc.createElement("th");
! 940: // th.appendChild(doc.createTextNode("Col " + i+1));
! 941: // tr.appendChild(th);
! 942: // }
! 943: // thead.appendChild(tr);
! 944: // table.appendChild(thead);
! 945: // }
! 946:
! 947: // tbody = doc.createElement("tbody");
! 948: // for (var i=0; i < rows; i++) {
! 949: // var tr = doc.createElement("tr");
! 950: // for (var j=0; j < cols; j++) {
! 951: // var td = doc.createElement("td");
! 952: // var content = doc.createTextNode('\u00a0');
! 953: // td.appendChild(content);
! 954: // tr.appendChild(td);
! 955: // }
! 956: // tbody.appendChild(tr);
! 957: // }
! 958: // table.appendChild(tbody);
! 959: // this.editor.insertNodeAtSelection(table);
! 960:
! 961: // this._setTableCellHandlers(table);
! 962:
! 963: // this.editor.logMessage(_('Table added'));
! 964: // this.editor.updateState();
! 965: // return table;
! 966: // };
! 967:
! 968: // this._setTableCellHandlers = function(table) {
! 969: // // make each cell select its full contents if it's clicked
! 970: // addEventHandler(table, 'click', this._selectContentIfEmpty, this);
! 971:
! 972: // var cells = table.getElementsByTagName('td');
! 973: // for (var i=0; i < cells.length; i++) {
! 974: // addEventHandler(cells[i], 'click', this._selectContentIfEmpty, this);
! 975: // };
! 976:
! 977: // // select the nbsp in the first cell
! 978: // var firstcell = cells[0];
! 979: // if (firstcell) {
! 980: // var children = firstcell.childNodes;
! 981: // if (children.length == 1 && children[0].nodeType == 3 &&
! 982: // children[0].nodeValue == '\xa0') {
! 983: // var selection = this.editor.getSelection();
! 984: // selection.selectNodeContents(firstcell);
! 985: // };
! 986: // };
! 987: // };
! 988:
! 989: // this._selectContentIfEmpty = function() {
! 990: // var selNode = this.editor.getSelectedNode();
! 991: // var cell = this.editor.getNearestParentOfType(selNode, 'td');
! 992: // if (!cell) {
! 993: // return;
! 994: // };
! 995: // var children = cell.childNodes;
! 996: // if (children.length == 1 && children[0].nodeType == 3 &&
! 997: // children[0].nodeValue == '\xa0') {
! 998: // var selection = this.editor.getSelection();
! 999: // selection.selectNodeContents(cell);
! 1000: // };
! 1001: // };
! 1002:
! 1003: // this.addTableRow = function() {
! 1004: // /* Find the current row and add a row after it */
! 1005: // var currnode = this.editor.getSelectedNode();
! 1006: // var currtbody = this.editor.getNearestParentOfType(currnode, "TBODY");
! 1007: // var bodytype = "tbody";
! 1008: // if (!currtbody) {
! 1009: // currtbody = this.editor.getNearestParentOfType(currnode, "THEAD");
! 1010: // bodytype = "thead";
! 1011: // }
! 1012: // var parentrow = this.editor.getNearestParentOfType(currnode, "TR");
! 1013: // var nextrow = parentrow.nextSibling;
! 1014:
! 1015: // // get the number of cells we should place
! 1016: // var colcount = 0;
! 1017: // for (var i=0; i < currtbody.childNodes.length; i++) {
! 1018: // var el = currtbody.childNodes[i];
! 1019: // if (el.nodeType != 1) {
! 1020: // continue;
! 1021: // }
! 1022: // if (el.nodeName.toLowerCase() == 'tr') {
! 1023: // var cols = 0;
! 1024: // for (var j=0; j < el.childNodes.length; j++) {
! 1025: // if (el.childNodes[j].nodeType == 1) {
! 1026: // cols++;
! 1027: // }
! 1028: // }
! 1029: // if (cols > colcount) {
! 1030: // colcount = cols;
! 1031: // }
! 1032: // }
! 1033: // }
! 1034:
! 1035: // var newrow = this.editor.getInnerDocument().createElement("TR");
! 1036:
! 1037: // for (var i = 0; i < colcount; i++) {
! 1038: // var newcell;
! 1039: // if (bodytype == 'tbody') {
! 1040: // newcell = this.editor.getInnerDocument().createElement("TD");
! 1041: // } else {
! 1042: // newcell = this.editor.getInnerDocument().createElement("TH");
! 1043: // }
! 1044: // var newcellvalue = this.editor.getInnerDocument().createTextNode("\u00a0");
! 1045: // newcell.appendChild(newcellvalue);
! 1046: // newrow.appendChild(newcell);
! 1047: // }
! 1048:
! 1049: // if (!nextrow) {
! 1050: // currtbody.appendChild(newrow);
! 1051: // } else {
! 1052: // currtbody.insertBefore(newrow, nextrow);
! 1053: // }
! 1054:
! 1055: // this.editor.focusDocument();
! 1056: // this.editor.logMessage(_('Table row added'));
! 1057: // };
! 1058:
! 1059: // this.delTableRow = function() {
! 1060: // /* Find the current row and delete it */
! 1061: // var currnode = this.editor.getSelectedNode();
! 1062: // var parentrow = this.editor.getNearestParentOfType(currnode, "TR");
! 1063: // if (!parentrow) {
! 1064: // this.editor.logMessage(_('No row to delete'), 1);
! 1065: // return;
! 1066: // }
! 1067:
! 1068: // // move selection aside
! 1069: // // XXX: doesn't work if parentrow is the only row of thead/tbody/tfoot
! 1070: // // XXX: doesn't preserve the colindex
! 1071: // var selection = this.editor.getSelection();
! 1072: // if (parentrow.nextSibling) {
! 1073: // selection.selectNodeContents(parentrow.nextSibling.firstChild);
! 1074: // } else if (parentrow.previousSibling) {
! 1075: // selection.selectNodeContents(parentrow.previousSibling.firstChild);
! 1076: // };
! 1077:
! 1078: // // remove the row
! 1079: // parentrow.parentNode.removeChild(parentrow);
! 1080:
! 1081: // this.editor.focusDocument();
! 1082: // this.editor.logMessage(_('Table row removed'));
! 1083: // };
! 1084:
! 1085: // this.addTableColumn = function() {
! 1086: // /* Add a new column after the current column */
! 1087: // var currnode = this.editor.getSelectedNode();
! 1088: // var currtd = this.editor.getNearestParentOfType(currnode, 'TD');
! 1089: // if (!currtd) {
! 1090: // currtd = this.editor.getNearestParentOfType(currnode, 'TH');
! 1091: // }
! 1092: // if (!currtd) {
! 1093: // this.editor.logMessage(_('No parentcolumn found!'), 1);
! 1094: // return;
! 1095: // }
! 1096: // var currtr = this.editor.getNearestParentOfType(currnode, 'TR');
! 1097: // var currtable = this.editor.getNearestParentOfType(currnode, 'TABLE');
! 1098:
! 1099: // // get the current index
! 1100: // var tdindex = this._getColIndex(currtd);
! 1101: // // XXX this looks like a debug message, remove
! 1102: // this.editor.logMessage(_('tdindex: ${tdindex}'));
! 1103:
! 1104: // // now add a column to all rows
! 1105: // // first the thead
! 1106: // var theads = currtable.getElementsByTagName('THEAD');
! 1107: // if (theads) {
! 1108: // for (var i=0; i < theads.length; i++) {
! 1109: // // let's assume table heads only have ths
! 1110: // var currthead = theads[i];
! 1111: // for (var j=0; j < currthead.childNodes.length; j++) {
! 1112: // var tr = currthead.childNodes[j];
! 1113: // if (tr.nodeType != 1) {
! 1114: // continue;
! 1115: // }
! 1116: // var currindex = 0;
! 1117: // for (var k=0; k < tr.childNodes.length; k++) {
! 1118: // var th = tr.childNodes[k];
! 1119: // if (th.nodeType != 1) {
! 1120: // continue;
! 1121: // }
! 1122: // if (currindex == tdindex) {
! 1123: // var doc = this.editor.getInnerDocument();
! 1124: // var newth = doc.createElement('th');
! 1125: // var text = doc.createTextNode('\u00a0');
! 1126: // newth.appendChild(text);
! 1127: // if (tr.childNodes.length == k+1) {
! 1128: // // the column will be on the end of the row
! 1129: // tr.appendChild(newth);
! 1130: // } else {
! 1131: // tr.insertBefore(newth, tr.childNodes[k + 1]);
! 1132: // }
! 1133: // break;
! 1134: // }
! 1135: // currindex++;
! 1136: // }
! 1137: // }
! 1138: // }
! 1139: // }
! 1140:
! 1141: // // then the tbody
! 1142: // var tbodies = currtable.getElementsByTagName('TBODY');
! 1143: // if (tbodies) {
! 1144: // for (var i=0; i < tbodies.length; i++) {
! 1145: // // let's assume table heads only have ths
! 1146: // var currtbody = tbodies[i];
! 1147: // for (var j=0; j < currtbody.childNodes.length; j++) {
! 1148: // var tr = currtbody.childNodes[j];
! 1149: // if (tr.nodeType != 1) {
! 1150: // continue;
! 1151: // }
! 1152: // var currindex = 0;
! 1153: // for (var k=0; k < tr.childNodes.length; k++) {
! 1154: // var td = tr.childNodes[k];
! 1155: // if (td.nodeType != 1) {
! 1156: // continue;
! 1157: // }
! 1158: // if (currindex == tdindex) {
! 1159: // var doc = this.editor.getInnerDocument();
! 1160: // var newtd = doc.createElement('td');
! 1161: // var text = doc.createTextNode('\u00a0');
! 1162: // newtd.appendChild(text);
! 1163: // if (tr.childNodes.length == k+1) {
! 1164: // // the column will be on the end of the row
! 1165: // tr.appendChild(newtd);
! 1166: // } else {
! 1167: // tr.insertBefore(newtd, tr.childNodes[k + 1]);
! 1168: // }
! 1169: // break;
! 1170: // }
! 1171: // currindex++;
! 1172: // }
! 1173: // }
! 1174: // }
! 1175: // }
! 1176: // this.editor.focusDocument();
! 1177: // this.editor.logMessage(_('Table column added'));
! 1178: // };
! 1179:
! 1180: // this.delTableColumn = function() {
! 1181: // /* remove a column */
! 1182: // var currnode = this.editor.getSelectedNode();
! 1183: // var currtd = this.editor.getNearestParentOfType(currnode, 'TD');
! 1184: // if (!currtd) {
! 1185: // currtd = this.editor.getNearestParentOfType(currnode, 'TH');
! 1186: // }
! 1187: // var currcolindex = this._getColIndex(currtd);
! 1188: // var currtable = this.editor.getNearestParentOfType(currnode, 'TABLE');
! 1189:
! 1190: // // move selection aside
! 1191: // var selection = this.editor.getSelection();
! 1192: // if (currtd.nextSibling) {
! 1193: // selection.selectNodeContents(currtd.nextSibling);
! 1194: // } else if (currtd.previousSibling) {
! 1195: // selection.selectNodeContents(currtd.previousSibling);
! 1196: // };
! 1197:
! 1198: // // remove the theaders
! 1199: // var heads = currtable.getElementsByTagName('THEAD');
! 1200: // if (heads.length) {
! 1201: // for (var i=0; i < heads.length; i++) {
! 1202: // var thead = heads[i];
! 1203: // for (var j=0; j < thead.childNodes.length; j++) {
! 1204: // var tr = thead.childNodes[j];
! 1205: // if (tr.nodeType != 1) {
! 1206: // continue;
! 1207: // }
! 1208: // var currindex = 0;
! 1209: // for (var k=0; k < tr.childNodes.length; k++) {
! 1210: // var th = tr.childNodes[k];
! 1211: // if (th.nodeType != 1) {
! 1212: // continue;
! 1213: // }
! 1214: // if (currindex == currcolindex) {
! 1215: // tr.removeChild(th);
! 1216: // break;
! 1217: // }
! 1218: // currindex++;
! 1219: // }
! 1220: // }
! 1221: // }
! 1222: // }
! 1223:
! 1224: // // now we remove the column field, a bit harder since we need to take
! 1225: // // colspan and rowspan into account XXX Not right, fix theads as well
! 1226: // var bodies = currtable.getElementsByTagName('TBODY');
! 1227: // for (var i=0; i < bodies.length; i++) {
! 1228: // var currtbody = bodies[i];
! 1229: // var relevant_rowspan = 0;
! 1230: // for (var j=0; j < currtbody.childNodes.length; j++) {
! 1231: // var tr = currtbody.childNodes[j];
! 1232: // if (tr.nodeType != 1) {
! 1233: // continue;
! 1234: // }
! 1235: // var currindex = 0
! 1236: // for (var k=0; k < tr.childNodes.length; k++) {
! 1237: // var cell = tr.childNodes[k];
! 1238: // if (cell.nodeType != 1) {
! 1239: // continue;
! 1240: // }
! 1241: // var colspan = cell.colSpan;
! 1242: // if (currindex == currcolindex) {
! 1243: // tr.removeChild(cell);
! 1244: // break;
! 1245: // }
! 1246: // currindex++;
! 1247: // }
! 1248: // }
! 1249: // }
! 1250: // this.editor.focusDocument();
! 1251: // this.editor.logMessage(_('Table column deleted'));
! 1252: // };
! 1253:
! 1254: // this.delTable = function() {
! 1255: // /* delete the current table */
! 1256: // var currnode = this.editor.getSelectedNode();
! 1257: // var table = this.editor.getNearestParentOfType(currnode, 'table');
! 1258: // if (!table) {
! 1259: // this.editor.logMessage(_('Not inside a table!'));
! 1260: // return;
! 1261: // };
! 1262: // table.parentNode.removeChild(table);
! 1263: // this.editor.logMessage(_('Table removed'));
! 1264: // };
! 1265:
! 1266: // this.setColumnAlign = function(newalign) {
! 1267: // /* change the alignment of a full column */
! 1268: // var currnode = this.editor.getSelectedNode();
! 1269: // var currtd = this.editor.getNearestParentOfType(currnode, "TD");
! 1270: // var bodytype = 'tbody';
! 1271: // if (!currtd) {
! 1272: // currtd = this.editor.getNearestParentOfType(currnode, "TH");
! 1273: // bodytype = 'thead';
! 1274: // }
! 1275: // var currcolindex = this._getColIndex(currtd);
! 1276: // var currtable = this.editor.getNearestParentOfType(currnode, "TABLE");
! 1277:
! 1278: // // unfortunately this is not enough to make the browsers display
! 1279: // // the align, we need to set it on individual cells as well and
! 1280: // // mind the rowspan...
! 1281: // for (var i=0; i < currtable.childNodes.length; i++) {
! 1282: // var currtbody = currtable.childNodes[i];
! 1283: // if (currtbody.nodeType != 1 ||
! 1284: // (currtbody.nodeName.toUpperCase() != "THEAD" &&
! 1285: // currtbody.nodeName.toUpperCase() != "TBODY")) {
! 1286: // continue;
! 1287: // }
! 1288: // for (var j=0; j < currtbody.childNodes.length; j++) {
! 1289: // var row = currtbody.childNodes[j];
! 1290: // if (row.nodeType != 1) {
! 1291: // continue;
! 1292: // }
! 1293: // var index = 0;
! 1294: // for (var k=0; k < row.childNodes.length; k++) {
! 1295: // var cell = row.childNodes[k];
! 1296: // if (cell.nodeType != 1) {
! 1297: // continue;
! 1298: // }
! 1299: // if (index == currcolindex) {
! 1300: // if (this.editor.config.use_css) {
! 1301: // cell.style.textAlign = newalign;
! 1302: // } else {
! 1303: // cell.setAttribute('align', newalign);
! 1304: // }
! 1305: // cell.className = 'align-' + newalign;
! 1306: // }
! 1307: // index++;
! 1308: // }
! 1309: // }
! 1310: // }
! 1311: // };
! 1312:
! 1313: // this.setTableClass = function(sel_class) {
! 1314: // /* set the class for the table */
! 1315: // var currnode = this.editor.getSelectedNode();
! 1316: // var currtable = this.editor.getNearestParentOfType(currnode, 'TABLE');
! 1317:
! 1318: // if (currtable) {
! 1319: // currtable.className = sel_class;
! 1320: // }
! 1321: // };
! 1322:
! 1323: // this._getColIndex = function(currcell) {
! 1324: // /* Given a node, return an integer for which column it is */
! 1325: // var prevsib = currcell.previousSibling;
! 1326: // var currcolindex = 0;
! 1327: // while (prevsib) {
! 1328: // if (prevsib.nodeType == 1 &&
! 1329: // (prevsib.tagName.toUpperCase() == "TD" ||
! 1330: // prevsib.tagName.toUpperCase() == "TH")) {
! 1331: // var colspan = prevsib.colSpan;
! 1332: // if (colspan) {
! 1333: // currcolindex += parseInt(colspan);
! 1334: // } else {
! 1335: // currcolindex++;
! 1336: // }
! 1337: // }
! 1338: // prevsib = prevsib.previousSibling;
! 1339: // if (currcolindex > 30) {
! 1340: // alert(_("Recursion detected when counting column position"));
! 1341: // return;
! 1342: // }
! 1343: // }
! 1344:
! 1345: // return currcolindex;
! 1346: // };
! 1347:
! 1348: // this._getColumnAlign = function(selNode) {
! 1349: // /* return the alignment setting of the current column */
! 1350: // var align;
! 1351: // var td = this.editor.getNearestParentOfType(selNode, 'td');
! 1352: // if (!td) {
! 1353: // td = this.editor.getNearestParentOfType(selNode, 'th');
! 1354: // };
! 1355: // if (td) {
! 1356: // align = td.getAttribute('align');
! 1357: // if (this.editor.config.use_css) {
! 1358: // align = td.style.textAlign;
! 1359: // };
! 1360: // };
! 1361: // return align;
! 1362: // };
! 1363:
! 1364: // this.fixTable = function(event) {
! 1365: // /* fix the table so it can be processed by Kupu */
! 1366: // // since this can be quite a nasty creature we can't just use the
! 1367: // // helper methods
! 1368:
! 1369: // // first we create a new tbody element
! 1370: // var currnode = this.editor.getSelectedNode();
! 1371: // var table = this.editor.getNearestParentOfType(currnode, 'TABLE');
! 1372: // if (!table) {
! 1373: // this.editor.logMessage(_('Not inside a table!'));
! 1374: // return;
! 1375: // };
! 1376: // this._fixTableHelper(table);
! 1377: // };
! 1378:
! 1379: // this._fixTableHelper = function(table) {
! 1380: // /* the code to actually fix tables */
! 1381: // var doc = this.editor.getInnerDocument();
! 1382: // var tbody = doc.createElement('tbody');
! 1383:
! 1384: // if (this.editor.config.table_classes) {
! 1385: // var allowed_classes = this.editor.config.table_classes['class'];
! 1386: // if (!allowed_classes.contains(table.className)) {
! 1387: // table.className = allowed_classes[0];
! 1388: // };
! 1389: // } else {
! 1390: // table.removeAttribute('class');
! 1391: // table.removeAttribute('className');
! 1392: // };
! 1393: // table.removeAttribute('border');
! 1394: // table.removeAttribute('cellpadding');
! 1395: // table.removeAttribute('cellPadding');
! 1396: // table.removeAttribute('cellspacing');
! 1397: // table.removeAttribute('cellSpacing');
! 1398:
! 1399: // // now get all the rows of the table, the rows can either be
! 1400: // // direct descendants of the table or inside a 'tbody', 'thead'
! 1401: // // or 'tfoot' element
! 1402: // var rows = new Array();
! 1403: // var parents = new Array('thead', 'tbody', 'tfoot');
! 1404: // for (var i=0; i < table.childNodes.length; i++) {
! 1405: // var node = table.childNodes[i];
! 1406: // if (node.nodeName.toLowerCase() == 'tr') {
! 1407: // rows.push(node);
! 1408: // } else if (parents.contains(node.nodeName.toLowerCase())) {
! 1409: // for (var j=0; j < node.childNodes.length; j++) {
! 1410: // var inode = node.childNodes[j];
! 1411: // if (inode.nodeName.toLowerCase() == 'tr') {
! 1412: // rows.push(inode);
! 1413: // };
! 1414: // };
! 1415: // };
! 1416: // };
! 1417:
! 1418: // // now find out how many cells our rows should have
! 1419: // var numcols = 0;
! 1420: // for (var i=0; i < rows.length; i++) {
! 1421: // var row = rows[i];
! 1422: // var currnumcols = 0;
! 1423: // for (var j=0; j < row.childNodes.length; j++) {
! 1424: // var node = row.childNodes[j];
! 1425: // if (node.nodeName.toLowerCase() == 'td' ||
! 1426: // node.nodeName.toLowerCase() == 'th') {
! 1427: // var colspan = 1;
! 1428: // if (node.getAttribute('colSpan')) {
! 1429: // colspan = parseInt(node.getAttribute('colSpan'));
! 1430: // };
! 1431: // currnumcols += colspan;
! 1432: // };
! 1433: // };
! 1434: // if (currnumcols > numcols) {
! 1435: // numcols = currnumcols;
! 1436: // };
! 1437: // };
! 1438:
! 1439: // // now walk through all rows to clean them up
! 1440: // for (var i=0; i < rows.length; i++) {
! 1441: // var row = rows[i];
! 1442: // var newrow = doc.createElement('tr');
! 1443: // var currcolnum = 0;
! 1444: // while (row.childNodes.length > 0) {
! 1445: // var node = row.childNodes[0];
! 1446: // if (node.nodeName.toLowerCase() != 'td' && node.nodeName.toLowerCase() != 'th') {
! 1447: // row.removeChild(node);
! 1448: // continue;
! 1449: // };
! 1450: // node.removeAttribute('colSpan');
! 1451: // node.removeAttribute('rowSpan');
! 1452: // newrow.appendChild(node);
! 1453: // };
! 1454: // if (newrow.childNodes.length) {
! 1455: // tbody.appendChild(newrow);
! 1456: // };
! 1457: // };
! 1458:
! 1459: // // now make sure all rows have the correct length
! 1460: // for (var i=0; i < tbody.childNodes.length; i++) {
! 1461: // var row = tbody.childNodes[i];
! 1462: // var cellname = row.childNodes[0].nodeName;
! 1463: // while (row.childNodes.length < numcols) {
! 1464: // var cell = doc.createElement(cellname);
! 1465: // var nbsp = doc.createTextNode('\u00a0');
! 1466: // cell.appendChild(nbsp);
! 1467: // row.appendChild(cell);
! 1468: // };
! 1469: // };
! 1470:
! 1471: // // now remove all the old stuff from the table and add the new tbody
! 1472: // var tlength = table.childNodes.length;
! 1473: // for (var i=0; i < tlength; i++) {
! 1474: // table.removeChild(table.childNodes[0]);
! 1475: // };
! 1476: // table.appendChild(tbody);
! 1477:
! 1478: // this.editor.focusDocument();
! 1479: // this.editor.logMessage(_('Table cleaned up'));
! 1480: // };
! 1481:
! 1482: // this.fixAllTables = function() {
! 1483: // /* fix all the tables in the document at once */
! 1484: // var tables = this.editor.getInnerDocument().getElementsByTagName('table');
! 1485: // for (var i=0; i < tables.length; i++) {
! 1486: // this._fixTableHelper(tables[i]);
! 1487: // };
! 1488: // };
! 1489: // };
! 1490:
! 1491: // TableTool.prototype = new KupuTool;
! 1492:
! 1493: // function TableToolBox(addtabledivid, edittabledivid, newrowsinputid,
! 1494: // newcolsinputid, makeheaderinputid, classselectid, alignselectid, addtablebuttonid,
! 1495: // addrowbuttonid, delrowbuttonid, addcolbuttonid, delcolbuttonid, fixbuttonid,
! 1496: // fixallbuttonid, toolboxid, plainclass, activeclass) {
! 1497: // /* The table tool */
! 1498:
! 1499: // // XXX There are some awfully long methods in here!!
! 1500:
! 1501:
! 1502: // // a lot of dependencies on html elements here, but most implementations
! 1503: // // will use them all I guess
! 1504: // this.addtablediv = getFromSelector(addtabledivid);
! 1505: // this.edittablediv = getFromSelector(edittabledivid);
! 1506: // this.newrowsinput = getFromSelector(newrowsinputid);
! 1507: // this.newcolsinput = getFromSelector(newcolsinputid);
! 1508: // this.makeheaderinput = getFromSelector(makeheaderinputid);
! 1509: // this.classselect = getFromSelector(classselectid);
! 1510: // this.alignselect = getFromSelector(alignselectid);
! 1511: // this.addtablebutton = getFromSelector(addtablebuttonid);
! 1512: // this.addrowbutton = getFromSelector(addrowbuttonid);
! 1513: // this.delrowbutton = getFromSelector(delrowbuttonid);
! 1514: // this.addcolbutton = getFromSelector(addcolbuttonid);
! 1515: // this.delcolbutton = getFromSelector(delcolbuttonid);
! 1516: // this.fixbutton = getFromSelector(fixbuttonid);
! 1517: // this.fixallbutton = getFromSelector(fixallbuttonid);
! 1518: // this.toolboxel = getFromSelector(toolboxid);
! 1519: // this.plainclass = plainclass;
! 1520: // this.activeclass = activeclass;
! 1521:
! 1522: // // register event handlers
! 1523: // this.initialize = function(tool, editor) {
! 1524: // /* attach the event handlers */
! 1525: // this.tool = tool;
! 1526: // this.editor = editor;
! 1527: // // build the select list of table classes if configured
! 1528: // if (this.editor.config.table_classes) {
! 1529: // var classes = this.editor.config.table_classes['class'];
! 1530: // while (this.classselect.hasChildNodes()) {
! 1531: // this.classselect.removeChild(this.classselect.firstChild);
! 1532: // };
! 1533: // for (var i=0; i < classes.length; i++) {
! 1534: // var classname = classes[i];
! 1535: // var option = document.createElement('option');
! 1536: // var content = document.createTextNode(classname);
! 1537: // option.appendChild(content);
! 1538: // option.setAttribute('value', classname);
! 1539: // this.classselect.appendChild(option);
! 1540: // };
! 1541: // };
! 1542: // addEventHandler(this.addtablebutton, "click", this.addTable, this);
! 1543: // addEventHandler(this.addrowbutton, "click", this.tool.addTableRow, this.tool);
! 1544: // addEventHandler(this.delrowbutton, "click", this.tool.delTableRow, this.tool);
! 1545: // addEventHandler(this.addcolbutton, "click", this.tool.addTableColumn, this.tool);
! 1546: // addEventHandler(this.delcolbutton, "click", this.tool.delTableColumn, this.tool);
! 1547: // addEventHandler(this.alignselect, "change", this.setColumnAlign, this);
! 1548: // addEventHandler(this.classselect, "change", this.setTableClass, this);
! 1549: // addEventHandler(this.fixbutton, "click", this.tool.fixTable, this.tool);
! 1550: // addEventHandler(this.fixallbutton, "click", this.tool.fixAllTables, this.tool);
! 1551: // this.addtablediv.style.display = "block";
! 1552: // this.edittablediv.style.display = "none";
! 1553: // this.editor.logMessage(_('Table tool initialized'));
! 1554: // };
! 1555:
! 1556: // this.updateState = function(selNode) {
! 1557: // /* update the state (add/edit) and update the pulldowns (if required) */
! 1558: // var table = this.editor.getNearestParentOfType(selNode, 'table');
! 1559: // if (table) {
! 1560: // this.addtablediv.style.display = "none";
! 1561: // this.edittablediv.style.display = "block";
! 1562:
! 1563: // var align = this.tool._getColumnAlign(selNode);
! 1564: // selectSelectItem(this.alignselect, align);
! 1565: // selectSelectItem(this.classselect, table.className);
! 1566: // if (this.toolboxel) {
! 1567: // this.toolboxel.className = this.activeclass;
! 1568: // };
! 1569: // } else {
! 1570: // this.edittablediv.style.display = "none";
! 1571: // this.addtablediv.style.display = "block";
! 1572: // this.alignselect.selectedIndex = 0;
! 1573: // this.classselect.selectedIndex = 0;
! 1574: // if (this.toolboxel) {
! 1575: // this.toolboxel.className = this.plainclass;
! 1576: // };
! 1577: // };
! 1578: // };
! 1579:
! 1580: // this.addTable = function() {
! 1581: // /* add a table */
! 1582: // var rows = this.newrowsinput.value;
! 1583: // var cols = this.newcolsinput.value;
! 1584: // var makeHeader = this.makeheaderinput.checked;
! 1585: // // XXX getFromSelector
! 1586: // var classchooser = getFromSelector("kupu-table-classchooser-add");
! 1587: // var tableclass = this.classselect.options[this.classselect.selectedIndex].value;
! 1588:
! 1589: // this.tool.createTable(rows, cols, makeHeader, tableclass);
! 1590: // };
! 1591:
! 1592: // this.setColumnAlign = function() {
! 1593: // /* set the alignment of the current column */
! 1594: // var newalign = this.alignselect.options[this.alignselect.selectedIndex].value;
! 1595: // this.tool.setColumnAlign(newalign);
! 1596: // };
! 1597:
! 1598: // this.setTableClass = function() {
! 1599: // /* set the class for the current table */
! 1600: // var sel_class = this.classselect.options[this.classselect.selectedIndex].value;
! 1601: // if (sel_class) {
! 1602: // this.tool.setTableClass(sel_class);
! 1603: // };
! 1604: // };
! 1605: // };
! 1606:
! 1607: // TableToolBox.prototype = new KupuToolBox;
! 1608:
! 1609: function ListTool(addulbuttonid, addolbuttonid, ulstyleselectid, olstyleselectid) {
! 1610: /* tool to set list styles */
! 1611:
! 1612: this.addulbutton = getFromSelector(addulbuttonid);
! 1613: this.addolbutton = getFromSelector(addolbuttonid);
! 1614: this.ulselect = getFromSelector(ulstyleselectid);
! 1615: this.olselect = getFromSelector(olstyleselectid);
! 1616:
! 1617: this.style_to_type = {'decimal': '1',
! 1618: 'lower-alpha': 'a',
! 1619: 'upper-alpha': 'A',
! 1620: 'lower-roman': 'i',
! 1621: 'upper-roman': 'I',
! 1622: 'disc': 'disc',
! 1623: 'square': 'square',
! 1624: 'circle': 'circle',
! 1625: 'none': 'none'
! 1626: };
! 1627: this.type_to_style = {'1': 'decimal',
! 1628: 'a': 'lower-alpha',
! 1629: 'A': 'upper-alpha',
! 1630: 'i': 'lower-roman',
! 1631: 'I': 'upper-roman',
! 1632: 'disc': 'disc',
! 1633: 'square': 'square',
! 1634: 'circle': 'circle',
! 1635: 'none': 'none'
! 1636: };
! 1637:
! 1638: this.initialize = function(editor) {
! 1639: /* attach event handlers */
! 1640: this.editor = editor;
! 1641: this._fixTabIndex(this.addulbutton);
! 1642: this._fixTabIndex(this.addolbutton);
! 1643: this._fixTabIndex(this.ulselect);
! 1644: this._fixTabIndex(this.olselect);
! 1645:
! 1646: addEventHandler(this.addulbutton, "click", this.addUnorderedList, this);
! 1647: addEventHandler(this.addolbutton, "click", this.addOrderedList, this);
! 1648: addEventHandler(this.ulselect, "change", this.setUnorderedListStyle, this);
! 1649: addEventHandler(this.olselect, "change", this.setOrderedListStyle, this);
! 1650: this.ulselect.style.display = "none";
! 1651: this.olselect.style.display = "none";
! 1652:
! 1653: this.editor.logMessage(_('List style tool initialized'));
! 1654: };
! 1655:
! 1656: this._handleStyles = function(currnode, onselect, offselect) {
! 1657: if (this.editor.config.use_css) {
! 1658: var currstyle = currnode.style.listStyleType;
! 1659: } else {
! 1660: var currstyle = this.type_to_style[currnode.getAttribute('type')];
! 1661: }
! 1662: selectSelectItem(onselect, currstyle);
! 1663: offselect.style.display = "none";
! 1664: onselect.style.display = "inline";
! 1665: offselect.selectedIndex = 0;
! 1666: };
! 1667:
! 1668: this.updateState = function(selNode) {
! 1669: /* update the visibility and selection of the list type pulldowns */
! 1670: // we're going to walk through the tree manually since we want to
! 1671: // check on 2 items at the same time
! 1672: for (var currnode=selNode; currnode; currnode=currnode.parentNode) {
! 1673: var tag = currnode.nodeName.toLowerCase();
! 1674: if (tag == 'ul') {
! 1675: this._handleStyles(currnode, this.ulselect, this.olselect);
! 1676: return;
! 1677: } else if (tag == 'ol') {
! 1678: this._handleStyles(currnode, this.olselect, this.ulselect);
! 1679: return;
! 1680: }
! 1681: }
! 1682: with(this.ulselect) {
! 1683: selectedIndex = 0;
! 1684: style.display = "none";
! 1685: };
! 1686: with(this.olselect) {
! 1687: selectedIndex = 0;
! 1688: style.display = "none";
! 1689: };
! 1690: };
! 1691:
! 1692: this.addList = function(command) {
! 1693: this.ulselect.style.display = "inline";
! 1694: this.olselect.style.display = "none";
! 1695: this.editor.execCommand(command);
! 1696: this.editor.focusDocument();
! 1697: };
! 1698: this.addUnorderedList = function() {
! 1699: /* add an unordered list */
! 1700: this.addList("insertunorderedlist");
! 1701: };
! 1702:
! 1703: this.addOrderedList = function() {
! 1704: /* add an ordered list */
! 1705: this.addList("insertorderedlist");
! 1706: };
! 1707:
! 1708: this.setListStyle = function(tag, select) {
! 1709: /* set the type of an ul */
! 1710: var currnode = this.editor.getSelectedNode();
! 1711: var l = this.editor.getNearestParentOfType(currnode, tag);
! 1712: var style = select.options[select.selectedIndex].value;
! 1713: if (this.editor.config.use_css) {
! 1714: l.style.listStyleType = style;
! 1715: } else {
! 1716: l.setAttribute('type', this.style_to_type[style]);
! 1717: }
! 1718: this.editor.focusDocument();
! 1719: this.editor.logMessage(_('List style changed'));
! 1720: };
! 1721:
! 1722: this.setUnorderedListStyle = function() {
! 1723: /* set the type of an ul */
! 1724: this.setListStyle('ul', this.ulselect);
! 1725: };
! 1726:
! 1727: this.setOrderedListStyle = function() {
! 1728: /* set the type of an ol */
! 1729: this.setListStyle('ol', this.olselect);
! 1730: };
! 1731:
! 1732: this.enable = function() {
! 1733: KupuButtonEnable(this.addulbutton);
! 1734: KupuButtonEnable(this.addolbutton);
! 1735: this.ulselect.disabled = "";
! 1736: this.olselect.disabled = "";
! 1737: }
! 1738: this.disable = function() {
! 1739: KupuButtonDisable(this.addulbutton);
! 1740: KupuButtonDisable(this.addolbutton);
! 1741: this.ulselect.disabled = "disabled";
! 1742: this.olselect.disabled = "disabled";
! 1743: }
! 1744: };
! 1745:
! 1746: ListTool.prototype = new KupuTool;
! 1747:
! 1748: function ShowPathTool() {
! 1749: /* shows the path to the current element in the status bar */
! 1750:
! 1751: this.updateState = function(selNode) {
! 1752: /* calculate and display the path */
! 1753: var path = '';
! 1754: var url = null; // for links we want to display the url too
! 1755: var currnode = selNode;
! 1756: while (currnode != null && currnode.nodeName != '#document') {
! 1757: if (currnode.nodeName.toLowerCase() == 'a') {
! 1758: url = currnode.getAttribute('href');
! 1759: };
! 1760: path = '/' + currnode.nodeName.toLowerCase() + path;
! 1761: currnode = currnode.parentNode;
! 1762: }
! 1763:
! 1764: try {
! 1765: window.status = url ?
! 1766: (path.toString() + ' - contains link to \'' +
! 1767: url.toString() + '\'') :
! 1768: path;
! 1769: } catch (e) {
! 1770: this.editor.logMessage(_('Could not set status bar message, ' +
! 1771: 'check your browser\'s security settings.'
! 1772: ), 1);
! 1773: };
! 1774: };
! 1775: };
! 1776:
! 1777: ShowPathTool.prototype = new KupuTool;
! 1778:
! 1779: function ViewSourceTool() {
! 1780: /* tool to provide a 'show source' context menu option */
! 1781: this.sourceWindow = null;
! 1782:
! 1783: this.viewSource = function() {
! 1784: /* open a window and write the current contents of the iframe to it */
! 1785: if (this.sourceWindow) {
! 1786: this.sourceWindow.close();
! 1787: };
! 1788: this.sourceWindow = window.open('#', 'sourceWindow');
! 1789:
! 1790: //var transform = this.editor._filterContent(this.editor.getInnerDocument().documentElement);
! 1791: //var contents = transform.xml;
! 1792: var contents = '<html>\n' + this.editor.getInnerDocument().documentElement.innerHTML + '\n</html>';
! 1793:
! 1794: var doc = this.sourceWindow.document;
! 1795: doc.write('\xa0');
! 1796: doc.close();
! 1797: var body = doc.getElementsByTagName("body")[0];
! 1798: while (body.hasChildNodes()) {
! 1799: body.removeChild(body.firstChild);
! 1800: };
! 1801: var pre = doc.createElement('pre');
! 1802: var textNode = doc.createTextNode(contents);
! 1803: body.appendChild(pre);
! 1804: pre.appendChild(textNode);
! 1805: };
! 1806:
! 1807: this.createContextMenuElements = function(selNode, event) {
! 1808: /* create the context menu element */
! 1809: return new Array(new ContextMenuElement(_('View source'), this.viewSource, this));
! 1810: };
! 1811: };
! 1812:
! 1813: ViewSourceTool.prototype = new KupuTool;
! 1814:
! 1815: function DefinitionListTool(dlbuttonid) {
! 1816: /* a tool for managing definition lists
! 1817:
! 1818: the dl elements should behave much like plain lists, and the keypress
! 1819: behaviour should be similar
! 1820: */
! 1821:
! 1822: this.dlbutton = getFromSelector(dlbuttonid);
! 1823:
! 1824: this.initialize = function(editor) {
! 1825: /* initialize the tool */
! 1826: this.editor = editor;
! 1827: this._fixTabIndex(this.dlbutton);
! 1828: addEventHandler(this.dlbutton, 'click', this.createDefinitionList, this);
! 1829: addEventHandler(editor.getInnerDocument(), 'keyup', this._keyDownHandler, this);
! 1830: addEventHandler(editor.getInnerDocument(), 'keypress', this._keyPressHandler, this);
! 1831: };
! 1832:
! 1833: // even though the following methods may seem view related, they belong
! 1834: // here, since they describe core functionality rather then view-specific
! 1835: // stuff
! 1836: this.handleEnterPress = function(selNode) {
! 1837: var dl = this.editor.getNearestParentOfType(selNode, 'dl');
! 1838: if (dl) {
! 1839: var dt = this.editor.getNearestParentOfType(selNode, 'dt');
! 1840: if (dt) {
! 1841: if (dt.childNodes.length == 1 && dt.childNodes[0].nodeValue == '\xa0') {
! 1842: this.escapeFromDefinitionList(dl, dt, selNode);
! 1843: return;
! 1844: };
! 1845:
! 1846: var selection = this.editor.getSelection();
! 1847: var startoffset = selection.startOffset();
! 1848: var endoffset = selection.endOffset();
! 1849: if (endoffset > startoffset) {
! 1850: // throw away any selected stuff
! 1851: selection.cutChunk(startoffset, endoffset);
! 1852: selection = this.editor.getSelection();
! 1853: startoffset = selection.startOffset();
! 1854: };
! 1855:
! 1856: var ellength = selection.getElementLength(selection.parentElement());
! 1857: if (startoffset >= ellength - 1) {
! 1858: // create a new element
! 1859: this.createDefinition(dl, dt);
! 1860: } else {
! 1861: var doc = this.editor.getInnerDocument();
! 1862: var newdt = selection.splitNodeAtSelection(dt);
! 1863: var newdd = doc.createElement('dd');
! 1864: while (newdt.hasChildNodes()) {
! 1865: if (newdt.firstChild != newdt.lastChild || newdt.firstChild.nodeName.toLowerCase() != 'br') {
! 1866: newdd.appendChild(newdt.firstChild);
! 1867: };
! 1868: };
! 1869: newdt.parentNode.replaceChild(newdd, newdt);
! 1870: selection.selectNodeContents(newdd);
! 1871: selection.collapse();
! 1872: };
! 1873: } else {
! 1874: var dd = this.editor.getNearestParentOfType(selNode, 'dd');
! 1875: if (!dd) {
! 1876: this.editor.logMessage(_('Not inside a definition list element!'));
! 1877: return;
! 1878: };
! 1879: if (dd.childNodes.length == 1 && dd.childNodes[0].nodeValue == '\xa0') {
! 1880: this.escapeFromDefinitionList(dl, dd, selNode);
! 1881: return;
! 1882: };
! 1883: var selection = this.editor.getSelection();
! 1884: var startoffset = selection.startOffset();
! 1885: var endoffset = selection.endOffset();
! 1886: if (endoffset > startoffset) {
! 1887: // throw away any selected stuff
! 1888: selection.cutChunk(startoffset, endoffset);
! 1889: selection = this.editor.getSelection();
! 1890: startoffset = selection.startOffset();
! 1891: };
! 1892: var ellength = selection.getElementLength(selection.parentElement());
! 1893: if (startoffset >= ellength - 1) {
! 1894: // create a new element
! 1895: this.createDefinitionTerm(dl, dd);
! 1896: } else {
! 1897: // add a break and continue in this element
! 1898: var br = this.editor.getInnerDocument().createElement('br');
! 1899: this.editor.insertNodeAtSelection(br, 1);
! 1900: //var selection = this.editor.getSelection();
! 1901: //selection.moveStart(1);
! 1902: selection.collapse(true);
! 1903: };
! 1904: };
! 1905: };
! 1906: };
! 1907:
! 1908: this.handleTabPress = function(selNode) {
! 1909: };
! 1910:
! 1911: this._keyDownHandler = function(event) {
! 1912: var selNode = this.editor.getSelectedNode();
! 1913: var dl = this.editor.getNearestParentOfType(selNode, 'dl');
! 1914: if (!dl) {
! 1915: return;
! 1916: };
! 1917: switch (event.keyCode) {
! 1918: case 13:
! 1919: if (event.preventDefault) {
! 1920: event.preventDefault();
! 1921: } else {
! 1922: event.returnValue = false;
! 1923: };
! 1924: break;
! 1925: };
! 1926: };
! 1927:
! 1928: this._keyPressHandler = function(event) {
! 1929: var selNode = this.editor.getSelectedNode();
! 1930: var dl = this.editor.getNearestParentOfType(selNode, 'dl');
! 1931: if (!dl) {
! 1932: return;
! 1933: };
! 1934: switch (event.keyCode) {
! 1935: case 13:
! 1936: this.handleEnterPress(selNode);
! 1937: if (event.preventDefault) {
! 1938: event.preventDefault();
! 1939: } else {
! 1940: event.returnValue = false;
! 1941: };
! 1942: break;
! 1943: case 9:
! 1944: if (event.preventDefault) {
! 1945: event.preventDefault();
! 1946: } else {
! 1947: event.returnValue = false;
! 1948: };
! 1949: this.handleTabPress(selNode);
! 1950: };
! 1951: };
! 1952:
! 1953: this.createDefinitionList = function() {
! 1954: /* create a new definition list (dl) */
! 1955: var selection = this.editor.getSelection();
! 1956: var doc = this.editor.getInnerDocument();
! 1957:
! 1958: var selection = this.editor.getSelection();
! 1959: var cloned = selection.cloneContents();
! 1960: // first get the 'first line' (until the first break) and use it
! 1961: // as the dt's content
! 1962: var iterator = new NodeIterator(cloned);
! 1963: var currnode = null;
! 1964: var remove = false;
! 1965: while (currnode = iterator.next()) {
! 1966: if (currnode.nodeName.toLowerCase() == 'br') {
! 1967: remove = true;
! 1968: };
! 1969: if (remove) {
! 1970: var next = currnode;
! 1971: while (!next.nextSibling) {
! 1972: next = next.parentNode;
! 1973: };
! 1974: next = next.nextSibling;
! 1975: iterator.setCurrent(next);
! 1976: currnode.parentNode.removeChild(currnode);
! 1977: };
! 1978: };
! 1979:
! 1980: var dtcontentcontainer = cloned;
! 1981: var collapsetoend = false;
! 1982:
! 1983: var dl = doc.createElement('dl');
! 1984: this.editor.insertNodeAtSelection(dl);
! 1985: var dt = this.createDefinitionTerm(dl);
! 1986: if (dtcontentcontainer.hasChildNodes()) {
! 1987: collapsetoend = true;
! 1988: while (dt.hasChildNodes()) {
! 1989: dt.removeChild(dt.firstChild);
! 1990: };
! 1991: while (dtcontentcontainer.hasChildNodes()) {
! 1992: dt.appendChild(dtcontentcontainer.firstChild);
! 1993: };
! 1994: };
! 1995:
! 1996: var selection = this.editor.getSelection();
! 1997: selection.selectNodeContents(dt);
! 1998: selection.collapse(collapsetoend);
! 1999: };
! 2000:
! 2001: this.createDefinitionTerm = function(dl, dd) {
! 2002: /* create a new definition term inside the current dl */
! 2003: var doc = this.editor.getInnerDocument();
! 2004: var dt = doc.createElement('dt');
! 2005: // somehow Mozilla seems to add breaks to all elements...
! 2006: if (dd) {
! 2007: if (dd.lastChild.nodeName.toLowerCase() == 'br') {
! 2008: dd.removeChild(dd.lastChild);
! 2009: };
! 2010: };
! 2011: // dd may be null here, if so we assume this is the first element in
! 2012: // the dl
! 2013: if (!dd || dl == dd.lastChild) {
! 2014: dl.appendChild(dt);
! 2015: } else {
! 2016: var nextsibling = dd.nextSibling;
! 2017: if (nextsibling) {
! 2018: dl.insertBefore(dt, nextsibling);
! 2019: } else {
! 2020: dl.appendChild(dt);
! 2021: };
! 2022: };
! 2023: var nbsp = doc.createTextNode('\xa0');
! 2024: dt.appendChild(nbsp);
! 2025: var selection = this.editor.getSelection();
! 2026: selection.selectNodeContents(dt);
! 2027: selection.collapse();
! 2028:
! 2029: this.editor.focusDocument();
! 2030: return dt;
! 2031: };
! 2032:
! 2033: this.createDefinition = function(dl, dt, initial_content) {
! 2034: var doc = this.editor.getInnerDocument();
! 2035: var dd = doc.createElement('dd');
! 2036: var nextsibling = dt.nextSibling;
! 2037: // somehow Mozilla seems to add breaks to all elements...
! 2038: if (dt) {
! 2039: if (dt.lastChild.nodeName.toLowerCase() == 'br') {
! 2040: dt.removeChild(dt.lastChild);
! 2041: };
! 2042: };
! 2043: while (nextsibling) {
! 2044: var name = nextsibling.nodeName.toLowerCase();
! 2045: if (name == 'dd' || name == 'dt') {
! 2046: break;
! 2047: } else {
! 2048: nextsibling = nextsibling.nextSibling;
! 2049: };
! 2050: };
! 2051: if (nextsibling) {
! 2052: dl.insertBefore(dd, nextsibling);
! 2053: //this._fixStructure(doc, dl, nextsibling);
! 2054: } else {
! 2055: dl.appendChild(dd);
! 2056: };
! 2057: if (initial_content) {
! 2058: for (var i=0; i < initial_content.length; i++) {
! 2059: dd.appendChild(initial_content[i]);
! 2060: };
! 2061: };
! 2062: var nbsp = doc.createTextNode('\xa0');
! 2063: dd.appendChild(nbsp);
! 2064: var selection = this.editor.getSelection();
! 2065: selection.selectNodeContents(dd);
! 2066: selection.collapse();
! 2067: };
! 2068:
! 2069: this.escapeFromDefinitionList = function(dl, currel, selNode) {
! 2070: var doc = this.editor.getInnerDocument();
! 2071: var p = doc.createElement('p');
! 2072: var nbsp = doc.createTextNode('\xa0');
! 2073: p.appendChild(nbsp);
! 2074:
! 2075: if (dl.lastChild == currel) {
! 2076: dl.parentNode.insertBefore(p, dl.nextSibling);
! 2077: } else {
! 2078: for (var i=0; i < dl.childNodes.length; i++) {
! 2079: var child = dl.childNodes[i];
! 2080: if (child == currel) {
! 2081: var newdl = this.editor.getInnerDocument().createElement('dl');
! 2082: while (currel.nextSibling) {
! 2083: newdl.appendChild(currel.nextSibling);
! 2084: };
! 2085: dl.parentNode.insertBefore(newdl, dl.nextSibling);
! 2086: dl.parentNode.insertBefore(p, dl.nextSibling);
! 2087: };
! 2088: };
! 2089: };
! 2090: currel.parentNode.removeChild(currel);
! 2091: var selection = this.editor.getSelection();
! 2092: selection.selectNodeContents(p);
! 2093: selection.collapse();
! 2094: this.editor.focusDocument();
! 2095: };
! 2096:
! 2097: this._fixStructure = function(doc, dl, offsetnode) {
! 2098: /* makes sure the order of the elements is correct */
! 2099: var currname = offsetnode.nodeName.toLowerCase();
! 2100: var currnode = offsetnode.nextSibling;
! 2101: while (currnode) {
! 2102: if (currnode.nodeType == 1) {
! 2103: var nodename = currnode.nodeName.toLowerCase();
! 2104: if (currname == 'dt' && nodename == 'dt') {
! 2105: var dd = doc.createElement('dd');
! 2106: while (currnode.hasChildNodes()) {
! 2107: dd.appendChild(currnode.childNodes[0]);
! 2108: };
! 2109: currnode.parentNode.replaceChild(dd, currnode);
! 2110: } else if (currname == 'dd' && nodename == 'dd') {
! 2111: var dt = doc.createElement('dt');
! 2112: while (currnode.hasChildNodes()) {
! 2113: dt.appendChild(currnode.childNodes[0]);
! 2114: };
! 2115: currnode.parentNode.replaceChild(dt, currnode);
! 2116: };
! 2117: };
! 2118: currnode = currnode.nextSibling;
! 2119: };
! 2120: };
! 2121: };
! 2122:
! 2123: DefinitionListTool.prototype = new KupuTool;
! 2124:
! 2125: function KupuZoomTool(buttonid, firsttab, lasttab) {
! 2126: this.button = getFromSelector(buttonid);
! 2127: firsttab = firsttab || 'kupu-tb-styles';
! 2128: lasttab = lasttab || 'kupu-logo-button';
! 2129:
! 2130: this.initialize = function(editor) {
! 2131: this.offclass = 'kupu-zoom';
! 2132: this.onclass = 'kupu-zoom-pressed';
! 2133: this.pressed = false;
! 2134:
! 2135: this.baseinitialize(editor);
! 2136: this.button.tabIndex = this.editor.document.editable.tabIndex;
! 2137: addEventHandler(window, "resize", this.onresize, this);
! 2138: addEventHandler(window, "scroll", this.onscroll, this);
! 2139:
! 2140: /* Toolbar tabbing */
! 2141: var lastbutton = getFromSelector(lasttab);
! 2142: var firstbutton = getFromSelector(firsttab);
! 2143: var iframe = editor.getInnerDocument();
! 2144: this.setTabbing(iframe, firstbutton, lastbutton);
! 2145: this.setTabbing(firstbutton, null, editor.getDocument().getWindow());
! 2146:
! 2147: this.editor.logMessage(_('Zoom tool initialized'));
! 2148: };
! 2149: };
! 2150:
! 2151: KupuZoomTool.prototype = new KupuLateFocusStateButton;
! 2152: KupuZoomTool.prototype.baseinitialize = KupuZoomTool.prototype.initialize;
! 2153:
! 2154: KupuZoomTool.prototype.onscroll = function() {
! 2155: if (!this.zoomed) return;
! 2156: /* XXX Problem here: Mozilla doesn't generate onscroll when window is
! 2157: * scrolled by focus move or selection. */
! 2158: var top = window.pageYOffset!=undefined ? window.pageYOffset : document.documentElement.scrollTop;
! 2159: var left = window.pageXOffset!=undefined ? window.pageXOffset : document.documentElement.scrollLeft;
! 2160: if (top || left) window.scrollTo(0, 0);
! 2161: }
! 2162:
! 2163: // Handle tab pressed from a control.
! 2164: KupuZoomTool.prototype.setTabbing = function(control, forward, backward) {
! 2165: function TabDown(event) {
! 2166: if (event.keyCode != 9 || !this.zoomed) return;
! 2167:
! 2168: var target = event.shiftKey ? backward : forward;
! 2169: if (!target) return;
! 2170:
! 2171: if (event.stopPropogation) event.stopPropogation();
! 2172: event.cancelBubble = true;
! 2173: event.returnValue = false;
! 2174:
! 2175: target.focus();
! 2176: return false;
! 2177: }
! 2178: addEventHandler(control, "keydown", TabDown, this);
! 2179: }
! 2180:
! 2181: KupuZoomTool.prototype.onresize = function() {
! 2182: if (!this.zoomed) return;
! 2183:
! 2184: var editor = this.editor;
! 2185: var iframe = editor.getDocument().editable;
! 2186: var sourcetool = editor.getTool('sourceedittool');
! 2187: var sourceArea = sourcetool?sourcetool.getSourceArea():null;
! 2188:
! 2189: var fulleditor = iframe.parentNode;
! 2190: var body = document.body;
! 2191:
! 2192: if (window.innerWidth) {
! 2193: var width = window.innerWidth;
! 2194: var height = window.innerHeight;
! 2195: } else if (document.documentElement) {
! 2196: var width = document.documentElement.offsetWidth-5;
! 2197: var height = document.documentElement.offsetHeight-5;
! 2198: } else {
! 2199: var width = document.body.offsetWidth-5;
! 2200: var height = document.body.offsetHeight-5;
! 2201: }
! 2202: width = width + 'px';
! 2203: var offset = iframe.offsetTop;
! 2204: if (sourceArea) offset = sourceArea.offsetTop-1;
! 2205: // XXX: TODO: Using wrong values here, figure out why.
! 2206: var nheight = Math.max(height - offset -1/*top border*/, 10);
! 2207: nheight = nheight + 'px';
! 2208: fulleditor.style.width = width; /*IE needs this*/
! 2209: iframe.style.width = width;
! 2210: iframe.style.height = nheight;
! 2211: if (sourceArea) {
! 2212: sourceArea.style.width = width;
! 2213: sourceArea.style.height = height;
! 2214: }
! 2215: }
! 2216:
! 2217: KupuZoomTool.prototype.checkfunc = function(selNode, button, editor, event) {
! 2218: return this.zoomed;
! 2219: }
! 2220:
! 2221: KupuZoomTool.prototype.commandfunc = function(button, editor) {
! 2222: /* Toggle zoom state */
! 2223: var zoom = button.pressed;
! 2224: this.zoomed = zoom;
! 2225:
! 2226: var zoomClass = 'kupu-fulleditor-zoomed';
! 2227: var iframe = editor.getDocument().getEditable();
! 2228:
! 2229: var body = document.body;
! 2230: var html = document.getElementsByTagName('html')[0];
! 2231: if (zoom) {
! 2232: html.style.overflow = 'hidden';
! 2233: window.scrollTo(0, 0);
! 2234: editor.setClass(zoomClass);
! 2235: body.className += ' '+zoomClass;
! 2236: this.onresize();
! 2237: } else {
! 2238: html.style.overflow = '';
! 2239: var fulleditor = iframe.parentNode;
! 2240: fulleditor.style.width = '';
! 2241: body.className = body.className.replace(' '+zoomClass, '');
! 2242: editor.clearClass(zoomClass);
! 2243:
! 2244: iframe.style.width = '';
! 2245: iframe.style.height = '';
! 2246:
! 2247: var sourcetool = editor.getTool('sourceedittool');
! 2248: var sourceArea = sourcetool?sourcetool.getSourceArea():null;
! 2249: if (sourceArea) {
! 2250: sourceArea.style.width = '';
! 2251: sourceArea.style.height = '';
! 2252: };
! 2253: }
! 2254: var doc = editor.getInnerDocument();
! 2255: // Mozilla needs this. Yes, really!
! 2256: doc.designMode=doc.designMode;
! 2257:
! 2258: window.scrollTo(0, iframe.offsetTop);
! 2259: editor.focusDocument();
! 2260: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>