You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2010/03/29 00:53:15 UTC

svn commit: r928511 [5/7] - /myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/

Modified: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupueditor.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupueditor.js?rev=928511&r1=928510&r2=928511&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupueditor.js (original)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupueditor.js Sun Mar 28 22:53:14 2010
@@ -7,7 +7,6 @@
  * Contributors see CREDITS.txt.
  *
  *****************************************************************************/
-
 // $Id$
 
 //----------------------------------------------------------------------------
@@ -30,12 +29,19 @@ function KupuDocument(iframe) {
     this.document = this.window.document;
 
     this._browser = _SARISSA_IS_IE ? 'IE' : 'Mozilla';
-    
+    var DEPRECATED = { 'contentReadOnly': 'readonly', 'styleWithCSS': 'useCSS' };
     // methods
     this.execCommand = function(command, arg) {
         /* delegate execCommand */
         if (arg === undefined) arg = null;
-        this.document.execCommand(command, false, arg);
+        try {
+            this.document.execCommand(command, false, arg);
+        } catch(e) {
+            command = DEPRECATED[command];
+            if (command) {
+                this.document.execCommand(command, false, !arg);
+            };
+        };
     };
     
     this.reloadSource = function() {
@@ -84,10 +90,12 @@ function KupuEditor(document, config, lo
     this.config = config; // an object that holds the config values
     this.log = logger; // simple logger object
     this.tools = {}; // mapping id->tool
-    this.filters = new Array(); // contentfilters
+    this.filters = []; // contentfilters
+    this.serializer = new XMLSerializer();
     
     this._designModeSetAttempts = 0;
     this._initialized = false;
+    this._wantDesignMode = false;
 
     // some properties to save the selection, required for IE to remember 
     // where in the iframe the selection was
@@ -115,7 +123,6 @@ function KupuEditor(document, config, lo
         } else {
             this._setDesignModeWhenReady();
         };
-        this.logMessage(_('Editor initialized'));
     };
 
     this.setContextMenu = function(menu) {
@@ -150,13 +157,13 @@ function KupuEditor(document, config, lo
     this.updateStateHandler = function(event) {
         /* check whether the event is interesting enough to trigger the 
         updateState machinery and act accordingly */
-        var interesting_codes = new Array(8, 13, 37, 38, 39, 40, 46);
+        var interesting_codes = [8, 13, 37, 38, 39, 40, 46];
         // unfortunately it's not possible to do this on blur, since that's
         // too late. also (some versions of?) IE 5.5 doesn't support the
         // onbeforedeactivate event, which would be ideal here...
         this._saveSelection();
 
-        if (event.type == 'click' || event.type=='mouseup' ||
+        if (event.type == 'click' ||
                 (event.type == 'keyup' && 
                     interesting_codes.contains(event.keyCode))) {
             // Filthy trick to make the updateState method get called *after*
@@ -181,8 +188,8 @@ function KupuEditor(document, config, lo
                     break;
                 } else {
                     this.logMessage(
-                        _('Exception while processing updateState on ' +
-                            '${id}: ${msg}', {'id': id, 'msg': e}), 2);
+                        'Exception while processing updateState on ' +
+                            '${id}: ${msg}', {'id': id, 'msg': e}, 2);
                 };
             };
         };
@@ -252,7 +259,7 @@ function KupuEditor(document, config, lo
             request.open("PUT", this.config.dst, false);
             request.setRequestHeader("Content-type", this.config.content_type);
             request.send(contents);
-            this.handleSaveResponse(request,redirect)
+            this.handleSaveResponse(request,redirect);
         };
     };
     
@@ -333,23 +340,15 @@ function KupuEditor(document, config, lo
             this._restoreSelection();
         } else {
             this.focusDocument();
-            if (command != 'useCSS') {
+            if (command != 'styleWithCSS') {
                 this.content_changed = true;
-                // note the negation: the argument doesn't work as
-                // expected...
                 // Done here otherwise it doesn't always work or gets lost
                 // after some commands
-                this.getDocument().execCommand('useCSS', !this.config.use_css);
+                this.getDocument().execCommand('styleWithCSS', false);
             };
         };
         this.getDocument().execCommand(command, param);
-        var message = _('Command ${command} executed', {'command': command});
-        if (param) {
-            message = _('Command ${command} executed with parameter ${param}',
-                            {'command': command, 'param': param});
-        }
         this.updateState();
-        this.logMessage(message);
     };
 
     this.getSelection = function() {
@@ -358,9 +357,12 @@ function KupuEditor(document, config, lo
         return this.getDocument().getSelection();
     };
 
-    this.getSelectedNode = function() {
+    this.getSelectedNode = function(allowmulti) {
         /* returns the selected node (read: parent) or none */
-        return this.getSelection().parentElement();
+        /* if allowmulti is true, returns the parent of all ranges in the
+           selection (in the rare case that selection has more than one
+           range) */
+        return this.getSelection().parentElement(allowmulti);
     };
 
     this.getNearestParentOfType = function(node, type) {
@@ -368,7 +370,7 @@ function KupuEditor(document, config, lo
         var type = type.toLowerCase();
         while (node) {
             if (node.nodeName.toLowerCase() == type) {
-                return node
+                return node;
             }   
             var node = node.parentNode;
         }
@@ -421,7 +423,7 @@ function KupuEditor(document, config, lo
 
     this.focusDocument = function() {
         this.getDocument().getWindow().focus();
-    }
+    };
 
     this.logMessage = function(message, severity) {
         /* log a message using the logger, severity can be 0 (message, default), 1 (warning) or 2 (error) */
@@ -479,7 +481,7 @@ function KupuEditor(document, config, lo
     this._saveCallback = function(request, redirect) {
         /* callback for Sarissa */
         if (request.readyState == 4) {
-            this.handleSaveResponse(request, redirect)
+            this.handleSaveResponse(request, redirect);
         };
     };
     
@@ -503,26 +505,78 @@ function KupuEditor(document, config, lo
         */
     };
 
+    // Fixup Mozilla breaking image src url when dragging images
+    this.imageInserted = function(event) {
+        var node = event.target;
+        if (node && node.nodeType==1) {
+            var nodes = (/^img$/i.test(node.nodeName))?[node]:node.getElementsByTagName('img');
+            for (var i = 0; i < nodes.length; i++) {
+                node = nodes[i];
+                var src = node.getAttribute('kupu-src');
+                if (src) { node.src = src; };
+            };
+        };
+    };
+    // Prevent Mozilla resizing of images
+    this.imageModified = function(event) {
+        var node = event.target;
+        if (node && (/^img$/i.test(node.nodeName))) {
+            if (event.attrName=="style" && event.attrChange==1 && (/height|width/.test(event.newValue))) {
+                timer_instance.registerFunction(this, this._clearStyle, 1, node);
+            }
+        };
+    };
+    // Make sure image size is set on width/height attributes not style.
+    this._clearStyle = function(node) {
+        var w = node.width;
+        var h = node.height;
+        node.style.width = "";
+        node.style.height = "";
+        if (this.okresize) {
+            if (w) {node.width = w;};
+            if (h) {node.height = h;};
+        };
+    };
+    this._cancelResize = function(evt) {
+        return false;
+    };
+
     this._initializeEventHandlers = function() {
         /* attache the event handlers to the iframe */
+        var win = this.getDocument().getWindow();
+        var idoc = this.getInnerDocument();
+        var e = this._addEventHandler;
+        var validattrs =  this.xhtmlvalid.tagAttributes.img;
+        this.okresize = validattrs.contains('width') && validattrs.contains('height');
+        // Set design mode on resize event:
+        e(win, 'resize', this._resizeHandler, this);
         // Initialize DOM2Event compatibility
         // XXX should come back and change to passing in an element
-        this._addEventHandler(this.getInnerDocument(), "click", this.updateStateHandler, this);
-        this._addEventHandler(this.getInnerDocument(), "dblclick", this.updateStateHandler, this);
-        this._addEventHandler(this.getInnerDocument(), "keyup", this.updateStateHandler, this);
-        this._addEventHandler(this.getInnerDocument(), "keyup", function() {this.content_changed = true}, this);
-        this._addEventHandler(this.getInnerDocument(), "mouseup", this.updateStateHandler, this);
+        e(idoc, "click", this.updateStateHandler, this);
+        e(idoc, "dblclick", this.updateStateHandler, this);
+        e(idoc, "keyup", this.updateStateHandler, this);
+        e(idoc, "keyup", function() {this.content_changed = true;}, this);
+        e(idoc, "mouseup", this.updateStateHandler, this);
+        if (this.getBrowserName() == "IE") {
+            e(idoc, "selectionchange", this.onSelectionChange, this);
+            if (!this.okresize) { e(idoc.documentElement, "resizestart", this._cancelResize, this);};
+        } else {
+            e(idoc, "DOMNodeInserted", this.imageInserted, this);
+            e(idoc, "DOMAttrModified", this.imageModified, this);
+        }
     };
 
+    this._resizeHandler = function() {
+        // Use the resize event to trigger setting design mode
+        if (this._wantDesignMode) {
+            this._setDesignModeWhenReady();
+        }
+    };
+    
     this._setDesignModeWhenReady = function() {
-        /* Rather dirty polling loop to see if Mozilla is done doing it's
-            initialization thing so design mode can be set.
-        */
-        this._designModeSetAttempts++;
-        if (this._designModeSetAttempts > 25) {
-            alert(_('Couldn\'t set design mode. Kupu will not work on this browser.'));
-            return;
-        };
+        /* Try to set design mode, but if we fail then just wait for a
+         * resize event.
+         */
         var success = false;
         try {
             this._setDesignMode();
@@ -564,12 +618,15 @@ function KupuEditor(document, config, lo
 			// END myFaces special code.
         };
         if (success) {
+            this._wantDesignMode = false;
             // provide an 'afterInit' method on KupuEditor.prototype
             // for additional bootstrapping (after editor init)
             if (this.afterInit) {
                 this.afterInit();
             };
-        };
+        } else {
+            this._wantDesignMode = true; // Enable the resize trigger
+        }
     };
 
     this._setDesignMode = function() {
@@ -584,21 +641,25 @@ function KupuEditor(document, config, lo
          selection in the iframe gets lost. We only save if the current 
          selection in the document */
         if (this._isDocumentSelected()) {
-            var currange = this.getInnerDocument().selection.createRange();
+            var cursel = this.getInnerDocument().selection;
+            var currange = cursel.createRange();
+            if (cursel.type=="Control" && currange.item(0).nodeName.toLowerCase()=="body") {
+                /* This happens when you try to active an embedded
+                 * object */
+                this._restoreSelection(true);
+                return;
+            }
             this._previous_range = currange;
         };
     };
 
-    this._restoreSelection = function() {
+    this._restoreSelection = function(force) {
         /* re-selects the previous selection in IE. We only restore if the
         current selection is not in the document.*/
-        if (this._previous_range && !this._isDocumentSelected()) {
+        if (this._previous_range && (force || !this._isDocumentSelected())) {
             try {
                 this._previous_range.select();
-            } catch (e) {
-                alert("Error placing back selection");
-                this.logMessage(_('Error placing back selection'));
-            };
+            } catch (e) { };
         };
     };
     
@@ -607,7 +668,13 @@ function KupuEditor(document, config, lo
         this._restoreSelection = function() {};
     }
 
+    this.onSelectionChange = function(event) {
+        this._saveSelection();
+    };
+
     this._isDocumentSelected = function() {
+        if (this.suspended) return false;
+
         var editable_body = this.getInnerDocument().getElementsByTagName('body')[0];
         try {
             var selrange = this.getInnerDocument().selection.createRange();
@@ -647,9 +714,9 @@ function KupuEditor(document, config, lo
         var bodies = transform.getElementsByTagName('body');
         var data = '';
         for (var i = 0; i < bodies.length; i++) {
-            data += Sarissa.serialize(bodies[i]);
+            data += this.serializer.serializeToString(bodies[i]);
         }
-        return this.escapeEntities(data);
+        return this.layoutsource(this.escapeEntities(data));
     };
 
     this.getHTMLBody = function() {
@@ -660,16 +727,35 @@ function KupuEditor(document, config, lo
         for (var i = 0; i < bodies.length; i++) {
             data += bodies[i].innerHTML;
         }
-        return this.escapeEntities(data);
+        return this.layoutsource(this.escapeEntities(data));
     };
 
     // If we have multiple bodies this needs to remove the extras.
     this.setHTMLBody = function(text) {
-        var bodies = this.getInnerDocument().documentElement.getElementsByTagName('body');
+        var doc = this.getInnerDocument().documentElement;
+        var bodies = doc.getElementsByTagName('body');
         for (var i = 0; i < bodies.length-1; i++) {
             bodies[i].parentNode.removeChild(bodies[i]);
         }
+        if (_SARISSA_IS_IE) { /* IE converts certain comments to visible text so strip them */
+            text = text.replace(/<!--\[.*?-->/g, '');
+
+        } else { /* Mozilla doesn't understand strong/em */
+            var fixups = { 'strong':'b', 'em':'i' };
+
+            text = text.replace(/<(\/?)(strong|em)\b([^>]*)>/gi, function(all,close,tag,attrs) {
+                tag = fixups[tag.toLowerCase()];
+                return '<'+close+tag+attrs+'>';
+            });
+        };
+        text = text.replace(/<p>(<hr.*?>)<\/p>/g,'$1');
         bodies[bodies.length-1].innerHTML = text;
+        /* Mozilla corrupts dragged images, so save the src attribute */
+        var nodes = doc.getElementsByTagName('img');
+        for (var i = 0; i < nodes.length; i++) {
+            var node = nodes[i];
+            node.setAttribute('kupu-src', node.src);
+        };
     };
 
     this._fixXML = function(doc, document) {
@@ -694,23 +780,23 @@ function KupuEditor(document, config, lo
             title.appendChild(titletext);
         };
         // create a closing element for all elements that require one in XHTML
-        var dualtons = new Array('a', 'abbr', 'acronym', 'address', 'applet', 
-                                    'b', 'bdo', 'big', 'blink', 'blockquote', 
-                                    'button', 'caption', 'center', 'cite', 
-                                    'comment', 'del', 'dfn', 'dir', 'div',
-                                    'dl', 'dt', 'em', 'embed', 'fieldset',
-                                    'font', 'form', 'frameset', 'h1', 'h2',
-                                    'h3', 'h4', 'h5', 'h6', 'i', 'iframe',
-                                    'ins', 'kbd', 'label', 'legend', 'li',
-                                    'listing', 'map', 'marquee', 'menu',
-                                    'multicol', 'nobr', 'noembed', 'noframes',
-                                    'noscript', 'object', 'ol', 'optgroup',
-                                    'option', 'p', 'pre', 'q', 's', 'script',
-                                    'select', 'small', 'span', 'strike', 
-                                    'strong', 'style', 'sub', 'sup', 'table',
-                                    'tbody', 'td', 'textarea', 'tfoot',
-                                    'th', 'thead', 'title', 'tr', 'tt', 'u',
-                                    'ul', 'xmp');
+        var dualtons = ['a', 'abbr', 'acronym', 'address', 'applet', 
+            'b', 'bdo', 'big', 'blink', 'blockquote', 
+            'button', 'caption', 'center', 'cite', 
+            'comment', 'del', 'dfn', 'dir', 'div',
+            'dl', 'dt', 'em', 'embed', 'fieldset',
+            'font', 'form', 'frameset', 'h1', 'h2',
+            'h3', 'h4', 'h5', 'h6', 'i', 'iframe',
+            'ins', 'kbd', 'label', 'legend', 'li',
+            'listing', 'map', 'marquee', 'menu',
+            'multicol', 'nobr', 'noembed', 'noframes',
+            'noscript', 'object', 'ol', 'optgroup',
+            'option', 'p', 'pre', 'q', 's', 'script',
+            'select', 'small', 'span', 'strike', 
+            'strong', 'style', 'sub', 'sup', 'table',
+            'tbody', 'td', 'textarea', 'tfoot',
+            'th', 'thead', 'title', 'tr', 'tt', 'u',
+            'ul', 'xmp'];
         // XXX I reckon this is *way* slow, can we use XPath instead or
         // something to speed this up?
         for (var i=0; i < dualtons.length; i++) {
@@ -750,7 +836,7 @@ function KupuEditor(document, config, lo
 
     this._fixupSingletons = function(xml) {
         return xml.replace(/<([^>]+)\/>/g, "<$1 />");
-    }
+    };
     this._serializeOutputToString = function(transform) {
         // XXX need to fix this.  Sometimes a spurious "\n\n" text 
         // node appears in the transform, which breaks the Moz 
@@ -760,13 +846,13 @@ function KupuEditor(document, config, lo
             var contents =  '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' + 
                             '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n' + 
                             '<html xmlns="http://www.w3.org/1999/xhtml">' +
-                            Sarissa.serialize(transform.getElementsByTagName("head")[0]) +
-                            Sarissa.serialize(transform.getElementsByTagName("body")[0]) +
+                            this.serializer.serializeToString(transform.getElementsByTagName("head")[0]) +
+                            this.serializer.serializeToString(transform.getElementsByTagName("body")[0]) +
                             '</html>';
         } else {
             var contents = '<html>' + 
-                            Sarissa.serialize(transform.getElementsByTagName("head")[0]) +
-                            Sarissa.serialize(transform.getElementsByTagName("body")[0]) +
+                            this.serializer.serializeToString(transform.getElementsByTagName("head")[0]) +
+                            this.serializer.serializeToString(transform.getElementsByTagName("body")[0]) +
                             '</html>';
         };
 
@@ -778,32 +864,57 @@ function KupuEditor(document, config, lo
         
         return contents;
     };
+    this.layoutsource = function(data) {
+        data = data.replace(
+            /\s*(<(p|div|h.|ul|ol|dl|menu|dir|pre|blockquote|address|center|table|thead|tbody|tfoot|tr|th|td))\b/ig, '\n$1');
+        data = data.replace(
+            /\s*(<\/(p|div|h.|ul|ol|dl|menu|dir|pre|blockquote|address|center|table|thead|tbody|tfoot|tr|th|td)>)\s*/ig, '$1\n');
+        data = data.replace(/\<pre\>((?:.|\n)*?)\<\/pre\>/gm, function(s) {
+            return s.replace(/<br\b[^>]*>/gi,'\n');
+            });
+        return data.strip();
+    };
     this.escapeEntities = function(xml) {
         // XXX: temporarily disabled
+        xml = xml.replace(/\xa0/g, '&nbsp;');
         return xml;
         // Escape non-ascii characters as entities.
-        return xml.replace(/[^\r\n -\177]/g,
-            function(c) {
-            return '&#'+c.charCodeAt(0)+';';
-        });
-    }
+//         return xml.replace(/[^\r\n -\177]/g,
+//             function(c) {
+//             return '&#'+c.charCodeAt(0)+';';
+//         });
+    };
 
     this.getFullEditor = function() {
         var fulleditor = this.getDocument().getEditable();
-        while (!/kupu-fulleditor/.test(fulleditor.className)) {
+        while (!(/kupu-fulleditor/.test(fulleditor.className))) {
             fulleditor = fulleditor.parentNode;
         }
         return fulleditor;
-    }
+    };
     // Control the className and hence the style for the whole editor.
     this.setClass = function(name) {
         this.getFullEditor().className += ' '+name;
-    }
+    };
     
     this.clearClass = function(name) {
         var fulleditor = this.getFullEditor();
         fulleditor.className = fulleditor.className.replace(' '+name, '');
-    }
+    };
+
+    var busycount = 0;
+    this.busy = function() {
+        if (busycount <= 0) {
+            this.setClass('kupu-busy');
+        }
+        busycount++;
+    };
+    this.notbusy = function(force) {
+        busycount = force?0:busycount?busycount-1:0;
+        if (busycount <= 0) {
+            this.clearClass('kupu-busy');
+        }
+    };
 
     this.suspendEditing = function() {
         this._previous_range = this.getSelection().getRange();
@@ -815,32 +926,38 @@ function KupuEditor(document, config, lo
             var body = this.getInnerDocument().getElementsByTagName('body')[0];
             body.setAttribute('contentEditable', 'false');
         } else {
-
-            this.getInnerDocument().designMode = "Off";
-            var iframe = this.getDocument().getEditable();
-            iframe.style.position = iframe.style.position?"":"relative"; // Changing this disables designMode!
+            this.getDocument().execCommand('contentReadOnly', 'true');
         }
         this.suspended = true;
-    }
+    };
     
     this.resumeEditing = function() {
         if (!this.suspended) {
             return;
         }
-        this.suspended = false;
         this.clearClass('kupu-modal');
         for (var id in this.tools) {
             this.tools[id].enable();
         }
         if (this.getBrowserName() == "IE") {
-            this._restoreSelection();
             var body = this.getInnerDocument().getElementsByTagName('body')[0];
             body.setAttribute('contentEditable', 'true');
+            this._restoreSelection();
         } else {
             var doc = this.getInnerDocument();
+            this.getDocument().execCommand('contentReadOnly', 'false');
             doc.designMode = "On";
+            this.focusDocument();
             this.getSelection().restoreRange(this._previous_range);
         }
-    }
+        this.suspended = false;
+    };
+    this.newElement = function(tagName) {
+        return newDocumentElement(this.getInnerDocument(), tagName, arguments);
+    };
+    this.newText = function(text) {
+        return this.getInnerDocument().createTextNode(text);
+    };
 }
 
+

Modified: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupuhelpers.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupuhelpers.js?rev=928511&r1=928510&r2=928511&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupuhelpers.js (original)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupuhelpers.js Sun Mar 28 22:53:14 2010
@@ -7,7 +7,6 @@
  * Contributors see CREDITS.txt.
  *
  *****************************************************************************/
-
 // $Id$
 
 /*
@@ -71,38 +70,93 @@ Some notes about the scripts:
 //----------------------------------------------------------------------------
 // Helper classes and functions
 //----------------------------------------------------------------------------
+function newDocumentElement(doc, tagName, args) {
+    /* Create a new element, set attributes, and append children */
+    if (_SARISSA_IS_IE) {
+        /* Braindead IE cannot set some attributes (e.g. NAME) except
+         * through bizarre use of createElement */
+        var attrs = [tagName];
+        for (var a = 1; a < args.length; a++) {
+            var arg = args[a];
+            if (arg.length===undefined) {
+                for (var attr in arg) {
+                    var val = arg[attr];
+                    if (val===true) val=attr;
+                    if (val===false) continue;
+                    if (attr=='className') attr='class';
+                    attrs.push(attr+'="'+val.replace(/"/,'&quot;')+'"');
+                };
+            };
+        };
+        tagName = "<"+attrs.join(' ')+"></"+tagName+">";
+    }
+    var node = doc.createElement(tagName);
+    for (var a = 1; a < args.length; a++) {
+        var arg = args[a];
+        if (arg.length===undefined) {
+            if (!_SARISSA_IS_IE) {
+                for (var attr in arg) {
+                    if (/^on/.test(attr)) {
+                        node.setAttribute(attr, arg[attr]);
+                    } else {
+                        node[attr] = arg[attr];
+                    };
+                };
+            };
+        } else {
+            for (var i = 0; i < arg.length; i++) {
+                if(typeof(arg[i])=='string') {
+                    node.appendChild(doc.createTextNode(arg[i]));
+                } else {
+                    node.appendChild(arg[i]);
+                }
+            }
+        }
+    }
+    return node;
+}
+
+function newElement(tagName) {
+    return newDocumentElement(document, tagName, arguments);
+}
 
 function addEventHandler(element, event, method, context) {
     /* method to add an event handler for both IE and Mozilla */
     var wrappedmethod = new ContextFixer(method, context);
-    var args = new Array(null, null);
+    var args = [null, null];
     for (var i=4; i < arguments.length; i++) {
         args.push(arguments[i]);
     };
     wrappedmethod.args = args;
     try {
-        if (_SARISSA_IS_MOZ) {
+        if (element.addEventListener) {
             element.addEventListener(event, wrappedmethod.execute, false);
-        } else if (_SARISSA_IS_IE) {
+        } else if (element.attachEvent) {
             element.attachEvent("on" + event, wrappedmethod.execute);
         } else {
             throw _("Unsupported browser!");
         };
         return wrappedmethod.execute;
     } catch(e) {
-        alert(_('exception ${message} while registering an event handler ' +
-                'for element ${element}, event ${event}, method ${method}',
-                {'message': e.message, 'element': element,
-                    'event': event,
-                    'method': method}));
+        var msg = _(
+            'exception ${message} while registering an event handler ' +
+            'for element ${element}, event ${event}, method ${method}, ',
+            {'message': e.message, 'element': element,
+                'event': event,
+                'method': method
+            });
+        if (e.stack) {
+            msg += _('\r\ntraceback:\r\n${traceback}', {'traceback': e.stack});
+        };
+        alert(msg);
     };
 };
 
 function removeEventHandler(element, event, method) {
     /* method to remove an event handler for both IE and Mozilla */
-    if (_SARISSA_IS_MOZ) {
-        window.removeEventListener(event, method, false);
-    } else if (_SARISSA_IS_IE) {
+    if (element.removeEventListener) {
+        element.removeEventListener(event, method, false);
+    } else if (element.detachEvent) {
         element.detachEvent("on" + event, method);
     } else {
         throw _("Unsupported browser!");
@@ -136,14 +190,13 @@ function getBaseTagClass(base, tag, clas
     return null;
 }
 
-function openPopup(url, width, height) {
+function openPopup(url, width, height, properties) {
     /* open and center a popup window */
-    var sw = screen.width;
-    var sh = screen.height;
-    var left = sw / 2 - width / 2;
-    var top = sh / 2 - height / 2;
-    var win = window.open(url, 'someWindow', 
-                'width=' + width + ',height=' + height + ',left=' + left + ',top=' + top);
+    var allprops = 'width=' + width + ',height=' + height;
+    if (properties) {
+        allprops += ',' + properties;
+    };
+    var win = window.open(url, 'someWindow', allprops);
     return win;
 };
 
@@ -159,13 +212,13 @@ function selectSelectItem(select, item) 
     select.selectedIndex = 0;
 };
 
-function ParentWithStyleChecker(tagnames, style, stylevalue, command) {
+function parentWithStyleChecker(tagnames, style, stylevalue, command) {
     /* small wrapper that provides a generic function to check if a
        button should look pressed in */
     return function(selNode, button, editor, event) {
         /* check if the button needs to look pressed in */
         if (command) {
-            var result = editor.getInnerDocument().queryCommandState(command)
+            var result = editor.getInnerDocument().queryCommandState(command);
             if (result || editor.getSelection().getContentLength() == 0) {
                 return result;
             };
@@ -212,9 +265,13 @@ function _load_dict_helper(element) {
                 };
             };
             var name = child.nodeName.toLowerCase();
+            var attr = child.attributes[0];
+            if (attr && !(/^([^_]|_moz)/.test(attr.name))) {
+                name += attr.name.toLowerCase(); // Fix for Opera
+            }
             if (dict[name] != undefined) {
                 if (!dict[name].push) {
-                    dict[name] = new Array(dict[name], value);
+                    dict[name] = [dict[name], value];
                 } else {
                     dict[name].push(value);
                 };
@@ -275,10 +332,10 @@ function NodeIterator(node, continueatne
             this.current = current.firstChild;
         } else {
             // walk up parents until we finish or find one with a nextSibling
-            while (current != this.terminator && !current.nextSibling) {
+            while (current !== this.terminator && !current.nextSibling) {
                 current = current.parentNode;
             };
-            if (current == this.terminator) {
+            if (current === this.terminator) {
                 this.current = false;
             } else {
                 this.current = current.nextSibling;
@@ -406,17 +463,35 @@ function BaseSelection() {
 };
 
 function MozillaSelection(document) {
+    var win = document.getWindow();
     this.document = document;
-    this.selection = document.getWindow().getSelection();
-    
+    this.selection = win.getSelection();
+
+    this._createRange = function() {
+        return this.document.getDocument().createRange();
+    };
     this.selectNodeContents = function(node) {
-        /* select the contents of a node */
-        this.selection.removeAllRanges();
-        this.selection.selectAllChildren(node);
+        if (node && node.parentNode) {
+            /* select the contents of a node */
+            var sel = this.selection;
+            sel.removeAllRanges();
+            if (sel.selectAllChildren && node.nodeType == 1) {
+                sel.selectAllChildren(node);
+            } else {
+                var range = this._createRange();
+                try {
+                    range.selectNode(node);
+                } catch (e) {
+                    range.selectNodeContents(node);
+                };
+                sel.addRange(range);
+            };
+        };
     };
 
     this.collapse = function(collapseToEnd) {
         try {
+            if (!this.selection) this.reset();
             if (!collapseToEnd) {
                 this.selection.collapseToStart();
             } else {
@@ -450,7 +525,7 @@ function MozillaSelection(document) {
         var pos = range.startOffset;
 
         // make a new range for the new selection
-        var range = this.document.getDocument().createRange();
+        var range = this._createRange();
 
         if (container.nodeType == 3 && node.nodeType == 3) {
             // if we insert text in a textnode, do optimized insertion
@@ -492,11 +567,11 @@ function MozillaSelection(document) {
                     container.insertBefore(node, afterNode);
                 } else {
                     container.appendChild(node);
+                    afterNode = container.nextSibling;
                 };
             }
-
-            range.setEnd(afterNode, 0);
-            range.setStart(afterNode, 0);
+            range.setEndAfter(node);
+            range.collapse(false);
         }
 
         if (selectAfterPlace) {
@@ -505,7 +580,7 @@ function MozillaSelection(document) {
             // JavaScript isn't as nice as Python in that respect (kwargs)
             // if selectAfterPlace is a DOM node, select all of that node's
             // contents, else select the newly added node's
-            this.selection = this.document.getWindow().getSelection();
+            this.selection = win.getSelection();
             this.selection.addRange(range);
             if (selectAfterPlace.nodeType == 1) {
                 this.selection.selectAllChildren(selectAfterPlace);
@@ -519,7 +594,7 @@ function MozillaSelection(document) {
                     this.selection.addRange(range);
                 };
             };
-            this.document.getWindow().focus();
+            win.focus();
         };
         return node;
     };
@@ -551,6 +626,9 @@ function MozillaSelection(document) {
             if (currnode.nodeType == 3) {
                 offset += currnode.nodeValue.length;
             };
+            while (!currnode.nextSibling) {
+                currnode = currnode.parentNode;
+            };
             currnode = currnode.nextSibling;
         };
         return offset + startnodeoffset;
@@ -562,9 +640,9 @@ function MozillaSelection(document) {
         var aoffset = this.selection.anchorOffset;
         var onode = this.selection.focusNode;
         var ooffset = this.selection.focusOffset;
-        var arange = this.document.getDocument().createRange();
+        var arange = this._createRange();
         arange.setStart(anode, aoffset);
-        var orange = this.document.getDocument().createRange();
+        var orange = this._createRange();
         orange.setStart(onode, ooffset);
         return arange.compareBoundaryPoints('START_TO_START', orange) <= 0 ? anode : onode;
     };
@@ -573,7 +651,7 @@ function MozillaSelection(document) {
         // XXX this should be on a range object
         var endnode = this.endNode();
         var endnodeoffset = 0;
-        if (endnode = this.selection.focusNode) {
+        if (endnode == this.selection.focusNode) {
             endnodeoffset = this.selection.focusOffset;
         } else {
             endnodeoffset = this.selection.anchorOffset;
@@ -603,7 +681,7 @@ function MozillaSelection(document) {
             };
             return 0;
         };
-        while (currnode != endnode) {
+        while (currnode && currnode != endnode) {
             if (currnode.nodeType == 3) { // should account for CDATA nodes as well
                 offset += currnode.nodeValue.length;
             };
@@ -618,9 +696,9 @@ function MozillaSelection(document) {
         var aoffset = this.selection.anchorOffset;
         var onode = this.selection.focusNode;
         var ooffset = this.selection.focusOffset;
-        var arange = this.document.getDocument().createRange();
+        var arange = this._createRange();
         arange.setStart(anode, aoffset);
-        var orange = this.document.getDocument().createRange();
+        var orange = this._createRange();
         orange.setStart(onode, ooffset);
         return arange.compareBoundaryPoints('START_TO_START', orange) > 0 ? anode : onode;
     };
@@ -660,7 +738,7 @@ function MozillaSelection(document) {
         var curroffset = 0;
 
         var endparent = null;
-        var endoffset = 0;
+        var endparentoffset = 0;
         
         while (currnode) {
             if (currnode.nodeType == 3) { // XXX need to add CDATA support
@@ -703,9 +781,12 @@ function MozillaSelection(document) {
         return length;
     };
 
-    this.parentElement = function() {
+    this.parentElement = function(allowmulti) {
         /* return the selected node (or the node containing the selection) */
         // XXX this should be on a range object
+        if (!this.selection) {
+            return null;
+        }
         if (this.selection.rangeCount == 0) {
             var parent = this.document.getDocument().body;
             while (parent.firstChild) {
@@ -713,45 +794,114 @@ function MozillaSelection(document) {
             };
         } else {
             var range = this.selection.getRangeAt(0);
-            var parent = range.commonAncestorContainer;
+            var parent = this.parentElementOfRange(range);
+            if( allowmulti ) {
+                var numRanges = this.selection.rangeCount;
+                for( var i = 1; i < numRanges; i = i + 1 )
+                {
+                    var parent1 = parent;
+                    var parent2 = null;
+                    var range1 = this._createRange();
+                    var range2 = this._createRange();
+                
+                    var parent2 = this.parentElementOfRange(this.selection.getRangeAt(i));
 
-            // the following deals with cases where only a single child is
-            // selected, e.g. after a click on an image
-            var inv = range.compareBoundaryPoints(Range.START_TO_END, range) < 0;
-            var startNode = inv ? range.endContainer : range.startContainer;
-            var startOffset = inv ? range.endOffset : range.startOffset;
-            var endNode = inv ? range.startContainer : range.endContainer;
-            var endOffset = inv ? range.startOffset : range.endOffset;
-
-            var selectedChild = null;
-            var child = parent.firstChild;
-            while (child) {
-                // XXX the additional conditions catch some invisible
-                // intersections, but still not all of them
-                if (range.intersectsNode(child) &&
-                    !(child == startNode && startOffset == child.length) &&
-                    !(child == endNode && endOffset == 0)) {
-                    if (selectedChild) {
-                        // current child is the second selected child found
-                        selectedChild = null;
-                        break;
+                    range1.selectNode(parent1);
+                    range2.selectNode(parent2);
+                    
+                    if( range1.compareBoundaryPoints(Range.START_TO_START, range2) <= 0 &&
+                        range1.compareBoundaryPoints(Range.END_TO_END, range2) >= 0 ) {
+                        //parent1 contains parent2
+                        parent = parent1;
+                    } else if( range1.compareBoundaryPoints(Range.START_TO_START, range2) >= 0 &&
+                        range1.compareBoundaryPoints(Range.END_TO_END, range2) <= 0 ) {
+                        //parent2 contains parent1
+                        parent = parent2;
+                    } else if( range1.compareBoundaryPoints(Range.START_TO_END, range2) <= 0 ) {
+                        //parent1 comes before parent2
+                        //commonAncestorContainer returns the node parent if a range is
+                        //just one node, which we don't want; but since parent1
+                        //and parent2 are different, their range is not just
+                        //one node
+                        var coverRange = this._createRange();
+                        coverRange.setStartBefore(parent1);
+                        coverRange.setEndAfter(parent2);
+                        parent = coverRange.commonAncestorContainer;
                     } else {
-                        // current child is the first selected child found
-                        selectedChild = child;
+                        //parent2 comes before parent1
+                        //commonAncestorContainer returns the node parent if a range is
+                        //just one node, which we don't want; but since parent1
+                        //and parent2 are different, their range is not just
+                        //one node
+                        var coverRange = this._createRange();
+                        coverRange.setStartBefore(parent2);
+                        coverRange.setEndAfter(parent1);
+                        parent = coverRange.commonAncestorContainer;                    
                     };
-                } else if (selectedChild) {
-                    // current child is after the selection
-                    break;
                 };
-                child = child.nextSibling;
             };
-            if (selectedChild) {
-                parent = selectedChild;
+        };            
+
+        if (parent.nodeType == Node.TEXT_NODE) {
+            parent = parent.parentNode;
+        };
+        return parent;
+    };
+
+    this.parentElementOfRange = function(range) {
+        if( range.compareBoundaryPoints(Range.START_TO_END, range) < 0 ) {
+            var startNode = range.endContainer;
+            var startOffset = range.endOffset;
+            var endNode = range.startContainer;
+            var endOffset = range.startOffset;
+            range.setStart( startNode, startOffset );
+            range.setEnd( endNode, endOffset );
+        }
+            
+        var parent = range.commonAncestorContainer;
+            
+        // if there is only a single node selected, e.g. after a click on
+        // an image, then this node itself should be returned as the
+        // parentElement. however, in this case, "parent" is the selected
+        // node's parent. the following searches if any other node
+        // intersects the selection range; if not, then the selected node
+        // is set to the parentElement.     
+        var inv = range.compareBoundaryPoints(Range.START_TO_END, range) < 0;
+        var startNode = inv ? range.endContainer : range.startContainer;
+        var startOffset = inv ? range.endOffset : range.startOffset;
+        var endNode = inv ? range.startContainer : range.endContainer;
+        var endOffset = inv ? range.startOffset : range.endOffset;
+
+        var selectedChild = null;
+        var child = parent.firstChild;
+        while (child) {
+            if (range.intersectsNode(child) &&
+                !(child == startNode && startOffset == child.length) &&
+                !(child == endNode && endOffset == 0)) {
+                if (selectedChild) {
+                    // current child is the second node found that
+                    // intersects the selection, so commonAncestorContainer
+                    // is the correct parentElement to use                        
+                    selectedChild = null;
+                    break;
+                } else {
+                    // current child is the first selected child found
+                    selectedChild = child;
+                };
+            } else if (selectedChild) {
+                // current child is after the selection
+                break;
             };
+            child = child.nextSibling;
+        };
+
+        if (selectedChild) {
+            parent = selectedChild;
         };
         if (parent.nodeType == Node.TEXT_NODE) {
             parent = parent.parentNode;
         };
+
         return parent;
     };
 
@@ -767,8 +917,6 @@ function MozillaSelection(document) {
         if (realoffset >= 0) {
             var currnode = offsetparent.firstChild;
             var curroffset = 0;
-            var startparent = null;
-            var startoffset = 0;
             while (currnode) {
                 if (currnode.nodeType == 3) { // XXX need to support CDATA sections
                     var nodelength = currnode.nodeValue.length;
@@ -830,7 +978,7 @@ function MozillaSelection(document) {
     };
 
     this.reset = function() {
-        this.selection = this.document.getWindow().getSelection();
+        this.selection = win.getSelection();
     };
 
     this.cloneContents = function() {
@@ -840,21 +988,76 @@ function MozillaSelection(document) {
     };
 
     this.containsNode = function(node) {
-        return this.selection.containsNode(node, true);
-    }
+        var sel = this.selection;
+        if (sel.containsNode) {
+            return sel.containsNode(node, true);
+        } else {
+            // kludge it for safari
+            for(var i = 0; i < sel.rangeCount; i++ ) {
+                if( sel.getRangeAt(i).containsNode(node) ) {
+                    return true;
+                }
+            };
+            return false;
+        }
+    };
 
     this.toString = function() {
         return this.selection.toString();
     };
 
     this.getRange = function() {
-        return this.selection.getRangeAt(0);
-    }
+        if (this.selection && this.selection.rangeCount > 0) {
+            return this.selection.getRangeAt(0);
+        }
+    };
     this.restoreRange = function(range) {
         var selection = this.selection;
-        selection.removeAllRanges();
-        selection.addRange(range);
-    }
+        if (selection) {
+            selection.removeAllRanges();
+            selection.addRange(range);
+        }
+    };
+
+    //sample kindly snipped from Mozilla's wiki
+    if( !win.Range.prototype.intersectsNode ){
+        win.Range.prototype.intersectsNode = function(node) {
+            var nodeRange = node.ownerDocument.createRange();
+            try {
+                nodeRange.selectNode(node);
+            } catch (e) {
+                nodeRange.selectNodeContents(node);
+            };
+
+            // selection end after node start and selection start
+            // before node end
+            return this.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
+                this.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
+        };
+    };
+    this.intersectsNode = function(node) {
+        for(var i = 0; i < this.selection.rangeCount; i++ ) {
+           if( this.selection.getRangeAt(i).intersectsNode(node) ) {
+               return true;
+           }
+        };
+        return false;
+    };
+    if( !win.Range.prototype.containsNode ){
+        win.Range.prototype.containsNode = function(node) {
+            var nodeRange = node.ownerDocument.createRange();
+            try {
+                nodeRange.selectNode(node);
+            } catch (e) {
+                nodeRange.selectNodeContents(node);
+            };
+
+            // selection start not after node start and selection end
+            // not before node end.
+            return this.compareBoundaryPoints(Range.START_TO_START, nodeRange) != -1 &&
+                    this.compareBoundaryPoints(Range.END_TO_END, nodeRange) != 1;
+        };
+    };
 };
 
 MozillaSelection.prototype = new BaseSelection;
@@ -867,7 +1070,7 @@ function IESelection(document) {
      * main page, so force an inner selection. */
     var doc = document.getDocument();
 
-    var range = this.selection.createRange()
+    var range = this.selection.createRange();
     var parent = this.selection.type=="Text" ?
         range.parentElement() :
         this.selection.type=="Control" ?  range.parentElement : null;
@@ -876,6 +1079,7 @@ function IESelection(document) {
             var range = doc.body.createTextRange();
             range.collapse();
             range.select();
+            this.reset();
     }
 
     this.selectNodeContents = function(node) {
@@ -884,21 +1088,21 @@ function IESelection(document) {
         // to just before the element instead of inside it, and since IE doesn't reserve
         // an index for the element itself as well the way to get it inside the element is
         // by moving the start one pos and then moving it back (yuck!)
-        var range = this.selection.createRange().duplicate();
+        var range = doc.body.createTextRange();
         range.moveToElementText(node);
         range.moveStart('character', 1);
         range.moveStart('character', -1);
         range.moveEnd('character', -1);
         range.moveEnd('character', 1);
         range.select();
-        this.selection = this.document.getDocument().selection;
+        this.reset();
     };
 
     this.collapse = function(collapseToEnd) {
         var range = this.selection.createRange();
         range.collapse(!collapseToEnd);
         range.select();
-        this.selection = document.getDocument().selection;
+        this.reset();
     };
 
     this.replaceWithNode = function(newnode, selectAfterPlace) {
@@ -926,7 +1130,7 @@ function IESelection(document) {
             var range = this.selection.createRange();
 
             range.pasteHTML('<img id="kupu-tempnode">');
-            tempnode = document.getElementById('kupu-tempnode');
+            var tempnode = document.getElementById('kupu-tempnode');
             tempnode.replaceNode(newnode);
 
             if (selectAfterPlace) {
@@ -1022,7 +1226,7 @@ function IESelection(document) {
         return length;
     };
 
-    this.parentElement = function() {
+    this.parentElement = function(allowmulti) {
         /* return the selected node (or the node containing the selection) */
         // XXX this should be on a range object
         if (this.selection.type == 'Control') {
@@ -1040,6 +1244,7 @@ function IESelection(document) {
         var range = this.selection.createRange();
         range.moveStart('character', offset);
         range.select();
+        this.reset();
     };
 
     this.moveEnd = function(offset) {
@@ -1047,6 +1252,7 @@ function IESelection(document) {
         var range = this.selection.createRange();
         range.moveEnd('character', offset);
         range.select();
+        this.reset();
     };
 
     this.reset = function() {
@@ -1086,18 +1292,34 @@ function IESelection(document) {
     
     this.getRange = function() {
         return this.selection.createRange();
-    }
+    };
 
     this.restoreRange = function(range) {
         try {
             range.select();
+            this.reset();
         } catch(e) {
         };
-    }
+    };
 
     this.toString = function() {
         return this.selection.createRange().text;
     };
+
+    this.intersectsNode = function(node) {
+        var noderange = doc.body.createTextRange();
+        noderange.moveToElementText(node);
+        
+        var selrange = this.selection.createRange();
+        
+        if((selrange.compareEndPoints('StartToStart', noderange) <= 0 &&
+            selrange.compareEndPoints('EndToStart', noderange) > 0) ||
+            (selrange.compareEndPoints('StartToStart', noderange) > 0 &&
+            selrange.compareEndPoints('StartToEnd', noderange) < 0)) {
+           return true;
+        }
+        return false;
+    };
 };
 
 IESelection.prototype = new BaseSelection;
@@ -1127,7 +1349,7 @@ function ContextFixer(func, context) {
     
     this.execute = function() {
         /* execute the method */
-        var args = new Array();
+        var args = [];
         // the first arguments will be the extra ones of the class
         for (var i=0; i < self.args.length - 2; i++) {
             args.push(self.args[i + 2]);
@@ -1179,12 +1401,12 @@ function Timer() {
                 
             all other args will be passed 1:1 to the function when called
         */
-        var args = new Array();
+        var args = [];
         for (var i=0; i < arguments.length - 3; i++) {
             args.push(arguments[i + 3]);
         }
         var id = this._createUniqueId();
-        this.functions[id] = new Array(object, func, args);
+        this.functions[id] = [object, func, args];
         setTimeout("timer_instance._handleFunction(" + id + ")", timeout);
     };
 
@@ -1266,16 +1488,16 @@ String.prototype.strip = function() {
 
 String.prototype.reduceWhitespace = function() {
     /* returns a string in which all whitespace is reduced 
-        to a single, plain space */
-    var spacereg = /(\s+)/g;
-    var copy = this;
-    while (true) {
-        var match = spacereg.exec(copy);
-        if (!match) {
-            return copy;
-        };
-        copy = copy.replace(match[0], ' ');
-    };
+    to a single, plain space */
+    return this.replace(/\s+/g, ' ');
+};
+String.prototype.truncate = function(len) {
+    if (this.length <= len) {
+        return this;
+    } else {
+        var trimmed = this.substring(0, len+1).replace(/\s[^\s]*$/, '...');
+        return trimmed;
+    }
 };
 
 String.prototype.entitize = function() {
@@ -1290,8 +1512,8 @@ String.prototype.entitize = function() {
 String.prototype.deentitize = function() {
     var ret = this.replace(/&gt;/g, '>');
     ret = ret.replace(/&lt;/g, '<');
-    ret = ret.replace(/&quot;/g, '"');
     ret = ret.replace(/&apos;/g, "'");
+    ret = ret.replace(/&quot;/g, '"');
     ret = ret.replace(/&amp;/g, '&');
     return ret;
 };
@@ -1343,3 +1565,53 @@ function Exception() {
 // update, may be required in situations where updateState changes the structure
 // of the document (e.g. does a cleanup or so)
 UpdateStateCancelBubble = new Exception();
+
+function kupuFixImage(image) {
+    image.removeAttribute('width');
+    image.removeAttribute('height');
+    var width = image.naturalWidth || image.width;
+    var height = image.naturalHeight || image.height;
+    if (height > width) {
+        if (height > 128) {
+            width = width * 128 / height;
+            height = 128;
+        };
+    } else {
+        if (width > 128) {
+            height = height * 128 / width;
+            width = 128;
+        };
+    };
+    if (width&&height) {
+        image.height = height;
+        image.width = width;
+    }
+}
+
+function toggleAltFieldVisibility(me) {
+    var label = document.getElementById('image-alt-label');
+    var vis = me.checked?'none':'';
+    if (label) {
+        label.style.display = vis;
+        var fld = document.getElementById(label.htmlFor);
+        if(fld) { fld.style.display = vis; }
+    }
+}
+
+function getOuterHtml(node) {
+    var html = '<';
+    html += node.nodeName.toLowerCase();
+    var attrs = node.attributes;
+    for (var a = 0; a < attrs.length; a++) {
+        var att = attrs[a];
+        if (att.specified) {
+            html += ' ' + att.nodeName.toLowerCase() + '="' + att.nodeValue + '"';
+        }
+    }
+    html += '>';
+    if (!(/hr|br|img|input/i.test(node.nodeName))) {
+        html += node.innerHTML;
+        html += '<\/' + node.nodeName.toLowerCase() + '>';
+    }
+    return html;
+}

Modified: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupuinit.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupuinit.js?rev=928511&r1=928510&r2=928511&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupuinit.js (original)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupuinit.js Sun Mar 28 22:53:14 2010
@@ -7,7 +7,6 @@
  * Contributors see CREDITS.txt.
  *
  *****************************************************************************/
-
 // $Id$
 
 
@@ -19,20 +18,20 @@ function initKupu(iframe) {
     /* Although this is meant to be a sample implementation, it can
         be used out-of-the box to run the sample pagetemplate or for simple
         implementations that just don't use some elements. When you want
-        to do some customization, this should probably be overridden. For 
-        larger customization actions you will have to subclass or roll your 
+        to do some customization, this should probably be overridden. For
+        larger customization actions you will have to subclass or roll your
         own UI object.
     */
 
     // first we create a logger
     var l = new PlainLogger('kupu-toolbox-debuglog', 5);
-    
+
     // now some config values
     var conf = loadDictFromXML(document, 'kupuconfig');
-    
+
     // the we create the document, hand it over the id of the iframe
     var doc = new KupuDocument(iframe);
-    
+
     // now we can create the controller
     var kupu = new KupuEditor(doc, conf, l);
 
@@ -47,7 +46,7 @@ function initKupu(iframe) {
     kupu.registerTool('ui', ui); // XXX Should this be a different method?
 
     // add the buttons to the toolbar
-    var savebuttonfunc = function(button, editor) {editor.saveDocument()};
+    var savebuttonfunc = function(button, editor) {editor.saveDocument();};
     var savebutton = new KupuButton('kupu-save-button', savebuttonfunc);
     kupu.registerTool('savebutton', savebutton);
 
@@ -58,34 +57,34 @@ function initKupu(iframe) {
         };
     };
 
-    var boldchecker = ParentWithStyleChecker(new Array('b', 'strong'),
+    var boldchecker = parentWithStyleChecker(['b', 'strong'],
                                              'fontWeight', 'bold', 'bold');
-    var boldbutton = new KupuStateButton('kupu-bold-button', 
+    var boldbutton = new KupuStateButton('kupu-bold-button',
                                          execCommand('bold'),
                                          boldchecker,
                                          'kupu-bold',
                                          'kupu-bold-pressed');
     kupu.registerTool('boldbutton', boldbutton);
 
-    var italicschecker = ParentWithStyleChecker(new Array('i', 'em'),
+    var italicschecker = parentWithStyleChecker(['i', 'em'],
                                               'fontStyle', 'italic', 'italic');
-    var italicsbutton = new KupuStateButton('kupu-italic-button', 
-                                           execCommand('italic'),
-                                           italicschecker, 
-                                           'kupu-italic', 
-                                           'kupu-italic-pressed');
+    var italicsbutton = new KupuStateButton('kupu-italic-button',
+                                            execCommand('italic'),
+                                            italicschecker,
+                                            'kupu-italic',
+                                            'kupu-italic-pressed');
     kupu.registerTool('italicsbutton', italicsbutton);
 
-    var underlinechecker = ParentWithStyleChecker(new Array('u'),
+    var underlinechecker = parentWithStyleChecker(['u'],
                                    'textDecoration', 'underline', 'underline');
-    var underlinebutton = new KupuStateButton('kupu-underline-button', 
+    var underlinebutton = new KupuStateButton('kupu-underline-button',
                                               execCommand('underline'),
                                               underlinechecker,
-                                              'kupu-underline', 
+                                              'kupu-underline',
                                               'kupu-underline-pressed');
     kupu.registerTool('underlinebutton', underlinebutton);
 
-    var subscriptchecker = ParentWithStyleChecker(new Array('sub'),
+    var subscriptchecker = parentWithStyleChecker(['sub'],
                                                   null, null, 'subscript');
     var subscriptbutton = new KupuStateButton('kupu-subscript-button',
                                               execCommand('subscript'),
@@ -94,12 +93,12 @@ function initKupu(iframe) {
                                               'kupu-subscript-pressed');
     kupu.registerTool('subscriptbutton', subscriptbutton);
 
-    var superscriptchecker = ParentWithStyleChecker(new Array('super', 'sup'),
+    var superscriptchecker = parentWithStyleChecker(['super', 'sup'],
                                                     null, null, 'superscript');
-    var superscriptbutton = new KupuStateButton('kupu-superscript-button', 
+    var superscriptbutton = new KupuStateButton('kupu-superscript-button',
                                                 execCommand('superscript'),
                                                 superscriptchecker,
-                                                'kupu-superscript', 
+                                                'kupu-superscript',
                                                 'kupu-superscript-pressed');
     kupu.registerTool('superscriptbutton', superscriptbutton);
 
@@ -121,23 +120,17 @@ function initKupu(iframe) {
     var indentbutton = new KupuButton('kupu-indent-button', execCommand('indent'));
     kupu.registerTool('indentbutton', indentbutton);
 
-    var undobutton = new KupuButton('kupu-undo-button', execCommand('undo'));
-    kupu.registerTool('undobutton', undobutton);
-
-    var redobutton = new KupuButton('kupu-redo-button', execCommand('redo'));
-    kupu.registerTool('redobutton', redobutton);
-
     var removeimagebutton = new KupuRemoveElementButton('kupu-removeimage-button',
-							'img',
-							'kupu-removeimage');
+                                                        'img',
+                                                        'kupu-removeimage');
     kupu.registerTool('removeimagebutton', removeimagebutton);
+
     var removelinkbutton = new KupuRemoveElementButton('kupu-removelink-button',
-						       'a',
-						       'kupu-removelink');
+                                                       'a',
+                                                       'kupu-removelink');
     kupu.registerTool('removelinkbutton', removelinkbutton);
 
     // add some tools
-    // XXX would it be better to pass along elements instead of ids?
     var colorchoosertool = new ColorchooserTool('kupu-forecolor-button',
                                                 'kupu-hilitecolor-button',
                                                 'kupu-colorchooser');
@@ -145,12 +138,13 @@ function initKupu(iframe) {
 
     var listtool = new ListTool('kupu-list-ul-addbutton',
                                 'kupu-list-ol-addbutton',
-                                'kupu-ulstyles', 'kupu-olstyles');
+                                'kupu-ulstyles',
+                                'kupu-olstyles');
     kupu.registerTool('listtool', listtool);
-    
+
     var definitionlisttool = new DefinitionListTool('kupu-list-dl-addbutton');
     kupu.registerTool('definitionlisttool', definitionlisttool);
-    
+
     var proptool = new PropertyTool('kupu-properties-title', 'kupu-properties-description');
     kupu.registerTool('proptool', proptool);
 
@@ -161,23 +155,27 @@ function initKupu(iframe) {
 
     var imagetool = new ImageTool();
     kupu.registerTool('imagetool', imagetool);
-    var imagetoolbox = new ImageToolBox('kupu-image-input', 'kupu-image-addbutton', 
-                                        'kupu-image-float-select', 'kupu-toolbox-images', 
+    var imagetoolbox = new ImageToolBox('kupu-image-input', 'kupu-image-addbutton',
+                                        'kupu-image-float-select', 'kupu-toolbox-images',
                                         'kupu-toolbox', 'kupu-toolbox-active');
     imagetool.registerToolBox('imagetoolbox', imagetoolbox);
 
     var tabletool = new TableTool();
     kupu.registerTool('tabletool', tabletool);
-    var tabletoolbox = new TableToolBox('kupu-toolbox-addtable', 
+    var tabletoolbox = new TableToolBox('kupu-toolbox-addtable',
         'kupu-toolbox-edittable', 'kupu-table-newrows', 'kupu-table-newcols',
-        'kupu-table-makeheader', 'kupu-table-classchooser', 'kupu-table-alignchooser',
-        'kupu-table-addtable-button', 'kupu-table-addrow-button', 'kupu-table-delrow-button', 
-        'kupu-table-addcolumn-button', 'kupu-table-delcolumn-button', 
-        'kupu-table-fix-button', 'kupu-table-fixall-button', 'kupu-toolbox-tables',
-        'kupu-toolbox', 'kupu-toolbox-active'
-        );
+        'kupu-table-makeheader', 'kupu-table-classchooser',
+        'kupu-table-alignchooser', 'kupu-table-addtable-button',
+        'kupu-table-addrow-button', 'kupu-table-delrow-button',
+        'kupu-table-addcolumn-button', 'kupu-table-delcolumn-button',
+        'kupu-table-fix-button', 'kupu-table-del-button',
+        'kupu-table-fixall-button', 'kupu-toolbox-tables',
+        'kupu-toolbox', 'kupu-toolbox-active');
     tabletool.registerToolBox('tabletoolbox', tabletoolbox);
 
+    var anchortool = new AnchorTool();
+    kupu.registerTool('anchortool', anchortool);
+
     var showpathtool = new ShowPathTool();
     kupu.registerTool('showpathtool', showpathtool);
 
@@ -189,7 +187,9 @@ function initKupu(iframe) {
                                             'spellcheck.cgi');
     kupu.registerTool('spellchecker', spellchecker);
 
-    var zoom = new KupuZoomTool('kupu-zoom-button');
+    var zoom = new KupuZoomTool('kupu-zoom-button',
+                                'kupu-tb-styles',
+                                'kupu-logo-button');
     kupu.registerTool('zoomtool', zoom);
 
     var cleanupexpressions = new CleanupExpressionsTool(
@@ -217,26 +217,30 @@ function initKupu(iframe) {
                                           opendrawer('linkdrawer'));
     kupu.registerTool('linkdrawerbutton', linkdrawerbutton);
 
+    var anchorbutton = new KupuButton('kupu-anchors',
+                                      opendrawer('anchordrawer'));
+    kupu.registerTool('anchorbutton', anchorbutton);
+
     var tabledrawerbutton = new KupuButton('kupu-tabledrawer-button',
                                            opendrawer('tabledrawer'));
     kupu.registerTool('tabledrawerbutton', tabledrawerbutton);
 
-    // create some drawers, drawers are some sort of popups that appear when a 
+    // create some drawers, drawers are some sort of popups that appear when a
     // toolbar button is clicked
     var drawertool = new DrawerTool();
     kupu.registerTool('drawertool', drawertool);
 
     try {
-        var linklibdrawer = new LinkLibraryDrawer(linktool, 
-                                                  conf['link_xsl_uri'],
-                                                  conf['link_libraries_uri'],
-                                                  conf['link_images_uri']);
+        var linklibdrawer = new LinkLibraryDrawer(linktool,
+                                                  conf.link_xsl_uri,
+                                                  conf.link_libraries_uri,
+                                                  conf.search_links_uri);
         drawertool.registerDrawer('linklibdrawer', linklibdrawer);
 
-        var imagelibdrawer = new ImageLibraryDrawer(imagetool, 
-                                                    conf['image_xsl_uri'],
-                                                    conf['image_libraries_uri'],
-                                                    conf['search_images_uri']);
+        var imagelibdrawer = new ImageLibraryDrawer(imagetool,
+                                                    conf.image_xsl_uri,
+                                                    conf.image_libraries_uri,
+                                                    conf.search_images_uri);
         drawertool.registerDrawer('imagelibdrawer', imagelibdrawer);
     } catch(e) {
         var msg = _('There was a problem initializing the drawers. Most ' +
@@ -250,9 +254,15 @@ function initKupu(iframe) {
     var linkdrawer = new LinkDrawer('kupu-linkdrawer', linktool);
     drawertool.registerDrawer('linkdrawer', linkdrawer);
 
+    var anchordrawer = new AnchorDrawer('kupu-anchordrawer', anchortool);
+    drawertool.registerDrawer('anchordrawer', anchordrawer);
+
     var tabledrawer = new TableDrawer('kupu-tabledrawer', tabletool);
     drawertool.registerDrawer('tabledrawer', tabledrawer);
 
+    var undotool = new KupuUndoTool('kupu-undo-button', 'kupu-redo-button');
+    kupu.registerTool('undotool', undotool);
+
     // register some cleanup filter
     // remove tags that aren't in the XHTML DTD
     var nonxhtmltagfilter = new NonXHTMLTagFilter();
@@ -263,6 +273,6 @@ function initKupu(iframe) {
                                                         'kupu-toolboxes');
         collapser.initialize();
     };
-    
+
     return kupu;
-};
+}

Added: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupuinit_experimental.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupuinit_experimental.js?rev=928511&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupuinit_experimental.js (added)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupuinit_experimental.js Sun Mar 28 22:53:14 2010
@@ -0,0 +1,224 @@
+/*****************************************************************************
+ *
+ * Copyright (c) 2003-2005 Kupu Contributors. All rights reserved.
+ *
+ * This software is distributed under the terms of the Kupu
+ * License. See LICENSE.txt for license text. For a list of Kupu
+ * Contributors see CREDITS.txt.
+ *
+ *****************************************************************************/
+// $Id: kupuinit_experimental.js 39345 2007-02-23 18:29:27Z yuppie $
+
+
+//----------------------------------------------------------------------------
+// Sample initialization function
+//----------------------------------------------------------------------------
+
+function initKupu(iframe) {
+    /* Although this is meant to be a sample implementation, it can
+        be used out-of-the box to run the sample pagetemplate or for simple
+        implementations that just don't use some elements. When you want
+        to do some customization, this should probably be overridden. For
+        larger customization actions you will have to subclass or roll your
+        own UI object.
+    */
+
+    // first we create a logger
+    var l = new PlainLogger('kupu-toolbox-debuglog', 5);
+
+    // now some config values
+    var conf = loadDictFromXML(document, 'kupuconfig');
+
+    // the we create the document, hand it over the id of the iframe
+    var doc = new KupuDocument(iframe);
+
+    // now we can create the controller
+    var kupu = new KupuEditor(doc, conf, l);
+
+    var contextmenu = new ContextMenu();
+    kupu.setContextMenu(contextmenu);
+
+    // now we can create a UI object which we can use from the UI
+    var ui = new KupuUI('kupu-tb-styles');
+
+    // the ui must be registered to the editor like a tool so it can be notified
+    // of state changes
+    kupu.registerTool('ui', ui); // XXX Should this be a different method?
+
+    // add the buttons to the toolbar
+    var savebuttonfunc = function(button, editor) {editor.saveDocument();};
+    var savebutton = new KupuButton('kupu-save-button', savebuttonfunc);
+    kupu.registerTool('savebutton', savebutton);
+
+    // function that returns a function to execute a button command
+    var execCommand = function(cmd) {
+        return function(button, editor) {
+            editor.execCommand(cmd);
+        };
+    };
+
+    var boldchecker = parentWithStyleChecker(['b', 'strong'],
+                                             'fontWeight', 'bold', 'bold');
+    var boldbutton = new KupuStateButton('kupu-bold-button',
+                                         execCommand('bold'),
+                                         boldchecker,
+                                         'kupu-bold',
+                                         'kupu-bold-pressed');
+    kupu.registerTool('boldbutton', boldbutton);
+
+    var italicschecker = parentWithStyleChecker(['i', 'em'],
+                                              'fontStyle', 'italic', 'italic');
+    var italicsbutton = new KupuStateButton('kupu-italic-button',
+                                            execCommand('italic'),
+                                            italicschecker,
+                                            'kupu-italic',
+                                            'kupu-italic-pressed');
+    kupu.registerTool('italicsbutton', italicsbutton);
+
+    var underlinechecker = parentWithStyleChecker(['u'],
+                                   'textDecoration', 'underline', 'underline');
+    var underlinebutton = new KupuStateButton('kupu-underline-button',
+                                              execCommand('underline'),
+                                              underlinechecker,
+                                              'kupu-underline',
+                                              'kupu-underline-pressed');
+    kupu.registerTool('underlinebutton', underlinebutton);
+
+    var subscriptchecker = parentWithStyleChecker(['sub'],
+                                                  null, null, 'subscript');
+    var subscriptbutton = new KupuStateButton('kupu-subscript-button',
+                                              execCommand('subscript'),
+                                              subscriptchecker,
+                                              'kupu-subscript',
+                                              'kupu-subscript-pressed');
+    kupu.registerTool('subscriptbutton', subscriptbutton);
+
+    var superscriptchecker = parentWithStyleChecker(['super', 'sup'],
+                                                    null, null, 'superscript');
+    var superscriptbutton = new KupuStateButton('kupu-superscript-button',
+                                                execCommand('superscript'),
+                                                superscriptchecker,
+                                                'kupu-superscript',
+                                                'kupu-superscript-pressed');
+    kupu.registerTool('superscriptbutton', superscriptbutton);
+
+    var justifyleftbutton = new KupuButton('kupu-justifyleft-button',
+                                           execCommand('justifyleft'));
+    kupu.registerTool('justifyleftbutton', justifyleftbutton);
+
+    var justifycenterbutton = new KupuButton('kupu-justifycenter-button',
+                                             execCommand('justifycenter'));
+    kupu.registerTool('justifycenterbutton', justifycenterbutton);
+
+    var justifyrightbutton = new KupuButton('kupu-justifyright-button',
+                                            execCommand('justifyright'));
+    kupu.registerTool('justifyrightbutton', justifyrightbutton);
+
+    var outdentbutton = new KupuButton('kupu-outdent-button', execCommand('outdent'));
+    kupu.registerTool('outdentbutton', outdentbutton);
+
+    var indentbutton = new KupuButton('kupu-indent-button', execCommand('indent'));
+    kupu.registerTool('indentbutton', indentbutton);
+
+    var undobutton = new KupuButton('kupu-undo-button', execCommand('undo'));
+    kupu.registerTool('undobutton', undobutton);
+
+    var redobutton = new KupuButton('kupu-redo-button', execCommand('redo'));
+    kupu.registerTool('redobutton', redobutton);
+
+    var removeimagebutton = new KupuRemoveElementButton('kupu-removeimage-button',
+                                                        'img',
+                                                        'kupu-removeimage');
+    kupu.registerTool('removeimagebutton', removeimagebutton);
+
+    var removelinkbutton = new KupuRemoveElementButton('kupu-removelink-button',
+                                                       'a',
+                                                       'kupu-removelink');
+    kupu.registerTool('removelinkbutton', removelinkbutton);
+
+    // add some tools
+    var colorchoosertool = new ColorchooserTool('kupu-forecolor-button',
+                                                'kupu-hilitecolor-button',
+                                                'kupu-colorchooser');
+    kupu.registerTool('colorchooser', colorchoosertool);
+
+    var listtool = new ListTool('kupu-list-ul-addbutton',
+                                'kupu-list-ol-addbutton',
+                                'kupu-ulstyles',
+                                'kupu-olstyles');
+    kupu.registerTool('listtool', listtool);
+
+    // since we use the inspector we don't need much else ;)
+    var inspector = new KupuInspector('kupu-inspector-form');
+    kupu.registerTool('inspector', inspector);
+
+    var linktool = new LinkTool();
+    kupu.registerTool('linktool', linktool);
+
+    var imagetool = new ImageTool();
+    kupu.registerTool('imagetool', imagetool);
+
+    var tabletool = new TableTool();
+    kupu.registerTool('tabletool', tabletool);
+
+    var showpathtool = new ShowPathTool();
+    kupu.registerTool('showpathtool', showpathtool);
+
+    var viewsourcetool = new ViewSourceTool();
+    kupu.registerTool('viewsourcetool', viewsourcetool);
+
+    // Drawers...
+
+    // Function that returns function to open a drawer
+    var opendrawer = function(drawerid) {
+        return function(button, editor) {
+            drawertool.openDrawer(drawerid);
+        };
+    };
+
+    var imagelibdrawerbutton = new KupuButton('kupu-imagelibdrawer-button',
+                                              opendrawer('imagelibdrawer'));
+    kupu.registerTool('imagelibdrawerbutton', imagelibdrawerbutton);
+
+    var linklibdrawerbutton = new KupuButton('kupu-linklibdrawer-button',
+                                             opendrawer('linklibdrawer'));
+    kupu.registerTool('linklibdrawerbutton', linklibdrawerbutton);
+
+    var linkdrawerbutton = new KupuButton('kupu-linkdrawer-button',
+                                          opendrawer('linkdrawer'));
+    kupu.registerTool('linkdrawerbutton', linkdrawerbutton);
+
+    var tabledrawerbutton = new KupuButton('kupu-tabledrawer-button',
+                                           opendrawer('tabledrawer'));
+    kupu.registerTool('tabledrawerbutton', tabledrawerbutton);
+
+    // create some drawers, drawers are some sort of popups that appear when a
+    // toolbar button is clicked
+    var drawertool = new DrawerTool();
+    kupu.registerTool('drawertool', drawertool);
+
+    var linklibdrawer = new LinkLibraryDrawer(linktool,
+                                              conf.link_xsl_uri,
+                                              conf.link_libraries_uri,
+                                              conf.search_links_uri);
+    drawertool.registerDrawer('linklibdrawer', linklibdrawer);
+
+    var imagelibdrawer = new ImageLibraryDrawer(imagetool,
+                                                conf.image_xsl_uri,
+                                                conf.image_libraries_uri,
+                                                conf.search_images_uri);
+    drawertool.registerDrawer('imagelibdrawer', imagelibdrawer);
+
+    var linkdrawer = new LinkDrawer('kupu-linkdrawer', linktool);
+    drawertool.registerDrawer('linkdrawer', linkdrawer);
+
+    var tabledrawer = new TableDrawer('kupu-tabledrawer', tabletool);
+    drawertool.registerDrawer('tabledrawer', tabledrawer);
+
+    // register some cleanup filter
+    // remove tags that aren't in the XHTML DTD
+    var nonxhtmltagfilter = new NonXHTMLTagFilter();
+    kupu.registerFilter(nonxhtmltagfilter);
+
+    return kupu;
+}