Updated to XLoadTree2(beta)
authorjollytoad <jollytoad>
Thu, 3 Mar 2005 14:35:13 +0000 (14:35 +0000)
committerjollytoad <jollytoad>
Thu, 3 Mar 2005 14:35:13 +0000 (14:35 +0000)
xloadtree/xloadtree.js [deleted file]
xloadtree/xloadtree2.js [new file with mode: 0644]
xloadtree/xmlextras.js
xloadtree/xtree.css [deleted file]
xloadtree/xtree.js [deleted file]
xloadtree/xtree2.js [new file with mode: 0644]

diff --git a/xloadtree/xloadtree.js b/xloadtree/xloadtree.js
deleted file mode 100644 (file)
index 6bbd9fd..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-/*----------------------------------------------------------------------------\\r
-|                               XLoadTree 1.11                                |\r
-|-----------------------------------------------------------------------------|\r
-|                         Created by Erik Arvidsson                           |\r
-|                  (http://webfx.eae.net/contact.html#erik)                   |\r
-|                      For WebFX (http://webfx.eae.net/)                      |\r
-|-----------------------------------------------------------------------------|\r
-| An extension to xTree that allows sub trees to be loaded at runtime by      |\r
-| reading XML files from the server. Works with IE5+ and Mozilla 1.0+         |\r
-|-----------------------------------------------------------------------------|\r
-|                   Copyright (c) 1999 - 2002 Erik Arvidsson                  |\r
-|-----------------------------------------------------------------------------|\r
-| This software is provided "as is", without warranty of any kind, express or |\r
-| implied, including  but not limited  to the warranties of  merchantability, |\r
-| fitness for a particular purpose and noninfringement. In no event shall the |\r
-| authors or  copyright  holders be  liable for any claim,  damages or  other |\r
-| liability, whether  in an  action of  contract, tort  or otherwise, arising |\r
-| from,  out of  or in  connection with  the software or  the  use  or  other |\r
-| dealings in the software.                                                   |\r
-| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |\r
-| This  software is  available under the  three different licenses  mentioned |\r
-| below.  To use this software you must chose, and qualify, for one of those. |\r
-| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |\r
-| The WebFX Non-Commercial License          http://webfx.eae.net/license.html |\r
-| Permits  anyone the right to use the  software in a  non-commercial context |\r
-| free of charge.                                                             |\r
-| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |\r
-| The WebFX Commercial license           http://webfx.eae.net/commercial.html |\r
-| Permits the  license holder the right to use  the software in a  commercial |\r
-| context. Such license must be specifically obtained, however it's valid for |\r
-| any number of  implementations of the licensed software.                    |\r
-| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |\r
-| GPL - The GNU General Public License    http://www.gnu.org/licenses/gpl.txt |\r
-| Permits anyone the right to use and modify the software without limitations |\r
-| as long as proper  credits are given  and the original  and modified source |\r
-| code are included. Requires  that the final product, software derivate from |\r
-| the original  source or any  software  utilizing a GPL  component, such  as |\r
-| this, is also licensed under the GPL license.                               |\r
-|-----------------------------------------------------------------------------|\r
-| 2001-09-27 | Original Version Posted.                                       |\r
-| 2002-01-19 | Added some simple error handling and string templates for      |\r
-|            | reporting the errors.                                          |\r
-| 2002-01-28 | Fixed loading issues in IE50 and IE55 that made the tree load  |\r
-|            | twice.                                                         |\r
-| 2002-10-10 | (1.1) Added reload method that reloads the XML file from the   |\r
-|            | server.                                                        |\r
-/ 2003-05-06 | Added support for target attribute                             |\r
-|-----------------------------------------------------------------------------|\r
-| Dependencies: xtree.js - original xtree library                             |\r
-|               xtree.css - simple css styling of xtree                       |\r
-|               xmlextras.js - provides xml http objects and xml document     |\r
-|                              objects                                        |\r
-|-----------------------------------------------------------------------------|\r
-| Created 2001-09-27 | All changes are in the log above. | Updated 2003-05-06 |\r
-\----------------------------------------------------------------------------*/\r
-\r
-\r
-webFXTreeConfig.loadingText = "Loading...";\r
-webFXTreeConfig.loadErrorTextTemplate = "Error loading \"%1%\"";\r
-webFXTreeConfig.emptyErrorTextTemplate = "Error \"%1%\" does not contain any tree items";\r
-\r
-/*\r
- * WebFXLoadTree class\r
- */\r
-\r
-function WebFXLoadTree(sText, sXmlSrc, sAction, sBehavior, sIcon, sOpenIcon) {\r
-       // call super\r
-       this.WebFXTree = WebFXTree;\r
-       this.WebFXTree(sText, sAction, sBehavior, sIcon, sOpenIcon);\r
-\r
-       // setup default property values\r
-       this.src = sXmlSrc;\r
-       this.loading = false;\r
-       this.loaded = false;\r
-       this.errorText = "";\r
-\r
-       // check start state and load if open\r
-       if (this.open)\r
-               _startLoadXmlTree(this.src, this);\r
-       else {\r
-               // and create loading item if not\r
-               this._loadingItem = new WebFXTreeItem(webFXTreeConfig.loadingText);\r
-               this.add(this._loadingItem);\r
-       }\r
-}\r
-\r
-WebFXLoadTree.prototype = new WebFXTree;\r
-\r
-// override the expand method to load the xml file\r
-WebFXLoadTree.prototype._webfxtree_expand = WebFXTree.prototype.expand;\r
-WebFXLoadTree.prototype.expand = function() {\r
-       if (!this.loaded && !this.loading) {\r
-               // load\r
-               _startLoadXmlTree(this.src, this);\r
-       }\r
-       this._webfxtree_expand();\r
-};\r
-\r
-/*\r
- * WebFXLoadTreeItem class\r
- */\r
-\r
-function WebFXLoadTreeItem(sText, sXmlSrc, sAction, eParent, sIcon, sOpenIcon) {\r
-       // call super\r
-       this.WebFXTreeItem = WebFXTreeItem;\r
-       this.WebFXTreeItem(sText, sAction, eParent, sIcon, sOpenIcon);\r
-\r
-       // setup default property values\r
-       this.src = sXmlSrc;\r
-       this.loading = false;\r
-       this.loaded = false;\r
-       this.errorText = "";\r
-\r
-       // check start state and load if open\r
-       if (this.open)\r
-               _startLoadXmlTree(this.src, this);\r
-       else {\r
-               // and create loading item if not\r
-               this._loadingItem = new WebFXTreeItem(webFXTreeConfig.loadingText);\r
-               this.add(this._loadingItem);\r
-       }\r
-}\r
-\r
-WebFXLoadTreeItem.prototype = new WebFXTreeItem;\r
-\r
-// override the expand method to load the xml file\r
-WebFXLoadTreeItem.prototype._webfxtreeitem_expand = WebFXTreeItem.prototype.expand;\r
-WebFXLoadTreeItem.prototype.expand = function() {\r
-       if (!this.loaded && !this.loading) {\r
-               // load\r
-               _startLoadXmlTree(this.src, this);\r
-       }\r
-       this._webfxtreeitem_expand();\r
-};\r
-\r
-// reloads the src file if already loaded\r
-WebFXLoadTree.prototype.reload =\r
-WebFXLoadTreeItem.prototype.reload = function () {\r
-       // if loading do nothing\r
-       if (this.loaded) {\r
-               var open = this.open;\r
-               // remove\r
-               while (this.childNodes.length > 0)\r
-                       this.childNodes[this.childNodes.length - 1].remove();\r
-\r
-               this.loaded = false;\r
-\r
-               this._loadingItem = new WebFXTreeItem(webFXTreeConfig.loadingText);\r
-               this.add(this._loadingItem);\r
-\r
-               if (open)\r
-                       this.expand();\r
-       }\r
-       else if (this.open && !this.loading)\r
-               _startLoadXmlTree(this.src, this);\r
-};\r
-\r
-/*\r
- * Helper functions\r
- */\r
-\r
-// creates the xmlhttp object and starts the load of the xml document\r
-function _startLoadXmlTree(sSrc, jsNode) {\r
-       if (jsNode.loading || jsNode.loaded)\r
-               return;\r
-       jsNode.loading = true;\r
-       var xmlHttp = XmlHttp.create();\r
-       xmlHttp.open("GET", sSrc, true);        // async\r
-       xmlHttp.onreadystatechange = function () {\r
-               if (xmlHttp.readyState == 4) {\r
-                       _xmlFileLoaded(xmlHttp.responseXML, jsNode);\r
-               }\r
-       };\r
-       // call in new thread to allow ui to update\r
-       window.setTimeout(function () {\r
-               xmlHttp.send(null);\r
-       }, 10);\r
-}\r
-\r
-\r
-// Converts an xml tree to a js tree. See article about xml tree format\r
-function _xmlTreeToJsTree(oNode) {\r
-       // retreive attributes\r
-       var text = oNode.getAttribute("text");\r
-       var action = oNode.getAttribute("action");\r
-       var parent = null;\r
-       var icon = oNode.getAttribute("icon");\r
-       var openIcon = oNode.getAttribute("openIcon");\r
-       var src = oNode.getAttribute("src");\r
-       var target = oNode.getAttribute("target");\r
-       // create jsNode\r
-       var jsNode;\r
-       if (src != null && src != "")\r
-               jsNode = new WebFXLoadTreeItem(text, src, action, parent, icon, openIcon);\r
-       else\r
-               jsNode = new WebFXTreeItem(text, action, parent, icon, openIcon);\r
-\r
-       if (target != "")\r
-               jsNode.target = target;\r
-\r
-       // go through childNOdes\r
-       var cs = oNode.childNodes;\r
-       var l = cs.length;\r
-       for (var i = 0; i < l; i++) {\r
-               if (cs[i].tagName == "tree")\r
-                       jsNode.add( _xmlTreeToJsTree(cs[i]), true );\r
-       }\r
-\r
-       return jsNode;\r
-}\r
-\r
-// Inserts an xml document as a subtree to the provided node\r
-function _xmlFileLoaded(oXmlDoc, jsParentNode) {\r
-       if (jsParentNode.loaded)\r
-               return;\r
-\r
-       var bIndent = false;\r
-       var bAnyChildren = false;\r
-       jsParentNode.loaded = true;\r
-       jsParentNode.loading = false;\r
-\r
-       // check that the load of the xml file went well\r
-       if( oXmlDoc == null || oXmlDoc.documentElement == null) {\r
-               alert(oXmlDoc.xml);\r
-               jsParentNode.errorText = parseTemplateString(webFXTreeConfig.loadErrorTextTemplate,\r
-                                                       jsParentNode.src);\r
-       }\r
-       else {\r
-               // there is one extra level of tree elements\r
-               var root = oXmlDoc.documentElement;\r
-\r
-               // loop through all tree children\r
-               var cs = root.childNodes;\r
-               var l = cs.length;\r
-               for (var i = 0; i < l; i++) {\r
-                       if (cs[i].tagName == "tree") {\r
-                               bAnyChildren = true;\r
-                               bIndent = true;\r
-                               jsParentNode.add( _xmlTreeToJsTree(cs[i]), true);\r
-                       }\r
-               }\r
-\r
-               // if no children we got an error\r
-               if (!bAnyChildren)\r
-                       jsParentNode.errorText = parseTemplateString(webFXTreeConfig.emptyErrorTextTemplate,\r
-                                                                               jsParentNode.src);\r
-       }\r
-\r
-       // remove dummy\r
-       if (jsParentNode._loadingItem != null) {\r
-               jsParentNode._loadingItem.remove();\r
-               bIndent = true;\r
-       }\r
-\r
-       if (bIndent) {\r
-               // indent now that all items are added\r
-               jsParentNode.indent();\r
-       }\r
-\r
-       // show error in status bar\r
-       if (jsParentNode.errorText != "")\r
-               window.status = jsParentNode.errorText;\r
-}\r
-\r
-// parses a string and replaces %n% with argument nr n\r
-function parseTemplateString(sTemplate) {\r
-       var args = arguments;\r
-       var s = sTemplate;\r
-\r
-       s = s.replace(/\%\%/g, "%");\r
-\r
-       for (var i = 1; i < args.length; i++)\r
-               s = s.replace( new RegExp("\%" + i + "\%", "g"), args[i] )\r
-\r
-       return s;\r
-}
\ No newline at end of file
diff --git a/xloadtree/xloadtree2.js b/xloadtree/xloadtree2.js
new file mode 100644 (file)
index 0000000..eb29adc
--- /dev/null
@@ -0,0 +1,531 @@
+/*----------------------------------------------------------------------------\\r
+|                        XLoadTree 2 PRE RELEASE                              |\r
+|                                                                             |\r
+| This is a pre release and redistribution is discouraged.                    |\r
+| Watch http://webfx.eae.net for the final version                            |\r
+|                                                                             |\r
+|-----------------------------------------------------------------------------|\r
+|                   Created by Erik Arvidsson & Emil A Eklund                 |\r
+|                  (http://webfx.eae.net/contact.html#erik)                   |\r
+|                  (http://webfx.eae.net/contact.html#emil)                   |\r
+|                      For WebFX (http://webfx.eae.net/)                      |\r
+|-----------------------------------------------------------------------------|\r
+| A tree menu system for IE 5.5+, Mozilla 1.4+, Opera 7.5+                    |\r
+|-----------------------------------------------------------------------------|\r
+|         Copyright (c) 1999 - 2004 Erik Arvidsson & Emil A Eklund            |\r
+|-----------------------------------------------------------------------------|\r
+| This software is provided "as is", without warranty of any kind, express or |\r
+| implied, including  but not limited  to the warranties of  merchantability, |\r
+| fitness for a particular purpose and noninfringement. In no event shall the |\r
+| authors or  copyright  holders be  liable for any claim,  damages or  other |\r
+| liability, whether  in an  action of  contract, tort  or otherwise, arising |\r
+| from,  out of  or in  connection with  the software or  the  use  or  other |\r
+| dealings in the software.                                                   |\r
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |\r
+| This  software is  available under the  three different licenses  mentioned |\r
+| below.  To use this software you must chose, and qualify, for one of those. |\r
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |\r
+| The WebFX Non-Commercial License          http://webfx.eae.net/license.html |\r
+| Permits  anyone the right to use the  software in a  non-commercial context |\r
+| free of charge.                                                             |\r
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |\r
+| The WebFX Commercial license           http://webfx.eae.net/commercial.html |\r
+| Permits the  license holder the right to use  the software in a  commercial |\r
+| context. Such license must be specifically obtained, however it's valid for |\r
+| any number of  implementations of the licensed software.                    |\r
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |\r
+| GPL - The GNU General Public License    http://www.gnu.org/licenses/gpl.txt |\r
+| Permits anyone the right to use and modify the software without limitations |\r
+| as long as proper  credits are given  and the original  and modified source |\r
+| code are included. Requires  that the final product, software derivate from |\r
+| the original  source or any  software  utilizing a GPL  component, such  as |\r
+| this, is also licensed under the GPL license.                               |\r
+|-----------------------------------------------------------------------------|\r
+| 2004-02-21 | Pre release distributed to a few selected tester               |\r
+|-----------------------------------------------------------------------------|\r
+| Dependencies: xtree2.js Supplies the tree control                           |\r
+|-----------------------------------------------------------------------------|\r
+| Created 2003-??-?? | All changes are in the log above. | Updated 2004-02-21 |\r
+\----------------------------------------------------------------------------*/\r
+\r
+\r
+webFXTreeConfig.loadingText = "Loading...";\r
+webFXTreeConfig.loadingIcon = "images/loading.gif";\r
+\r
+\r
+function WebFXLoadTree(sText, sXmlSrc, oAction, sBehavior, sIcon, sOpenIcon)\r
+{\r
+       WebFXTree.call(this, sText, oAction, sBehavior, sIcon, sOpenIcon);\r
+\r
+       // setup default property values\r
+       this.src = sXmlSrc;\r
+       this.loading = !sXmlSrc;\r
+       this.loaded = !sXmlSrc;\r
+       this.errorText = "";\r
+\r
+       if (this.src)\r
+       {\r
+               /// add loading Item\r
+               this._loadingItem = WebFXLoadTree.createLoadingItem();\r
+               this.add(this._loadingItem);\r
+\r
+               if (this.getExpanded())\r
+                       WebFXLoadTree.loadXmlDocument(this);\r
+       }\r
+}\r
+\r
+WebFXLoadTree.createLoadingItem = function ()\r
+{\r
+       return new WebFXTreeItem(webFXTreeConfig.loadingText, null, null,\r
+                                                        webFXTreeConfig.loadingIcon);\r
+};\r
+\r
+WebFXLoadTree.prototype = new WebFXTree;\r
+\r
+WebFXLoadTree.prototype.setExpanded = function (b)\r
+{\r
+       WebFXTree.prototype.setExpanded.call(this, b);\r
+\r
+       if (this.src && b)\r
+       {\r
+               if (!this.loaded && !this.loading)\r
+               {\r
+                       // load\r
+                       WebFXLoadTree.loadXmlDocument(this);\r
+               }\r
+       }\r
+};\r
+\r
+function WebFXLoadTreeItem(sText, sXmlSrc, oAction, eParent, sIcon, sOpenIcon)\r
+{\r
+       WebFXTreeItem.call(this, sText, oAction, eParent, sIcon, sOpenIcon);\r
+\r
+// setup default property values\r
+       this.src = sXmlSrc;\r
+       this.loading = !sXmlSrc;\r
+       this.loaded = !sXmlSrc;\r
+       this.errorText = "";\r
+\r
+       if (this.src)\r
+       {\r
+               /// add loading Item\r
+               this._loadingItem = WebFXLoadTree.createLoadingItem();\r
+               this.add(this._loadingItem);\r
+\r
+               if (this.getExpanded())\r
+                       WebFXLoadTree.loadXmlDocument(this);\r
+       }\r
+}\r
+\r
+WebFXLoadTreeItem.prototype = new WebFXTreeItem;\r
+\r
+WebFXLoadTreeItem.prototype.setExpanded = function (b)\r
+{\r
+       WebFXTreeItem.prototype.setExpanded.call(this, b);\r
+\r
+       if (this.src && b)\r
+       {\r
+               if (!this.loaded && !this.loading)\r
+               {\r
+                       // load\r
+                       WebFXLoadTree.loadXmlDocument(this);\r
+               }\r
+       }\r
+};\r
+\r
+// reloads the src file if already loaded\r
+WebFXLoadTree.prototype.reload =\r
+WebFXLoadTreeItem.prototype.reload = function ()\r
+{\r
+       // if loading do nothing\r
+       if (this.loaded)\r
+       {\r
+               var t = this.getTree();\r
+               var expanded = this.getExpanded();\r
+               var sr = t.getSuspendRedraw();\r
+               t.setSuspendRedraw(true);\r
+\r
+               // remove\r
+               while (this.childNodes.length > 0)\r
+                       this.remove(this.childNodes[this.childNodes.length - 1]);\r
+\r
+               this.loaded = false;\r
+\r
+               this._loadingItem = WebFXLoadTree.createLoadingItem();\r
+               this.add(this._loadingItem);\r
+\r
+               if (expanded)\r
+                       this.setExpanded(true);\r
+\r
+               t.setSuspendRedraw(sr);\r
+               this.update();\r
+       }\r
+       else if (this.open && !this.loading)\r
+               WebFXLoadTree.loadXmlDocument(this);\r
+};\r
+\r
+\r
+\r
+WebFXLoadTree.prototype.setSrc =\r
+WebFXLoadTreeItem.prototype.setSrc = function (sSrc)\r
+{\r
+       var oldSrc = this.src;\r
+       if (sSrc == oldSrc) return;\r
+\r
+       var expanded = this.getExpanded();\r
+\r
+       // remove all\r
+       this._callSuspended(function ()\r
+       {\r
+               // remove\r
+               while (this.childNodes.length > 0)\r
+                       this.remove(this.childNodes[this.childNodes.length - 1]);\r
+       });\r
+       this.update();\r
+\r
+       this.loaded = false;\r
+       this.loading = false;\r
+       if (this._loadingItem)\r
+       {\r
+               this._loadingItem.dispose();\r
+               this._loadingItem = null;\r
+       }\r
+       this.src = sSrc;\r
+\r
+       if (sSrc)\r
+       {\r
+               this._loadingItem = WebFXLoadTree.createLoadingItem();\r
+               this.add(this._loadingItem);\r
+       }\r
+\r
+       this.setExpanded(expanded);\r
+};\r
+\r
+WebFXLoadTree.prototype.getSrc =\r
+WebFXLoadTreeItem.prototype.getSrc = function ()\r
+{\r
+       return this.src;\r
+};\r
+\r
+WebFXLoadTree.prototype.dispose = function ()\r
+{\r
+       WebFXTree.prototype.dispose.call(this);\r
+       if (this._xmlHttp)\r
+       {\r
+               if (this._xmlHttp.dispose)\r
+                       this._xmlHttp.dispose();\r
+               try\r
+               {\r
+                       this._xmlHttp.onreadystatechange = null;\r
+                       this._xmlHttp.abort();\r
+               }\r
+               catch (ex) {}\r
+               this._xmlHttp = null;\r
+       }\r
+};\r
+\r
+WebFXLoadTreeItem.prototype.dispose = function ()\r
+{\r
+       WebFXTreeItem.prototype.dispose.call(this);\r
+       if (this._xmlHttp)\r
+       {\r
+               if (this._xmlHttp.dispose)\r
+                       this._xmlHttp.dispose();\r
+               try\r
+               {\r
+                       this._xmlHttp.onreadystatechange = null;\r
+                       this._xmlHttp.abort();\r
+               }\r
+               catch (ex) {}\r
+               this._xmlHttp = null;\r
+       }\r
+};\r
+\r
+\r
+// The path is divided by '/' and the item is identified by the text\r
+WebFXLoadTree.prototype.openPath =\r
+WebFXLoadTreeItem.prototype.openPath = function (sPath, bSelect, bFocus)\r
+{\r
+       // remove any old pending paths to open\r
+       delete this._pathToOpen;\r
+       //delete this._pathToOpenById;\r
+       this._selectPathOnLoad = bSelect;\r
+       this._focusPathOnLoad = bFocus;\r
+\r
+       if (sPath == "")\r
+       {\r
+               if (bSelect)\r
+                       this.select();\r
+               if (bFocus)\r
+                       window.setTimeout("WebFXTreeAbstractNode._onTimeoutFocus(\"" + this.getId() + "\")", 10);\r
+               return;\r
+       }\r
+\r
+       var parts = sPath.split("/");\r
+       var remainingPath = parts.slice(1).join("/");\r
+\r
+       if (sPath.charAt(0) == "/")\r
+       {\r
+               this.getTree().openPath(remainingPath, bSelect, bFocus);\r
+       }\r
+       else\r
+       {\r
+               // open\r
+               this.setExpanded(true);\r
+               if (this.loaded)\r
+               {\r
+                       parts = sPath.split("/");\r
+                       var ti = this.findChildByText(parts[0]);\r
+                       if (!ti)\r
+                               throw "Could not find child node with text \"" + parts[0] + "\"";\r
+\r
+                       ti.openPath(remainingPath, bSelect, bFocus);\r
+               }\r
+               else\r
+               {\r
+                       this._pathToOpen = sPath;\r
+               }\r
+       }\r
+};\r
+\r
+\r
+// Opera has some serious attribute problems. We need to use getAttribute\r
+// for certain attributes\r
+WebFXLoadTree._attrs = ["text", "src", "action", "id", "target"];\r
+\r
+WebFXLoadTree.createItemFromElement = function (oNode)\r
+{\r
+       var jsAttrs = {};\r
+       var domAttrs = oNode.attributes;\r
+       var i, l;\r
+\r
+       l = domAttrs.length;\r
+       for (i = 0; i < l; i++)\r
+       {\r
+               if (domAttrs[i] == null)\r
+               {\r
+                       continue;\r
+               }\r
+               jsAttrs[domAttrs[i].nodeName] = domAttrs[i].nodeValue;\r
+       }\r
+\r
+\r
+       var name, val;\r
+       for (i = 0; i < WebFXLoadTree._attrs.length; i++)\r
+       {\r
+               name = WebFXLoadTree._attrs[i];\r
+               value = oNode.getAttribute(name);\r
+               if (value)\r
+                       jsAttrs[name] = value;\r
+       }\r
+\r
+       var action;\r
+       if (jsAttrs.onaction)\r
+               action = new Function(jsAttrs.onaction);\r
+       else if (jsAttrs.action)\r
+               action = jsAttrs.action;\r
+       var jsNode = new WebFXLoadTreeItem(jsAttrs.html || "", jsAttrs.src, action,\r
+                                                                          null, jsAttrs.icon, jsAttrs.openIcon);\r
+       if (jsAttrs.text)\r
+               jsNode.setText(jsAttrs.text);\r
+\r
+       if (jsAttrs.target)\r
+               jsNode.target = jsAttrs.target;\r
+       if (jsAttrs.id)\r
+               jsNode.setId(jsAttrs.id);\r
+       if (jsAttrs.toolTip)\r
+               jsNode.toolTip = jsAttrs.toolTip;\r
+       if (jsAttrs.expanded)\r
+               jsNode.setExpanded(jsAttrs.expanded != "false");\r
+       if (jsAttrs.onload)\r
+               jsNode.onload = new Function(jsAttrs.onload);\r
+       if (jsAttrs.onerror)\r
+               jsNode.onerror = new Function(jsAttrs.onerror);\r
+\r
+       jsNode.attributes = jsAttrs;\r
+\r
+       // go through childNodes\r
+       var cs = oNode.childNodes;\r
+       l = cs.length;\r
+       for (i = 0; i < l; i++)\r
+       {\r
+               if (cs[i].tagName == "tree")\r
+                       jsNode.add(WebFXLoadTree.createItemFromElement(cs[i]));\r
+       }\r
+\r
+       return jsNode;\r
+};\r
+\r
+WebFXLoadTree.loadXmlDocument = function (jsNode)\r
+{\r
+       if (jsNode.loading || jsNode.loaded)\r
+               return;\r
+       jsNode.loading = true;\r
+       var id = jsNode.getId();\r
+       jsNode._xmlHttp = XmlHttp.create();\r
+       jsNode._xmlHttp.open("GET", jsNode.src, true);  // async\r
+       jsNode._xmlHttp.onreadystatechange = new Function("WebFXLoadTree._onload(\"" + id + "\")");\r
+\r
+       // call in new thread to allow ui to update\r
+       window.setTimeout("WebFXLoadTree._ontimeout(\"" + id + "\")", 10);\r
+};\r
+\r
+WebFXLoadTree._onload = function (sId)\r
+{\r
+       var jsNode = webFXTreeHandler.all[sId];\r
+       if (jsNode._xmlHttp.readyState == 4)\r
+       {\r
+               WebFXLoadTree.documentLoaded(jsNode);\r
+               webFXLoadTreeQueue.remove(jsNode);\r
+               if (jsNode._xmlHttp.dispose)\r
+                       jsNode._xmlHttp.dispose();\r
+               jsNode._xmlHttp = null;\r
+       }\r
+};\r
+\r
+WebFXLoadTree._ontimeout = function (sId)\r
+{\r
+       var jsNode = webFXTreeHandler.all[sId];\r
+       webFXLoadTreeQueue.add(jsNode);\r
+};\r
+\r
+\r
+\r
+// Inserts an xml document as a subtree to the provided node\r
+WebFXLoadTree.documentLoaded = function (jsNode)\r
+{\r
+       if (jsNode.loaded)\r
+               return;\r
+\r
+       jsNode.errorText = "";\r
+       jsNode.loaded = true;\r
+       jsNode.loading = false;\r
+\r
+       var t = jsNode.getTree();\r
+       var oldSuspend = t.getSuspendRedraw();\r
+       t.setSuspendRedraw(true);\r
+\r
+       var doc = jsNode._xmlHttp.responseXML;\r
+\r
+       // check that the load of the xml file went well\r
+       if(!doc || doc.parserError && doc.parseError.errorCode != 0 || !doc.documentElement)\r
+       {\r
+               if (!doc || doc.parseError.errorCode == 0)\r
+               {\r
+                       jsNode.errorText = "Error loading " + jsNode.src + " (" + jsNode._xmlHttp.status + ": " + jsNode._xmlHttp.statusText + ")";\r
+               }\r
+               else\r
+               {\r
+                       jsNode.errorText = "Error loading " + jsNode.src + " (" + doc.parseError.reason + ")";\r
+               }\r
+       }\r
+       else\r
+       {\r
+               // there is one extra level of tree elements\r
+               var root = doc.documentElement;\r
+\r
+               // loop through all tree children\r
+               var count = 0;\r
+               var cs = root.childNodes;\r
+               var l = cs.length;\r
+               for (var i = 0; i < l; i++)\r
+               {\r
+                       if (cs[i].tagName == "tree")\r
+                       {\r
+                               jsNode.add(WebFXLoadTree.createItemFromElement(cs[i]));\r
+                               count++;\r
+                       }\r
+               }\r
+\r
+               // if no children we got an error\r
+               if (count == 0)\r
+               {\r
+                       jsNode.errorText = "Error loading " + jsNode.src + " (???)";\r
+               }\r
+       }\r
+\r
+       if (jsNode.errorText != "")\r
+       {\r
+               jsNode._loadingItem.icon = "images/exclamation.16.gif";\r
+               jsNode._loadingItem.text = jsNode.errorText;\r
+               jsNode._loadingItem.action = WebFXLoadTree._reloadParent;\r
+               jsNode._loadingItem.toolTip = "Click to reload";\r
+\r
+               t.setSuspendRedraw(oldSuspend);\r
+\r
+               jsNode._loadingItem.update();\r
+\r
+               if (typeof jsNode.onerror == "function")\r
+                       jsNode.onerror();\r
+       }\r
+       else\r
+       {\r
+               // remove dummy\r
+               if (jsNode._loadingItem != null)\r
+                       jsNode.remove(jsNode._loadingItem);\r
+\r
+               if (jsNode._pathToOpen)\r
+                       jsNode.openPath(jsNode._pathToOpen, jsNode._selectPathOnLoad, jsNode._focusPathOnLoad);\r
+\r
+               t.setSuspendRedraw(oldSuspend);\r
+               jsNode.update();\r
+               if (typeof jsNode.onload == "function")\r
+                       jsNode.onload();\r
+       }\r
+};\r
+\r
+WebFXLoadTree._reloadParent = function ()\r
+{\r
+       this.getParent().reload();\r
+};\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+var webFXLoadTreeQueue = {\r
+       _nodes: [],\r
+       _ie:    /msie/i.test(navigator.userAgent),\r
+       _opera: /opera/i.test(navigator.userAgent),\r
+\r
+       add: function (jsNode)\r
+       {\r
+               if (this._ie || this._opera)\r
+               {\r
+                       this._nodes.push(jsNode);\r
+                       if (this._nodes.length == 1)\r
+                               this._send();\r
+               }\r
+               else\r
+               {\r
+                       jsNode._xmlHttp.send(null);\r
+               }\r
+       },\r
+\r
+\r
+       remove: function (jsNode)\r
+       {\r
+               if (this._ie || this._opera)\r
+               {\r
+                       arrayHelper.remove(this._nodes, jsNode);\r
+                       if (this._nodes.length > 0)\r
+                               this._send();\r
+               }\r
+       },\r
+\r
+       // IE only\r
+       _send:  function ()\r
+       {\r
+               var id = this._nodes[0].getId();\r
+               var jsNode = webFXTreeHandler.all[id];\r
+               if (!jsNode)\r
+                       return;\r
+               // if no _xmlHttp then remove it\r
+               if (!jsNode._xmlHttp)\r
+                       this.remove(jsNode);\r
+               else\r
+                       jsNode._xmlHttp.send(null);\r
+       }\r
+};\r
index 5b56dbe00f6a8aea4c0922cee6643ba8ec1d1924..6a675121856fcb6860b330653a3c9fe5983dc2fd 100644 (file)
@@ -1,4 +1,50 @@
-//<script>\r
+/*----------------------------------------------------------------------------\\r
+|                               XML Extras 1.01                               |\r
+|-----------------------------------------------------------------------------|\r
+|                         Created by Erik Arvidsson                           |\r
+|                  (http://webfx.eae.net/contact.html#erik)                   |\r
+|                      For WebFX (http://webfx.eae.net/)                      |\r
+|-----------------------------------------------------------------------------|\r
+| A library that makes working with XML documents in Mozilla more similar to  |\r
+| working with MSXML.                                                         |\r
+|-----------------------------------------------------------------------------|\r
+|                   Copyright (c) 1999 - 2003 Erik Arvidsson                  |\r
+|-----------------------------------------------------------------------------|\r
+| This software is provided "as is", without warranty of any kind, express or |\r
+| implied, including  but not limited  to the warranties of  merchantability, |\r
+| fitness for a particular purpose and noninfringement. In no event shall the |\r
+| authors or  copyright  holders be  liable for any claim,  damages or  other |\r
+| liability, whether  in an  action of  contract, tort  or otherwise, arising |\r
+| from,  out of  or in  connection with  the software or  the  use  or  other |\r
+| dealings in the software.                                                   |\r
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |\r
+| This  software is  available under the  three different licenses  mentioned |\r
+| below.  To use this software you must chose, and qualify, for one of those. |\r
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |\r
+| The WebFX Non-Commercial License          http://webfx.eae.net/license.html |\r
+| Permits  anyone the right to use the  software in a  non-commercial context |\r
+| free of charge.                                                             |\r
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |\r
+| The WebFX Commercial license           http://webfx.eae.net/commercial.html |\r
+| Permits the  license holder the right to use  the software in a  commercial |\r
+| context. Such license must be specifically obtained, however it's valid for |\r
+| any number of  implementations of the licensed software.                    |\r
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |\r
+| GPL - The GNU General Public License    http://www.gnu.org/licenses/gpl.txt |\r
+| Permits anyone the right to use and modify the software without limitations |\r
+| as long as proper  credits are given  and the original  and modified source |\r
+| code are included. Requires  that the final product, software derivate from |\r
+| the original  source or any  software  utilizing a GPL  component, such  as |\r
+| this, is also licensed under the GPL license.                               |\r
+|-----------------------------------------------------------------------------|\r
+| ????-??-?? | Original Version Posted.                                       |\r
+| 2003-09-25 | Added support for parseError getters. Also changed to extend   |\r
+|            | only XMLDocument instead of Document                           |\r
+|-----------------------------------------------------------------------------|\r
+| Created ????-??-?? | All changes are in the log above. | Updated 2003-09-25 |\r
+\----------------------------------------------------------------------------*/\r
+\r
+\r
 //////////////////\r
 // Helper Stuff //\r
 //////////////////\r
