summaryrefslogtreecommitdiff
path: root/js/dojo/dojox/xml
diff options
context:
space:
mode:
Diffstat (limited to 'js/dojo/dojox/xml')
-rw-r--r--js/dojo/dojox/xml/DomParser.js396
-rw-r--r--js/dojo/dojox/xml/README40
-rw-r--r--js/dojo/dojox/xml/Script.js21
-rw-r--r--js/dojo/dojox/xml/parser.js194
-rw-r--r--js/dojo/dojox/xml/widgetParser.js179
5 files changed, 830 insertions, 0 deletions
diff --git a/js/dojo/dojox/xml/DomParser.js b/js/dojo/dojox/xml/DomParser.js
new file mode 100644
index 0000000..187ab60
--- /dev/null
+++ b/js/dojo/dojox/xml/DomParser.js
@@ -0,0 +1,396 @@
+//>>built
+define("dojox/xml/DomParser", [
+ "dojo/_base/kernel",// dojo.getObject
+ "dojo/_base/array" // dojo.forEach
+], function(dojo){
+dojo.getObject("xml", true, dojox);
+
+dojox.xml.DomParser=new (function(){
+ /**********************************************************
+ * The DomParser is a close-to (but not entirely)
+ * conforming XML parser based on regular
+ * expressions. It will take any XML fragment
+ * and return a lightweight JS structure that is
+ * similar to (but not exactly) the DOM specification.
+ *
+ * Getter and setter methods are NOT available; the goal
+ * was to keep the resulting object model entirely JS-like.
+ *
+ * All node types but document fragments are supported;
+ * all nodes support getElementsByTagName and
+ * getElementsByTagNameNS (with short names byName and
+ * byNameNS). The document node supports getElementById
+ * (byId), and all nodes support a supplimental
+ * childrenByName/childrenByNameNS method as well.
+ *
+ * The object model is intended to be a READONLY format;
+ * mutation events are NOT supported, and though you
+ * can change properties on a node-by-node basis, certain
+ * operations are not supported (such as changing the ID
+ * of an element).
+ **********************************************************/
+
+ // internal use only.
+ var nodeTypes={ ELEMENT:1, ATTRIBUTE:2, TEXT:3, CDATA_SECTION:4, PROCESSING_INSTRUCTION:7, COMMENT:8, DOCUMENT:9 };
+
+ // compile the regular expressions once.
+ var reTags=/<([^>\/\s+]*)([^>]*)>([^<]*)/g;
+ var reAttr=/([^=]*)=(("([^"]*)")|('([^']*)'))/g; // patch from tdedischew AT gmail, with additional grouping
+ var reEntity=/<!ENTITY\s+([^"]*)\s+"([^"]*)">/g;
+ var reCData=/<!\[CDATA\[([\u0001-\uFFFF]*?)\]\]>/g;
+ var reComments=/<!--([\u0001-\uFFFF]*?)-->/g;
+ var trim=/^\s+|\s+$/g;
+ var normalize=/\s+/g;
+ var egt=/\&gt;/g;
+ var elt=/\&lt;/g;
+ var equot=/\&quot;/g;
+ var eapos=/\&apos;/g;
+ var eamp=/\&amp;/g;
+ var dNs="_def_";
+
+ // create a root node.
+ function _doc(){
+ return new (function(){
+ var all={};
+ this.nodeType=nodeTypes.DOCUMENT;
+ this.nodeName="#document";
+ this.namespaces={};
+ this._nsPaths={};
+ this.childNodes=[];
+ this.documentElement=null;
+
+ // any element with an ID attribute will be added to the internal hashtable.
+ this._add=function(obj){
+ if(typeof(obj.id)!="undefined"){ all[obj.id]=obj; }
+ };
+ this._remove=function(id){
+ if(all[id]){ delete all[id]; }
+ };
+
+ this.byId=this.getElementById=function(id){ return all[id]; };
+ this.byName=this.getElementsByTagName=byName;
+ this.byNameNS=this.getElementsByTagNameNS=byNameNS;
+ this.childrenByName=childrenByName;
+ this.childrenByNameNS=childrenByNameNS;
+ })();
+ }
+
+ // functions attached to element nodes
+ function byName(name){
+ // return all descendants with name. Fully qualified (i.e. svg:svg)
+ function __(node, name, arr){
+ dojo.forEach(node.childNodes, function(c){
+ if(c.nodeType==nodeTypes.ELEMENT){
+ if(name=="*"){ arr.push(c); }
+ else if(c.nodeName==name){ arr.push(c); }
+ __(c, name, arr);
+ }
+ });
+ }
+ var a=[];
+ __(this, name, a);
+ return a;
+ }
+ function byNameNS(name, ns){
+ // return all descendants with name by namespace. If no namespace passed, the default is used.
+ function __(node, name, ns, arr){
+ dojo.forEach(node.childNodes, function(c){
+ if(c.nodeType==nodeTypes.ELEMENT){
+ if(name=="*"&&c.ownerDocument._nsPaths[ns]==c.namespace){ arr.push(c); }
+ else if(c.localName==name&&c.ownerDocument._nsPaths[ns]==c.namespace){ arr.push(c); }
+ __(c, name, ns, arr);
+ }
+ });
+ }
+ if(!ns){ ns=dNs; }
+ var a=[];
+ __(this, name, ns, a);
+ return a;
+ }
+ // Only child nodes with name.
+ function childrenByName(name){
+ var a=[];
+ dojo.forEach(this.childNodes, function(c){
+ if(c.nodeType==nodeTypes.ELEMENT){
+ if(name=="*"){ a.push(c); }
+ else if(c.nodeName==name){ a.push(c); }
+ }
+ });
+ return a;
+ }
+
+ function childrenByNameNS(name, ns){
+ var a=[];
+ dojo.forEach(this.childNodes, function(c){
+ if(c.nodeType==nodeTypes.ELEMENT){
+ if(name=="*"&&c.ownerDocument._nsPaths[ns]==c.namespace){ a.push(c); }
+ else if(c.localName==name&&c.ownerDocument._nsPaths[ns]==c.namespace){ a.push(c); }
+ }
+ });
+ return a;
+ }
+
+ function _createTextNode(v){
+ return {
+ nodeType:nodeTypes.TEXT,
+ nodeName:"#text",
+ nodeValue:v.replace(normalize," ").replace(egt,">").replace(elt,"<").replace(eapos,"'").replace(equot,'"').replace(eamp,"&")
+ };
+ }
+
+ // attribute functions
+ function getAttr(name){
+ for(var i=0; i<this.attributes.length; i++){
+ if(this.attributes[i].nodeName==name){
+ return this.attributes[i].nodeValue;
+ }
+ }
+ return null;
+ }
+ function getAttrNS(name, ns){
+ for(var i=0; i<this.attributes.length; i++){
+ if(this.ownerDocument._nsPaths[ns]==this.attributes[i].namespace
+ &&this.attributes[i].localName==name
+ ){
+ return this.attributes[i].nodeValue;
+ }
+ }
+ return null;
+ }
+ // note that you can only swap IDs using setAttribute, NOT with setAttributeNS.
+ function setAttr(name, val){
+ var old=null;
+ for(var i=0; i<this.attributes.length; i++){
+ if(this.attributes[i].nodeName==name){
+ old=this.attributes[i].nodeValue;
+ this.attributes[i].nodeValue=val;
+ break;
+ }
+ }
+ if(name=="id"){
+ if(old!=null){ this.ownerDocument._remove(old); }
+ this.ownerDocument._add(this);
+ }
+ }
+ function setAttrNS(name, val, ns){
+ for(var i=0; i<this.attributes.length; i++){
+ if(this.ownerDocument._nsPaths[ns]==this.attributes[i].namespace
+ &&this.attributes[i].localName==name
+ ){
+ this.attributes[i].nodeValue=val;
+ return;
+ }
+ }
+ }
+
+ // navigation
+ function prev(){
+ var p=this.parentNode;
+ if(p){
+ for(var i=0;i<p.childNodes.length;i++){
+ if(p.childNodes[i]==this&&i>0){
+ return p.childNodes[i-1];
+ }
+ }
+ }
+ return null;
+ }
+ function next(){
+ var p=this.parentNode;
+ if(p){
+ for(var i=0;i<p.childNodes.length;i++){
+ if(p.childNodes[i]==this&&(i+1)<p.childNodes.length){
+ return p.childNodes[i+1];
+ }
+ }
+ }
+ return null;
+ }
+
+ // the main method.
+ this.parse=function(/* String */str){
+ var root=_doc();
+ if(str==null){ return root; }
+ if(str.length==0){ return root; }
+
+ // preprocess custom entities
+ if(str.indexOf("<!ENTITY")>0){
+ var entity, eRe=[];
+ if(reEntity.test(str)){
+ reEntity.lastIndex=0;
+ // match entities
+ while((entity=reEntity.exec(str))!=null){
+ eRe.push({
+ entity:"&"+entity[1].replace(trim,"")+";",
+ expression:entity[2]
+ });
+ }
+ // replace instances in the document.
+ for(var i=0; i<eRe.length; i++){
+ str=str.replace(new RegExp(eRe[i].entity, "g"), eRe[i].expression);
+ }
+ }
+ }
+
+ // pre-parse for CData, and tokenize.
+ var cdSections=[], cdata;
+ while((cdata=reCData.exec(str))!=null){ cdSections.push(cdata[1]); }
+ for(var i=0; i<cdSections.length; i++){ str=str.replace(cdSections[i], i); }
+
+ // pre-parse for comments, and tokenize.
+ var comments=[], comment;
+ while((comment=reComments.exec(str))!=null){ comments.push(comment[1]); }
+ for(i=0; i<comments.length; i++){ str=str.replace(comments[i], i); }
+
+ // parse the document
+ var res, obj=root;
+ while((res=reTags.exec(str))!=null){
+ // closing tags.
+ if(res[2].charAt(0)=="/" && res[2].replace(trim, "").length>1){
+ if(obj.parentNode){
+ obj=obj.parentNode;
+ }
+ var text=(res[3]||"").replace(trim, "");
+ if(text.length>0) {
+ obj.childNodes.push(_createTextNode(text));
+ }
+ }
+
+ // open tags.
+ else if(res[1].length>0){
+ // figure out the type of node.
+ if(res[1].charAt(0)=="?"){
+ // processing instruction
+ var name=res[1].substr(1);
+ var target=res[2].substr(0,res[2].length-2);
+ obj.childNodes.push({
+ nodeType:nodeTypes.PROCESSING_INSTRUCTION,
+ nodeName:name,
+ nodeValue:target
+ });
+ }
+ else if(res[1].charAt(0)=="!"){
+ // CDATA; skip over any declaration elements.
+ if(res[1].indexOf("![CDATA[")==0){
+ var val=parseInt(res[1].replace("![CDATA[","").replace("]]",""));
+ obj.childNodes.push({
+ nodeType:nodeTypes.CDATA_SECTION,
+ nodeName:"#cdata-section",
+ nodeValue:cdSections[val]
+ });
+ }
+ // Comments.
+ else if(res[1].substr(0,3)=="!--"){
+ var val=parseInt(res[1].replace("!--","").replace("--",""));
+ obj.childNodes.push({
+ nodeType:nodeTypes.COMMENT,
+ nodeName:"#comment",
+ nodeValue:comments[val]
+ });
+ }
+ }
+ else {
+ // Elements (with attribute and text)
+ var name=res[1].replace(trim,"");
+ var o={
+ nodeType:nodeTypes.ELEMENT,
+ nodeName:name,
+ localName:name,
+ namespace:dNs,
+ ownerDocument:root,
+ attributes:[],
+ parentNode:null,
+ childNodes:[]
+ };
+
+ // check to see if it's namespaced.
+ if(name.indexOf(":")>-1){
+ var t=name.split(":");
+ o.namespace=t[0];
+ o.localName=t[1];
+ }
+
+ // set the function references.
+ o.byName=o.getElementsByTagName=byName;
+ o.byNameNS=o.getElementsByTagNameNS=byNameNS;
+ o.childrenByName=childrenByName;
+ o.childrenByNameNS=childrenByNameNS;
+ o.getAttribute=getAttr;
+ o.getAttributeNS=getAttrNS;
+ o.setAttribute=setAttr;
+ o.setAttributeNS=setAttrNS;
+ o.previous=o.previousSibling=prev;
+ o.next=o.nextSibling=next;
+
+ // parse the attribute string.
+ var attr;
+ while((attr=reAttr.exec(res[2]))!=null){
+ if(attr.length>0){
+ var name=attr[1].replace(trim,"");
+ var val=(attr[4]||attr[6]||"").replace(normalize," ")
+ .replace(egt,">")
+ .replace(elt,"<")
+ .replace(eapos,"'")
+ .replace(equot,'"')
+ .replace(eamp,"&");
+ if(name.indexOf("xmlns")==0){
+ if(name.indexOf(":")>0){
+ var ns=name.split(":");
+ root.namespaces[ns[1]]=val;
+ root._nsPaths[val]=ns[1];
+ } else {
+ root.namespaces[dNs]=val;
+ root._nsPaths[val]=dNs;
+ }
+ } else {
+ var ln=name;
+ var ns=dNs;
+ if(name.indexOf(":")>0){
+ var t=name.split(":");
+ ln=t[1];
+ ns=t[0];
+ }
+ o.attributes.push({
+ nodeType:nodeTypes.ATTRIBUTE,
+ nodeName:name,
+ localName:ln,
+ namespace:ns,
+ nodeValue:val
+ });
+
+ // only add id as a property.
+ if(ln=="id"){ o.id=val; }
+ }
+ }
+ }
+ root._add(o);
+
+ if(obj){
+ obj.childNodes.push(o);
+ o.parentNode=obj;
+ // if it's not a self-closing node.
+ if(res[2].charAt(res[2].length-1)!="/"){
+ obj=o;
+ }
+ }
+ var text=res[3];
+ if(text.length>0){
+ obj.childNodes.push(_createTextNode(text));
+ }
+ }
+ }
+ }
+
+ // set the document element
+ for(var i=0; i<root.childNodes.length; i++){
+ var e=root.childNodes[i];
+ if(e.nodeType==nodeTypes.ELEMENT){
+ root.documentElement=e;
+ break;
+ }
+ }
+ return root;
+ };
+})();
+return dojox.xml.DomParser;
+});
diff --git a/js/dojo/dojox/xml/README b/js/dojo/dojox/xml/README
new file mode 100644
index 0000000..c00122a
--- /dev/null
+++ b/js/dojo/dojox/xml/README
@@ -0,0 +1,40 @@
+-------------------------------------------------------------------------------
+DojoX XML Utilities
+-------------------------------------------------------------------------------
+Version 0.1
+Release date: 05/30/2007
+-------------------------------------------------------------------------------
+Project state:
+experimental
+-------------------------------------------------------------------------------
+Credits
+ Tom Trenka (ttrenka@gmail.com): DomParser
+
+-------------------------------------------------------------------------------
+Project description
+
+The goal of DojoX XML Utilities is provide differing XML utilities for use
+in various places. Currently this includes a native JS DomParser, but will
+most likely be expanded to include things as dealing with x-browser forks
+(like the Sarissa project), various DOM utilites, and more.
+-------------------------------------------------------------------------------
+Dependencies:
+
+DojoX XML relies only on the Dojo Base package system.
+-------------------------------------------------------------------------------
+Documentation
+
+None at the time of writing. The only object is dojox.xml.DomParser (a singleton),
+which has one method: parse:
+
+dojox.xml.DomParser.parse(xmlString)
+-------------------------------------------------------------------------------
+Installation instructions
+
+Grab the following from the Dojo SVN Repository:
+http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/xml/*
+
+Install into the following directory structure:
+/dojox/xml/
+
+...which should be at the same level as your Dojo checkout.
diff --git a/js/dojo/dojox/xml/Script.js b/js/dojo/dojox/xml/Script.js
new file mode 100644
index 0000000..a67d21d
--- /dev/null
+++ b/js/dojo/dojox/xml/Script.js
@@ -0,0 +1,21 @@
+//>>built
+define("dojox/xml/Script", [
+ "dojo/_base/kernel", // dojo.getObject
+ "dojo/_base/declare",
+ "dojo/parser",
+ "./widgetParser"
+], function(declare, parser, widgetParser){
+
+dojo.getObject("xml", true, dojox);
+
+declare("dojox.xml.Script", null, {
+ constructor: function(props, node){
+ parser.instantiate(
+ widgetParser._processScript(node)
+ );
+ }
+});
+
+return dojox.xml.Script;
+
+});
diff --git a/js/dojo/dojox/xml/parser.js b/js/dojo/dojox/xml/parser.js
new file mode 100644
index 0000000..a1a6946
--- /dev/null
+++ b/js/dojo/dojox/xml/parser.js
@@ -0,0 +1,194 @@
+//>>built
+define("dojox/xml/parser", ['dojo/_base/kernel', 'dojo/_base/lang', 'dojo/_base/array', 'dojo/_base/window', 'dojo/_base/sniff'], function(dojo){
+
+dojo.getObject("xml.parser", true, dojox);
+
+//DOM type to int value for reference.
+//Ints make for more compact code than full constant names.
+//ELEMENT_NODE = 1;
+//ATTRIBUTE_NODE = 2;
+//TEXT_NODE = 3;
+//CDATA_SECTION_NODE = 4;
+//ENTITY_REFERENCE_NODE = 5;
+//ENTITY_NODE = 6;
+//PROCESSING_INSTRUCTION_NODE = 7;
+//COMMENT_NODE = 8;
+//DOCUMENT_NODE = 9;
+//DOCUMENT_TYPE_NODE = 10;
+//DOCUMENT_FRAGMENT_NODE = 11;
+//NOTATION_NODE = 12;
+
+dojox.xml.parser.parse = function(/*String?*/ str, /*String?*/ mimetype){
+ // summary:
+ // cross-browser implementation of creating an XML document object from null, empty string, and XML text..
+ //
+ // str:
+ // Optional text to create the document from. If not provided, an empty XML document will be created.
+ // If str is empty string "", then a new empty document will be created.
+ // mimetype:
+ // Optional mimetype of the text. Typically, this is text/xml. Will be defaulted to text/xml if not provided.
+ var _document = dojo.doc;
+ var doc;
+
+ mimetype = mimetype || "text/xml";
+ if(str && dojo.trim(str) && "DOMParser" in dojo.global){
+ //Handle parsing the text on Mozilla based browsers etc..
+ var parser = new DOMParser();
+ doc = parser.parseFromString(str, mimetype);
+ var de = doc.documentElement;
+ var errorNS = "http://www.mozilla.org/newlayout/xml/parsererror.xml";
+ if(de.nodeName == "parsererror" && de.namespaceURI == errorNS){
+ var sourceText = de.getElementsByTagNameNS(errorNS, 'sourcetext')[0];
+ if(sourceText){
+ sourceText = sourceText.firstChild.data;
+ }
+ throw new Error("Error parsing text " + de.firstChild.data + " \n" + sourceText);
+ }
+ return doc;
+
+ }else if("ActiveXObject" in dojo.global){
+ //Handle IE.
+ var ms = function(n){ return "MSXML" + n + ".DOMDocument"; };
+ var dp = ["Microsoft.XMLDOM", ms(6), ms(4), ms(3), ms(2)];
+ dojo.some(dp, function(p){
+ try{
+ doc = new ActiveXObject(p);
+ }catch(e){ return false; }
+ return true;
+ });
+ if(str && doc){
+ doc.async = false;
+ doc.loadXML(str);
+ var pe = doc.parseError;
+ if(pe.errorCode !== 0){
+ throw new Error("Line: " + pe.line + "\n" +
+ "Col: " + pe.linepos + "\n" +
+ "Reason: " + pe.reason + "\n" +
+ "Error Code: " + pe.errorCode + "\n" +
+ "Source: " + pe.srcText);
+ }
+ }
+ if(doc){
+ return doc; //DOMDocument
+ }
+ }else if(_document.implementation && _document.implementation.createDocument){
+ if(str && dojo.trim(str) && _document.createElement){
+ //Everyone else that we couldn't get to work. Fallback case.
+ // FIXME: this may change all tags to uppercase!
+ var tmp = _document.createElement("xml");
+ tmp.innerHTML = str;
+ var xmlDoc = _document.implementation.createDocument("foo", "", null);
+ dojo.forEach(tmp.childNodes, function(child){
+ xmlDoc.importNode(child, true);
+ });
+ return xmlDoc; // DOMDocument
+ }else{
+ return _document.implementation.createDocument("", "", null); // DOMDocument
+ }
+ }
+ return null; // null
+};
+
+dojox.xml.parser.textContent = function(/*Node*/node, /*String?*/text){
+ // summary:
+ // Implementation of the DOM Level 3 attribute; scan node for text
+ // description:
+ // Implementation of the DOM Level 3 attribute; scan node for text
+ // This function can also update the text of a node by replacing all child
+ // content of the node.
+ // node:
+ // The node to get the text off of or set the text on.
+ // text:
+ // Optional argument of the text to apply to the node.
+ if(arguments.length>1){
+ var _document = node.ownerDocument || dojo.doc; //Preference is to get the node owning doc first or it may fail
+ dojox.xml.parser.replaceChildren(node, _document.createTextNode(text));
+ return text; // String
+ }else{
+ if(node.textContent !== undefined){ //FF 1.5 -- remove?
+ return node.textContent; // String
+ }
+ var _result = "";
+ if(node){
+ dojo.forEach(node.childNodes, function(child){
+ switch(child.nodeType){
+ case 1: // ELEMENT_NODE
+ case 5: // ENTITY_REFERENCE_NODE
+ _result += dojox.xml.parser.textContent(child);
+ break;
+ case 3: // TEXT_NODE
+ case 2: // ATTRIBUTE_NODE
+ case 4: // CDATA_SECTION_NODE
+ _result += child.nodeValue;
+ }
+ });
+ }
+ return _result; // String
+ }
+};
+
+dojox.xml.parser.replaceChildren = function(/*Element*/node, /*Node || Array*/ newChildren){
+ // summary:
+ // Removes all children of node and appends newChild. All the existing
+ // children will be destroyed.
+ // description:
+ // Removes all children of node and appends newChild. All the existing
+ // children will be destroyed.
+ // node:
+ // The node to modify the children on
+ // newChildren:
+ // The children to add to the node. It can either be a single Node or an
+ // array of Nodes.
+ var nodes = [];
+
+ if(dojo.isIE){
+ dojo.forEach(node.childNodes, function(child){
+ nodes.push(child);
+ });
+ }
+
+ dojox.xml.parser.removeChildren(node);
+ dojo.forEach(nodes, dojo.destroy);
+
+ if(!dojo.isArray(newChildren)){
+ node.appendChild(newChildren);
+ }else{
+ dojo.forEach(newChildren, function(child){
+ node.appendChild(child);
+ });
+ }
+};
+
+dojox.xml.parser.removeChildren = function(/*Element*/node){
+ // summary:
+ // removes all children from node and returns the count of children removed.
+ // The children nodes are not destroyed. Be sure to call dojo.destroy on them
+ // after they are not used anymore.
+ // node:
+ // The node to remove all the children from.
+ var count = node.childNodes.length;
+ while(node.hasChildNodes()){
+ node.removeChild(node.firstChild);
+ }
+ return count; // int
+};
+
+
+dojox.xml.parser.innerXML = function(/*Node*/node){
+ // summary:
+ // Implementation of MS's innerXML function.
+ // node:
+ // The node from which to generate the XML text representation.
+ if(node.innerXML){
+ return node.innerXML; // String
+ }else if(node.xml){
+ return node.xml; // String
+ }else if(typeof XMLSerializer != "undefined"){
+ return (new XMLSerializer()).serializeToString(node); // String
+ }
+ return null;
+};
+
+return dojox.xml.parser;
+
+});
diff --git a/js/dojo/dojox/xml/widgetParser.js b/js/dojo/dojox/xml/widgetParser.js
new file mode 100644
index 0000000..d1e8118
--- /dev/null
+++ b/js/dojo/dojox/xml/widgetParser.js
@@ -0,0 +1,179 @@
+//>>built
+define("dojox/xml/widgetParser", [
+ "dojo/_base/lang", // dojo.getObject
+ "dojo/_base/window", // dojo.doc
+ "dojo/_base/sniff", // dojo.isIE
+ "dojo/query",
+ "dojo/parser",
+ "dojox/xml/parser"
+], function(dojo, window, has, query, parser, dxparser){
+
+var dXml = lang.getObject("dojox.xml", true);
+
+/**
+Take some sort of xml block
+* like <dojo.button caption="blah"/> and turn
+* it into a widget..
+*/
+
+ /**
+ * We want to support something like:
+ * <body>
+ * <script>
+ * <dijit.layout.SplitContainer>
+ * <dijit.button/>
+ * <div>...</div>
+ * </dijit.layout.SplitContainer>
+ * </body>
+ *
+ * This is very tricky because if we parse this as XML then the <div> tag
+ * is actually an XML tag, not an XML tag, which is problematic in at least
+ * IE.
+ *
+ * So the strategy is this, silly as it may be: Convert EVERYTHING to HTML
+ * nodes, including the dijit.layout.SplitContainer by converting it to a
+ * div with the dojoType. Then run it through the standard parser.
+ * The more HTML you have relative to XML the less extra overhead this is.
+ *
+ * For something that is all XML we could have a different approach,
+ * perhaps signified by a different type of script tag. In that case we
+ * could just instantiate all the elements without a sourceNodeRef and then
+ * add the top level components to the app.
+ *
+ * That is very straightforward but I haven't done it.
+ *
+ * Right now there is no mechanism to have an intermediary bridge between
+ * the XML and the widget, because we are relying on dojo.parser
+ * to do the instantiation. It isn't clear to me why we would want
+ * those bridges in this approach and not in that approach.
+ *
+ */
+
+xXml.widgetParser = new function(){
+
+ var d = dojo;
+
+ this.parseNode = function(node){
+
+ var toBuild = [];
+ //TODO figure out the proper type
+ d.query("script[type='text/xml']", node).forEach(function(script){
+ toBuild.push.apply(toBuild, this._processScript(script));
+ }, this).orphan();
+
+ //instantiate everything at the end, doing it piecewise can give ID conflicts
+ return d.parser.instantiate(toBuild);
+ };
+
+ this._processScript = function(script){
+ //the text is either loaded from a separate file by the src
+ //attribute or underneath the src tag
+ var text = script.src ? d._getText(script.src) : script.innerHTML || script.firstChild.nodeValue;
+ var htmlNode = this.toHTML( dojox.xml.parser.parse(text).firstChild );
+
+ //make the list BEFORE we copy things over to keep the query scope as
+ //small as possible
+ var ret = d.query('[dojoType]', htmlNode);
+ //remove the script tag and replace with new HTML block
+ query(">", htmlNode).place(script, "before")
+ script.parentNode.removeChild(script);
+ return ret;
+ };
+
+ /**
+ * Given an XML node converts it to HTML where the existing HTML
+ * is preserved and the dojo widget tags are converted to divs
+ * with dojoType on them.
+ */
+ this.toHTML = function (/*XmlNode*/ node){
+ var newNode;
+ var nodeName = node.nodeName;
+ var dd = window.doc;
+ var type = node.nodeType;
+
+
+ ///node type 3 and 4 are text and cdata
+ if(type >= 3){
+ return dd.createTextNode( (type == 3 || type == 4) ? node.nodeValue : "" );
+ }
+
+ var localName = node.localName||nodeName.split(":").pop();
+
+ //TODO:
+ // only check for namespace ONCE ever, instead of each time here,
+ // by mixing in the right check for each browser?
+ var namespace = node.namespaceURI || (node.getNamespaceUri ? node.getNamespaceUri() : "");
+
+ //TODO check for some real namespace
+ if(namespace == "html"){
+ newNode = dd.createElement(localName);
+ }else{
+ var dojoType = namespace + "." + localName;
+
+ /**
+ * This is a horrible hack we need because creating a <div>
+ * with <option> children doesn't work well. Specifically with
+ * dojo.Declaration at some point the <option> tags get lost
+ * entirely so we need the parent of <option> tags to be <select>
+ * tags. (Not a problem outside of dojo.Delcaration)
+ * There are a couple other ways we could do this:
+ * 1. Look at the first element child to see if it is an option and
+ * if so create a <select> here.
+ * 2. When we add a child to parent fix up the parent then if the
+ * child is an <option> and the parent isn't a <select>.
+ * Both of those are a bit messy and slower than this.
+ *
+ * This is potentially a problem for other tag combinations as well,
+ * such as <tr> under a <table> or <li> under a <ul>/<ol>.
+ * (dojox.widget.SortList for example). Probably need a robust strategy for
+ * dealing with this. Worst case scenario for now is that user has to use
+ * html tag with dojoType for misbehaving widget.
+ */
+ newNode = newNode || dd.createElement((dojoType == "dijit.form.ComboBox") ? "select" : "div");
+ newNode.setAttribute("dojoType", dojoType);
+ }
+
+ // TODO:
+ // we should probably set this up different, mixin a function
+ // depending on if it is IE rather than checking every time here
+ // the xmlns problem and the style problem are both IE specific
+ d.forEach(node.attributes, function(attr){
+ // NOTE: IE always iterates *all* properties!!!
+ var name = attr.name || attr.nodeName;
+ var value = attr.value || attr.nodeValue;
+ if(name.indexOf("xmlns") != 0){
+ // style=blah blah blah is a problem, in IE if you use
+ // setAttribute here you get all sorts of problems. Maybe it
+ // would be better to just create a giant string of HTML
+ // instead of an object graph, then set innerHTML on something
+ // to get the object graph? That might be cleaner... that way
+ // is uses the browser HTML parsing exactly at is and won't
+ // cause any sort of issues. We could just special case style
+ // as well?
+ if(has("ie") && name == "style"){
+ newNode.style.setAttribute("cssText", value);
+ }else{
+ newNode.setAttribute(name, value);
+ }
+ }
+ });
+ d.forEach(node.childNodes, function(cn){
+ var childNode = this.toHTML(cn);
+
+ // script tags in IE don't like appendChild, innerHTML or innerText
+ // so if we are creating one programatically set text instead
+ // could special case this for IE only
+ if(localName == "script"){
+ newNode.text += childNode.nodeValue;
+ }else{
+ newNode.appendChild(childNode);
+ }
+ }, this);
+ return newNode;
+ };
+
+}();
+
+return dXml.widgetParser;
+
+});