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 [4/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/kupudrawers.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupudrawers.js?rev=928511&r1=928510&r2=928511&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupudrawers.js (original)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupudrawers.js Sun Mar 28 22:53:14 2010
@@ -1,23 +1,27 @@
 /*****************************************************************************
  *
- * Copyright (c) 2003-2005 Kupu Contributors. All rights reserved.
+ * Copyright (c) 2003-2008 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$
 
+function kupu_busy(ed) {
+    if (ed.busy) ed.busy();
+}
+function kupu_notbusy(ed, force) {
+    if (ed.notbusy) ed.notbusy(force);
+}
 function DrawerTool() {
     /* a tool to open and fill drawers
-
-        this tool has to (and should!) only be instantiated once
+       this tool has to (and should!) only be instantiated once
     */
     this.drawers = {};
     this.current_drawer = null;
-    
+
     this.initialize = function(editor) {
         this.editor = editor;
         this.isIE = this.editor.getBrowserName() == 'IE';
@@ -30,7 +34,7 @@ function DrawerTool() {
         drawer.initialize(editor || this.editor, this);
     };
 
-    this.openDrawer = function(id) {
+    this.openDrawer = function(id, args) {
         /* open a drawer */
         if (this.current_drawer) {
             this.closeDrawer();
@@ -39,9 +43,14 @@ function DrawerTool() {
         if (this.isIE) {
             drawer.editor._saveSelection();
         }
-        drawer.createContent();
-        drawer.editor.suspendEditing();
         this.current_drawer = drawer;
+        if (args===undefined) args = [];
+        if (this.isIE) {
+            drawer.initMask(drawer.element);
+        }
+        drawer.createContent.apply(drawer, args);
+        drawer.editor.suspendEditing();
+        drawer.fixMask();
     };
 
     this.updateState = function(selNode) {
@@ -54,28 +63,8 @@ function DrawerTool() {
         this.current_drawer.hide();
         this.current_drawer.editor.resumeEditing();
         this.current_drawer = null;
+        kupu_notbusy(this.editor, true);
     };
-
-//     this.getDrawerEnv = function(iframe_win) {
-//         var drawer = null;
-//         for (var id in this.drawers) {
-//             var ldrawer = this.drawers[id];
-//             // Note that we require drawers to provide us with an
-//             // element property!
-//             if (ldrawer.element.contentWindow == iframe_win) {
-//                 drawer = ldrawer;
-//             };
-//         };
-//         if (!drawer) {
-//             this.editor.logMessage("Drawer not found", 1);
-//             return;
-//         };
-//         return {
-//             'drawer': drawer,
-//             'drawertool': this,
-//             'tool': drawer.tool
-//         };
-//     };
 };
 
 DrawerTool.prototype = new KupuTool;
@@ -85,102 +74,392 @@ function Drawer(elementid, tool) {
 
     this.element = getFromSelector(elementid);
     this.tool = tool;
-    
-    this.initialize = function(editor, drawertool) {
-        this.editor = editor;
-        this.drawertool = drawertool;
-    };
-    
-    this.createContent = function() {
-        /* fill the drawer with some content */
-        // here's where any intelligence and XSLT transformation and such 
-        // is done
-        this.element.style.display = 'block';
-        this.focusElement();
-    };
+}
+var proto = Drawer.prototype;
 
-    this.hide = function() {
-        this.element.style.display = 'none';
-        this.focussed = false;
-    };
+proto.initialize = function(editor, drawertool) {
+    this.editor = editor;
+    this.drawertool = drawertool;
+    // on a small screen, the appearance of the drawer could scroll the screen.
+    // Here we stored the position, so that we can restore it for the user.
+    this.scrollPosition = document.documentElement.scrollTop;
+
+};
+
+proto.createContent = function() {
+    /* fill the drawer with some content */
+    // here's where any intelligence and XSLT transformation and such
+    // is done
+    this.element.style.display = 'block';
+    this.focusElement();
+};
+
+proto.hide = function() {
+    if (this.maskframe) {
+        this.maskframe.style.display='none';
+    }
+    this.element.style.display = 'none';
+    this.focussed = false;
+    document.documentElement.scrollTop = this.scrollPosition; // see initialize
+};
 
-    this.focusElement = function() {
-        // IE can focus the drawer element, but Mozilla needs more help
-        this.focussed = false;
-        var iterator = new NodeIterator(this.element);
-        var currnode = iterator.next();
-        while (currnode) {
-            if (currnode.tagName && (currnode.tagName.toUpperCase()=='BUTTON' ||
-                (currnode.tagName.toUpperCase()=='INPUT' && !(/nofocus/.test(currnode.className)))
-                )) {
-                this.focussed = true;
-                function focusit() {
+proto.focusElement = function() {
+    // IE can focus the drawer element, but Mozilla needs more help
+    this.focussed = false;
+    var iterator = new NodeIterator(this.element);
+    var currnode = iterator.next();
+    while (currnode) {
+        if (currnode.tagName && (currnode.tagName.toUpperCase()=='BUTTON' ||
+            (currnode.tagName.toUpperCase()=='INPUT' && !(/nofocus/.test(currnode.className)))
+            )) {
+            this.focussed = true;
+            function focusit() {
+                try {
                     currnode.focus();
-                }
-                timer_instance.registerFunction(this, focusit, 100);
-                return;
+                }catch(e){};
             }
-            currnode = iterator.next();
+            timer_instance.registerFunction(this, focusit, 100);
+            return;
         }
+        currnode = iterator.next();
     }
 };
 
-function LinkDrawer(elementid, tool, wrap) {
-    /* Link drawer */
-    this.element = getFromSelector(elementid);
-    this.tool = tool;
-    function wrap(id, tag) {
-        return '#'+this.element.id+' '+tag+'.'+id;
+proto.initMask = function(el) {
+    var e = (this.maskframe = document.getElementById('kupu-maskframe'));
+    if (!this.maskframe) {
+        e = this.maskframe = newElement('iframe',
+            {'id':'kupu-maskframe','src':"javascript:false;", 'frameBorder':"0", 'scrolling':"no" });
+        var style = e.style;
+        style.display = 'none';
+    }
+    el.parentNode.insertBefore(e, el);
+};
+
+proto.fixMask = function() {
+    var mask = this.maskframe;
+    if (mask) {
+        if (mask.parentNode != this.element.parentNode) {
+            this.element.parentNode.insertBefore(mask, this.element);
+        }
+        // display the mask to hide SELECT boxes in IE
+        var el = this.element;
+        var st = mask.style;
+        var st1 = el.style;
+        st.top=st1.top;
+        st.left=st1.left;
+        st.width = el.offsetWidth+'px';
+        st.height = el.offsetHeight+'px';
+        st.left = (el.offsetLeft)+'px';
+        st.position = 'absolute';
+        st.display = '';
+    }
+};
+
+proto.switchMode = function(event) {
+    event = event || window.event;
+    var target = event.currentTarget || event.srcElement;
+    var el = target;
+    while (!(/^li$/i.test(el.nodeName))) { el = el.parentNode; };
+    var thistab = el;
+    while (!(/^ul$/i.test(el.nodeName))) { el = el.parentNode; };
+    var tabs = el.getElementsByTagName('li');
+    for (var i = 0; i < tabs.length; i++) {
+        var el = tabs[i];
+        var cls = el.className.replace(/\s*selected/g, '');
+        if (el===thistab) {
+            this.panel.className = 'kupu-panels '+cls;
+            cls += ' selected';
+        }
+        if (el.className != cls) {
+            el.className = cls;
+        }
+    }
+    if (this.fillList) this.fillList();
+    this.fixMask();
+    if (event.preventDefault) { event.preventDefault();}
+    event.returnValue = false;
+    return false;
+};
+
+
+function DrawerWithAnchors(editor, drawertool, anchorui) {
+    Drawer.call(this, editor, drawertool);
+    this.anchorui = anchorui;
+    this.anchorframe = null;
+}
+DrawerWithAnchors.prototype = new Drawer;
+proto = DrawerWithAnchors.prototype;
+
+proto.initAnchors = function() {
+    var limit = 40;
+    var anchorframe = this.anchorframe;
+    var ed = this.editor;
+    function onloadEvent() {
+        var state = anchorframe.readyState;
+        if (state && !(/complete/.test(state))) {
+            if (limit-- && anchorframe.src==src) {
+                timer_instance.registerFunction(this, onloadEvent, 500);
+            } else {
+                kupu_notbusy(ed, true);
+            }
+            return;
+        };
+        if(window.drawertool && window.drawertool.current_drawer) {
+            window.drawertool.current_drawer.anchorframe_loaded();
+        };
+        kupu_notbusy(ed);
+    };
+
+    var id = 'kupu-linkdrawer-anchors';
+    var base = (this.anchorui = getBaseTagClass(this.element, 'div', id));
+    if (base) {
+        var inp = base.getElementsByTagName('input');
+        if (inp.length > 1) {
+            inp[1].disabled = true;
+        }
+        var src = inp[0].value;
+        inp[0].value = "";
+        if (!src) { return; }
+        kupu_busy(ed);
+        if (this.anchorframe.readyState) { // IE
+            anchorframe.src = src;
+            onloadEvent();
+        } else { // FF
+            this.anchorframe.onload = onloadEvent;
+            anchorframe.src = src;
+        }
+    }
+};
+proto.anchorSelect = function() {
+    return this.anchorui && this.anchorui.getElementsByTagName('select')[0];
+};
+
+proto.addSelectEvent = function() {
+    var s = this.anchorSelect();
+    if (s) {
+        addEventHandler(s, 'change', this.selChange, this);
+    }
+};
+
+proto.hideAnchors = function() {
+    this.anchorui.style.display = 'none';
+};
+
+proto.anchorText = function(a) {
+    // Text inside anchor, or immediate sibling block tag, or parent block.
+    var blocktag = /^div|p|body|td|h.$/i;
+    var txt = '';
+    var prefix = '#' + a.name;
+
+    for (var node = a; node && !txt; node=node.parentNode) {
+        var txt = node.textContent || node.innerText || '';
+        if (txt || blocktag.test(node.nodeName)) {
+            break;
+        }
+
+        for (var sibling = node.nextSibling; sibling && !txt; sibling = sibling.nextSibling) {
+            if (sibling.nodeName.toLowerCase()=='#text') {
+                txt = sibling.data.strip();
+            } else {
+                txt += sibling.textContent || sibling.innerText ||'';
+            };
+            txt = txt.strip();
+        }
+    }
+    if (txt) {
+        txt = ' (' + (txt||'').substring(0,80).reduceWhitespace().strip()+')';
+    }
+    return prefix + txt;
+};
+
+proto.selChange = function() {};
+
+proto.anchorframe_loaded = function() {
+    this.showAnchors('');
+};
+
+proto.showAnchors = function(selected) {
+    var select = this.anchorSelect();
+    if (select == undefined) return;
+    var opts = select.options;
+
+    while (opts.length > 1) opts[1] = null;
+    try {
+        var doc = this.anchorframe.contentWindow.document;
+        var anchors = doc.anchors;
+    } catch(e) {
+        this.hideAnchors();
+        return;
+    }
+    for (var i = 0; i < anchors.length; i++) {
+        var a = anchors[i];
+        if (a.name) {
+            var opt = document.createElement('option');
+            opt.text = this.anchorText(anchors[i]);
+            var v = anchors[i].name;
+            opt.value = v;
+            if (v==selected) opt.selected = true;
+            select.options.add(opt);
+        }
     }
+    select.disabled = false;
+    if (opts.length > 1) {
+        this.anchorui.style.display = '';
+    }
+};
+
+proto.getFragment = function() {
+    var select = this.anchorSelect();
+    if (select) {
+        var anchor = select.options[select.selectedIndex].value;
+        if (anchor) return '#' + anchor;
+    }
+    return '';
+};
+
+function LinkDrawer(elementid, tool) {
+    /* Link drawer */
+    DrawerWithAnchors.call(this, elementid, tool);
+
     var input = getBaseTagClass(this.element, 'input', 'kupu-linkdrawer-input');
+    var embed = getBaseTagClass(this.element, 'textarea', 'kupu-embed-input');
     var preview = getBaseTagClass(this.element, 'iframe', 'kupu-linkdrawer-preview');
+    var watermark = getBaseTagClass(this.element, 'div', 'watermark');
+    this.anchorframe = preview;
+    this.anchorui = getBaseTagClass(this.element, 'tr', 'kupu-linkdrawer-anchors');
+    this.target = '';
+    this.panel = getBaseTagClass(this.element, 'div', 'kupu-panels');
+    var kuputabs = getBaseTagClass(this.element, 'ul', 'kupu-tabs');
+    if (kuputabs) {
+	var tabs = kuputabs.getElementsByTagName('a');
+	for (var i = 0; i < tabs.length; i++) {
+            addEventHandler(tabs[i], 'click', this.switchMode, this);
+	}
+    }
+    if (embed) {
+	addEventHandler(embed, 'click', function() { if(embed.defaultValue==embed.value) {embed.select();} });
+    }
+
+    this.selChange = function() {
+        var anchor = this.getFragment();
+
+        input.value = input.value.replace(/#[^#]*$/, '');
+        if (anchor) {
+            input.value += anchor;
+        }
+    };
+    this.addSelectEvent();
 
     this.createContent = function() {
         /* display the drawer */
-        var currnode = this.editor.getSelectedNode();
-        var linkel = this.editor.getNearestParentOfType(currnode, 'a');
+        var ed = this.editor;
+        var currnode = ed.getSelectedNode();
+        var linkel = ed.getNearestParentOfType(currnode, 'a');
         input.value = "";
+
         this.preview();
         if (linkel) {
             input.value = linkel.getAttribute('href');
         } else {
             input.value = 'http://';
         };
+        var obj = ed.getNearestParentOfType(currnode, 'object') || ed.getNearestParentOfType(currnode, 'embed');
+        if (obj) {
+            embed.value = getOuterHtml(obj);
+        } else {
+            embed.value = embed.defaultValue;
+        }
         this.element.style.display = 'block';
+        this.hideAnchors();
         this.focusElement();
     };
 
     this.save = function() {
         /* add or modify a link */
         this.editor.resumeEditing();
-        var url = input.value;
-        var target = '_self';
-        if (this.target) target = this.target;
-        this.tool.createLink(url, null, null, target);
-        input.value = '';
-
+        if (this.getMode()) {
+            var url = input.value;
+            this.tool.createLink(url, null, null, this.target, null, 'external-link');
+            input.value = '';
+        } else {
+            // Import the html
+            var doc = this.editor.getInnerDocument();
+            var selection = this.editor.getSelection();
+            var dummy = doc.createElement("div");
+            dummy.innerHTML = embed.value;
+            try {
+                for (var j=dummy.childNodes.length-1; j >= 0; j--) {
+                    var c = dummy.childNodes[j];
+                    if (/^\//.test(c.nodeName))
+                    {
+                        dummy.removeChild(c);
+                    }
+                }
+                while (dummy.firstChild) {
+                    var c= dummy.firstChild;
+                    selection.replaceWithNode(c, !c.nextSibling);
+                };
+            } catch(e) {};
+        }
         // XXX when reediting a link, the drawer does not close for
         // some weird reason. BUG! Close the drawer manually until we
         // find a fix:
         this.drawertool.closeDrawer();
     };
-    
+
+
+    function currentAnchor() {
+        var bits = input.value.split('#');
+        var current = bits.length > 1 ? bits[bits.length-1] : '';
+        return current;
+    }
+
+    this.getMode = function() {
+        return !!(/addlink/.test(this.panel.className));
+    };
     this.preview = function() {
-        preview.src = input.value;
-        if (this.editor.getBrowserName() == 'IE') {
-            preview.width = "800";
-            preview.height = "365";
-            preview.style.zoom = "60%";
+        if (this.getMode()) {
+            var ok = false;
+            watermark.style.display='';
+            if (/^http(s?):\x2f\x2f./.test(input.value)) {
+                try {
+                    preview.src = input.value;
+                    ok = true;
+                } catch(e) { alert('Preview blew up"'+input.value+'"');};
+            } else {
+                preview.src = '';
+                if (input.value.strip()) {
+                    alert(_('Can only preview web urls'));
+                }
+            }
+            if (ok) {
+                this.showAnchors(currentAnchor());
+                if (this.editor.getBrowserName() == 'IE') {
+                    preview.width = "800";
+                    preview.height = "365";
+                    preview.style.zoom = "60%";
+                };
+            }
         };
-    }
+    };
+
     this.preview_loaded = function() {
-        if (input.value  != preview.src) {
-            input.value = preview.src;
+        watermark.style.display = (/^http(s?):\x2f\x2f./.test(input.value))?'none':'';
+        var here = input.value;
+        try {
+            var there = preview.contentWindow.location.href;
+        } catch(e) { return; }
+
+        if (there && here != there && !(/^about:/.test(there))) {
+            input.value = there;
         }
-    }
+        this.showAnchors(currentAnchor());
+    };
+    addEventHandler(preview, "load", this.preview_loaded, this);
 };
 
-LinkDrawer.prototype = new Drawer;
+LinkDrawer.prototype = new DrawerWithAnchors;
 
 function TableDrawer(elementid, tool) {
     /* Table drawer */
@@ -221,9 +500,9 @@ function TableDrawer(elementid, tool) {
         };
         fixClasses(addclassselect);
         fixClasses(editclassselect);
-        
-        var table = editor.getNearestParentOfType(selNode, 'table');
 
+        var table = editor.getNearestParentOfType(selNode, 'table');
+        var show, hide;
         if (!table) {
             // show add table drawer
             show = this.addpanel;
@@ -251,41 +530,55 @@ function TableDrawer(elementid, tool) {
         this.tool.createTable(parseInt(rows), parseInt(cols), add_header, style);
         this.drawertool.closeDrawer();
     };
+
     this.delTableRow = function() {
         this.editor.resumeEditing();
         this.tool.delTableRow();
         this.editor.suspendEditing();
     };
+
     this.addTableRow = function() {
         this.editor.resumeEditing();
         this.tool.addTableRow();
         this.editor.suspendEditing();
     };
+
     this.delTableColumn = function() {
         this.editor.resumeEditing();
         this.tool.delTableColumn();
         this.editor.suspendEditing();
     };
+
     this.addTableColumn = function() {
         this.editor.resumeEditing();
         this.tool.addTableColumn();
         this.editor.suspendEditing();
     };
+
     this.fixTable = function() {
         this.editor.resumeEditing();
         this.tool.fixTable();
         this.editor.suspendEditing();
     };
+
     this.fixAllTables = function() {
         this.editor.resumeEditing();
         this.tool.fixAllTables();
         this.editor.suspendEditing();
     };
+
+    this.delTable = function() {
+        this.editor.resumeEditing();
+        this.tool.delTable();
+        this.drawertool.closeDrawer();
+    };
+
     this.setTableClass = function(className) {
         this.editor.resumeEditing();
         this.tool.setTableClass(className);
         this.editor.suspendEditing();
     };
+
     this.setColumnAlign = function(align) {
         this.editor.resumeEditing();
         this.tool.setColumnAlign(align);
@@ -295,18 +588,22 @@ function TableDrawer(elementid, tool) {
 
 TableDrawer.prototype = new Drawer;
 
-function LibraryDrawer(tool, xsluri, libsuri, searchuri, baseelement) {
-    /* a drawer that loads XSLT and XML from the server 
+function LibraryDrawer(tool, xsluri, libsuri, searchuri, baseelement, selecturi) {
+    /* a drawer that loads XSLT and XML from the server
        and converts the XML to XHTML for the drawer using the XSLT
 
        there are 2 types of XML file loaded from the server: the first
-       contains a list of 'libraries', partitions for the data items, 
+       contains a list of 'libraries', partitions for the data items,
        and the second a list of data items for a certain library
 
        all XML loading is done async, since sync loading can freeze Mozilla
     */
+    this.showupload = '';
+    this.showanchors = '';
+    this.multiple = false;
+    this.currentSelection = [];
 
-    this.init = function(tool, xsluri, libsuri, searchuri, baseelement) {
+    this.init = function(tool, xsluri, libsuri, searchuri, baseelement, selecturi) {
         /* This method is there to thin out the constructor and to be
            able to inherit it in sub-prototypes. Don't confuse this
            method with the component initializer (initialize()).
@@ -318,92 +615,122 @@ function LibraryDrawer(tool, xsluri, lib
         this.librariespanelid = 'kupu-librariespanel';
         this.resourcespanelid = 'kupu-resourcespanel';
         this.propertiespanelid = 'kupu-propertiespanel';
+        this.breadcrumbsid = 'kupu-breadcrumbs';
 
         if (baseelement) {
             this.baseelement = getFromSelector(baseelement);
         } else {
             this.baseelement = getBaseTagClass(document.body, 'div', 'kupu-librarydrawer-parent');
         }
-
+        this.anchorframe = getBaseTagClass(this.baseelement, 'iframe', 'kupu-anchorframe');
+        var e;
         this.tool = tool;
         this.element = document.getElementById(this.drawerid);
         if (!this.element) {
-            var e = document.createElement('div');
+            e = document.createElement('div');
             e.id = this.drawerid;
             e.className = 'kupu-drawer '+this.drawerid;
             this.baseelement.appendChild(e);
             this.element = e;
         }
         this.shared.xsluri = xsluri;
-        this.shared.libsuri = libsuri;
-        this.shared.searchuri = searchuri;
-        
+        this.libsuri = libsuri;
+        this.searchuri = searchuri;
+        this.selecturi = selecturi;
+
         // marker that gets set when a new image has been uploaded
         this.shared.newimages = null;
 
         // the following vars will be available after this.initialize()
         // has been called
-    
+
         // this will be filled by this._libXslCallback()
         this.shared.xsl = null;
-        // this will be filled by this.loadLibraries(), which is called 
-        // somewhere further down the chain starting with 
+        // this will be filled by this.loadLibraries(), which is called
+        // somewhere further down the chain starting with
         // this._libsXslCallback()
-        this.shared.xmldata = null;
+        this.xmldata = null;
 
     };
     if (tool) {
-        this.init(tool, xsluri, libsuri, searchuri);
+        this.init(tool, xsluri, libsuri, searchuri, baseelement, selecturi);
     }
 
     this.initialize = function(editor, drawertool) {
         this.editor = editor;
         this.drawertool = drawertool;
-        this.selecteditemid = '';
 
         // load the xsl and the initial xml
-        var wrapped_callback = new ContextFixer(this._libsXslCallback, this);
-        this._loadXML(this.shared.xsluri, wrapped_callback.execute);
+        this._loadXML(this.shared.xsluri, this._libsXslCallback);
+    };
+
+    this.hide = function() {
+        var el = this.element;
+        el.style.left = el.style.top = '';
+        LibraryDrawer.prototype.hide.call(this);
     };
 
+
+
+
     /*** bootstrapping ***/
 
     this._libsXslCallback = function(dom) {
         /* callback for when the xsl for the libs is loaded
-        
+
             this is called on init and since the initial libs need
             to be loaded as well (and everything is async with callbacks
             so there's no way to wait until the XSL is loaded) this
             will also make the first loadLibraries call
         */
         this.shared.xsl = dom;
+        Sarissa.getDomDocument(); /* Work round Sarissa initialisation glitch */
 
-        // Change by Paul to have cached xslt transformers for reuse of 
+        // Change by Paul to have cached xslt transformers for reuse of
         // multiple transforms and also xslt params
         try {
             var xsltproc =  new XSLTProcessor();
             this.shared.xsltproc = xsltproc;
             xsltproc.importStylesheet(dom);
+            xsltproc.setParameter("", "ie", this.editor.getBrowserName() == 'IE');
             xsltproc.setParameter("", "drawertype", this.drawertype);
             xsltproc.setParameter("", "drawertitle", this.drawertitle);
             xsltproc.setParameter("", "showupload", this.showupload);
-            if (this.editor.config.captions) {
+            xsltproc.setParameter("", "showanchors", this.showanchors);
+            if (this.target !== undefined) {
+                xsltproc.setParameter("", "link_target", this.target);
+            }
+            if (this.editor.config && !!this.editor.config.captions) {
                 xsltproc.setParameter("", "usecaptions", 'yes');
             }
         } catch(e) {
+            if (e && e.name && e.message) e = e.name+': '+e.message;
+            alert("xlstproc error:" + e);
             return; // No XSLT Processor, maybe IE 5.5?
         }
+        if (this.xmldata) {
+            this.updateDisplay(this.drawerid);
+        };
+    };
+
+    this.setTitle = function(t) {
+        this.drawertitle = t;
+        var xsltproc = this.shared.xsltproc;
+        if (xsltproc) {
+            xsltproc.setParameter("", "drawertitle", this.drawertitle);
+        };
     };
 
     this.createContent = function() {
+        this.removeSelection();
         // Make sure the drawer XML is in the current Kupu instance
         if (this.element.parentNode != this.baseelement) {
             this.baseelement.appendChild(this.element);
         }
         // load the initial XML
-        if(!this.shared.xmldata) {
-            // Do a meaningful test to see if this is IE5.5 or some other 
-            // editor-enabled version whose XML support isn't good enough 
+        if(!this.xmldata) {
+            // Do a meaningful test to see if this is IE5.5 or some other
+            // editor-enabled version whose XML support isn't good enough
             // for the drawers
             if (!window.XSLTProcessor) {
                alert("This function requires better XML support in your browser.");
@@ -411,6 +738,11 @@ function LibraryDrawer(tool, xsluri, lib
             }
             this.loadLibraries();
         } else {
+            var libraries = this.xmldata.selectSingleNode("/libraries");
+            var old = libraries.selectSingleNode("library[@id='kupu-current-selection']");
+            if (old) {
+                libraries.removeChild(old);
+            }
             if (this.shared.newimages) {
                 this.reloadCurrent();
                 this.shared.newimages = null;
@@ -434,8 +766,7 @@ function LibraryDrawer(tool, xsluri, lib
 
     this.loadLibraries = function() {
         /* load the libraries and display them in a redrawn drawer */
-        var wrapped_callback = new ContextFixer(this._libsContentCallback, this);
-        this._loadXML(this.shared.libsuri, wrapped_callback.execute);
+        this._loadXML(this.libsuri, this._libsContentCallback);
     };
 
     this._libsContentCallback = function(dom) {
@@ -444,8 +775,8 @@ function LibraryDrawer(tool, xsluri, lib
             does the xslt transformation to set up or renew the drawer's full
             content and adds the content to the drawer
         */
-        this.shared.xmldata = dom;
-        this.shared.xmldata.setProperty("SelectionLanguage", "XPath");
+        this.xmldata = dom;
+        this.xmldata.setProperty("SelectionLanguage", "XPath");
 
         // replace whatever is in there with our stuff
         this.updateDisplay(this.drawerid);
@@ -453,13 +784,17 @@ function LibraryDrawer(tool, xsluri, lib
     };
 
     this.initialSelection = function() {
+        if (this.selectedSrc && this.selecturi) {
+            this.selectCurrent();
+            return;
+        }
         var libnode_path = '/libraries/library[@selected]';
-        var libnode = this.shared.xmldata.selectSingleNode(libnode_path);
+        var libnode = this.xmldata.selectSingleNode(libnode_path);
         if (libnode) {
             var id = libnode.getAttribute('id');
             this.selectLibrary(id);
         }
-    }
+    };
 
     this.updateDisplay = function(id) {
       /* (re-)transform XML and (re-)display the necessary part
@@ -467,31 +802,71 @@ function LibraryDrawer(tool, xsluri, lib
         if(!id) {
             id = this.drawerid;
         };
-        try {
-            this.shared.xsltproc.setParameter("", "showupload", this.showupload);
-        } catch(e) {};
+
+        var xsltproc = this.shared.xsltproc;
+        if (!xsltproc) {
+            return;
+        }
+        for (var k in this.options) {
+            xsltproc.setParameter("", k, this.options[k]);
+        }
+        xsltproc.setParameter("", "multiple", this.multiple ? "yes" : "");
+        xsltproc.setParameter("", "showupload", this.showupload ? "yes" : "");
+        xsltproc.setParameter("", "showanchors", this.showanchors);
+
         var doc = this._transformXml();
         var sourcenode = doc.selectSingleNode('//*[@id="'+id+'"]');
         var targetnode = document.getElementById(id);
-        sourcenode = document.importNode(sourcenode, true);
+        if (!sourcenode || !targetnode) return;
+
+        var cls = sourcenode.getAttribute('class');
+        if (cls) {
+            targetnode.className = cls;
+        }
         Sarissa.copyChildNodes(sourcenode, targetnode);
         if (!this.focussed) {
             this.focusElement();
         }
+        var el = document.getElementById('kupu-preview-image');
+        if (el && el.width=='1') {
+            kupuFixImage(el);
+        }
+        // Mark drawer as having a selection or not
+        var el = this.element;
+        el.className = el.className.replace(' kupu-has-selection', '');
+        if (this.xmldata.selectSingleNode("//*[@selected]//*[@checked]")) {
+            this.element.className += ' kupu-has-selection';
+        };
 
         if (this.editor.getBrowserName() == 'IE' && id == this.resourcespanelid) {
             this.updateDisplay(this.drawerid);
         };
+        this.fixMask();
+    };
+
+    this.updateResources = function() {
+        if (this.editor.getBrowserName() == 'IE') {
+            this.updateDisplay(this.drawerid);
+        } else {
+            this.updateDisplay(this.breadcrumbsid);
+            this.updateDisplay(this.resourcespanelid);
+            this.updateDisplay(this.propertiespanelid);
+        }
     };
 
     this.deselectActiveCollection = function() {
+        var librariespanel = document.getElementById(this.librariespanelid);
+        if (!librariespanel) return;
+
+        var divs = librariespanel.getElementsByTagName('div');
+        for (var i = 0; i < divs.length; i++) {
+            var div = divs[i];
+            div.className = div.className.replace(/[ -]*selected/,'');
+        }
         /* Deselect the currently active collection or library */
-        while (1) {
+        var selected;
+        while ((selected = this.xmldata.selectSingleNode('//*[@selected]'))) {
             // deselect selected DOM node
-            var selected = this.shared.xmldata.selectSingleNode('//*[@selected]');
-            if (!selected) {
-                return;
-            };
             selected.removeAttribute('selected');
         };
     };
@@ -501,7 +876,7 @@ function LibraryDrawer(tool, xsluri, lib
     this.selectLibrary = function(id) {
         /* unselect the currently selected lib and select a new one
 
-            the selected lib (libraries pane) will have a specific CSS class 
+            the selected lib (libraries pane) will have a specific CSS class
             (selected)
         */
         // remove selection in the DOM
@@ -516,54 +891,67 @@ function LibraryDrawer(tool, xsluri, lib
         };
 
         var libnode_path = '/libraries/library[@id="' + id + '"]';
-        var libnode = this.shared.xmldata.selectSingleNode(libnode_path);
+        var libnode = this.xmldata.selectSingleNode(libnode_path);
         libnode.setAttribute('selected', '1');
 
         var items_xpath = "items";
         var items_node = libnode.selectSingleNode(items_xpath);
-        
+
         if (items_node && !this.shared.newimages) {
             // The library has already been loaded before or was
             // already provided with an items list. No need to do
             // anything except for displaying the contents in the
             // middle pane. Newimages is set if we've lately
             // added an image.
-            this.updateDisplay(this.resourcespanelid);
-            this.updateDisplay(this.propertiespanelid);
+            this.useCollection(libnode);
         } else {
             // We have to load the library from XML first.
             var src_uri = libnode.selectSingleNode('src/text()').nodeValue;
             src_uri = src_uri.strip(); // needs kupuhelpers.js
             // Now load the library into the items pane. Since we have
             // to load the XML, do this via a call back
-            var wrapped_callback = new ContextFixer(this._libraryContentCallback, this);
-            this._loadXML(src_uri, wrapped_callback.execute, null);
+            this._loadXML(src_uri, this._libraryContentCallback, null, false, libnode);
             this.shared.newimages = null;
         };
-        // instead of running the full transformations again we get a 
+    };
+    this.flagSelectedLib = function(id) {
+        // instead of running the full transformations again we get a
         // reference to the element and set the classname...
         var newseldiv = document.getElementById(id);
-        newseldiv.className = 'kupu-libsource-selected';
+        if (newseldiv) {
+            newseldiv.className = 'kupu-libsource-selected';
+        }
     };
 
-    this._libraryContentCallback = function(dom, src_uri) {
+    this._libraryContentCallback = function(dom, src_uri, libnode) {
         /* callback for when a library's contents (item list) is loaded
 
         This is also used as he handler for reloading a standard
         collection.
         */
-        var libnode = this.shared.xmldata.selectSingleNode('//*[@selected]');
+        //var libnode = this.xmldata.selectSingleNode('//*[@selected]');
         var itemsnode = libnode.selectSingleNode("items");
+        var bcnode = libnode.selectSingleNode("breadcrumbs");
         var newitemsnode = dom.selectSingleNode("//items");
+        var newbc = dom.selectSingleNode("//breadcrumbs");
 
         // IE does not support importNode on XML document nodes. As an
-        // evil hack, clonde the node instead.
+        // evil hack, clone the node instead.
 
         if (this.editor.getBrowserName() == 'IE') {
             newitemsnode = newitemsnode.cloneNode(true);
+            if (newbc) newbc = newbc.cloneNode(true);
         } else {
-            newitemsnode = this.shared.xmldata.importNode(newitemsnode, true);
+            newitemsnode = this.xmldata.importNode(newitemsnode, true);
+            if (newbc) newbc = this.xmldata.importNode(newbc, true);
         }
+        if (newbc) {
+            if (bcnode) {
+                libnode.replaceChild(newbc, bcnode);
+            } else {
+                libnode.appendChild(newbc);
+            };
+        };
         if (!itemsnode) {
             // We're loading this for the first time
             libnode.appendChild(newitemsnode);
@@ -571,47 +959,97 @@ function LibraryDrawer(tool, xsluri, lib
             // User has clicked reload
             libnode.replaceChild(newitemsnode, itemsnode);
         };
-        this.updateDisplay(this.resourcespanelid);
-        this.updateDisplay(this.propertiespanelid);
+        this.useCollection(libnode);
     };
 
+    this.selectBreadcrumb = function(item) {
+        var src_uri = item.href;
+        if (/\$src\$$/.test(src_uri)) {
+            var target = this.xmldata.selectSingleNode('//resource[@selected]/uri/text()');
+            if (target) {
+                target = target.nodeValue.strip();
+                src_uri = src_uri.replace(/\$src\$/, encodeURIComponent(target));
+            } else {
+                return false;
+            };
+        };
+        this.deselectActiveCollection();
+        this.removeSelection();
+
+        // Case 2: We've already loaded the data, but there hasn't
+        // been a reference made yet. So, make one :)
+
+        var collnode_path = "/libraries/*[src/text()='" + src_uri + "']";
+        var collnode = this.xmldata.selectSingleNode(collnode_path);
+        if (collnode) {
+            var items_node = collnode.selectSingleNode("items");
+            if (items_node) {
+                collnode.setAttribute('selected', '1');
+                this.useCollection(collnode);
+                return;
+            }
+        };
+
+        // Case 3: We've not loaded the data yet, so we need to load it
+        this._loadXML(src_uri, this._collectionContentCallback, null);
+        return false;
+    };
+
+    this.useCollection = function(collnode) {
+        if (this.currentSelection) {
+            var leafnodes = collnode.selectNodes("//*[@checked]");
+            for (var j = 0; j < leafnodes.length; j++) {
+                leafnodes[j].removeAttribute('checked');
+            };
+            var sel = this.currentSelection;
+            for (var i = 0; i < sel.length; i++) {
+                var leafnodes = collnode.selectNodes("//*[@id='"+sel[i]+"']");
+                for (var j = 0; j < leafnodes.length; j++) {
+                    leafnodes[j].setAttribute('checked', '1');
+                    if (!this.multiple) {
+                        leafnodes[j].setAttribute('selected', '1');
+                    };
+                };
+            };
+        };
+        collnode.setAttribute('selected', '1');
+        this.flagSelectedLib(collnode.getAttribute('id'));
+        this.updateResources();
+    };
     /*** Load a collection ***/
+    this.selectCollection = function(item, tag) {
+        var id = item.id;
 
-    this.selectCollection = function(id) {
+        tag = tag || 'collection';
         this.deselectActiveCollection();
 
         // First turn off current selection, if any
         this.removeSelection();
-        
-        var leafnode_path = "//collection[@id='" + id + "']";
-        var leafnode = this.shared.xmldata.selectSingleNode(leafnode_path);
+
+        var leafnode_path = "//"+tag+"[@id='" + id + "']";
+        var leafnode = this.xmldata.selectSingleNode(leafnode_path);
 
         // Case 1: We've already loaded the data, so we just need to
         // refer to the data by id.
         var loadedInNode = leafnode.getAttribute('loadedInNode');
         if (loadedInNode) {
-            var collnode_path = "/libraries/collection[@id='" + loadedInNode + "']";
-            var collnode = this.shared.xmldata.selectSingleNode(collnode_path);
+            var collnode_path = "/libraries/*[@id='" + loadedInNode + "']";
+            var collnode = this.xmldata.selectSingleNode(collnode_path);
             if (collnode) {
-                collnode.setAttribute('selected', '1');
-                this.updateDisplay(this.resourcespanelid);
-                this.updateDisplay(this.propertiespanelid);
+                this.useCollection(collnode);
                 return;
             };
         };
 
         // Case 2: We've already loaded the data, but there hasn't
         // been a reference made yet. So, make one :)
-        uri = leafnode.selectSingleNode('uri/text()').nodeValue;
-        uri = (new String(uri)).strip(); // needs kupuhelpers.js
-        var collnode_path = "/libraries/collection/uri[text()='" + uri + "']/..";
-        var collnode = this.shared.xmldata.selectSingleNode(collnode_path);
+        var src_uri = leafnode.selectSingleNode('src/text()').nodeValue.strip();
+        var collnode_path = "/libraries/*[src/text()='" + src_uri + "'][items]";
+        var collnode = this.xmldata.selectSingleNode(collnode_path);
         if (collnode) {
             id = collnode.getAttribute('id');
             leafnode.setAttribute('loadedInNode', id);
-            collnode.setAttribute('selected', '1');
-            this.updateDisplay(this.resourcespanelid);
-            this.updateDisplay(this.propertiespanelid);
+            this.useCollection(collnode);
             return;
         };
 
@@ -619,10 +1057,8 @@ function LibraryDrawer(tool, xsluri, lib
         // this is just so we can find the leafnode much easier in the
         // callback.
         leafnode.setAttribute('selected', '1');
-        var src_uri = leafnode.selectSingleNode('src/text()').nodeValue;
-        src_uri = src_uri.strip(); // needs kupuhelpers.js
-        var wrapped_callback = new ContextFixer(this._collectionContentCallback, this);
-        this._loadXML(src_uri, wrapped_callback.execute, null);
+        src_uri = leafnode.selectSingleNode('src/text()').nodeValue.strip();
+        this._loadXML(src_uri, this._collectionContentCallback, null);
     };
 
     this._collectionContentCallback = function(dom, src_uri) {
@@ -631,30 +1067,31 @@ function LibraryDrawer(tool, xsluri, lib
         // that is handled in _libraryContentCallback anyway).
         // We need to give the newly retrieved data a unique ID, we
         // just use the time.
-        date = new Date();
-        time = date.getTime();
+        var date = new Date();
+        var time = date.getTime();
 
         // attach 'loadedInNode' attribute to leaf node so Case 1
         // applies next time.
-        var leafnode = this.shared.xmldata.selectSingleNode('//*[@selected]');
-        leafnode.setAttribute('loadedInNode', time);
-        this.deselectActiveCollection()
+        var leafnode = this.xmldata.selectSingleNode('//*[@selected]');
+        if (leafnode) {
+            leafnode.setAttribute('loadedInNode', time);
+        }
+        this.deselectActiveCollection();
 
         var collnode = dom.selectSingleNode('/collection');
         collnode.setAttribute('id', time);
         collnode.setAttribute('selected', '1');
 
-        var libraries = this.shared.xmldata.selectSingleNode('/libraries');
+        var libraries = this.xmldata.selectSingleNode('/libraries');
 
-        // IE does not support importNode on XML documet nodes
+        // IE does not support importNode on XML document nodes
         if (this.editor.getBrowserName() == 'IE') {
             collnode = collnode.cloneNode(true);
         } else {
-            collnode = this.shared.xmldata.importNode(collnode, true);
+            collnode = this.xmldata.importNode(collnode, true);
         }
         libraries.appendChild(collnode);
-        this.updateDisplay(this.resourcespanelid);
-        this.updateDisplay(this.propertiespanelid);
+        this.useCollection(collnode);
     };
 
     /*** Reloading a collection or library ***/
@@ -662,7 +1099,7 @@ function LibraryDrawer(tool, xsluri, lib
     this.reloadCurrent = function() {
         // Reload current collection or library
         this.showupload = '';
-        var current = this.shared.xmldata.selectSingleNode('//*[@selected]');
+        var current = this.xmldata.selectSingleNode('//*[@selected]');
         // make sure we're dealing with a collection even though a
         // resource might be selected
         if (current.tagName == "resource") {
@@ -678,53 +1115,93 @@ function LibraryDrawer(tool, xsluri, lib
         };
 
         var src_uri = src_node.selectSingleNode('text()').nodeValue;
-        
         src_uri = src_uri.strip(); // needs kupuhelpers.js
-
-        var wrapped_callback = new ContextFixer(this._libraryContentCallback, this);
-        this._loadXML(src_uri, wrapped_callback.execute);
+        this._loadXML(src_uri, this._libraryContentCallback, null, true, current);
     };
 
     this.removeSelection = function() {
-        // turn off current selection, if any
-        var oldselxpath = '/libraries/*[@selected]//resource[@selected]';
-        var oldselitem = this.shared.xmldata.selectSingleNode(oldselxpath);
-        if (oldselitem) {
-            oldselitem.removeAttribute("selected");
+        // Mark the drawer as having no selection
+        if (!this.xmldata) return;
+
+        if (!this.multiple) {
+            var items = this.xmldata.selectNodes('//resource[@checked]');
+            for (var i = 0; i < items.length; i++) {
+                items[i].removeAttribute('checked');
+            };
         };
-        if (this.selecteditemid) {
-            var item = document.getElementById(this.selecteditemid);
+
+        // turn off current selection, if any
+        var oldselxpath = '//resource[@selected]';
+        var oldselitems = this.xmldata.selectNodes(oldselxpath);
+        for (var i = 0; i < oldselitems.length; i++) {
+            oldselitems[i].removeAttribute("selected");
+            var id = oldselitems[i].getAttribute('id');
+
+            var item = document.getElementById(id);
             if (item) {
-                var span = item.getElementsByTagName('span');
-                if (span.length > 0) {
-                    span = span[0];
-                    span.className = span.className.replace(' selected-item', '');
+                var spans = item.getElementsByTagName('span');
+                for (var j = 0; j < spans.length; j++) {
+                    var p = spans[j].parentNode;
+                    p.className = p.className.replace(/(\s+|^)selected-item/, '');
                 }
             }
-            this.selecteditemid = '';
         }
         this.showupload = '';
-    }
+    };
 
     this.selectUpload = function() {
         this.removeSelection();
         this.showupload = 'yes';
-        this.updateDisplay(this.resourcespanelid);
-        this.updateDisplay(this.propertiespanelid);
-    }
+        this.updateResources();
+    };
     /*** Selecting a resource ***/
 
-    this.selectItem = function (item, id) {
+    this.selectItem = function (item, event) {
+        var id = item.id;
+        var newselxpath = '/libraries/*[@selected]//resource[@id="' + id + '"]';
+        var src = this.xmldata.selectSingleNode(newselxpath+'/src');
+        if (src) {
+            event = event || window.event;
+            if (event) {
+                var target = event.target || event.srcElement;
+            }
+            if (target.nodeName.toLowerCase()!='input') {
+                this.selectCollection(item, 'resource');
+                return;
+            }
+        }
+
         /* select an item in the item pane, show the item's metadata */
 
         // First turn off current selection, if any
         this.removeSelection();
-        
+
         // Grab XML DOM node for clicked "resource" and mark it selected
-        var newselxpath = '/libraries/*[@selected]//resource[@id="' + id + '"]';
-        var newselitem = this.shared.xmldata.selectSingleNode(newselxpath);
+        var newselitem = this.xmldata.selectSingleNode(newselxpath);
         newselitem.setAttribute("selected", "1");
-        //this.updateDisplay(this.resourcespanelid);
+
+        var check = true;
+        if (this.multiple) {
+            if (newselitem.getAttribute('checked')) {
+                check = false;
+                var sel = this.currentSelection;
+                for (var i=0; i < sel.length; i++) {
+                    if (sel[i]==id) {
+                        sel.splice(i, 1);
+                        break;
+                    };
+                };
+            } else {
+                this.currentSelection.push(id);
+            };
+        } else {
+            this.currentSelection = [id];
+        };
+        if (check) {
+            newselitem.setAttribute('checked','1');
+        } else {
+            newselitem.removeAttribute('checked');
+        };
         this.updateDisplay(this.propertiespanelid);
 
         // Don't want to reload the resource panel xml as it scrolls to
@@ -732,37 +1209,40 @@ function LibraryDrawer(tool, xsluri, lib
         var span = item.getElementsByTagName('span');
         if (span.length > 0) {
             span = span[0];
-            span.className += ' selected-item';
+            var p = span.parentNode;
+            p.className += ' selected-item';
+            var inp = p.getElementsByTagName('input');
+            if (inp) inp[0].checked = check;
         }
-        this.selecteditemid = id;
+
         if (this.editor.getBrowserName() == 'IE') {
-            var ppanel = document.getElementById(this.propertiespanelid)
+            var ppanel = document.getElementById(this.propertiespanelid);
             var height = ppanel.clientHeight;
             if (height > ppanel.scrollHeight) height = ppanel.scrollHeight;
             if (height < 260) height = 260;
             document.getElementById(this.resourcespanelid).style.height = height+'px';
         }
         return;
-    }
+    };
 
 
     this.search = function() {
         /* search */
+        this.removeSelection();
         var searchvalue = getFromSelector('kupu-searchbox-input').value;
         //XXX make search variable configurable
-        var body = 'SearchableText=' + escape(searchvalue);
+        var body = 'SearchableText=' + encodeURIComponent(searchvalue);
 
         // the search uri might contain query parameters in HTTP GET
         // style. We want to do a POST though, so find any possible
         // parameters, trim them from the URI and append them to the
         // POST body instead.
-        var chunks = this.shared.searchuri.split('?');
+        var chunks = this.searchuri.split('?');
         var searchuri = chunks[0];
         if (chunks[1]) {
             body += "&" + chunks[1];
         };
-        var wrapped_callback = new ContextFixer(this._searchCallback, this);
-        this._loadXML(searchuri, wrapped_callback.execute, body);
+        this._loadXML(searchuri, this._searchCallback, body);
     };
 
     this._searchCallback = function(dom) {
@@ -776,8 +1256,8 @@ function LibraryDrawer(tool, xsluri, lib
 
         // we need to give the newly retrieved data a unique ID, we
         // just use the time.
-        date = new Date();
-        time = date.getTime();
+        var date = new Date();
+        var time = date.getTime();
         resultlib.setAttribute("id", time);
 
         // deselect the previous collection and mark the result
@@ -789,14 +1269,58 @@ function LibraryDrawer(tool, xsluri, lib
         if (this.editor.getBrowserName() == 'IE') {
             resultlib = resultlib.cloneNode(true);
         } else {
-            this.shared.xmldata.importNode(resultlib, true);
+            resultlib = this.xmldata.importNode(resultlib, true);
         }
-        var libraries = this.shared.xmldata.selectSingleNode("/libraries");
+        var libraries = this.xmldata.selectSingleNode("/libraries");
         libraries.appendChild(resultlib);
 
         this.updateDisplay(this.drawerid);
         var newseldiv = getFromSelector(time);
-        newseldiv.className = 'selected';
+        newseldiv.className = 'kupu-libsource-selected';
+    };
+
+    this.selectCurrent = function() {
+        var src = this.selectedSrc;
+        var body = 'src=' + encodeURIComponent(src);
+
+        // the uri might contain query parameters in HTTP GET
+        // style. We want to do a POST though, so find any possible
+        // parameters, trim them from the URI and append them to the
+        // POST body instead.
+        var chunks = this.selecturi.split('?');
+        var uri = chunks[0];
+        if (chunks[1]) {
+            body += "&" + chunks[1];
+        };
+        this._loadXML(uri, this._selectedCallback, body);
+    };
+
+    this._selectedCallback = function(dom) {
+        var resultlib = dom.selectSingleNode("/library");
+        var id = "kupu-current-selection";
+        resultlib.setAttribute("id", id);
+        var leafnodes = resultlib.selectNodes("//resource");
+        this.currentSelection = [];
+        for (var i = 0; i < leafnodes.length; i++) {
+            this.currentSelection.push(leafnodes[i].getAttribute('id'));
+        };
+        // deselect the previous collection and mark the result
+        // library as selected
+        this.deselectActiveCollection();
+        resultlib.setAttribute("selected", "1");
+
+        // now hook the result library into our DOM
+        if (this.editor.getBrowserName() == 'IE') {
+            resultlib = resultlib.cloneNode(true);
+        } else {
+            resultlib = this.xmldata.importNode(resultlib, true);
+        }
+        var libraries = this.xmldata.selectSingleNode("/libraries");
+        libraries.appendChild(resultlib);
+        this.useCollection(resultlib);
+        this.updateDisplay(this.librariespanelid);
+        this.flagSelectedLib(id);
+        this.updateDisplay(this.breadcrumbsid);
     };
 
     this.save = function() {
@@ -807,139 +1331,212 @@ function LibraryDrawer(tool, xsluri, lib
     /*** Auxiliary methods ***/
 
     this._transformXml = function() {
-        /* transform this.shared.xmldata to HTML using this.shared.xsl and return it */
-        var doc = Sarissa.getDomDocument();
-	var result = this.shared.xsltproc.transformToDocument(this.shared.xmldata);
+        /* transform this.xmldata to HTML using this.shared.xsl and return it */
+	var result = this.shared.xsltproc.transformToDocument(this.xmldata);
         return result;
     };
 
-    this._loadXML = function(uri, callback, body) {
-        /* load the XML from a uri
-        
-            calls callback with one arg (the XML DOM) when done
-            the (optional) body arg should contain the body for the request
-*/
-	var xmlhttp = new XMLHttpRequest();
-        var method = 'GET';
-        if (body) {
-          method = 'POST';
-        } else {
-          // be sure that body is null and not an empty string or
-          // something
-          body = null;
-        };
-        xmlhttp.open(method, uri, true);
-        // use ContextFixer to wrap the Sarissa callback, both for isolating 
-        // the 'this' problem and to be able to pass in an extra argument 
-        // (callback)
-        var wrapped_callback = new ContextFixer(this._sarissaCallback, xmlhttp,
-                                                callback, uri);
-        xmlhttp.onreadystatechange = wrapped_callback.execute;
-        if (method == "POST") {
-            // by default, we would send a 'text/xml' request, which
-            // is a dirty lie; explicitly set the content type to what
-            // a web server expects from a POST.
-            xmlhttp.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
-        };
-        xmlhttp.send(body);
-    };
-
-    this._sarissaCallback = function(user_callback, uri) {
+    this._loadXML = function(uri, callback, body, reload, extra) {
+        function _sarissaCallback() {
         /* callback for Sarissa
             when the callback is called because the data's ready it
             will get the responseXML DOM and call user_callback
             with the DOM as the first argument and the uri loaded
             as the second
-            
-            note that this method should be called in the context of an 
+
+            note that this method should be called in the context of an
             xmlhttp object
         */
-        var errmessage = 'Error loading XML: ';
-        if (uri) {
-            errmessage = 'Error loading ' + uri + ':';
-        };
-        if (this.readyState == 4) {
-            if (this.status && this.status != 200) {
-                alert(errmessage + this.status);
-                throw "Error loading XML";
+            if (xmlhttp.readyState == 4) {
+                if (xmlhttp.status && xmlhttp.status != 200) {
+                    var errmessage = 'Error '+xmlhttp.status+' loading '+(uri||'XML');
+                    kupu_notbusy(ed, true);
+                    alert(errmessage);
+                    throw "Error loading XML";
+                };
+                var dom = xmlhttp.responseXML;
+                if (!dom || !dom.documentElement) { /* IE bug! */
+                    dom = Sarissa.getDomDocument();
+                    dom.loadXML(xmlhttp.responseText);
+                }
+                callback.apply(self, [dom, uri, extra]);
+                kupu_notbusy(ed);
             };
-            var dom = this.responseXML;
-            user_callback(dom, uri);
         };
+        var self = this;
+        var ed = this.editor;
+        /* load the XML from a uri
+           calls callback with one arg (the XML DOM) when done
+           the (optional) body arg should contain the body for the request
+         */
+	var xmlhttp = new XMLHttpRequest();
+        var method = body?'POST':'GET';
+        // be sure that body is null and not an empty string or
+        // something
+        body=body?body:null;
+
+        kupu_busy(ed);
+        try {
+            xmlhttp.open(method, uri, true);
+            xmlhttp.onreadystatechange = _sarissaCallback;
+            if (method == "POST") {
+                // by default, we would send a 'text/xml' request, which
+                // is a dirty lie; explicitly set the content type to what
+                // a web server expects from a POST.
+                xmlhttp.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
+            };
+            if (reload) {
+                xmlhttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
+            }
+            xmlhttp.send(body);
+        } catch(e) {
+            if (e && e.name && e.message) { // Microsoft
+                e = e.name + ': ' + e.message;
+            }
+            kupu_notbusy(ed, true);
+            alert(e);
+        }
     };
+
 };
 
-LibraryDrawer.prototype = new Drawer;
+LibraryDrawer.prototype = new DrawerWithAnchors;
 LibraryDrawer.prototype.shared = {}; // Shared data
 
-function ImageLibraryDrawer(tool, xsluri, libsuri, searchuri, baseelement) {
+function ImageLibraryDrawer(tool, xsluri, libsuri, searchuri, baseelement, selecturi) {
     /* a specific LibraryDrawer for images */
 
     this.drawertitle = "Insert Image";
     this.drawertype = "image";
-    this.showupload = '';
+
     if (tool) {
-        this.init(tool, xsluri, libsuri, searchuri, baseelement);
+        this.init(tool, xsluri, libsuri, searchuri, baseelement, selecturi);
     }
- 
-    
+
+    this.createContent = function() {
+        function getSel(sel, p, t) {
+            var nodes = p.getElementsByTagName(t);
+            for (var i = 0; i < nodes.length; i++) {
+                if (sel.containsNode(nodes[i])) {
+                    return nodes[i];
+                };
+            };
+        }
+        var ed = this.editor;
+        var sel = ed.getSelection();
+        var currnode = ed.getSelectedNode();
+        var currimg = ed.getNearestParentOfType(currnode, 'OBJECT') || ed.getNearestParentOfType(currnode, 'IMG') ||
+                      getSel(sel, currnode, 'object') || getSel(sel, currnode, 'img');
+        this.selectedSrc = currimg?(currimg.data||currimg.src||null):null;
+        this.options = {};
+        if (currimg) {
+            ed.getSelection().selectNodeContents(currimg);
+            var className = currimg.className;
+            var align = /\bimage-(left|right|inline)\b/.exec(className);
+            if (align && align.length > 1) {
+                this.options['image-align'] = align[1];
+            };
+            this.options['image-caption'] = /\bcaptioned\b/.test(className);
+            this.options['image-class'] = className.replace(/\b(image-(left|right|inline)|captioned)\b/g,'').strip();
+        }
+        ImageLibraryDrawer.prototype.createContent.call(this);
+    };
+
     // upload, on submit/insert press
     this.uploadImage = function() {
-        var form = document.kupu_upload_form;
-        if (!form || form.node_prop_image.value=='') return;
+        var form = document.getElementById('kupu_upload_form');
+        if (!form || (form.node_prop_image && form.node_prop_image.value == '')) {
+            return;
+        }
 
-        if (form.node_prop_caption.value == "") {
+        if (form.node_prop_title && form.node_prop_title.value == "") {
             alert("Please enter a title for the image you are uploading");
-            return;        
+            return;
         };
-        
-        var targeturi =  this.shared.xmldata.selectSingleNode('/libraries/*[@selected]/uri/text()').nodeValue
-        document.kupu_upload_form.action =  targeturi + "/kupuUploadImage";
-        document.kupu_upload_form.submit();
+        this.upload_title = form.node_prop_title ? form.node_prop_title.value : '';
+        if (form.node_prop_desc) {
+            form.node_prop_desc.value = form.node_prop_desc.value.replace(/^\xa0|\xa0$/g,'');
+        }
+        form.submit();
     };
-    
+
     // called for example when no permission to upload for some reason
     this.cancelUpload = function(msg) {
-        var s = this.shared.xmldata.selectSingleNode('/libraries/*[@selected]');     
+        var s = this.xmldata.selectSingleNode('/libraries/*[@selected]');
         s.removeAttribute("selected");
         this.updateDisplay();
         if (msg != '') {
             alert(msg);
         };
     };
-    
+
     // called by onLoad within document sent by server
-    this.finishUpload = function(url) {
+    this.finishUpload = function(uri, media, width, height) {
         this.editor.resumeEditing();
-        var imgclass = 'image-inline';
-        if (this.editor.config.captions) {
+        var sizeselector = document.getElementsByName('image-size-selector');
+        if (sizeselector && sizeselector.length > 0) {
+            sizeselector = sizeselector[0];
+            var index = sizeselector.selectedIndex;
+            if (sizeselector.length > 0 && index >= 0) {
+                uri += sizeselector.options[index].value;
+            }
+        }
+        var radios = document.getElementsByName('image-align');
+        var imgclass = "";
+        for (var i = 0; i < radios.length; i++) {
+            if (radios[i].checked) {
+                imgclass = radios[i].value;
+            };
+        };
+        var caption = document.getElementsByName('image-caption');
+        if (caption && caption.length>0 && caption[0].checked) {
             imgclass += " captioned";
         };
-        this.tool.createImage(url, null, imgclass);
+        var classnames = document.getElementById('kupu-image-class');
+        if (classnames && classnames.selectedIndex >= 0) {
+            imgclass += " "+classnames.options[classnames.selectedIndex].value;
+        } else {
+            imgclass += ' image-inline';
+        }
+        imgclass = imgclass.strip();
+
+        if (media !== undefined && this.tool['create_' + media]) {
+            this.tool['create_' + media](uri, this.upload_title, imgclass, width, height);
+        } else {
+            this.tool.createImage(uri, this.upload_title, imgclass);
+        }
+
         this.shared.newimages = 1;
         this.drawertool.closeDrawer();
     };
-    
+
 
     this.save = function() {
         this.editor.resumeEditing();
         /* create an image in the iframe according to collected data
            from the drawer */
         var selxpath = '//resource[@selected]';
-        var selnode = this.shared.xmldata.selectSingleNode(selxpath);
-        
+        var selnode = this.xmldata.selectSingleNode(selxpath);
+
         // If no image resource is selected, check for upload
         if (!selnode) {
-            var uploadbutton = this.shared.xmldata.selectSingleNode("/libraries/*[@selected]//uploadbutton");
+            var uploadbutton = this.xmldata.selectSingleNode("/libraries/*[@selected]//uploadbutton");
             if (uploadbutton) {
                 this.uploadImage();
             };
             return;
         };
 
-        var uri = selnode.selectSingleNode('uri/text()').nodeValue;
+        var sizeselector = document.getElementsByName('image-size-selector');
+        if (sizeselector && sizeselector.length > 0) {
+            sizeselector = sizeselector[0];
+            var uri = sizeselector.options[sizeselector.selectedIndex].value;
+        } else {
+            var uri = selnode.selectSingleNode('uri/text()').nodeValue;
+        }
         uri = uri.strip();  // needs kupuhelpers.js
-        var alt = getFromSelector('image_alt').value;
+        var alt = getFromSelector('image-alt');
+        alt = alt?alt.value:undefined;
 
         var radios = document.getElementsByName('image-align');
         for (var i = 0; i < radios.length; i++) {
@@ -952,8 +1549,19 @@ function ImageLibraryDrawer(tool, xsluri
         if (caption && caption.length>0 && caption[0].checked) {
             imgclass += " captioned";
         };
-
-        this.tool.createImage(uri, alt, imgclass);
+        var classnames = document.getElementById('kupu-image-class');
+        if (classnames && classnames.selectedIndex >= 0) {
+            imgclass += " "+classnames.options[classnames.selectedIndex].value;
+        }
+        var media = document.getElementById('kupu-media').value;
+        var width = document.getElementById('kupu-width').value;
+        var height = document.getElementById('kupu-height').value;
+        if (this.tool['create_' + media]) {
+            this.tool['create_' + media](uri, alt, imgclass, width, height);
+        } else {
+            this.tool.createImage(uri, alt, imgclass);
+        }
+        kupu.content_changed = true;
         this.drawertool.closeDrawer();
     };
 };
@@ -961,41 +1569,52 @@ function ImageLibraryDrawer(tool, xsluri
 ImageLibraryDrawer.prototype = new LibraryDrawer;
 ImageLibraryDrawer.prototype.shared = {}; // Shared data
 
-function LinkLibraryDrawer(tool, xsluri, libsuri, searchuri, baseelement) {
+function LinkLibraryDrawer(tool, xsluri, libsuri, searchuri, baseelement, selecturi) {
     /* a specific LibraryDrawer for links */
 
     this.drawertitle = "Insert Link";
     this.drawertype = "link";
-    this.showupload = '';
+    this.showanchors = "yes";
+
     if (tool) {
-        this.init(tool, xsluri, libsuri, searchuri, baseelement);
+        this.init(tool, xsluri, libsuri, searchuri, baseelement, selecturi);
     }
 
+    this.createContent = function() {
+        var currnode = this.editor.getSelectedNode();
+        var curranchor = this.editor.getNearestParentOfType(currnode, 'A');
+        this.selectedSrc = curranchor?curranchor.href:null;
+        this.options = {};
+        if (curranchor) {
+            this.options.link_name = curranchor.name || '';
+            this.options.link_target = curranchor.target || '';
+        }
+        LinkLibraryDrawer.prototype.createContent.call(this);
+    };
+
     this.save = function() {
         this.editor.resumeEditing();
         /* create a link in the iframe according to collected data
            from the drawer */
         var selxpath = '//resource[@selected]';
-        var selnode = this.shared.xmldata.selectSingleNode(selxpath);
+        var selnode = this.xmldata.selectSingleNode(selxpath);
         if (!selnode) {
             return;
         };
 
         var uri = selnode.selectSingleNode('uri/text()').nodeValue;
-        uri = uri.strip();  // needs kupuhelpers.js
+        uri = uri.strip() + this.getFragment();
         var title = '';
         title = selnode.selectSingleNode('title/text()').nodeValue;
         title = title.strip();
 
         // XXX requiring the user to know what link type to enter is a
         // little too much I think. (philiKON)
-        var type = null;
         var name = getFromSelector('link_name').value;
-        var target = null;
-        if (getFromSelector('link_target') && getFromSelector('link_target').value != '')
-            target = getFromSelector('link_target').value;
-        
-        this.tool.createLink(uri, type, name, target, title);
+        var node = getFromSelector('link_target');
+        var target = node && node.value;
+
+        this.tool.createLink(uri, null, name, target, title, 'internal-link');
         this.drawertool.closeDrawer();
     };
 };
@@ -1003,23 +1622,216 @@ function LinkLibraryDrawer(tool, xsluri,
 LinkLibraryDrawer.prototype = new LibraryDrawer;
 LinkLibraryDrawer.prototype.shared = {}; // Shared data
 
+function AnchorDrawer(elementid, tool) {
+    Drawer.call(this, elementid, tool);
+
+    this.initialize = function(editor, tool) {
+        Drawer.prototype.initialize.apply(this, [editor, tool]);
+        this.panel = getBaseTagClass(this.element, 'div', 'kupu-panels');
+        this.style1 = getFromSelector('kupu-bm-sel1');
+        this.style2 = getFromSelector('kupu-bm-sel2');
+        this.ostyle = getFromSelector('kupu-bm-outcls');
+        this.nstyle = getFromSelector('kupu-bm-number');
+        var tabs = getBaseTagClass(this.element, 'ul', 'kupu-tabs').getElementsByTagName('a');
+        this.paralist = getBaseTagClass(this.element, 'div', 'kupu-bm-paras');
+        this.checkall = getFromSelector('kupu-bm-checkall');
+
+        for (var i = 0; i < tabs.length; i++) {
+            addEventHandler(tabs[i], 'click', this.switchMode, this);
+        }
+        addEventHandler(this.checkall, 'click', this.checkAll, this);
+        addEventHandler(this.style1, 'change', this.fillList, this);
+        addEventHandler(this.style2, 'change', this.fillList, this);
+        this.tool.fillStyleSelect(this.style1);
+        this.tool.fillStyleSelect(this.style2);
+        this.tool.fillStyleSelect(this.ostyle);
+    };
+    this.getMode = function() { /* tab 0, 1, or 2 */
+        if (/kupu-ins-bm/.test(this.panel.className)) return 0;
+        if (/kupu-anchor/.test(this.panel.className)) return 1;
+        return 2;
+    };
+
+    this.checkAll = function() {
+        var nodes = this.paralist.getElementsByTagName('input');
+        var state = this.checkall.checked;
+        for (var i = 0; i < nodes.length; i++) {
+            var n = nodes[i];
+            if (n.type=="checkbox" && !n.disabled) {
+                nodes[i].checked = state;
+            };
+        };
+    };
+
+    this.fillList = function() {
+        var el = newElement;
+        while (this.paralist.firstChild) {
+            this.paralist.removeChild(this.paralist.firstChild);
+        }
+
+        this.styleNames = ['', ''];
+
+        var mode = this.getMode();
+        var s = ['', ''];
+        for (var idx=0; idx < (mode==2?2:1); idx++) {
+            var sel = this['style'+(idx+1)];
+            var i = sel.selectedIndex;
+            if (i >= 0) {
+                s[idx] = sel.options[i].value;
+                this.styleNames[idx] = sel.options[i].firstChild.data;
+            }
+        }
+
+        if (mode==1) {
+            var inuse = this.tool.getAnchorsInUse();
+        }
+        var paras = (this.nodelist = this.tool.grubParas(s[0], s[1]));
+        for (var i = 0; i < paras.length; i++) {
+            var node = paras[i][0];
+            var text = Sarissa.getText(node, true).strip().truncate(60);
+            if (!text) continue;
+            var content = document.createTextNode(text);
+            var anchor = '';
+            if (mode==1) {
+                anchor = this.tool.getAnchor(node, true);
+                if (anchor) {
+                    anchor = '#'+anchor;
+                }
+            }
+            var checked;
+            switch (mode) {
+                case 0: checked = i==0; break;
+                case 1: checked = !!anchor; break;
+                case 2: checked = this.checkall.checked; break;
+            }
+            var control = el('input', {
+                'type': (mode==0)?"radio":"checkbox",
+                checked: checked, title:'hello',
+                name: "kupu-bm-paralist"});
+            if (anchor && inuse && inuse[decodeURIComponent(anchor)]) {
+                control.disabled = true;
+            }
+
+            var inner = [control, el('span', [content])];
+            if (anchor) {
+                inner.push(el('a', {href:anchor, className:'kupu-anchor-link',onclick:'return false;',
+                    title:_('Right click to copy link')}, [anchor]));
+            };
+            var div = el('div', {className: "kupu-bm-level" + paras[i][1] },
+                [el('label', inner)]);
+
+            this.paralist.appendChild(div);
+        };
+    };
+    this.createContent = function() {
+        this.fillList();
+        this.element.style.display = 'block';
+        this.focusElement();
+    };
+    this.save = function() {
+        var mode = this.getMode();
+        var selected = this.paralist.getElementsByTagName('input');
+        var ed = this.editor;
+
+        ed.resumeEditing();
+
+        if (mode==2) {
+            var toc = ed.newElement('ul');
+        };
+        var lvl1=0, lvl2=0;
+        for (var i = 0; i < selected.length; i++) {
+            var nodeinfo = this.nodelist[i];
+            var node = nodeinfo[0];
+            var level = nodeinfo[1];
+            if (selected[i].checked) {
+                var a = this.tool.getAnchor(node);
+                var caption = Sarissa.getText(node, true).strip().truncate(140);
+                switch (mode) {
+                case 0:
+                    this.tool.createLink('#'+a, null, null, null, caption);
+                    break;
+                case 1:
+                    break;
+                case 2:
+                    /* Insert TOC entry here */
+                    var number;
+                    if (level==0) {
+                        number = ++lvl1;
+                        lvl2 = 0;
+                    } else {
+                        number = lvl1 + '.' + (++lvl2);
+                    };
+                    var li = ed.newElement('li', {'className': 'level'+level},
+                        [ed.newElement('a', {'href': '#'+a},
+                        [ed.newText((this.nstyle.checked?number + ' ':'') + caption)])]);
+
+                    if (level==0) {
+                        toc.appendChild(li);
+                    } else {
+                        if (!toc.lastChild || toc.lastChild.nodeName.toLowerCase() != 'ul') {
+                            toc.appendChild(ed.newElement('ul'));
+                        }
+                        toc.lastChild.appendChild(li);
+                    };
+                    break;
+                };
+            } else {
+                if (mode==1) {
+                    this.tool.removeAnchor(node);
+                }
+            };
+        };
+        if (mode==2 && toc.firstChild) {
+            var o = this.ostyle.selectedIndex;
+            if (o > 0) {
+                var ostyle = this.ostyle.options[o].value.split('|');
+                if (ostyle[0]=='ul') {
+                    toc.className=ostyle[1];
+                } else {
+                    toc = ed.newElement(ostyle[0], {'className': ostyle[1]}, [toc]);
+                };
+            }
+            var node = ed.getSelection().parentElement();
+            if (node.nodeName.toLowerCase() == 'body') {
+                node.insertBefore(toc, node.firstChild);
+            } else {
+                while (node.parentNode.nodeName.toLowerCase() != 'body') {
+                    node = node.parentNode;
+                }
+                node.parentNode.insertBefore(toc, node);
+            }
+        }
+        this.nodelist = null;
+        this.drawertool.closeDrawer();
+    };
+    this.hide = function() {
+        this.nodelist = null;
+        Drawer.prototype.hide.apply(this, []);
+    };
+};
+
+AnchorDrawer.prototype = new Drawer;
+
 /* Function to suppress enter key in drawers */
 function HandleDrawerEnter(event, clickid) {
-    var key;
     event = event || window.event;
-    key = event.which || event.keyCode;
-
+    var key = event.which || event.keyCode;
+    var button;
     if (key==13) {
         if (clickid) {
-            var button = document.getElementById(clickid);
-            if (button) {
+            button = document.getElementById(clickid);
+            if (button && !button.disabled) {
                 button.click();
             }
         }
         event.cancelBubble = true;
-        if (event.stopPropogation) event.stopPropogation();
-
+        if (event.stopPropagation) {
+            event.stopPropagation();
+        }
+        event.returnValue = false;
         return false;
     }
     return true;
 }
+
+

Modified: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupudrawerstyles.css
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupudrawerstyles.css?rev=928511&r1=928510&r2=928511&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupudrawerstyles.css (original)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/inputHtml/resource/kupudrawerstyles.css Sun Mar 28 22:53:14 2010
@@ -21,10 +21,15 @@
   padding: 0 8px 8px 8px;
   height: auto;
   width: 640px;
-  z-index: 2;
+  z-index: 3;
   color: black;
 }
 
+.kupu-maskframe {
+  position:absolute;
+  z-index: 3;
+}
+
 .kupu-tabledrawer {
   width: 408px;
   left: 320px;
@@ -35,10 +40,18 @@
   width: 400px;
 }
 
-.kupu-drawer h1 {
+h1.kupu-library-title {
    height: auto; width: auto;
+   margin-bottom: 0;
+   clear: none;
 }
 
+#kupu-searchbox {
+  float: right;
+}
+#kupu-searchbox form {
+  margin-bottom: 0;
+}
 input#kupu-searchbox-input {
   width: 8em;
   margin-bottom: 6px;
@@ -46,20 +59,53 @@ input#kupu-searchbox-input {
   padding: 2px;
 }
 
+.kupu-title-row label,
+.kupu-description-row label,
+.kupu-alt-row label {
+   display: block;
+}
+
 div.kupu-linkdrawer-addlink td {
   border: 0;
 }
-input.kupu-linkdrawer-input {
+.kupu-alt-row input { width: 220px; }
+.kupu-linkdrawer-input {
+   width: 500px;
+}
+.kupu-embed-input {
    width: 500px;
+   height: 20em;
 }
 iframe.kupu-linkdrawer-preview {
-   width: 100%;
+  width: 100%; height:20em;
+}
+.kupu-preview-row {
+  float: right;
+  text-align:right;
+  padding: 0 0 0.5em 0.5em;
+  background-color: white;
+}
+.kupu-preview-row img {
+   padding-top: 0.5em;
 }
 
-div#kupu-librarydrawer h1, div.kupu-drawer h1 {
+h1.kupu-drawer-title {
   margin-top: 12px;
+  padding: 0;
+  clear:none;
 }
 
+h1.kupu-title-row, div.kupu-description-row {
+   margin-top: 0;
+   padding-top: 0;
+   clear: none;
+   height: auto; line-height: 1.1em;
+}
+.kupu-description-row p { height: auto !IMPORTANT; }
+
+h1.kupu-title-row { font-size: 136%; }
+
+
 div.kupu-dialogbuttons {
   text-align: right;
   margin-top: 6px;
@@ -67,10 +113,6 @@ div.kupu-dialogbuttons {
   width: 640px; /* Mozilla bug */
 }
 
-div.kupu-drawer button {
-  margin-right: 0.3em;
-}
-
 div.kupu-panels {
   width: 100%;
   background-color: ButtonFace;
@@ -92,21 +134,24 @@ div.kupu-panels table {
  margin: 0; 
  padding: 0; 
  border: 0;
+ clear:left;
+ border-spacing: 2px;
 }
 
 td.panel {
-  height: 260px;
+  height: 260px; padding:0; margin:0;
 }
 
 td#kupu-librariespanel {
   overflow: auto;
-  width: 105px;
+  width: 130px;
 }
 
 div#kupu-librariesitems {
-  width: 105px;
-  white-space: pre;
-  height: 100%;
+  width: 130px;
+  white-space: nowrap;
+  height: 260px;
+  padding: 0;
 }
 
 td#kupu-resourcespanel {
@@ -115,22 +160,22 @@ td#kupu-resourcespanel {
 }
 
 div#kupu-resourceitems {
-  white-space: pre;
+  white-space: nowrap;
   width: 200px;
-  height: 100%;
+  padding: 0;
 }
-
-div#kupu-properties {
-  height: 100%;
+.upload-allowed div#kupu-resourceitems {
+  height:236px;
 }
 
-div#kupu-librariesitems, div#kupu-resourceitems, div#kupu-properties {
-  padding: 6px;
+div#kupu-properties {
+  height: 260px;
+  padding: 0 6px;
 }
 
 .overflow {
   overflow: auto;
-  height: 100%;
+  height: 260px;
 }
 
 div.response, div.collection {
@@ -143,27 +188,54 @@ div.response, div.collection {
 }
 
 div.kupu-libsource, div.kupu-libsource-selected,
-div.kupu-resource, div.kupu-collection, div.kupu-upload {
+div.kupu-resource, div.kupu-collection {
   cursor: pointer;
-  margin-bottom: 2px;
+  margin-bottom: 0;
+  padding: 2px 2px 2px 20px;
   vertical-align: text-bottom;
-  white-space: pre;
+  white-space: nowrap;
 }
-div.kupu-upload {
-   text-align: right; font-style: italic;
+
+.kupu-busy, .kupu-busy div, .kupu-busy a:hover, .kupu-busy input , .kupu-busy select {
+  cursor: wait !IMPORTANT;
 }
 
-/*div.kupu-libsource-selected {
-  background-repeat: no-repeat;
-}*/
+div.kupu-resource, div.kupu-collection { padding: 0; }
+div.kupu-resource span, div.kupu-collection span { padding: 4px 1ex 4px 0; }
+div.kupu-resource input, div.kupu-collection input {
+  margin-bottom: 5px;
+  background: transparent;
+  border: none;
+}
 
-/*div.kupu-libsource-selected span,
- div.kupu-libsource span{
-  margin-top: 3px;
-  display: inline;
-}*/
+.drawer-item-radio {
+  vertical-align: text-middle;
+  margin: 0;
+}
+
+.library-icon-library {
+  width:16px; height:16px;
+  margin: 0 2px 0 -18px;
+}
 
-div.kupu-libsource-selected span {
+.kupu-image-fields {
+  width: 270px; margin:0; padding:0;
+}
+.kupu-detail {
+  float:left;
+  width: 185px;
+  margin: 2px 0; padding: 0;
+}
+label.kupu-detail {
+  clear:left; width:75px; text-align:right;
+  margin-right: 5px;
+}
+#image-caption, #image-align-left { margin-left: 0; }
+#image-align-left, #image-align-right, #image-align-inline, #image-caption {
+  border: none;
+}
+
+div.kupu-libsource-selected {
   background-color: ButtonFace;  
 }
 
@@ -172,18 +244,12 @@ div.kupu-libsource-selected span {
 }
 
 img.library-icon-collection, img.library-icon-resource {
-  margin-right: 5px;
+  padding-right: 5px;
   height: 16px;
   width: 16px;
 }
 
-span.drawer-item-title {
-  padding-left: 2px;
-  padding-right: 2px;
-  padding-top: 2px;
-}
-
-span.drawer-item-title.selected-item {
+.selected-item span {
   background-color:#C0C0C0;
 }
 
@@ -207,4 +273,91 @@ th.kupu-toolbox-label {
    text-align:right;
    width: 5%;
    white-space: nowrap;
-}
\ No newline at end of file
+}
+
+ul.kupu-tabs { border-bottom: 1px solid; margin: 0; padding: 0.5em 0.5em 1px 1.5em; }
+.kupu-tabs li {
+  display: inline; padding: 2px; border: 1px solid; margin: 0 5px 0 0;
+}
+.kupu-tabs a { text-decoration: none; }
+.kupu-tabs li.selected { background: white; border-bottom: none !IMPORTANT; padding-bottom: 3px;}
+.kupu-panels table.kupu-tabbed { border:none; border-spacing: 0;}
+
+.kupu-linkdrawer-addlink .kupu-embed,
+.kupu-linkdrawer-embed .kupu-addlink { display: none; }
+.kupu-linkdrawer-addlink .watermark {
+  position: relative;
+  text-align:center;
+  top: 98px;
+  font-size: 20pt;
+}
+.kupu-linkdrawer-addlink .watermark span {
+  background-color: white;
+  opacity:0.5;
+  filter:alpha(opacity=50);
+}
+.kupu-ins-bm .hide-ins-bm, .kupu-anchor .hide-anchor, .kupu-toc .hide-toc {
+  display: none;
+}
+.kupu-ins-bm .invis-ins-bm, .kupu-anchor .invis-anchor, .kupu-toc .invis-toc {
+        visibility: hidden; /* Hide controls without changing surrounding layout */
+}
+
+.image-dimensions {
+  display: none;
+}
+
+table.kupu-ins-bm, table.kupu-toc {
+   height: 20em;
+}
+td.kupu-bm-select {
+   width: 1%;
+}
+.kupu-bm-paras {
+   height: 18em; width:100%;
+   white-space: nowrap;
+   overflow: auto;
+}
+.kupu-bm-level1 SPAN { padding-left: 2em; }
+/* Anchor drawer */
+
+.kupu-bm-help { min-height: 2.5em; }
+.kupu-bm-heading { line-height: 2em; border-bottom: 1px solid; }
+.kupu-bm-tablestyle, .kupu-bm-numbering { float:right; padding-left: 0.5em; }
+
+.kupu-drawer label {
+  font-weight: normal;
+  vertical-align:middle;
+  margin-right: 2px;
+  display: inline;
+}
+#kupu-breadcrumbs {
+  text-align: left; clear:left;
+  padding-left: 1em; padding-right: 1em;
+  height: 20px;
+  width: 600px;
+  overflow:hidden;
+}
+#kupu-breadcrumbs a {
+ text-decoration: none;
+}
+.kupu-breadcrumbSeparator {
+    font-size: 120%;
+}
+
+.kupu-locate {
+    visibility:hidden;
+    display: block;
+}
+
+.kupu-has-selection .kupu-locate {
+    visibility:visible;
+}
+.kupu-has-selection .kupu-locate a {
+    background: transparent url(kupuimages/treeCollapsed.gif) 4px 6px no-repeat;
+    padding: 1px 0px 1px 16px;
+    font-style: italic;
+}
+a.kupu-anchor-link {
+    margin-left: 1em;
+}