| /* |
| Copyright (c) 2004-2005, The Dojo Foundation |
| All Rights Reserved. |
| |
| Licensed under the Academic Free License version 2.1 or above OR the |
| modified BSD license. For more information on Dojo licensing, see: |
| |
| http://dojotoolkit.org/community/licensing.shtml |
| */ |
| |
| dojo.provide("dojo.dom"); |
| dojo.require("dojo.lang"); |
| |
| dojo.dom.ELEMENT_NODE = 1; |
| dojo.dom.ATTRIBUTE_NODE = 2; |
| dojo.dom.TEXT_NODE = 3; |
| dojo.dom.CDATA_SECTION_NODE = 4; |
| dojo.dom.ENTITY_REFERENCE_NODE = 5; |
| dojo.dom.ENTITY_NODE = 6; |
| dojo.dom.PROCESSING_INSTRUCTION_NODE = 7; |
| dojo.dom.COMMENT_NODE = 8; |
| dojo.dom.DOCUMENT_NODE = 9; |
| dojo.dom.DOCUMENT_TYPE_NODE = 10; |
| dojo.dom.DOCUMENT_FRAGMENT_NODE = 11; |
| dojo.dom.NOTATION_NODE = 12; |
| |
| dojo.dom.dojoml = "http://www.dojotoolkit.org/2004/dojoml"; |
| |
| /** |
| * comprehensive list of XML namespaces |
| **/ |
| dojo.dom.xmlns = { |
| svg : "http://www.w3.org/2000/svg", |
| smil : "http://www.w3.org/2001/SMIL20/", |
| mml : "http://www.w3.org/1998/Math/MathML", |
| cml : "http://www.xml-cml.org", |
| xlink : "http://www.w3.org/1999/xlink", |
| xhtml : "http://www.w3.org/1999/xhtml", |
| xul : "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", |
| xbl : "http://www.mozilla.org/xbl", |
| fo : "http://www.w3.org/1999/XSL/Format", |
| xsl : "http://www.w3.org/1999/XSL/Transform", |
| xslt : "http://www.w3.org/1999/XSL/Transform", |
| xi : "http://www.w3.org/2001/XInclude", |
| xforms : "http://www.w3.org/2002/01/xforms", |
| saxon : "http://icl.com/saxon", |
| xalan : "http://xml.apache.org/xslt", |
| xsd : "http://www.w3.org/2001/XMLSchema", |
| dt: "http://www.w3.org/2001/XMLSchema-datatypes", |
| xsi : "http://www.w3.org/2001/XMLSchema-instance", |
| rdf : "http://www.w3.org/1999/02/22-rdf-syntax-ns#", |
| rdfs : "http://www.w3.org/2000/01/rdf-schema#", |
| dc : "http://purl.org/dc/elements/1.1/", |
| dcq: "http://purl.org/dc/qualifiers/1.0", |
| "soap-env" : "http://schemas.xmlsoap.org/soap/envelope/", |
| wsdl : "http://schemas.xmlsoap.org/wsdl/", |
| AdobeExtensions : "http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" |
| }; |
| |
| dojo.dom.isNode = dojo.lang.isDomNode = function(wh){ |
| if(typeof Element == "object") { |
| try { |
| return wh instanceof Element; |
| } catch(E) {} |
| } else { |
| // best-guess |
| return wh && !isNaN(wh.nodeType); |
| } |
| } |
| dojo.lang.whatAmI.custom["node"] = dojo.dom.isNode; |
| |
| dojo.dom.getTagName = function(node){ |
| var tagName = node.tagName; |
| if(tagName.substr(0,5).toLowerCase()!="dojo:"){ |
| |
| if(tagName.substr(0,4).toLowerCase()=="dojo"){ |
| // FIXME: this assuumes tag names are always lower case |
| return "dojo:" + tagName.substring(4).toLowerCase(); |
| } |
| |
| // allow lower-casing |
| var djt = node.getAttribute("dojoType")||node.getAttribute("dojotype"); |
| if(djt){ |
| return "dojo:"+djt.toLowerCase(); |
| } |
| |
| if((node.getAttributeNS)&&(node.getAttributeNS(this.dojoml,"type"))){ |
| return "dojo:" + node.getAttributeNS(this.dojoml,"type").toLowerCase(); |
| } |
| try{ |
| // FIXME: IE really really doesn't like this, so we squelch |
| // errors for it |
| djt = node.getAttribute("dojo:type"); |
| }catch(e){ /* FIXME: log? */ } |
| if(djt){ |
| return "dojo:"+djt.toLowerCase(); |
| } |
| |
| if((!dj_global["djConfig"])||(!djConfig["ignoreClassNames"])){ |
| // FIXME: should we make this optionally enabled via djConfig? |
| var classes = node.className||node.getAttribute("class"); |
| // FIXME: following line, without check for existence of classes.indexOf |
| // breaks firefox 1.5's svg widgets |
| if((classes)&&(classes.indexOf)&&(classes.indexOf("dojo-") != -1)){ |
| var aclasses = classes.split(" "); |
| for(var x=0; x<aclasses.length; x++){ |
| if((aclasses[x].length>5)&&(aclasses[x].indexOf("dojo-")>=0)){ |
| return "dojo:"+aclasses[x].substr(5).toLowerCase(); |
| } |
| } |
| } |
| } |
| |
| } |
| return tagName.toLowerCase(); |
| } |
| |
| dojo.dom.getUniqueId = function(){ |
| do { |
| var id = "dj_unique_" + (++arguments.callee._idIncrement); |
| }while(document.getElementById(id)); |
| return id; |
| } |
| dojo.dom.getUniqueId._idIncrement = 0; |
| |
| dojo.dom.firstElement = dojo.dom.getFirstChildElement = function(parentNode, tagName){ |
| var node = parentNode.firstChild; |
| while(node && node.nodeType != dojo.dom.ELEMENT_NODE){ |
| node = node.nextSibling; |
| } |
| if(tagName && node && node.tagName && node.tagName.toLowerCase() != tagName.toLowerCase()) { |
| node = dojo.dom.nextElement(node, tagName); |
| } |
| return node; |
| } |
| |
| dojo.dom.lastElement = dojo.dom.getLastChildElement = function(parentNode, tagName){ |
| var node = parentNode.lastChild; |
| while(node && node.nodeType != dojo.dom.ELEMENT_NODE) { |
| node = node.previousSibling; |
| } |
| if(tagName && node && node.tagName && node.tagName.toLowerCase() != tagName.toLowerCase()) { |
| node = dojo.dom.prevElement(node, tagName); |
| } |
| return node; |
| } |
| |
| dojo.dom.nextElement = dojo.dom.getNextSiblingElement = function(node, tagName){ |
| if(!node) { return null; } |
| do { |
| node = node.nextSibling; |
| } while(node && node.nodeType != dojo.dom.ELEMENT_NODE); |
| |
| if(node && tagName && tagName.toLowerCase() != node.tagName.toLowerCase()) { |
| return dojo.dom.nextElement(node, tagName); |
| } |
| return node; |
| } |
| |
| dojo.dom.prevElement = dojo.dom.getPreviousSiblingElement = function(node, tagName){ |
| if(!node) { return null; } |
| if(tagName) { tagName = tagName.toLowerCase(); } |
| do { |
| node = node.previousSibling; |
| } while(node && node.nodeType != dojo.dom.ELEMENT_NODE); |
| |
| if(node && tagName && tagName.toLowerCase() != node.tagName.toLowerCase()) { |
| return dojo.dom.prevElement(node, tagName); |
| } |
| return node; |
| } |
| |
| // TODO: hmph |
| /*this.forEachChildTag = function(node, unaryFunc) { |
| var child = this.getFirstChildTag(node); |
| while(child) { |
| if(unaryFunc(child) == "break") { break; } |
| child = this.getNextSiblingTag(child); |
| } |
| }*/ |
| |
| dojo.dom.moveChildren = function(srcNode, destNode, trim){ |
| var count = 0; |
| if(trim) { |
| while(srcNode.hasChildNodes() && |
| srcNode.firstChild.nodeType == dojo.dom.TEXT_NODE) { |
| srcNode.removeChild(srcNode.firstChild); |
| } |
| while(srcNode.hasChildNodes() && |
| srcNode.lastChild.nodeType == dojo.dom.TEXT_NODE) { |
| srcNode.removeChild(srcNode.lastChild); |
| } |
| } |
| while(srcNode.hasChildNodes()){ |
| destNode.appendChild(srcNode.firstChild); |
| count++; |
| } |
| return count; |
| } |
| |
| dojo.dom.copyChildren = function(srcNode, destNode, trim){ |
| var clonedNode = srcNode.cloneNode(true); |
| return this.moveChildren(clonedNode, destNode, trim); |
| } |
| |
| dojo.dom.removeChildren = function(node){ |
| var count = node.childNodes.length; |
| while(node.hasChildNodes()){ node.removeChild(node.firstChild); } |
| return count; |
| } |
| |
| dojo.dom.replaceChildren = function(node, newChild){ |
| // FIXME: what if newChild is an array-like object? |
| dojo.dom.removeChildren(node); |
| node.appendChild(newChild); |
| } |
| |
| dojo.dom.removeNode = function(node){ |
| if(node && node.parentNode){ |
| // return a ref to the removed child |
| return node.parentNode.removeChild(node); |
| } |
| } |
| |
| dojo.dom.getAncestors = function(node, filterFunction, returnFirstHit) { |
| var ancestors = []; |
| var isFunction = dojo.lang.isFunction(filterFunction); |
| while(node) { |
| if (!isFunction || filterFunction(node)) { |
| ancestors.push(node); |
| } |
| if (returnFirstHit && ancestors.length > 0) { return ancestors[0]; } |
| |
| node = node.parentNode; |
| } |
| if (returnFirstHit) { return null; } |
| return ancestors; |
| } |
| |
| dojo.dom.getAncestorsByTag = function(node, tag, returnFirstHit) { |
| tag = tag.toLowerCase(); |
| return dojo.dom.getAncestors(node, function(el){ |
| return ((el.tagName)&&(el.tagName.toLowerCase() == tag)); |
| }, returnFirstHit); |
| } |
| |
| dojo.dom.getFirstAncestorByTag = function(node, tag) { |
| return dojo.dom.getAncestorsByTag(node, tag, true); |
| } |
| |
| dojo.dom.isDescendantOf = function(node, ancestor, guaranteeDescendant){ |
| // guaranteeDescendant allows us to be a "true" isDescendantOf function |
| if(guaranteeDescendant && node) { node = node.parentNode; } |
| while(node) { |
| if(node == ancestor){ return true; } |
| node = node.parentNode; |
| } |
| return false; |
| } |
| |
| dojo.dom.innerXML = function(node){ |
| if(node.innerXML){ |
| return node.innerXML; |
| }else if(typeof XMLSerializer != "undefined"){ |
| return (new XMLSerializer()).serializeToString(node); |
| } |
| } |
| |
| dojo.dom.createDocumentFromText = function(str, mimetype){ |
| if(!mimetype) { mimetype = "text/xml"; } |
| if(typeof DOMParser != "undefined") { |
| var parser = new DOMParser(); |
| return parser.parseFromString(str, mimetype); |
| }else if(typeof ActiveXObject != "undefined"){ |
| var domDoc = new ActiveXObject("Microsoft.XMLDOM"); |
| if(domDoc) { |
| domDoc.async = false; |
| domDoc.loadXML(str); |
| return domDoc; |
| }else{ |
| dojo.debug("toXml didn't work?"); |
| } |
| /* |
| }else if((dojo.render.html.capable)&&(dojo.render.html.safari)){ |
| // FIXME: this doesn't appear to work! |
| // from: http://web-graphics.com/mtarchive/001606.php |
| // var xml = '<?xml version="1.0"?>'+str; |
| var mtype = "text/xml"; |
| var xml = '<?xml version="1.0"?>'+str; |
| var url = "data:"+mtype+";charset=utf-8,"+encodeURIComponent(xml); |
| var request = new XMLHttpRequest(); |
| request.open("GET", url, false); |
| request.overrideMimeType(mtype); |
| request.send(null); |
| return request.responseXML; |
| */ |
| }else if(document.createElement){ |
| // FIXME: this may change all tags to uppercase! |
| var tmp = document.createElement("xml"); |
| tmp.innerHTML = str; |
| if(document.implementation && document.implementation.createDocument) { |
| var xmlDoc = document.implementation.createDocument("foo", "", null); |
| for(var i = 0; i < tmp.childNodes.length; i++) { |
| xmlDoc.importNode(tmp.childNodes.item(i), true); |
| } |
| return xmlDoc; |
| } |
| // FIXME: probably not a good idea to have to return an HTML fragment |
| // FIXME: the tmp.doc.firstChild is as tested from IE, so it may not |
| // work that way across the board |
| return tmp.document && tmp.document.firstChild ? |
| tmp.document.firstChild : tmp; |
| } |
| return null; |
| } |
| |
| dojo.dom.prependChild = function(node, parent) { |
| if(parent.firstChild) { |
| parent.insertBefore(node, parent.firstChild); |
| } else { |
| parent.appendChild(node); |
| } |
| return true; |
| } |
| |
| dojo.dom.insertBefore = function(node, ref, force){ |
| if (force != true && |
| (node === ref || node.nextSibling === ref)){ return false; } |
| var parent = ref.parentNode; |
| parent.insertBefore(node, ref); |
| return true; |
| } |
| |
| dojo.dom.insertAfter = function(node, ref, force){ |
| var pn = ref.parentNode; |
| if(ref == pn.lastChild){ |
| if((force != true)&&(node === ref)){ |
| return false; |
| } |
| pn.appendChild(node); |
| }else{ |
| return this.insertBefore(node, ref.nextSibling, force); |
| } |
| return true; |
| } |
| |
| dojo.dom.insertAtPosition = function(node, ref, position){ |
| if((!node)||(!ref)||(!position)){ return false; } |
| switch(position.toLowerCase()){ |
| case "before": |
| return dojo.dom.insertBefore(node, ref); |
| case "after": |
| return dojo.dom.insertAfter(node, ref); |
| case "first": |
| if(ref.firstChild){ |
| return dojo.dom.insertBefore(node, ref.firstChild); |
| }else{ |
| ref.appendChild(node); |
| return true; |
| } |
| break; |
| default: // aka: last |
| ref.appendChild(node); |
| return true; |
| } |
| } |
| |
| dojo.dom.insertAtIndex = function(node, containingNode, insertionIndex){ |
| var siblingNodes = containingNode.childNodes; |
| |
| // if there aren't any kids yet, just add it to the beginning |
| |
| if (!siblingNodes.length){ |
| containingNode.appendChild(node); |
| return true; |
| } |
| |
| // otherwise we need to walk the childNodes |
| // and find our spot |
| |
| var after = null; |
| |
| for(var i=0; i<siblingNodes.length; i++){ |
| |
| var sibling_index = siblingNodes.item(i)["getAttribute"] ? parseInt(siblingNodes.item(i).getAttribute("dojoinsertionindex")) : -1; |
| |
| if (sibling_index < insertionIndex){ |
| after = siblingNodes.item(i); |
| } |
| } |
| |
| if (after){ |
| // add it after the node in {after} |
| |
| return dojo.dom.insertAfter(node, after); |
| }else{ |
| // add it to the start |
| |
| return dojo.dom.insertBefore(node, siblingNodes.item(0)); |
| } |
| } |
| |
| /** |
| * implementation of the DOM Level 3 attribute. |
| * |
| * @param node The node to scan for text |
| * @param text Optional, set the text to this value. |
| */ |
| dojo.dom.textContent = function(node, text){ |
| if (text) { |
| dojo.dom.replaceChildren(node, document.createTextNode(text)); |
| return text; |
| } else { |
| var _result = ""; |
| if (node == null) { return _result; } |
| for (var i = 0; i < node.childNodes.length; i++) { |
| switch (node.childNodes[i].nodeType) { |
| case 1: // ELEMENT_NODE |
| case 5: // ENTITY_REFERENCE_NODE |
| _result += dojo.dom.textContent(node.childNodes[i]); |
| break; |
| case 3: // TEXT_NODE |
| case 2: // ATTRIBUTE_NODE |
| case 4: // CDATA_SECTION_NODE |
| _result += node.childNodes[i].nodeValue; |
| break; |
| default: |
| break; |
| } |
| } |
| return _result; |
| } |
| } |
| |
| dojo.dom.collectionToArray = function(collection){ |
| dojo.deprecated("dojo.dom.collectionToArray", "use dojo.lang.toArray instead"); |
| return dojo.lang.toArray(collection); |
| } |
| |
| dojo.dom.hasParent = function(node) { |
| if(!node || !node.parentNode || (node.parentNode && !node.parentNode.tagName)) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Determines if node has any of the provided tag names and |
| * returns the tag name that matches, empty string otherwise. |
| * |
| * Examples: |
| * |
| * myFooNode = <foo /> |
| * isTag(myFooNode, "foo"); // returns "foo" |
| * isTag(myFooNode, "bar"); // returns "" |
| * isTag(myFooNode, "FOO"); // returns "" |
| * isTag(myFooNode, "hey", "foo", "bar"); // returns "foo" |
| **/ |
| dojo.dom.isTag = function(node /* ... */) { |
| if(node && node.tagName) { |
| var arr = dojo.lang.toArray(arguments, 1); |
| return arr[ dojo.lang.find(node.tagName, arr) ] || ""; |
| } |
| return ""; |
| } |