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>