The main idea is to create sub classes to WebFXTree
and
WebFXTreeItem
and overload the expand
methods
to start the loading of an xml file. Once the loading is done the xml file
is tranformed into WebFXTreeItem
s and WebFXLoadTreeItem
s
and inserted.
First we create a new constructor and inside this we call the super constructor to make sure that the instance will be correctly initiated. After that we set some property values and finally we check whether the tree is open, if it is we start to load the sub trees. If not, we add a dummy tree item that displays the loading text.
After the constructor is created we set the protype to a new
WebFXTree
.
function WebFXLoadTree(sText, sXmlSrc, sAction, sBehavior, sIcon, sOpenIcon) { // call super this.WebFXTree = WebFXTree; this.WebFXTree(sText, sAction, sBehavior, sIcon, sOpenIcon); // setup default property values this.src = sXmlSrc; this.loading = false; this.loaded = false; this.errorText = ""; // check start state and load if open if (this.open) _startLoadXmlTree(this.src, this); else { // and create loading item if not this._loadingItem = new WebFXTreeItem(webFXTreeConfig.loadingText); this.add(this._loadingItem); } } WebFXLoadTree.prototype = new WebFXTree;
The constructor is fairly straight forward and does not do much. Notice however
how super is called by binding WebFXTree
as a method and then
calling it.
Next we need to override the expand
method but since we still need
to be able to call the original expand
method we create a new method
called _webfxtree_expand
that points to the function object used
by WebFXTree
objects. This is the standard way to access super methods
but the first few times it might look a bit odd.
The logic in the expand
method is really simple. We just check if
we should start loading the xml file and then we expand it using the super
expand (_webfxtree_expand
) method.
// override the expand method to load the xml file WebFXLoadTree.prototype._webfxtree_expand = WebFXTree.prototype.expand; WebFXLoadTree.prototype.expand = function() { if (!this.loaded && !this.loading) { // load _startLoadXmlTree(this.src, this); } this._webfxtree_expand(); };
This class is too similar to WebFXLoadTree
for me to be entirely
comfortable. Since JavaScript does not support multiple inheritance, and I did
not want to fake it using expandos, we just have to repeat the code. For everyone
that are interested, the code for this can be found in
xloadtree.js.
As you can see in the code above there is a function called
_startLoadXmlTree
that is called to load the actual xml file. This function uses
an XmlHttp
object to do the actual loading. The loading of the xml
file is done asynchronously to prevent the UI to lock up while the file is
being loaded and therefore we wait for the onreadystatechange
event to fire before we continue. See the
Xml Extras article for a more detailed
description about the XmlHttp
object.
// creates the xmlhttp object and starts the load of the xml document function _startLoadXmlTree(sSrc, jsNode) { jsNode.loading = true; var xmlHttp = XmlHttp.create(); xmlHttp.open("GET", sSrc, true); // async xmlHttp.onreadystatechange = function () { if (xmlHttp.readyState == 4) _xmlFileLoaded(xmlHttp.responseXML, jsNode); }; // call in new thread to allow ui to update window.setTimeout(function () { xmlHttp.send(null); }, 10); }
Once the xml file has finished loading we call the function _xmlFileLoaded
.
This function checks that we got an xml document back and if we did it goes through the
document and recursively converts the xml elements to js WebFXTreeItem
and
inserts them. Once the xml elements have been converted and inserted we remove the
dummy tree item that was only used to show that we were loading the contents.
// Inserts an xml document as a subtree to the provided node function _xmlFileLoaded(oXmlDoc, jsParentNode) { var bIndent = false; var bAnyChildren = false; jsParentNode.loaded = true; jsParentNode.loading = false; // check that the load of the xml file went well if( oXmlDoc == null || oXmlDoc.documentElement == null) { jsParentNode.errorText = parseTemplateString(webFXTreeConfig.loadErrorTextTemplate, jsParentNode.src); } else { // there is one extra level of tree elements var root = oXmlDoc.documentElement; // loop through all tree children var cs = root.childNodes; var l = cs.length; for (var i = 0; i < l; i++) { if (cs[i].tagName == "tree") { bAnyChildren = true; bIndent = true; jsParentNode.add( _xmlTreeToJsTree(cs[i]), true); } } // if no children we got an error if (!bAnyChildren) jsParentNode.errorText = parseTemplateString(webFXTreeConfig.emptyErrorTextTemplate, jsParentNode.src); } // remove dummy if (jsParentNode._loadingItem != null) { jsParentNode._loadingItem.remove(); bIndent = true; } if (bIndent) { // indent now that all items are added jsParentNode.indent(); } // show error in status bar if (jsParentNode.errorText != "") window.status = jsParentNode.errorText; }
A few more things happen in this function but nothing really important. There is some
code that checks the errors and a few properties are set to reflect the state of the
WebFXLoadTree
or WebFXLoadTreeItem
object.
The only important thing left to do is to convert the xml tree item to a js
WebFXTreeItem
. This is done in the function _xmlTreeToJsTree
.
Here we retreive the xml attributes and if there was a src
attribute
defined we create a new WebFXLoadTreeItem
and otherwise a
WebFXTreeItem
. Once that is created we go through all the
childNodes
of the xml node and convert and add those as well.
// Converts an xml tree to a js tree. See article about xml tree format function _xmlTreeToJsTree(oNode) { // retreive attributes var text = oNode.getAttribute("text"); var action = oNode.getAttribute("action"); var parent = null; var icon = oNode.getAttribute("icon"); var openIcon = oNode.getAttribute("openIcon"); var src = oNode.getAttribute("src"); // create jsNode var jsNode; if (src != null && src != "") jsNode = new WebFXLoadTreeItem(text, src, action, parent, icon, openIcon); else jsNode = new WebFXTreeItem(text, action, parent, icon, openIcon); // go through childNOdes var cs = oNode.childNodes; var l = cs.length; for (var i = 0; i < l; i++) { if (cs[i].tagName == "tree") jsNode.add( _xmlTreeToJsTree(cs[i]), true ); } return jsNode; }