diff options
Diffstat (limited to 'js/dojo/dojox/xml')
| -rw-r--r-- | js/dojo/dojox/xml/DomParser.js | 396 | ||||
| -rw-r--r-- | js/dojo/dojox/xml/README | 40 | ||||
| -rw-r--r-- | js/dojo/dojox/xml/Script.js | 21 | ||||
| -rw-r--r-- | js/dojo/dojox/xml/parser.js | 194 | ||||
| -rw-r--r-- | js/dojo/dojox/xml/widgetParser.js | 179 |
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=/\>/g; + var elt=/\</g; + var equot=/\"/g; + var eapos=/\'/g; + var eamp=/\&/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; + +}); |