@@ -7,7 +53,7 @@
 function getDomDocumentPrefix() {\r
        if (getDomDocumentPrefix.prefix)\r
                return getDomDocumentPrefix.prefix;\r
-       \r
+\r
        var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];\r
        var o;\r
        for (var i = 0; i < prefixes.length; i++) {\r
@@ -18,14 +64,14 @@ function getDomDocumentPrefix() {
                }\r
                catch (ex) {};\r
        }\r
-       \r
+\r
        throw new Error("Could not find an installed XML parser");\r
 }\r
 \r
 function getXmlHttpPrefix() {\r
        if (getXmlHttpPrefix.prefix)\r
                return getXmlHttpPrefix.prefix;\r
-       \r
+\r
        var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];\r
        var o;\r
        for (var i = 0; i < prefixes.length; i++) {\r
@@ -36,7 +82,7 @@ function getXmlHttpPrefix() {
                }\r
                catch (ex) {};\r
        }\r
-       \r
+\r
        throw new Error("Could not find an installed XML parser");\r
 }\r
 \r
@@ -52,7 +98,7 @@ XmlHttp.create = function () {
        try {\r
                if (window.XMLHttpRequest) {\r
                        var req = new XMLHttpRequest();\r
-                       \r
+\r
                        // some versions of Moz do not support the readyState property\r
                        // and the onreadystate event so we patch it!\r
                        if (req.readyState == null) {\r
@@ -63,7 +109,7 @@ XmlHttp.create = function () {
                                                req.onreadystatechange();\r
                                }, false);\r
                        }\r
-                       \r
+\r
                        return req;\r
                }\r
                if (window.ActiveXObject) {\r
@@ -83,7 +129,7 @@ XmlDocument.create = function () {
                // DOM2\r
                if (document.implementation && document.implementation.createDocument) {\r
                        var doc = document.implementation.createDocument("", "", null);\r
-                       \r
+\r
                        // some versions of Moz do not support the readyState property\r
                        // and the onreadystate event so we patch it!\r
                        if (doc.readyState == null) {\r
@@ -94,7 +140,7 @@ XmlDocument.create = function () {
                                                doc.onreadystatechange();\r
                                }, false);\r
                        }\r
-                       \r
+\r
                        return doc;\r
                }\r
                if (window.ActiveXObject)\r
@@ -111,23 +157,23 @@ if (window.DOMParser &&
 \r
        // XMLDocument did not extend the Document interface in some versions\r
        // of Mozilla. Extend both!\r
-       XMLDocument.prototype.loadXML = \r
-       Document.prototype.loadXML = function (s) {\r
-               \r
-               // parse the string to a new doc        \r
+       //XMLDocument.prototype.loadXML =\r
+       XMLDocument.prototype.loadXML = function (s) {\r
+\r
+               // parse the string to a new doc\r
                var doc2 = (new DOMParser()).parseFromString(s, "text/xml");\r
-               \r
+\r
                // remove all initial children\r
                while (this.hasChildNodes())\r
                        this.removeChild(this.lastChild);\r
-                       \r
+\r
                // insert and import nodes\r
                for (var i = 0; i < doc2.childNodes.length; i++) {\r
                        this.appendChild(this.importNode(doc2.childNodes[i], true));\r
                }\r
        };\r
-       \r
-       \r
+\r
+\r
        /*\r
         * xml getter\r
         *\r
@@ -136,12 +182,51 @@ if (window.DOMParser &&
         * Usage: var sXml = oNode.xml\r
         *\r
         */\r
-       // XMLDocument did not extend the Document interface in some versions\r
-       // of Mozilla. Extend both!\r
-       XMLDocument.prototype.__defineGetter__("xml", function () {\r
+\r
+       // Node, should really be XMLNode but there is no such interface\r
+       Node.prototype.__defineGetter__("xml", function () {\r
                return (new XMLSerializer()).serializeToString(this);\r
        });\r
-       Document.prototype.__defineGetter__("xml", function () {\r
-               return (new XMLSerializer()).serializeToString(this);\r
+\r
+       XMLDocument.prototype.__defineGetter__("parseError", function () {\r
+               var hasError = !this.documentElement ||\r
+                       this.documentElement.localName == "parsererror" &&\r
+                       this.documentElement.getAttribute("xmlns") == "http://www.mozilla.org/newlayout/xml/parsererror.xml";\r
+               var res = {\r
+                       errorCode:      0,\r
+                       filepos:        0,      // not supported\r
+                       line:           0,\r
+                       linepos:        0,\r
+                       reason:         "",\r
+                       srcText:        "",\r
+                       url:            ""\r
+               };\r
+               if (hasError) {\r
+                       res.errorCode = -1;\r
+                       try {\r
+                               res.srcText = this.getElementsByTagName("sourcetext")[0].firstChild.data;\r
+                               res.srcText = res.srcText.replace( /\n\-\^$/, "");\r
+                       }\r
+                       catch (ex) {\r
+                               res.srcText = "";\r
+                       }\r
+\r
+                       try {\r
+                               // now we need to parse the first text node\r
+                               var s = this.documentElement.firstChild.data;\r
+\r
+                               var re = /XML Parsing Error\: (.+)\nLocation\: (.+)\nLine Number (\d+)\, Column (\d+)/;\r
+                               var a = re.exec( s );\r
+                               res.reason = a[1];\r
+                               res.url = a[2];\r
+                               res.line = a[3];\r
+                               res.linepos = a[4];\r
+                       }\r
+                       catch (ex) {\r
+                               res.reason = "Uknown";\r
+                       }\r
+               }\r
+\r
+               return res;\r
        });\r
 }
\ No newline at end of file
diff --git a/xloadtree/xtree.css b/xloadtree/xtree.css
deleted file mode 100644 (file)
index 9764366..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-.webfx-tree-container {
-       margin: 0px;
-       padding: 0px;
-       font: icon;
-       white-space: nowrap;
-}
-
-.webfx-tree-item {
-       padding: 0px;
-       margin: 0px;
-       font: icon;
-       color: WindowText;
-       white-space: nowrap;
-       height: 16px;
-}
-
-.webfx-tree-item a, .webfx-tree-item a:active, .webfx-tree-item a:hover {
-       margin-left: 3px;
-       padding: 0px 2px 1px 2px;
-}
-
-.webfx-tree-item a {
-       color: black;
-       text-decoration: none;
-}
-
-.webfx-tree-item a:hover {
-       color: blue;
-       text-decoration: underline;
-}
-
-.webfx-tree-item a:active {
-       background: highlight;
-       color: highlighttext;
-       text-decoration: none;
-}
-
-.webfx-tree-item img {
-       vertical-align: middle;
-       border: 0px;
-}
-
-.webfx-tree-icon {
-       width: 16px;
-       height: 16px;
-}
\ No newline at end of file
diff --git a/xloadtree/xtree.js b/xloadtree/xtree.js
deleted file mode 100644 (file)
index 58d2d95..0000000
+++ /dev/null
@@ -1,541 +0,0 @@
-/*----------------------------------------------------------------------------\
-|                       Cross Browser Tree Widget 1.17                        |
-|-----------------------------------------------------------------------------|
-|                          Created by Emil A Eklund                           |
-|                  (http://webfx.eae.net/contact.html#emil)                   |
-|                      For WebFX (http://webfx.eae.net/)                      |
-|-----------------------------------------------------------------------------|
-| An object based tree widget,  emulating the one found in microsoft windows, |
-| with persistence using cookies. Works in IE 5+, Mozilla and konqueror 3.    |
-|-----------------------------------------------------------------------------|
-|                   Copyright (c) 1999 - 2002 Emil A Eklund                   |
-|-----------------------------------------------------------------------------|
-| This software is provided "as is", without warranty of any kind, express or |
-| implied, including  but not limited  to the warranties of  merchantability, |
-| fitness for a particular purpose and noninfringement. In no event shall the |
-| authors or  copyright  holders be  liable for any claim,  damages or  other |
-| liability, whether  in an  action of  contract, tort  or otherwise, arising |
-| from,  out of  or in  connection with  the software or  the  use  or  other |
-| dealings in the software.                                                   |
-| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
-| This  software is  available under the  three different licenses  mentioned |
-| below.  To use this software you must chose, and qualify, for one of those. |
-| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
-| The WebFX Non-Commercial License          http://webfx.eae.net/license.html |
-| Permits  anyone the right to use the  software in a  non-commercial context |
-| free of charge.                                                             |
-| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
-| The WebFX Commercial license           http://webfx.eae.net/commercial.html |
-| Permits the  license holder the right to use  the software in a  commercial |
-| context. Such license must be specifically obtained, however it's valid for |
-| any number of  implementations of the licensed software.                    |
-| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
-| GPL - The GNU General Public License    http://www.gnu.org/licenses/gpl.txt |
-| Permits anyone the right to use and modify the software without limitations |
-| as long as proper  credits are given  and the original  and modified source |
-| code are included. Requires  that the final product, software derivate from |
-| the original  source or any  software  utilizing a GPL  component, such  as |
-| this, is also licensed under the GPL license.                               |
-|-----------------------------------------------------------------------------|
-| Dependencies: xtree.css (To set up the CSS of the tree classes)             |
-|-----------------------------------------------------------------------------|
-| 2001-01-10 | Original Version Posted.                                       |
-| 2001-03-18 | Added getSelected and get/setBehavior  that can make it behave |
-|            | more like windows explorer, check usage for more information.  |
-| 2001-09-23 | Version 1.1 - New features included  keyboard  navigation (ie) |
-|            | and the ability  to add and  remove nodes dynamically and some |
-|            | other small tweaks and fixes.                                  |
-| 2002-01-27 | Version 1.11 - Bug fixes and improved mozilla support.         |
-| 2002-06-11 | Version 1.12 - Fixed a bug that prevented the indentation line |
-|            | from  updating correctly  under some  circumstances.  This bug |
-|            | happened when removing the last item in a subtree and items in |
-|            | siblings to the remove subtree where not correctly updated.    |
-| 2002-06-13 | Fixed a few minor bugs cased by the 1.12 bug-fix.              |
-| 2002-08-20 | Added usePersistence flag to allow disable of cookies.         |
-| 2002-10-23 | (1.14) Fixed a plus icon issue                                 |
-| 2002-10-29 | (1.15) Last changes broke more than they fixed. This version   |
-|            | is based on 1.13 and fixes the bugs 1.14 fixed withou breaking |
-|            | lots of other things.                                          |
-| 2003-02-15 | The  selected node can now be made visible even when  the tree |
-|            | control  loses focus.  It uses a new class  declaration in the |
-|            | css file '.webfx-tree-item a.selected-inactive', by default it |
-|            | puts a light-gray rectangle around the selected node.          |
-| 2003-03-16 | Adding target support after lots of lobbying...                |
-|-----------------------------------------------------------------------------|
-| Created 2000-12-11 | All changes are in the log above. | Updated 2003-03-16 |
-\----------------------------------------------------------------------------*/
-
-var webFXTreeConfig = {
-       rootIcon        : 'images/foldericon.png',
-       openRootIcon    : 'images/openfoldericon.png',
-       folderIcon      : 'images/foldericon.png',
-       openFolderIcon  : 'images/openfoldericon.png',
-       fileIcon        : 'images/file.png',
-       iIcon           : 'images/I.png',
-       lIcon           : 'images/L.png',
-       lMinusIcon      : 'images/Lminus.png',
-       lPlusIcon       : 'images/Lplus.png',
-       tIcon           : 'images/T.png',
-       tMinusIcon      : 'images/Tminus.png',
-       tPlusIcon       : 'images/Tplus.png',
-       blankIcon       : 'images/blank.png',
-       defaultText     : 'Tree Item',
-       defaultAction   : 'javascript:void(0);',
-       defaultBehavior : 'classic',
-       usePersistence  : true
-};
-
-var webFXTreeHandler = {
-       idCounter : 0,
-       idPrefix  : "webfx-tree-object-",
-       all       : {},
-       behavior  : null,
-       selected  : null,
-       onSelect  : null, /* should be part of tree, not handler */
-       getId     : function() { return this.idPrefix + this.idCounter++; },
-       toggle    : function (oItem) { this.all[oItem.id.replace('-plus','')].toggle(); },
-       select    : function (oItem) { this.all[oItem.id.replace('-icon','')].select(); },
-       focus     : function (oItem) { this.all[oItem.id.replace('-anchor','')].focus(); },
-       blur      : function (oItem) { this.all[oItem.id.replace('-anchor','')].blur(); },
-       keydown   : function (oItem, e) { return this.all[oItem.id].keydown(e.keyCode); },
-       cookies   : new WebFXCookie(),
-       insertHTMLBeforeEnd     :       function (oElement, sHTML) {
-               if (oElement.insertAdjacentHTML != null) {
-                       oElement.insertAdjacentHTML("BeforeEnd", sHTML)
-                       return;
-               }
-               var df; // DocumentFragment
-               var r = oElement.ownerDocument.createRange();
-               r.selectNodeContents(oElement);
-               r.collapse(false);
-               df = r.createContextualFragment(sHTML);
-               oElement.appendChild(df);
-       }
-};
-
-/*
- * WebFXCookie class
- */
-
-function WebFXCookie() {
-       if (document.cookie.length) { this.cookies = ' ' + document.cookie; }
-}
-
-WebFXCookie.prototype.setCookie = function (key, value) {
-       document.cookie = key + "=" + escape(value);
-}
-
-WebFXCookie.prototype.getCookie = function (key) {
-       if (this.cookies) {
-               var start = this.cookies.indexOf(' ' + key + '=');
-               if (start == -1) { return null; }
-               var end = this.cookies.indexOf(";", start);
-               if (end == -1) { end = this.cookies.length; }
-               end -= start;
-               var cookie = this.cookies.substr(start,end);
-               return unescape(cookie.substr(cookie.indexOf('=') + 1, cookie.length - cookie.indexOf('=') + 1));
-       }
-       else { return null; }
-}
-
-/*
- * WebFXTreeAbstractNode class
- */
-
-function WebFXTreeAbstractNode(sText, sAction) {
-       this.childNodes  = [];
-       this.id     = webFXTreeHandler.getId();
-       this.text   = sText || webFXTreeConfig.defaultText;
-       this.action = sAction || webFXTreeConfig.defaultAction;
-       this._last  = false;
-       webFXTreeHandler.all[this.id] = this;
-}
-
-/*
- * To speed thing up if you're adding multiple nodes at once (after load)
- * use the bNoIdent parameter to prevent automatic re-indentation and call
- * the obj.ident() method manually once all nodes has been added.
- */
-
-WebFXTreeAbstractNode.prototype.add = function (node, bNoIdent) {
-       node.parentNode = this;
-       this.childNodes[this.childNodes.length] = node;
-       var root = this;
-       if (this.childNodes.length >= 2) {
-               this.childNodes[this.childNodes.length - 2]._last = false;
-       }
-       while (root.parentNode) { root = root.parentNode; }
-       if (root.rendered) {
-               if (this.childNodes.length >= 2) {
-                       document.getElementById(this.childNodes[this.childNodes.length - 2].id + '-plus').src = ((this.childNodes[this.childNodes.length -2].folder)?((this.childNodes[this.childNodes.length -2].open)?webFXTreeConfig.tMinusIcon:webFXTreeConfig.tPlusIcon):webFXTreeConfig.tIcon);
-                       this.childNodes[this.childNodes.length - 2].plusIcon = webFXTreeConfig.tPlusIcon;
-                       this.childNodes[this.childNodes.length - 2].minusIcon = webFXTreeConfig.tMinusIcon;
-                       this.childNodes[this.childNodes.length - 2]._last = false;
-               }
-               this._last = true;
-               var foo = this;
-               while (foo.parentNode) {
-                       for (var i = 0; i < foo.parentNode.childNodes.length; i++) {
-                               if (foo.id == foo.parentNode.childNodes[i].id) { break; }
-                       }
-                       if (i == foo.parentNode.childNodes.length - 1) { foo.parentNode._last = true; }
-                       else { foo.parentNode._last = false; }
-                       foo = foo.parentNode;
-               }
-               webFXTreeHandler.insertHTMLBeforeEnd(document.getElementById(this.id + '-cont'), node.toString());
-               if ((!this.folder) && (!this.openIcon)) {
-                       this.icon = webFXTreeConfig.folderIcon;
-                       this.openIcon = webFXTreeConfig.openFolderIcon;
-               }
-               if (!this.folder) { this.folder = true; this.collapse(true); }
-               if (!bNoIdent) { this.indent(); }
-       }
-       return node;
-}
-
-WebFXTreeAbstractNode.prototype.toggle = function() {
-       if (this.folder) {
-               if (this.open) { this.collapse(); }
-               else { this.expand(); }
-}      }
-
-WebFXTreeAbstractNode.prototype.select = function() {
-       document.getElementById(this.id + '-anchor').focus();
-}
-
-WebFXTreeAbstractNode.prototype.deSelect = function() {
-       document.getElementById(this.id + '-anchor').className = '';
-       webFXTreeHandler.selected = null;
-}
-
-WebFXTreeAbstractNode.prototype.focus = function() {
-       if ((webFXTreeHandler.selected) && (webFXTreeHandler.selected != this)) { webFXTreeHandler.selected.deSelect(); }
-       webFXTreeHandler.selected = this;
-       if ((this.openIcon) && (webFXTreeHandler.behavior != 'classic')) { document.getElementById(this.id + '-icon').src = this.openIcon; }
-       document.getElementById(this.id + '-anchor').className = 'selected';
-       document.getElementById(this.id + '-anchor').focus();
-       if (webFXTreeHandler.onSelect) { webFXTreeHandler.onSelect(this); }
-}
-
-WebFXTreeAbstractNode.prototype.blur = function() {
-       if ((this.openIcon) && (webFXTreeHandler.behavior != 'classic')) { document.getElementById(this.id + '-icon').src = this.icon; }
-       document.getElementById(this.id + '-anchor').className = 'selected-inactive';
-}
-
-WebFXTreeAbstractNode.prototype.doExpand = function() {
-       if (webFXTreeHandler.behavior == 'classic') { document.getElementById(this.id + '-icon').src = this.openIcon; }
-       if (this.childNodes.length) {  document.getElementById(this.id + '-cont').style.display = 'block'; }
-       this.open = true;
-       if (webFXTreeConfig.usePersistence) {
-               webFXTreeHandler.cookies.setCookie(this.id.substr(18,this.id.length - 18), '1');
-}      }
-
-WebFXTreeAbstractNode.prototype.doCollapse = function() {
-       if (webFXTreeHandler.behavior == 'classic') { document.getElementById(this.id + '-icon').src = this.icon; }
-       if (this.childNodes.length) { document.getElementById(this.id + '-cont').style.display = 'none'; }
-       this.open = false;
-       if (webFXTreeConfig.usePersistence) {
-               webFXTreeHandler.cookies.setCookie(this.id.substr(18,this.id.length - 18), '0');
-}      }
-
-WebFXTreeAbstractNode.prototype.expandAll = function() {
-       this.expandChildren();
-       if ((this.folder) && (!this.open)) { this.expand(); }
-}
-
-WebFXTreeAbstractNode.prototype.expandChildren = function() {
-       for (var i = 0; i < this.childNodes.length; i++) {
-               this.childNodes[i].expandAll();
-} }
-
-WebFXTreeAbstractNode.prototype.collapseAll = function() {
-       this.collapseChildren();
-       if ((this.folder) && (this.open)) { this.collapse(true); }
-}
-
-WebFXTreeAbstractNode.prototype.collapseChildren = function() {
-       for (var i = 0; i < this.childNodes.length; i++) {
-               this.childNodes[i].collapseAll();
-} }
-
-WebFXTreeAbstractNode.prototype.indent = function(lvl, del, last, level, nodesLeft) {
-       /*
-        * Since we only want to modify items one level below ourself,
-        * and since the rightmost indentation position is occupied by
-        * the plus icon we set this to -2
-        */
-       if (lvl == null) { lvl = -2; }
-       var state = 0;
-       for (var i = this.childNodes.length - 1; i >= 0 ; i--) {
-               state = this.childNodes[i].indent(lvl + 1, del, last, level);
-               if (state) { return; }
-       }
-       if (del) {
-               if ((level >= this._level) && (document.getElementById(this.id + '-plus'))) {
-                       if (this.folder) {
-                               document.getElementById(this.id + '-plus').src = (this.open)?webFXTreeConfig.lMinusIcon:webFXTreeConfig.lPlusIcon;
-                               this.plusIcon = webFXTreeConfig.lPlusIcon;
-                               this.minusIcon = webFXTreeConfig.lMinusIcon;
-                       }
-                       else if (nodesLeft) { document.getElementById(this.id + '-plus').src = webFXTreeConfig.lIcon; }
-                       return 1;
-       }       }
-       var foo = document.getElementById(this.id + '-indent-' + lvl);
-       if (foo) {
-               if ((foo._last) || ((del) && (last))) { foo.src =  webFXTreeConfig.blankIcon; }
-               else { foo.src =  webFXTreeConfig.iIcon; }
-       }
-       return 0;
-}
-
-/*
- * WebFXTree class
- */
-
-function WebFXTree(sText, sAction, sBehavior, sIcon, sOpenIcon) {
-       this.base = WebFXTreeAbstractNode;
-       this.base(sText, sAction);
-       this.icon      = sIcon || webFXTreeConfig.rootIcon;
-       this.openIcon  = sOpenIcon || webFXTreeConfig.openRootIcon;
-       /* Defaults to open */
-       if (webFXTreeConfig.usePersistence) {
-               this.open  = (webFXTreeHandler.cookies.getCookie(this.id.substr(18,this.id.length - 18)) == '0')?false:true;
-       } else { this.open  = true; }
-       this.folder    = true;
-       this.rendered  = false;
-       this.onSelect  = null;
-       if (!webFXTreeHandler.behavior) {  webFXTreeHandler.behavior = sBehavior || webFXTreeConfig.defaultBehavior; }
-}
-
-WebFXTree.prototype = new WebFXTreeAbstractNode;
-
-WebFXTree.prototype.setBehavior = function (sBehavior) {
-       webFXTreeHandler.behavior =  sBehavior;
-};
-
-WebFXTree.prototype.getBehavior = function (sBehavior) {
-       return webFXTreeHandler.behavior;
-};
-
-WebFXTree.prototype.getSelected = function() {
-       if (webFXTreeHandler.selected) { return webFXTreeHandler.selected; }
-       else { return null; }
-}
-
-WebFXTree.prototype.remove = function() { }
-
-WebFXTree.prototype.expand = function() {
-       this.doExpand();
-}
-
-WebFXTree.prototype.collapse = function(b) {
-       if (!b) { this.focus(); }
-       this.doCollapse();
-}
-
-WebFXTree.prototype.getFirst = function() {
-       return null;
-}
-
-WebFXTree.prototype.getLast = function() {
-       return null;
-}
-
-WebFXTree.prototype.getNextSibling = function() {
-       return null;
-}
-
-WebFXTree.prototype.getPreviousSibling = function() {
-       return null;
-}
-
-WebFXTree.prototype.keydown = function(key) {
-       if (key == 39) {
-               if (!this.open) { this.expand(); }
-               else if (this.childNodes.length) { this.childNodes[0].select(); }
-               return false;
-       }
-       if (key == 37) { this.collapse(); return false; }
-       if ((key == 40) && (this.open) && (this.childNodes.length)) { this.childNodes[0].select(); return false; }
-       return true;
-}
-
-WebFXTree.prototype.toString = function() {
-       var str = "<div id=\"" + this.id + "\" ondblclick=\"webFXTreeHandler.toggle(this);\" class=\"webfx-tree-item\" onkeydown=\"return webFXTreeHandler.keydown(this, event)\">" +
-               "<img id=\"" + this.id + "-icon\" class=\"webfx-tree-icon\" src=\"" + ((webFXTreeHandler.behavior == 'classic' && this.open)?this.openIcon:this.icon) + "\" onclick=\"webFXTreeHandler.select(this);\">" +
-               "<a href=\"" + this.action + "\" id=\"" + this.id + "-anchor\" onfocus=\"webFXTreeHandler.focus(this);\" onblur=\"webFXTreeHandler.blur(this);\"" +
-               (this.target ? " target=\"" + this.target + "\"" : "") +
-               ">" + this.text + "</a></div>" +
-               "<div id=\"" + this.id + "-cont\" class=\"webfx-tree-container\" style=\"display: " + ((this.open)?'block':'none') + ";\">";
-       var sb = [];
-       for (var i = 0; i < this.childNodes.length; i++) {
-               sb[i] = this.childNodes[i].toString(i, this.childNodes.length);
-       }
-       this.rendered = true;
-       return str + sb.join("") + "</div>";
-};
-
-/*
- * WebFXTreeItem class
- */
-
-function WebFXTreeItem(sText, sAction, eParent, sIcon, sOpenIcon) {
-       this.base = WebFXTreeAbstractNode;
-       this.base(sText, sAction);
-       /* Defaults to close */
-       if (webFXTreeConfig.usePersistence) {
-               this.open = (webFXTreeHandler.cookies.getCookie(this.id.substr(18,this.id.length - 18)) == '1')?true:false;
-       } else { this.open = false; }
-       if (sIcon) { this.icon = sIcon; }
-       if (sOpenIcon) { this.openIcon = sOpenIcon; }
-       if (eParent) { eParent.add(this); }
-}
-
-WebFXTreeItem.prototype = new WebFXTreeAbstractNode;
-
-WebFXTreeItem.prototype.remove = function() {
-       var iconSrc = document.getElementById(this.id + '-plus').src;
-       var parentNode = this.parentNode;
-       var prevSibling = this.getPreviousSibling(true);
-       var nextSibling = this.getNextSibling(true);
-       var folder = this.parentNode.folder;
-       var last = ((nextSibling) && (nextSibling.parentNode) && (nextSibling.parentNode.id == parentNode.id))?false:true;
-       this.getPreviousSibling().focus();
-       this._remove();
-       if (parentNode.childNodes.length == 0) {
-               document.getElementById(parentNode.id + '-cont').style.display = 'none';
-               parentNode.doCollapse();
-               parentNode.folder = false;
-               parentNode.open = false;
-       }
-       if (!nextSibling || last) { parentNode.indent(null, true, last, this._level, parentNode.childNodes.length); }
-       if ((prevSibling == parentNode) && !(parentNode.childNodes.length)) {
-               prevSibling.folder = false;
-               prevSibling.open = false;
-               iconSrc = document.getElementById(prevSibling.id + '-plus').src;
-               iconSrc = iconSrc.replace('minus', '').replace('plus', '');
-               document.getElementById(prevSibling.id + '-plus').src = iconSrc;
-               document.getElementById(prevSibling.id + '-icon').src = webFXTreeConfig.fileIcon;
-       }
-       if (document.getElementById(prevSibling.id + '-plus')) {
-               if (parentNode == prevSibling.parentNode) {
-                       iconSrc = iconSrc.replace('minus', '').replace('plus', '');
-                       document.getElementById(prevSibling.id + '-plus').src = iconSrc;
-}      }       }
-
-WebFXTreeItem.prototype._remove = function() {
-       for (var i = this.childNodes.length - 1; i >= 0; i--) {
-               this.childNodes[i]._remove();
-       }
-       for (var i = 0; i < this.parentNode.childNodes.length; i++) {
-               if (this == this.parentNode.childNodes[i]) {
-                       for (var j = i; j < this.parentNode.childNodes.length; j++) {
-                               this.parentNode.childNodes[j] = this.parentNode.childNodes[j+1];
-                       }
-                       this.parentNode.childNodes.length -= 1;
-                       if (i + 1 == this.parentNode.childNodes.length) { this.parentNode._last = true; }
-                       break;
-       }       }
-       webFXTreeHandler.all[this.id] = null;
-       var tmp = document.getElementById(this.id);
-       if (tmp) { tmp.parentNode.removeChild(tmp); }
-       tmp = document.getElementById(this.id + '-cont');
-       if (tmp) { tmp.parentNode.removeChild(tmp); }
-}
-
-WebFXTreeItem.prototype.expand = function() {
-       this.doExpand();
-       document.getElementById(this.id + '-plus').src = this.minusIcon;
-}
-
-WebFXTreeItem.prototype.collapse = function(b) {
-       if (!b) { this.focus(); }
-       this.doCollapse();
-       document.getElementById(this.id + '-plus').src = this.plusIcon;
-}
-
-WebFXTreeItem.prototype.getFirst = function() {
-       return this.childNodes[0];
-}
-
-WebFXTreeItem.prototype.getLast = function() {
-       if (this.childNodes[this.childNodes.length - 1].open) { return this.childNodes[this.childNodes.length - 1].getLast(); }
-       else { return this.childNodes[this.childNodes.length - 1]; }
-}
-
-WebFXTreeItem.prototype.getNextSibling = function() {
-       for (var i = 0; i < this.parentNode.childNodes.length; i++) {
-               if (this == this.parentNode.childNodes[i]) { break; }
-       }
-       if (++i == this.parentNode.childNodes.length) { return this.parentNode.getNextSibling(); }
-       else { return this.parentNode.childNodes[i]; }
-}
-
-WebFXTreeItem.prototype.getPreviousSibling = function(b) {
-       for (var i = 0; i < this.parentNode.childNodes.length; i++) {
-               if (this == this.parentNode.childNodes[i]) { break; }
-       }
-       if (i == 0) { return this.parentNode; }
-       else {
-               if ((this.parentNode.childNodes[--i].open) || (b && this.parentNode.childNodes[i].folder)) { return this.parentNode.childNodes[i].getLast(); }
-               else { return this.parentNode.childNodes[i]; }
-} }
-
-WebFXTreeItem.prototype.keydown = function(key) {
-       if ((key == 39) && (this.folder)) {
-               if (!this.open) { this.expand(); }
-               else { this.getFirst().select(); }
-               return false;
-       }
-       else if (key == 37) {
-               if (this.open) { this.collapse(); }
-               else { this.parentNode.select(); }
-               return false;
-       }
-       else if (key == 40) {
-               if (this.open) { this.getFirst().select(); }
-               else {
-                       var sib = this.getNextSibling();
-                       if (sib) { sib.select(); }
-               }
-               return false;
-       }
-       else if (key == 38) { this.getPreviousSibling().select(); return false; }
-       return true;
-}
-
-WebFXTreeItem.prototype.toString = function (nItem, nItemCount) {
-       var foo = this.parentNode;
-       var indent = '';
-       if (nItem + 1 == nItemCount) { this.parentNode._last = true; }
-       var i = 0;
-       while (foo.parentNode) {
-               foo = foo.parentNode;
-               indent = "<img id=\"" + this.id + "-indent-" + i + "\" src=\"" + ((foo._last)?webFXTreeConfig.blankIcon:webFXTreeConfig.iIcon) + "\">" + indent;
-               i++;
-       }
-       this._level = i;
-       if (this.childNodes.length) { this.folder = 1; }
-       else { this.open = false; }
-       if ((this.folder) || (webFXTreeHandler.behavior != 'classic')) {
-               if (!this.icon) { this.icon = webFXTreeConfig.folderIcon; }
-               if (!this.openIcon) { this.openIcon = webFXTreeConfig.openFolderIcon; }
-       }
-       else if (!this.icon) { this.icon = webFXTreeConfig.fileIcon; }
-       var label = this.text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
-       var str = "<div id=\"" + this.id + "\" ondblclick=\"webFXTreeHandler.toggle(this);\" class=\"webfx-tree-item\" onkeydown=\"return webFXTreeHandler.keydown(this, event)\">" +
-               indent +
-               "<img id=\"" + this.id + "-plus\" src=\"" + ((this.folder)?((this.open)?((this.parentNode._last)?webFXTreeConfig.lMinusIcon:webFXTreeConfig.tMinusIcon):((this.parentNode._last)?webFXTreeConfig.lPlusIcon:webFXTreeConfig.tPlusIcon)):((this.parentNode._last)?webFXTreeConfig.lIcon:webFXTreeConfig.tIcon)) + "\" onclick=\"webFXTreeHandler.toggle(this);\">" +
-               "<img id=\"" + this.id + "-icon\" class=\"webfx-tree-icon\" src=\"" + ((webFXTreeHandler.behavior == 'classic' && this.open)?this.openIcon:this.icon) + "\" onclick=\"webFXTreeHandler.select(this);\">" +
-               "<a href=\"" + this.action + "\" id=\"" + this.id + "-anchor\" onfocus=\"webFXTreeHandler.focus(this);\" onblur=\"webFXTreeHandler.blur(this);\"" +
-               (this.target ? " target=\"" + this.target + "\"" : "") +
-               ">" + label + "</a></div>" +
-               "<div id=\"" + this.id + "-cont\" class=\"webfx-tree-container\" style=\"display: " + ((this.open)?'block':'none') + ";\">";
-       var sb = [];
-       for (var i = 0; i < this.childNodes.length; i++) {
-               sb[i] = this.childNodes[i].toString(i,this.childNodes.length);
-       }
-       this.plusIcon = ((this.parentNode._last)?webFXTreeConfig.lPlusIcon:webFXTreeConfig.tPlusIcon);
-       this.minusIcon = ((this.parentNode._last)?webFXTreeConfig.lMinusIcon:webFXTreeConfig.tMinusIcon);
-       return str + sb.join("") + "</div>";
-}
\ No newline at end of file
diff --git a/xloadtree/xtree2.js b/xloadtree/xtree2.js
new file mode 100644 (file)
index 0000000..26244ba
--- /dev/null
@@ -0,0 +1,1664 @@
+/*----------------------------------------------------------------------------\
+|                            XTree 2 PRE RELEASE                              |
+|                                                                             |
+| This is a pre release and redistribution is discouraged.                    |
+| Watch http://webfx.eae.net for the final version                            |
+|                                                                             |
+|-----------------------------------------------------------------------------|
+|                   Created by Erik Arvidsson & Emil A Eklund                 |
+|                  (http://webfx.eae.net/contact.html#erik)                   |
+|                  (http://webfx.eae.net/contact.html#emil)                   |
+|                      For WebFX (http://webfx.eae.net/)                      |
+|-----------------------------------------------------------------------------|
+| A tree menu system for IE 5.5+, Mozilla 1.4+, Opera 7, KHTML                |
+|-----------------------------------------------------------------------------|
+|         Copyright (c) 1999 - 2004 Erik Arvidsson & Emil A Eklund            |
+|-----------------------------------------------------------------------------|
+| This software is provided "as is", without warranty of any kind, express or |
+| implied, including  but not limited  to the warranties of  merchantability, |
+| fitness for a particular purpose and noninfringement. In no event shall the |
+| authors or  copyright  holders be  liable for any claim,  damages or  other |
+| liability, whether  in an  action of  contract, tort  or otherwise, arising |
+| from,  out of  or in  connection with  the software or  the  use  or  other |
+| dealings in the software.                                                   |
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
+| This  software is  available under the  three different licenses  mentioned |
+| below.  To use this software you must chose, and qualify, for one of those. |
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
+| The WebFX Non-Commercial License          http://webfx.eae.net/license.html |
+| Permits  anyone the right to use the  software in a  non-commercial context |
+| free of charge.                                                             |
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
+| The WebFX Commercial license           http://webfx.eae.net/commercial.html |
+| Permits the  license holder the right to use  the software in a  commercial |
+| context. Such license must be specifically obtained, however it's valid for |
+| any number of  implementations of the licensed software.                    |
+| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
+| GPL - The GNU General Public License    http://www.gnu.org/licenses/gpl.txt |
+| Permits anyone the right to use and modify the software without limitations |
+| as long as proper  credits are given  and the original  and modified source |
+| code are included. Requires  that the final product, software derivate from |
+| the original  source or any  software  utilizing a GPL  component, such  as |
+| this, is also licensed under the GPL license.                               |
+|-----------------------------------------------------------------------------|
+| 2004-02-21 | Pre release distributed to a few selected tester               |
+|-----------------------------------------------------------------------------|
+| Dependencies: xtree2.css Used to define the look and feel                   |
+|-----------------------------------------------------------------------------|
+| Created 2003-??-?? | All changes are in the log above. | Updated 2004-02-21 |
+\----------------------------------------------------------------------------*/
+
+
+//
+// WebFXTreePersisitance
+function WebFXTreePersistence() {}
+WebFXTreePersistence.prototype.getExpanded = function (oNode) { return false; };
+WebFXTreePersistence.prototype.setExpanded = function (oNode, bOpen) {};
+
+
+
+// Cookie handling
+function WebFXCookie() {}
+
+WebFXCookie.prototype.setCookie = function (sName, sValue, nDays)
+{
+       var expires = "";
+       if (typeof nDays == "number")
+       {
+               var d = new Date();
+               d.setTime(d.getTime() + nDays * 24 * 60 * 60 * 1000);
+               expires = "; expires=" + d.toGMTString();
+       }
+
+       document.cookie = sName + "=" + escape(sValue) + expires + "; path=/";
+};
+
+WebFXCookie.prototype.getCookie = function (sName)
+{
+       var re = new RegExp("(\;|^)[^;]*(" + sName + ")\=([^;]*)(;|$)");
+       var res = re.exec(document.cookie);
+       return res != null ? unescape(res[3]) : null;
+};
+
+WebFXCookie.prototype.removeCookie = function (name)
+{
+       this.setCookie(name, "", -1);
+};
+
+
+//
+// persistence using cookies
+//
+// This is uses one cookie with the ids of the expanded nodes separated using '+'
+//
+function WebFXTreeCookiePersistence()
+{
+       this._openedMap = {};
+       this._cookies = new WebFXCookie;
+       var s = this._cookies.getCookie(this.cookieName);
+       if (s)
+       {
+               var a = s.split("+");
+               for (var i = a.length - 1; i >= 0; i--)
+                       this._openedMap[a[i]] = true;
+       }
+}
+
+WebFXTreeCookiePersistence.prototype = new WebFXTreePersistence;
+
+WebFXTreeCookiePersistence.prototype.cookieName = "webfx-tree-cookie-persistence"
+
+WebFXTreeCookiePersistence.prototype.getExpanded = function (oNode)
+{
+       return oNode.id in this._openedMap;
+};
+
+WebFXTreeCookiePersistence.prototype.setExpanded = function (oNode, bOpen)
+{
+       var old = this.getExpanded(oNode);
+       if (old != bOpen)
+       {
+               if (bOpen)
+                       this._openedMap[oNode.id] = true;
+               else
+                       delete this._openedMap[oNode.id];
+
+               var res = [];
+               var i = 0;
+               for (var id in this._openedMap)
+                       res[i++] = id;
+               this._cookies.setCookie(this.cookieName, res.join("+"));
+       }
+};
+
+
+
+// this object provides a few useful methods when working with arrays
+var arrayHelper =
+{
+       indexOf:                function (a, o)
+       {
+               for (var i = 0; i < a.length; i++)
+               {
+                       if (a[i] == o)
+                               return i;
+               }
+               return -1;
+       },
+
+       insertBefore:   function (a, o, o2)
+       {
+               var i = this.indexOf(a, o2);
+               if (i == -1)
+                       a.push(o);
+               else
+                       a.splice(i, 0, o);
+       },
+
+       remove:                 function (a, o)
+       {
+               var i = this.indexOf(a, o);
+               if (i != -1)
+                       a.splice(i, 1);
+       }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// WebFX Tree Config object                                                  //
+///////////////////////////////////////////////////////////////////////////////
+var webFXTreeConfig = {
+       rootIcon        : 'images/folder.png',
+       openRootIcon    : 'images/openfolder.png',
+       folderIcon      : 'images/folder.png',
+       openFolderIcon  : 'images/openfolder.png',
+       fileIcon        : 'images/file.png',
+       iIcon           : 'images/I.png',
+       lIcon           : 'images/L.png',
+       lMinusIcon      : 'images/Lminus.png',
+       lPlusIcon       : 'images/Lplus.png',
+       tIcon           : 'images/T.png',
+       tMinusIcon      : 'images/Tminus.png',
+       tPlusIcon       : 'images/Tplus.png',
+       plusIcon        : 'images/plus.png',
+       minusIcon       : 'images/minus.png',
+       blankIcon       : 'images/blank.png',
+       defaultText     : 'Tree Item',
+       defaultAction   : null,
+       defaultBehavior : 'classic',
+       usePersistence  : true
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// WebFX Tree Handler object                                                 //
+///////////////////////////////////////////////////////////////////////////////
+
+var webFXTreeHandler = {
+       ie:             /msie/i.test(navigator.userAgent),
+       idCounter : 0,
+       idPrefix  : "wfxt-",
+       getUniqueId:    function ()
+       {
+               return this.idPrefix + this.idCounter++;
+       },
+       all       : {},
+       getNodeById:    function (sId)
+       {
+               return all[sId];
+       },
+       addNode:        function (oNode)
+       {
+               this.all[oNode.id] = oNode;
+       },
+       removeNode:     function (oNode)
+       {
+               delete this.all[oNode.id];
+       },
+
+       handleEvent:    function (e)
+       {
+               var el = e.target || e.srcElement;
+               while (el != null && !this.all[el.id])
+                       el = el.parentNode;
+
+               if (el == null)
+                       return false;
+               var node = this.all[el.id];
+               switch (e.type)
+               {
+                       case "mousedown":
+                               return node._onMouseDown(e);
+                       case "click":
+                               return node._onClick(e);
+                       case "dblclick":
+                               return node._onDblClick(e);
+                       case "focus":
+                               return node._onFocus(e);
+                       case "blur":
+                               return node._onBlur(e);
+                       case "keydown":
+                               return node._onKeyDown(e);
+                       case "keypress":
+                               return node._onKeyPress(e);
+               }
+               return false;
+       },
+
+       dispose:        function ()
+       {
+               if (this.disposed) return;
+               for (var id in this.all)
+                       this.all[id].dispose();
+               this.disposed = true;
+       },
+
+       opera:          /opera/i.test(navigator.userAgent),
+
+       htmlToText:             function (s)
+       {
+               return String(s).replace(/\s+|<([^>])+>|&amp;|&lt;|&gt;|&quot;|&nbsp;/gi, this._htmlToText);
+       },
+
+       _htmlToText:    function (s)
+       {
+               switch (s)
+               {
+                       case "&amp;":
+                               return "&";
+                       case "&lt;":
+                               return "<";
+                       case "&gt;":
+                               return ">";
+                       case "&quot;":
+                               return "\"";
+                       case "&nbsp;":
+                               return String.fromCharCode(160);
+                       default:
+                               if (/\s+/.test(s))
+                                       return " ";
+                               if (/^<BR/gi.test(s))
+                                       return "\n";
+                               return "";
+               }
+       },
+
+       textToHtml:             function (s)
+       {
+               return String(s).replace(/&|<|>|\n|\"\u00A0/g, this._textToHtml);
+       },
+
+       _textToHtml:    function (s)
+       {
+               switch (s)
+               {
+                       case "&":
+                               return "&amp;";
+                       case "<":
+                               return "&lt;";
+                       case ">":
+                               return "&gt;";
+                       case "\n":
+                               return "<BR>";
+                       case "\"":
+                               return "&quot;";        // so we can use this in attributes
+                       default:
+                               return "&nbsp;";
+               }
+       },
+
+       persistenceManager:     new WebFXTreeCookiePersistence()
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// WebFXTreeAbstractNode
+///////////////////////////////////////////////////////////////////////////////
+
+function WebFXTreeAbstractNode(sText, oAction)
+{
+       this.childNodes = [];
+       if (sText) this.text = sText;
+       if (oAction) this.action = oAction;
+       this.id = webFXTreeHandler.getUniqueId();
+       if (webFXTreeConfig.usePersistence)
+               this.open = webFXTreeHandler.persistenceManager.getExpanded(this);
+       webFXTreeHandler.addNode(this);
+}
+
+
+var _p = WebFXTreeAbstractNode.prototype;
+_p._selected = false;
+_p.indentWidth = 19;
+_p.open = false;
+_p.text = webFXTreeConfig.defaultText;
+_p.action = null;
+_p.target = null;
+_p.toolTip = null;
+_p._focused = false;
+
+/* begin tree model */
+
+_p.add = function (oChild, oBefore)
+{
+       var oldLast;
+       var emptyBefore = this.childNodes.length == 0;
+       var p = oChild.parentNode;
+
+       if (oBefore == null)
+       { // append
+               if (p != null)
+                       p.remove(oChild);
+               oldLast = this.getLastChild();
+               this.childNodes.push(oChild);
+       }
+       else
+       { // insertBefore
+               if (oBefore.parentNode != this)
+                       throw new Error("Can only add nodes before siblings");
+               if (p != null)
+                       p.remove(oChild);
+
+               arrayHelper.insertBefore(this.childNodes, oChild, oBefore);
+       }
+
+       oChild.parentNode = this;
+       var t = this.getTree();
+       if (t)
+               oChild.tree = t;
+       var d = this.getDepth();
+       if (d != null)
+               oChild.depth = d + 1;
+
+       if (this.getCreated() && !t.getSuspendRedraw())
+       {
+               var el = this.getChildrenElement();
+               var newEl = oChild.create();
+               var refEl = oBefore ? oBefore.getElement() : null;
+               el.insertBefore(newEl, refEl);
+
+               if (oldLast)
+               {
+                       oldLast.updateExpandIcon();
+               }
+               if (emptyBefore)
+               {
+                       this.setExpanded(this.getExpanded());
+                       // if we are using classic expand will not update icon
+                       if (t && t.getBehavior() != "classic")
+                               this.updateIcon();
+               }
+       }
+
+       return oChild;
+};
+
+
+
+_p.remove = function (oChild)
+{
+       // backwards compatible. If no argument remove the node
+       if (arguments.length == 0)
+       {
+               if (this.parentNode)
+                       return this.parentNode.remove(this);
+               return null;
+       }
+
+       // if we remove selected or tree with the selected we should select this
+       var t = this.getTree();
+       var si = t ? t.getSelected() : null;
+       if (si == oChild || oChild.contains(si))
+       {
+               if (si.getFocused())
+               {
+                       this.select();
+                       window.setTimeout("WebFXTreeAbstractNode._onTimeoutFocus(\"" + this.id + "\")", 10);
+               }
+               else
+                       this.select();
+       }
+
+       var wasLast = oChild.isLastSibling();
+
+       if (oChild.parentNode != this)
+               throw new Error("Can only remove children");
+       arrayHelper.remove(this.childNodes, oChild);
+
+       oChild.parentNode = null;
+       oChild.tree = null;
+       oChild.depth = null;
+
+       if (t && this.getCreated() && !t.getSuspendRedraw())
+       {
+               var el = this.getChildrenElement();
+               var childEl = oChild.getElement();
+               el.removeChild(childEl);
+               if (wasLast)
+               {
+                       var newLast = this.getLastChild();
+                       if (newLast)
+                               newLast.updateExpandIcon();
+               }
+               if (!this.hasChildren())
+               {
+                       //this.setExpanded(this.getExpanded());
+                       el.style.display = "none";
+                       this.updateExpandIcon();
+                       this.updateIcon();
+               }
+       }
+
+       return oChild;
+};
+
+WebFXTreeAbstractNode._onTimeoutFocus = function (sId)
+{
+       var jsNode = webFXTreeHandler.all[sId];
+       jsNode.focus();
+};
+
+_p.getId = function ()
+{
+       return this.id;
+};
+
+_p.getTree = function ()
+{
+       throw new Error("getTree called on Abstract Node");
+};
+
+_p.getDepth = function ()
+{
+       throw new Error("getDepth called on Abstract Node");
+};
+
+_p.getCreated = function ()
+{
+       var t = this.getTree();
+       return t && t.rendered;
+};
+
+_p.getParent = function ()
+{
+       return this.parentNode;
+};
+
+_p.contains = function (oDescendant)
+{
+       if (oDescendant == null) return false;
+       if (oDescendant == this) return true;
+       var p = oDescendant.parentNode;
+       return this.contains(p);
+};
+
+_p.getChildren = _p.getChildNodes = function ()
+{
+       return this.childNodes;
+};
+
+_p.getFirstChild = function ()
+{
+       return this.childNodes[0];
+};
+
+_p.getLastChild = function ()
+{
+       return this.childNodes[this.childNodes.length - 1];
+};
+
+_p.getPreviousSibling = function ()
+{
+       var p = this.parentNode;
+       if (p == null) return null;
+       var cs = p.childNodes;
+       return cs[arrayHelper.indexOf(cs, this) - 1]
+};
+
+_p.getNextSibling = function ()
+{
+       var p = this.parentNode;
+       if (p == null) return null;
+       var cs = p.childNodes;
+       return cs[arrayHelper.indexOf(cs, this) + 1]
+};
+
+_p.hasChildren = function ()
+{
+       return this.childNodes.length > 0;
+};
+
+
+_p.isLastSibling = function ()
+{
+       return this.parentNode && this == this.parentNode.getLastChild();
+};
+
+_p.findChildByText = function (s, n)
+{
+       if (!n)
+               n = 0;
+       var isRe = s instanceof RegExp;
+       for (var i = 0; i < this.childNodes.length; i++)
+       {
+               if (isRe && s.test(this.childNodes[i].getText()) || this.childNodes[i].getText() == s)
+               {
+                       if (n == 0)
+                               return this.childNodes[i];
+                       n--;
+               }
+       }
+       return null;
+};
+
+_p.findNodeByText = function (s, n)
+{
+       if (!n)
+               n = 0;
+       var isRe = s instanceof RegExp;
+
+       if (isRe && s.test(this.getText()) || this.getText() == s)
+       {
+               if (n == 0)
+                       return this.childNodes[i];
+               n--;
+       }
+
+       var res;
+       for (var i = 0; i < this.childNodes.length; i++)
+       {
+               res = this.childNodes[i].findNodeByText(s, n);
+               if (res)
+                       return res;
+       }
+       return null;
+};
+
+/* end tree model */
+
+_p.setId = function (sId)
+{
+       var el = this.getElement();
+       webFXTreeHandler.removeNode(this);
+       this.id = sId;
+       if (el)
+               el.id = sId;
+       webFXTreeHandler.addNode(this);
+};
+
+_p.isSelected = function ()
+{
+       return this._selected;
+};
+
+_p.select = function () { this._setSelected(true); };
+_p.deselect = function () { this._setSelected(false); };
+
+_p._setSelected = function (b)
+{
+       var t = this.getTree();
+       if (!t) return;
+       if (this._selected != b)
+       {
+               this._selected = b;
+
+               var wasFocused = false; // used to keep focus state
+               var si = t.getSelected();
+               if (b && si != null && si != this)
+               {
+                       var oldFireChange = t._fireChange;
+                       wasFocused = si._focused;
+                       t._fireChange = false;
+                       si._setSelected(false);
+                       t._fireChange = oldFireChange;
+               }
+
+               var el = this.getRowElement();
+               if (el)
+               {
+                       el.className = this.getRowClassName();
+               }
+               if (b)
+               {
+                       t._selectedItem = this;
+                       t._fireOnChange();
+                       t.setSelected(this);
+                       if (wasFocused)
+                               this.focus();
+               }
+
+               if (t.getBehavior() != "classic")
+                       this.updateIcon();
+       }
+};
+
+
+_p.getExpanded = function ()
+{
+       return this.open;
+};
+
+_p.setExpanded = function (b)
+{
+       var ce;
+       this.open = b;
+       var t = this.getTree();
+       if (this.hasChildren())
+       {
+               var si = t ? t.getSelected() : null;
+               if (!b && this.contains(si))
+                       this.select();
+
+               var el = this.getElement();
+               if (el)
+               {
+                       ce = this.getChildrenElement();
+                       if (ce)
+                               ce.style.display = b ? "block" : "none";
+                       var eie = this.getExpandIconElement();
+                       if (eie)
+                               eie.src = this.getExpandIconSrc();
+               }
+
+               if (webFXTreeConfig.usePersistence)
+                       webFXTreeHandler.persistenceManager.setExpanded(this, b);
+       }
+       else
+       {
+               ce = this.getChildrenElement();
+               if (ce)
+                       ce.style.display = "none";
+       }
+       if (t && t.getBehavior() == "classic")
+               this.updateIcon();
+};
+
+_p.toggle = function ()
+{
+       this.setExpanded(!this.getExpanded());
+};
+
+_p.expand = function ()
+{
+       this.setExpanded(true);
+};
+
+_p.collapse = function ()
+{
+       this.setExpanded(false);
+};
+
+_p.collapseChildren = function()
+{
+       var cs = this.childNodes;
+       for (var i = 0; i < cs.length; i++)
+               cs[i].collapseAll();
+};
+
+_p.collapseAll = function()
+{
+       this.collapseChildren();
+       this.collapse();
+};
+
+_p.expandChildren = function()
+{
+       var cs = this.childNodes;
+       for (var i = 0; i < cs.length; i++)
+               cs[i].expandAll();
+};
+
+_p.expandAll = function ()
+{
+       this.expandChildren();
+       this.expand();
+};
+
+_p.reveal = function ()
+{
+       var p = this.getParent();
+       if (p)
+       {
+               p.setExpanded(true);
+               p.reveal();
+       }
+};
+
+_p.openPath = function (sPath, bSelect, bFocus)
+{
+       if (sPath == "")
+       {
+               if (bSelect)
+                       this.select();
+               if (bFocus)
+                       window.setTimeout("WebFXTreeAbstractNode._onTimeoutFocus(\"" + this.id + "\")", 10);
+               return;
+       }
+
+       var parts = sPath.split("/");
+       var remainingPath = parts.slice(1).join("/");
+       var t = this.getTree();
+       if (sPath.charAt(0) == "/")
+       {
+               if (t)
+                       t.openPath(remainingPath, bSelect, bFocus);
+               else
+                       throw "Invalid path";
+       }
+       else
+       {
+               // open
+               this.setExpanded(true);
+               parts = sPath.split("/");
+               var ti = this.findChildByText(parts[0]);
+               if (!ti)
+                       throw "Could not find child node with text \"" + parts[0] + "\"";
+               ti.openPath(remainingPath, bSelect, bFocus);
+       }
+};
+
+_p.focus = function ()
+{
+       var el = this.getLabelElement();
+       if (el)
+               el.focus();
+};
+
+_p.getFocused = function ()
+{
+       return this._focused;
+};
+
+// HTML generation
+
+_p.toHtml = function ()
+{
+       var childrenSb = [];
+       var cs = this.childNodes;
+       var l = cs.length;
+       for (var y = 0; y < l; y++)
+               childrenSb[y] = cs[y].toHtml();
+
+       var t = this.getTree();
+       var hideLines = !t.getShowLines() || t == this.parentNode && !t.getShowRootLines();
+
+       var childrenHtml = "<div class=\"webfx-tree-children" +
+               (hideLines ? "-nolines" : "") + "\" style=\"" +
+               this.getLineStyle() +
+               (this.getExpanded() && this.hasChildren() ? "" : "display:none;") +
+               "\">" +
+               childrenSb.join("") +
+               "</div>";
+
+       return "<div class=\"webfx-tree-item\" id=\"" +
+               this.id + "\"" + this.getEventHandlersHtml() + ">" +
+               this.getRowHtml() +
+               childrenHtml +
+               "</div>";
+};
+
+_p.getRowHtml = function ()
+{
+       var t = this.getTree();
+       return "<div class=\"" + this.getRowClassName() + "\" style=\"padding-left:" +
+               (this.getDepth() - 1) * this.indentWidth + "px\">" +
+               this.getExpandIconHtml() +
+               //"<span class=\"webfx-tree-icon-and-label\">" +
+               this.getIconHtml() +
+               this.getLabelHtml() +
+               //"</span>" +
+               "</div>";
+};
+
+_p.getRowClassName = function ()
+{
+       return "webfx-tree-row" + (this.isSelected() ? " selected" : "") +
+               (this.action ? "" : " no-action");
+};
+
+_p.getLabelHtml = function ()
+{
+       var toolTip = this.getToolTip();
+       var target = this.getTarget();
+       return "<a href=\"" + webFXTreeHandler.textToHtml(this._getHref()) +
+               "\" class=\"webfx-tree-item-label\"" +
+               (toolTip ? " title=\"" + webFXTreeHandler.textToHtml(toolTip) + "\"" : "") +
+               (target ? " target=\"" + target + "\"" : "") +
+               " onfocus=\"webFXTreeHandler.handleEvent(event)\"" +
+               " onblur=\"webFXTreeHandler.handleEvent(event)\">" +
+               this.getHtml() + "</a>";
+};
+
+_p._getHref = function ()
+{
+       if (typeof this.action == "string")
+               return this.action;
+       else
+               return "#";
+};
+
+_p.getEventHandlersHtml = function ()
+{
+       return "";
+};
+
+_p.getIconHtml = function ()
+{
+       // here we are not using textToHtml since the file names rarerly contains
+       // HTML...
+       return "<img class=\"webfx-tree-icon\" src=\"" + this.getIconSrc() + "\">";
+};
+
+_p.getIconSrc = function ()
+{
+       throw new Error("getIconSrc called on Abstract Node");
+};
+
+_p.getExpandIconHtml = function ()
+{
+       // here we are not using textToHtml since the file names rarerly contains
+       // HTML...
+       return "<img class=\"webfx-tree-expand-icon\" src=\"" +
+               this.getExpandIconSrc() + "\">";
+};
+
+
+_p.getExpandIconSrc = function ()
+{
+       var src;
+       var t = this.getTree();
+       var hideLines = !t.getShowLines() || t == this.parentNode && !t.getShowRootLines();
+
+       if (this.hasChildren())
+       {
+               var bits = 0;
+               /*
+                       Bitmap used to determine which icon to use
+                       1  Plus
+                       2  Minus
+                       4  T Line
+                       8  L Line
+               */
+
+               if (t && t.getShowExpandIcons())
+               {
+                       if (this.getExpanded())
+                               bits = 2;
+                       else
+                               bits = 1;
+               }
+
+               if (t && !hideLines)
+               {
+                       if (this.isLastSibling())
+                               bits += 4;
+                       else
+                               bits += 8;
+               }
+
+               switch (bits)
+               {
+                       case 1:
+                               return webFXTreeConfig.plusIcon;
+                       case 2:
+                               return webFXTreeConfig.minusIcon;
+                       case 4:
+                               return webFXTreeConfig.lIcon;
+                       case 5:
+                               return webFXTreeConfig.lPlusIcon;
+                       case 6:
+                               return webFXTreeConfig.lMinusIcon;
+                       case 8:
+                               return webFXTreeConfig.tIcon;
+                       case 9:
+                               return webFXTreeConfig.tPlusIcon;
+                       case 10:
+                               return webFXTreeConfig.tMinusIcon;
+                       default:        // 0
+                               return webFXTreeConfig.blankIcon;
+               }
+       }
+       else
+       {
+               if (t && hideLines)
+                       return webFXTreeConfig.blankIcon;
+               else if (this.isLastSibling())
+                       return webFXTreeConfig.lIcon;
+               else
+                       return webFXTreeConfig.tIcon;
+       }
+};
+
+_p.getLineStyle = function ()
+{
+       return "background-position:" + this.getLineStyle2() + ";";
+};
+
+_p.getLineStyle2 = function ()
+{
+       return (this.isLastSibling() ? "-100" : (this.getDepth() - 1) * this.indentWidth) + "px 0";
+};
+
+// End HTML generation
+
+// DOM
+// this returns the div for the tree node
+_p.getElement = function ()
+{
+       return document.getElementById(this.id);
+};
+
+// the row is the div that is used to draw the node without the children
+_p.getRowElement = function ()
+{
+       var el = this.getElement();
+       if (!el) return null;
+       return el.firstChild;
+};
+
+// plus/minus image
+_p.getExpandIconElement = function ()
+{
+       var el = this.getRowElement();
+       if (!el) return null;
+       return el.firstChild;
+};
+
+_p.getIconElement = function ()
+{
+       var el = this.getRowElement();
+       if (!el) return null;
+       return el.childNodes[1];
+};
+
+// anchor element
+_p.getLabelElement = function ()
+{
+       var el = this.getRowElement();
+       if (!el) return null;
+       return el.lastChild;
+};
+
+// the div containing the children
+_p.getChildrenElement = function ()
+{
+       var el = this.getElement();
+       if (!el) return null;
+       return el.lastChild;
+};
+
+
+// IE uses about:blank if not attached to document and this can cause Win2k3
+// to fail
+if (webFXTreeHandler.ie)
+{
+       _p.create = function ()
+       {
+               var dummy = document.createElement("div");
+               dummy.style.display = "none";
+               document.body.appendChild(dummy);
+               dummy.innerHTML = this.toHtml();
+               var res = dummy.removeChild(dummy.firstChild);
+               document.body.removeChild(dummy);
+               return res;
+       };
+}
+else
+{
+       _p.create = function ()
+       {
+               var dummy = document.createElement("div");
+               dummy.innerHTML = this.toHtml();
+               return dummy.removeChild(dummy.firstChild);
+       };
+
+}
+
+// Getters and setters for some common fields
+
+_p.setIcon = function (s)
+{
+       this.icon = s;
+       if (this.getCreated())
+               this.updateIcon();
+};
+
+_p.getIcon = function ()
+{
+       return this.icon;
+};
+
+_p.setOpenIcon = function (s)
+{
+       this.openIcon = s;
+       if (this.getCreated())
+               this.updateIcon();
+};
+
+_p.getOpenIcon = function ()
+{
+       return this.openIcon;
+};
+
+_p.setText = function (s)
+{
+       this.setHtml(webFXTreeHandler.textToHtml(s));
+};
+
+_p.getText = function ()
+{
+       return webFXTreeHandler.htmlToText(this.getHtml());
+};
+
+_p.setHtml = function (s)
+{
+       this.text = s;
+       var el = this.getLabelElement();
+       if (el)
+               el.innerHTML = s;
+};
+
+_p.getHtml = function ()
+{
+       return this.text;
+};
+
+_p.setTarget = function (s)
+{
+       this.target = s;
+};
+
+_p.getTarget = function ()
+{
+       return this.target;
+};
+
+_p.setToolTip = function (s)
+{
+       this.toolTip = s;
+       var el = this.getLabelElement();
+       if (el)
+               el.title = s;
+};
+
+_p.getToolTip = function ()
+{
+       return this.toolTip;
+};
+
+_p.setAction = function (oAction)
+{
+       this.action = oAction;
+       var el = this.getLabelElement();
+       if (el)
+               el.href = this._getHref();
+       el = this.getRowElement();
+       if (el)
+               el.className = this.getRowClassName();
+};
+
+_p.getAction = function ()
+{
+       return this.action;
+};
+
+// update methods
+
+_p.update = function ()
+{
+       var t = this.getTree();
+       if (t.suspendRedraw) return;
+       var el = this.getElement();
+       if (!el || !el.parentNode) return;
+       var newEl = this.create();
+       el.parentNode.replaceChild(newEl, el);
+
+       var si = t.getSelected();
+       if (si && si.getFocused())
+               si.focus();
+};
+
+_p.updateExpandIcon = function ()
+{
+       var t = this.getTree();
+       if (t.suspendRedraw) return;
+       var img = this.getExpandIconElement();
+       img.src = this.getExpandIconSrc();
+       var cel = this.getChildrenElement();
+       cel.style.backgroundPosition = this.getLineStyle2();
+};
+
+_p.updateIcon = function ()
+{
+       var t = this.getTree();
+       if (t.suspendRedraw) return;
+       var img = this.getIconElement();
+       img.src = this.getIconSrc();
+};
+
+// End DOM
+
+
+_p._callSuspended = function (f)
+{
+       var t = this.getTree();
+       var sr = t.getSuspendRedraw();
+       t.setSuspendRedraw(true);
+       f.call(this);
+       t.setSuspendRedraw(sr);
+};
+
+// Event handlers
+
+_p._onMouseDown = function (e)
+{
+       var el = e.target || e.srcElement;
+       // expand icon
+       if (/webfx-tree-expand-icon/.test(el.className) && this.hasChildren())
+       {
+               this.toggle();
+               if ( webFXTreeHandler.ie )
+                       window.setTimeout("WebFXTreeAbstractNode._onTimeoutFocus(\"" + this.id + "\")", 10);
+               return false;
+       }
+
+       this.select();
+       if (!/webfx-tree-item-label/.test(el.className) && !webFXTreeHandler.opera)     // opera cancels the click if focus is called
+       {
+               // in case we are not clicking on the label
+               if (webFXTreeHandler.ie)
+                       window.setTimeout("WebFXTreeAbstractNode._onTimeoutFocus(\"" + this.id + "\")", 10);
+               else
+                       this.focus();
+       }
+       var rowEl = this.getRowElement();
+       if (rowEl)
+               rowEl.className = this.getRowClassName();
+
+       return false;
+};
+
+_p._onClick = function (e)
+{
+       var el = e.target || e.srcElement;
+       // expand icon
+       if (/webfx-tree-expand-icon/.test(el.className) && this.hasChildren())
+               return false;
+
+       if (typeof this.action == "function")
+               this.action();
+       else if (this.action != null)
+               window.open(this.action, this.target || "_self");
+       return false;
+};
+
+
+_p._onDblClick = function (e)
+{
+       var el = e.target || e.srcElement;
+       // expand icon
+       if (/webfx-tree-expand-icon/.test(el.className) && this.hasChildren())
+               return;
+
+       this.toggle();
+};
+
+_p._onFocus = function (e)
+{
+       this.select();
+       this._focused = true;
+};
+
+_p._onBlur = function (e)
+{
+       this._focused = false;
+};
+
+_p._onKeyDown = function (e)
+{
+       var n;
+       var rv = true;
+       switch (e.keyCode)
+       {
+               case 39:        // RIGHT
+                       if (e.altKey)
+                       {
+                               rv = true;
+                               break;
+                       }
+                       if (this.hasChildren())
+                       {
+                               if (!this.getExpanded())
+                                       this.setExpanded(true);
+                               else
+                               {
+                                       this.getFirstChild().focus();
+                               }
+                       }
+                       rv = false;
+                       break;
+               case 37:        // LEFT
+                       if (e.altKey)
+                       {
+                               rv = true;
+                               break;
+                       }
+                       if (this.hasChildren() && this.getExpanded())
+                               this.setExpanded(false);
+                       else
+                       {
+                               var p = this.getParent();
+                               var t = this.getTree();
+                               // don't go to root if hidden
+                               if (p && (t.showRootNode || p != t))
+                               {
+                                       p.focus();
+                               }
+                       }
+                       rv = false;
+                       break;
+
+               case 40:        // DOWN
+                       n = this.getNextShownNode();
+                       if (n)
+                       {
+                               n.focus();
+                       }
+                       rv = false;
+                       break;
+               case 38:        // UP
+                       n = this.getPreviousShownNode()
+                       if (n)
+                       {
+                               n.focus();
+                       }
+                       rv = false;
+                       break;
+       }
+
+       if (!rv && e.preventDefault)
+               e.preventDefault();
+       e.returnValue = rv;
+       return rv;
+};
+
+_p._onKeyPress = function (e)
+{
+       if (!e.altKey && e.keyCode >= 37 && e.keyCode <= 40)
+       {
+               if (e.preventDefault)
+                       e.preventDefault();
+               e.returnValue = false;
+               return false;
+       }
+};
+
+// End event handlers
+
+_p.dispose = function ()
+{
+       if (this.disposed) return;
+       for (var i = this.childNodes.length - 1; i >= 0; i--)
+               this.childNodes[i].dispose();
+       this.tree = null;
+       this.parentNode = null;
+       this.childNodes = null;
+       this.disposed = true;
+};
+
+// Some methods that are usable when navigating the tree using the arrows
+_p.getLastShownDescendant = function ()
+{
+       if (!this.getExpanded() || !this.hasChildren())
+               return this;
+       // we know there is at least 1 child
+       return this.getLastChild().getLastShownDescendant();
+};
+
+_p.getNextShownNode = function ()
+{
+       if (this.hasChildren() && this.getExpanded())
+               return this.getFirstChild();
+       else
+       {
+               var p = this;
+               var next;
+               while (p != null)
+               {
+                       next = p.getNextSibling();
+                       if (next != null)
+                               return next;
+                       p = p.getParent();
+               }
+               return null;
+       }
+};
+
+_p.getPreviousShownNode = function ()
+{
+       var ps = this.getPreviousSibling();
+       if (ps != null)
+       {
+               return ps.getLastShownDescendant();
+       }
+       var p = this.getParent();
+       var t = this.getTree();
+       if (!t.showRootNode && p == t)
+               return null;
+       return p;
+};
+
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// WebFXTree
+///////////////////////////////////////////////////////////////////////////////
+
+function WebFXTree(sText, oAction, sBehavior, sIcon, sOpenIcon)
+{
+       WebFXTreeAbstractNode.call(this, sText, oAction);
+
+       if (sIcon)
+               this.icon = sIcon;
+       if (sOpenIcon)
+               this.openIcon = sOpenIcon;
+       if (sBehavior)
+               this.behavior = sBehavior;
+}
+
+_p = WebFXTree.prototype = new WebFXTreeAbstractNode;
+_p.indentWidth = 19;
+_p.open = true;
+_p._selectedItem = null;
+_p._fireChange = true;
+_p.rendered = false;
+_p.suspendRedraw = false;
+_p.showLines = true;
+_p.showExpandIcons = true;
+_p.showRootNode = true;
+_p.showRootLines = true;
+
+_p.getTree = function ()
+{
+       return this;
+};
+
+_p.getDepth = function ()
+{
+       return 0;
+};
+
+_p.getCreated = function ()
+{
+       return this.rendered;
+};
+
+
+/* end tree model */
+
+_p.getExpanded = function ()
+{
+       return !this.showRootNode || WebFXTreeAbstractNode.prototype.getExpanded.call(this);
+};
+
+_p.setExpanded = function (b)
+{
+       if (!this.showRootNode)
+               this.open = b;
+       else
+               WebFXTreeAbstractNode.prototype.setExpanded.call(this, b);
+};
+
+_p.getExpandIconHtml = function ()
+{
+       return "";
+};
+
+// we don't have an expand icon here
+_p.getIconElement = function ()
+{
+       var el = this.getRowElement();
+       if (!el) return null;
+       return el.firstChild;
+};
+
+// no expand icon for root element
+_p.getExpandIconElement = function (oDoc)
+{
+       return null;
+};
+
+_p.updateExpandIcon = function ()
+{
+       // no expand icon
+};
+
+_p.getRowClassName = function ()
+{
+       return WebFXTreeAbstractNode.prototype.getRowClassName.call(this) +
+               (this.showRootNode ? "" : " webfx-tree-hide-root");
+};
+
+
+// if classic then the openIcon is used for expanded, otherwise openIcon is used
+// for selected
+
+_p.getIconSrc = function ()
+{
+       var behavior = this.getTree() ? this.getTree().getBehavior() : webFXTreeConfig.defaultBehavior;
+       var open = behavior == "classic" && this.getExpanded() ||
+                          behavior != "classic" && this.isSelected();
+       if (open && this.openIcon)
+               return this.openIcon;
+       if (!open && this.icon)
+               return this.icon;
+       // fall back on default icons
+       return open ? webFXTreeConfig.openRootIcon : webFXTreeConfig.rootIcon;
+};
+
+_p.getEventHandlersHtml = function ()
+{
+       return " onclick=\"return webFXTreeHandler.handleEvent(event)\" " +
+               "onmousedown=\"return webFXTreeHandler.handleEvent(event)\" " +
+               "ondblclick=\"return webFXTreeHandler.handleEvent(event)\" " +
+               "onkeydown=\"return webFXTreeHandler.handleEvent(event)\" " +
+               "onkeypress=\"return webFXTreeHandler.handleEvent(event)\"";
+};
+
+_p.setSelected = function (o)
+{
+       if (this._selectedItem != o)
+       {
+               if (o)
+                       o._setSelected(true);
+       }
+};
+
+_p._fireOnChange = function ()
+{
+       if (this._fireChange && typeof this.onchange == "function")
+               this.onchange();
+};
+
+_p.getSelected = function ()
+{
+       return this._selectedItem;
+};
+
+_p.setBehavior = function (s)
+{
+       this.behavior = s;
+};
+
+_p.getBehavior = function ()
+{
+       return this.behavior || webFXTreeConfig.defaultBehavior;
+};
+
+_p.setShowLines = function (b)
+{
+       if (this.showLines != b)
+       {
+               this.showLines = b;
+               if (this.rendered)
+                       this.update();
+       }
+};
+
+_p.getShowLines = function ()
+{
+       return this.showLines;
+};
+
+_p.setShowRootLines = function (b)
+{
+       if (this.showRootLines != b)
+       {
+               this.showRootLines = b;
+               if (this.rendered)
+                       this.update();
+       }
+};
+
+_p.getShowRootLines = function ()
+{
+       return this.showRootLines;
+};
+
+_p.setShowExpandIcons = function (b)
+{
+       if (this.showExpandIcons != b)
+       {
+               this.showExpandIcons = b;
+               if (this.rendered)
+                       this.getTree().update();
+       }
+};
+
+_p.getShowExpandIcons = function ()
+{
+       return this.showExpandIcons;
+};
+
+_p.setShowRootNode = function (b)
+{
+       if (this.showRootNode != b)
+       {
+               this.showRootNode = b;
+               if (this.rendered)
+                       this.getTree().update();
+       }
+};
+
+_p.getShowRoootNode = function ()
+{
+       return this.showRootNode;
+};
+
+_p.onchange = function () {};
+
+_p.create = function ()
+{
+       var el = WebFXTreeAbstractNode.prototype.create.call(this);
+       this.rendered = true;
+       return el;
+};
+
+_p.write = function ()
+{
+       document.write(this.toHtml());
+       this.rendered = true;
+};
+
+_p.setSuspendRedraw = function (b)
+{
+       this.suspendRedraw = b;
+};
+
+_p.getSuspendRedraw = function ()
+{
+       return this.suspendRedraw;
+};
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// WebFXTreeItem
+///////////////////////////////////////////////////////////////////////////////
+
+function WebFXTreeItem(sText, oAction, eParent, sIcon, sOpenIcon)
+{
+       WebFXTreeAbstractNode.call(this, sText, oAction);
+       if (sIcon)
+               this.icon = sIcon;
+       if (sOpenIcon)
+               this.openIcon = sOpenIcon;
+       if (eParent)
+               eParent.add(this);
+}
+
+_p = WebFXTreeItem.prototype = new WebFXTreeAbstractNode;
+_p.tree = null;
+
+/* tree model */
+
+_p.getDepth = function ()
+{
+       if (this.depth != null)
+               return this.depth;
+       if (this.parentNode)
+       {
+               var pd = this.parentNode.getDepth();
+               return this.depth = (pd != null ? pd + 1 : null);
+       }
+       return null;
+};
+
+_p.getTree = function ()
+{
+       if (this.tree)
+               return this.tree;
+       if (this.parentNode)
+               return this.tree = this.parentNode.getTree();
+       return null;
+};
+
+_p.getCreated = function ()
+{
+       var t = this.getTree();
+       return t && t.getCreated();
+};
+
+// if classic then the openIcon is used for expanded, otherwise openIcon is used
+// for selected
+_p.getIconSrc = function ()
+{
+       var behavior = this.getTree() ? this.getTree().getBehavior() : webFXTreeConfig.defaultBehavior;
+       var open = behavior == "classic" && this.getExpanded() ||
+                  behavior != "classic" && this.isSelected();
+       if (open && this.openIcon)
+               return this.openIcon;
+       if (!open && this.icon)
+               return this.icon;
+
+       // fall back on default icons
+       if (this.hasChildren())
+               return open ? webFXTreeConfig.openFolderIcon : webFXTreeConfig.folderIcon;
+       return webFXTreeConfig.fileIcon;
+};
+
+/* end tree model */
+
+
+
+
+if (window.attachEvent)
+{
+       window.attachEvent("onunload", function ()
+       {
+               for (var id in webFXTreeHandler.all)
+                       webFXTreeHandler.all[id].dispose();
+       });
+}