2
Copyright (c) 2004-2006, The Dojo Foundation
5
Licensed under the Academic Free License version 2.1 or above OR the
6
modified BSD license. For more information on Dojo licensing, see:
8
http://dojotoolkit.org/community/licensing.shtml
11
dojo.provide("dojo.dom");
13
dojo.dom.ELEMENT_NODE = 1;
14
dojo.dom.ATTRIBUTE_NODE = 2;
15
dojo.dom.TEXT_NODE = 3;
16
dojo.dom.CDATA_SECTION_NODE = 4;
17
dojo.dom.ENTITY_REFERENCE_NODE = 5;
18
dojo.dom.ENTITY_NODE = 6;
19
dojo.dom.PROCESSING_INSTRUCTION_NODE = 7;
20
dojo.dom.COMMENT_NODE = 8;
21
dojo.dom.DOCUMENT_NODE = 9;
22
dojo.dom.DOCUMENT_TYPE_NODE = 10;
23
dojo.dom.DOCUMENT_FRAGMENT_NODE = 11;
24
dojo.dom.NOTATION_NODE = 12;
26
dojo.dom.dojoml = "http://www.dojotoolkit.org/2004/dojoml";
29
* comprehensive list of XML namespaces
33
// aliases for various common XML namespaces
34
svg : "http://www.w3.org/2000/svg",
35
smil : "http://www.w3.org/2001/SMIL20/",
36
mml : "http://www.w3.org/1998/Math/MathML",
37
cml : "http://www.xml-cml.org",
38
xlink : "http://www.w3.org/1999/xlink",
39
xhtml : "http://www.w3.org/1999/xhtml",
40
xul : "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
41
xbl : "http://www.mozilla.org/xbl",
42
fo : "http://www.w3.org/1999/XSL/Format",
43
xsl : "http://www.w3.org/1999/XSL/Transform",
44
xslt : "http://www.w3.org/1999/XSL/Transform",
45
xi : "http://www.w3.org/2001/XInclude",
46
xforms : "http://www.w3.org/2002/01/xforms",
47
saxon : "http://icl.com/saxon",
48
xalan : "http://xml.apache.org/xslt",
49
xsd : "http://www.w3.org/2001/XMLSchema",
50
dt: "http://www.w3.org/2001/XMLSchema-datatypes",
51
xsi : "http://www.w3.org/2001/XMLSchema-instance",
52
rdf : "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
53
rdfs : "http://www.w3.org/2000/01/rdf-schema#",
54
dc : "http://purl.org/dc/elements/1.1/",
55
dcq: "http://purl.org/dc/qualifiers/1.0",
56
"soap-env" : "http://schemas.xmlsoap.org/soap/envelope/",
57
wsdl : "http://schemas.xmlsoap.org/wsdl/",
58
AdobeExtensions : "http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
61
dojo.dom.isNode = function(/* object */wh){
63
// checks to see if wh is actually a node.
64
if(typeof Element == "function") {
66
return wh instanceof Element; // boolean
70
return wh && !isNaN(wh.nodeType); // boolean
74
dojo.dom.getUniqueId = function(){
76
// returns a unique string for use with any DOM element
77
var _document = dojo.doc();
79
var id = "dj_unique_" + (++arguments.callee._idIncrement);
80
}while(_document.getElementById(id));
83
dojo.dom.getUniqueId._idIncrement = 0;
85
dojo.dom.firstElement = dojo.dom.getFirstChildElement = function(/* Element */parentNode, /* string? */tagName){
87
// returns the first child element matching tagName
88
var node = parentNode.firstChild;
89
while(node && node.nodeType != dojo.dom.ELEMENT_NODE){
90
node = node.nextSibling;
92
if(tagName && node && node.tagName && node.tagName.toLowerCase() != tagName.toLowerCase()) {
93
node = dojo.dom.nextElement(node, tagName);
95
return node; // Element
98
dojo.dom.lastElement = dojo.dom.getLastChildElement = function(/* Element */parentNode, /* string? */tagName){
100
// returns the last child element matching tagName
101
var node = parentNode.lastChild;
102
while(node && node.nodeType != dojo.dom.ELEMENT_NODE) {
103
node = node.previousSibling;
105
if(tagName && node && node.tagName && node.tagName.toLowerCase() != tagName.toLowerCase()) {
106
node = dojo.dom.prevElement(node, tagName);
108
return node; // Element
111
dojo.dom.nextElement = dojo.dom.getNextSiblingElement = function(/* Node */node, /* string? */tagName){
113
// returns the next sibling element matching tagName
114
if(!node) { return null; }
116
node = node.nextSibling;
117
} while(node && node.nodeType != dojo.dom.ELEMENT_NODE);
119
if(node && tagName && tagName.toLowerCase() != node.tagName.toLowerCase()) {
120
return dojo.dom.nextElement(node, tagName);
122
return node; // Element
125
dojo.dom.prevElement = dojo.dom.getPreviousSiblingElement = function(/* Node */node, /* string? */tagName){
127
// returns the previous sibling element matching tagName
128
if(!node) { return null; }
129
if(tagName) { tagName = tagName.toLowerCase(); }
131
node = node.previousSibling;
132
} while(node && node.nodeType != dojo.dom.ELEMENT_NODE);
134
if(node && tagName && tagName.toLowerCase() != node.tagName.toLowerCase()) {
135
return dojo.dom.prevElement(node, tagName);
137
return node; // Element
141
/*this.forEachChildTag = function(node, unaryFunc) {
142
var child = this.getFirstChildTag(node);
144
if(unaryFunc(child) == "break") { break; }
145
child = this.getNextSiblingTag(child);
149
dojo.dom.moveChildren = function(/* Element */srcNode, /* Element */destNode, /* boolean? */trim){
151
// Moves children from srcNode to destNode and returns the count of children moved;
152
// will trim off text nodes if trim == true
155
while(srcNode.hasChildNodes() &&
156
srcNode.firstChild.nodeType == dojo.dom.TEXT_NODE) {
157
srcNode.removeChild(srcNode.firstChild);
159
while(srcNode.hasChildNodes() &&
160
srcNode.lastChild.nodeType == dojo.dom.TEXT_NODE) {
161
srcNode.removeChild(srcNode.lastChild);
164
while(srcNode.hasChildNodes()){
165
destNode.appendChild(srcNode.firstChild);
168
return count; // number
171
dojo.dom.copyChildren = function(/* Element */srcNode, /* Element */destNode, /* boolean? */trim){
173
// Copies children from srcNde to destNode and returns the count of children copied;
174
// will trim off text nodes if trim == true
175
var clonedNode = srcNode.cloneNode(true);
176
return this.moveChildren(clonedNode, destNode, trim); // number
179
dojo.dom.removeChildren = function(/* Element */node){
181
// removes all children from node and returns the count of children removed.
182
var count = node.childNodes.length;
183
while(node.hasChildNodes()){ node.removeChild(node.firstChild); }
184
return count; // number
187
dojo.dom.replaceChildren = function(/* Element */node, /* Node */newChild){
189
// Removes all children of node and appends newChild
190
// FIXME: what if newChild is an array-like object?
191
dojo.dom.removeChildren(node);
192
node.appendChild(newChild);
195
dojo.dom.removeNode = function(/* Node */node){
197
// if node has a parent, removes node from parent and returns a reference to the removed child.
198
if(node && node.parentNode){
199
// return a ref to the removed child
200
return node.parentNode.removeChild(node); // Node
204
dojo.dom.getAncestors = function(/* Node */node, /* function? */filterFunction, /* boolean? */returnFirstHit) {
206
// returns all ancestors matching optional filterFunction; will return only the first if returnFirstHit
208
var isFunction = (filterFunction && (filterFunction instanceof Function || typeof filterFunction == "function"));
210
if (!isFunction || filterFunction(node)) {
211
ancestors.push(node);
213
if (returnFirstHit && ancestors.length > 0) {
214
return ancestors[0]; // Node
217
node = node.parentNode;
219
if (returnFirstHit) { return null; }
220
return ancestors; // array
223
dojo.dom.getAncestorsByTag = function(/* Node */node, /* string */tag, /* boolean? */returnFirstHit) {
225
// returns all ancestors matching tag (as tagName), will only return first one if returnFirstHit
226
tag = tag.toLowerCase();
227
return dojo.dom.getAncestors(node, function(el){
228
return ((el.tagName)&&(el.tagName.toLowerCase() == tag));
229
}, returnFirstHit); // Node || array
232
dojo.dom.getFirstAncestorByTag = function(/* Node */node, /* string */tag) {
234
// Returns first ancestor of node with tag tagName
235
return dojo.dom.getAncestorsByTag(node, tag, true); // Node
238
dojo.dom.isDescendantOf = function(/* Node */node, /* Node */ancestor, /* boolean? */guaranteeDescendant){
240
// Returns boolean if node is a descendant of ancestor
241
// guaranteeDescendant allows us to be a "true" isDescendantOf function
242
if(guaranteeDescendant && node) { node = node.parentNode; }
244
if(node == ancestor){
245
return true; // boolean
247
node = node.parentNode;
249
return false; // boolean
252
dojo.dom.innerXML = function(/* Node */node){
254
// Implementation of MS's innerXML function.
256
return node.innerXML; // string
258
return node.xml; // string
259
}else if(typeof XMLSerializer != "undefined"){
260
return (new XMLSerializer()).serializeToString(node); // string
264
dojo.dom.createDocument = function(){
266
// cross-browser implementation of creating an XML document object.
268
var _document = dojo.doc();
270
if(!dj_undef("ActiveXObject")){
271
var prefixes = [ "MSXML2", "Microsoft", "MSXML", "MSXML3" ];
272
for(var i = 0; i<prefixes.length; i++){
274
doc = new ActiveXObject(prefixes[i]+".XMLDOM");
275
}catch(e){ /* squelch */ };
279
}else if((_document.implementation)&&
280
(_document.implementation.createDocument)){
281
doc = _document.implementation.createDocument("", "", null);
284
return doc; // DOMDocument
287
dojo.dom.createDocumentFromText = function(/* string */str, /* string? */mimetype){
289
// attempts to create a Document object based on optional mime-type, using str as the contents of the document
290
if(!mimetype){ mimetype = "text/xml"; }
291
if(!dj_undef("DOMParser")){
292
var parser = new DOMParser();
293
return parser.parseFromString(str, mimetype); // DOMDocument
294
}else if(!dj_undef("ActiveXObject")){
295
var domDoc = dojo.dom.createDocument();
297
domDoc.async = false;
299
return domDoc; // DOMDocument
301
dojo.debug("toXml didn't work?");
304
}else if((dojo.render.html.capable)&&(dojo.render.html.safari)){
305
// FIXME: this doesn't appear to work!
306
// from: http://web-graphics.com/mtarchive/001606.php
307
// var xml = '<?xml version="1.0"?>'+str;
308
var mtype = "text/xml";
309
var xml = '<?xml version="1.0"?>'+str;
310
var url = "data:"+mtype+";charset=utf-8,"+encodeURIComponent(xml);
311
var req = new XMLHttpRequest();
312
req.open("GET", url, false);
313
req.overrideMimeType(mtype);
315
return req.responseXML;
318
var _document = dojo.doc();
319
if(_document.createElement){
320
// FIXME: this may change all tags to uppercase!
321
var tmp = _document.createElement("xml");
323
if(_document.implementation && _document.implementation.createDocument) {
324
var xmlDoc = _document.implementation.createDocument("foo", "", null);
325
for(var i = 0; i < tmp.childNodes.length; i++) {
326
xmlDoc.importNode(tmp.childNodes.item(i), true);
328
return xmlDoc; // DOMDocument
330
// FIXME: probably not a good idea to have to return an HTML fragment
331
// FIXME: the tmp.doc.firstChild is as tested from IE, so it may not
332
// work that way across the board
333
return ((tmp.document)&&
334
(tmp.document.firstChild ? tmp.document.firstChild : tmp)); // DOMDocument
340
dojo.dom.prependChild = function(/* Element */node, /* Element */parent) {
342
// prepends node to parent's children nodes
343
if(parent.firstChild) {
344
parent.insertBefore(node, parent.firstChild);
346
parent.appendChild(node);
348
return true; // boolean
351
dojo.dom.insertBefore = function(/* Node */node, /* Node */ref, /* boolean? */force){
353
// Try to insert node before ref
355
(node === ref || node.nextSibling === ref)){ return false; }
356
var parent = ref.parentNode;
357
parent.insertBefore(node, ref);
358
return true; // boolean
361
dojo.dom.insertAfter = function(/* Node */node, /* Node */ref, /* boolean? */force){
363
// Try to insert node after ref
364
var pn = ref.parentNode;
365
if(ref == pn.lastChild){
366
if((force != true)&&(node === ref)){
367
return false; // boolean
369
pn.appendChild(node);
371
return this.insertBefore(node, ref.nextSibling, force); // boolean
373
return true; // boolean
376
dojo.dom.insertAtPosition = function(/* Node */node, /* Node */ref, /* string */position){
378
// attempt to insert node in relation to ref based on position
379
if((!node)||(!ref)||(!position)){
380
return false; // boolean
382
switch(position.toLowerCase()){
384
return dojo.dom.insertBefore(node, ref); // boolean
386
return dojo.dom.insertAfter(node, ref); // boolean
389
return dojo.dom.insertBefore(node, ref.firstChild); // boolean
391
ref.appendChild(node);
392
return true; // boolean
395
default: // aka: last
396
ref.appendChild(node);
397
return true; // boolean
401
dojo.dom.insertAtIndex = function(/* Node */node, /* Element */containingNode, /* number */insertionIndex){
403
// insert node into child nodes nodelist of containingNode at insertionIndex.
404
var siblingNodes = containingNode.childNodes;
406
// if there aren't any kids yet, just add it to the beginning
408
if (!siblingNodes.length){
409
containingNode.appendChild(node);
410
return true; // boolean
413
// otherwise we need to walk the childNodes
418
for(var i=0; i<siblingNodes.length; i++){
420
var sibling_index = siblingNodes.item(i)["getAttribute"] ? parseInt(siblingNodes.item(i).getAttribute("dojoinsertionindex")) : -1;
422
if (sibling_index < insertionIndex){
423
after = siblingNodes.item(i);
428
// add it after the node in {after}
430
return dojo.dom.insertAfter(node, after); // boolean
432
// add it to the start
434
return dojo.dom.insertBefore(node, siblingNodes.item(0)); // boolean
438
dojo.dom.textContent = function(/* Node */node, /* string */text){
440
// implementation of the DOM Level 3 attribute; scan node for text
441
if (arguments.length>1) {
442
var _document = dojo.doc();
443
dojo.dom.replaceChildren(node, _document.createTextNode(text));
444
return text; // string
446
if(node.textContent != undefined){ //FF 1.5
447
return node.textContent; // string
450
if (node == null) { return _result; }
451
for (var i = 0; i < node.childNodes.length; i++) {
452
switch (node.childNodes[i].nodeType) {
453
case 1: // ELEMENT_NODE
454
case 5: // ENTITY_REFERENCE_NODE
455
_result += dojo.dom.textContent(node.childNodes[i]);
458
case 2: // ATTRIBUTE_NODE
459
case 4: // CDATA_SECTION_NODE
460
_result += node.childNodes[i].nodeValue;
466
return _result; // string
470
dojo.dom.hasParent = function (/* Node */node) {
472
// returns whether or not node is a child of another node.
473
return node && node.parentNode && dojo.dom.isNode(node.parentNode); // boolean
479
* myFooNode = <foo />
480
* isTag(myFooNode, "foo"); // returns "foo"
481
* isTag(myFooNode, "bar"); // returns ""
482
* isTag(myFooNode, "FOO"); // returns ""
483
* isTag(myFooNode, "hey", "foo", "bar"); // returns "foo"
485
dojo.dom.isTag = function(/* Node */node /* ... */) {
487
// determines if node has any of the provided tag names and returns the tag name that matches, empty string otherwise.
488
if(node && node.tagName) {
489
for(var i=1; i<arguments.length; i++){
490
if(node.tagName==String(arguments[i])){
491
return String(arguments[i]); // string
498
dojo.dom.setAttributeNS = function(/* Element */elem, /* string */namespaceURI, /* string */attrName, /* string */attrValue){
500
// implementation of DOM2 setAttributeNS that works cross browser.
501
if(elem == null || ((elem == undefined)&&(typeof elem == "undefined"))){
502
dojo.raise("No element given to dojo.dom.setAttributeNS");
505
if(!((elem.setAttributeNS == undefined)&&(typeof elem.setAttributeNS == "undefined"))){ // w3c
506
elem.setAttributeNS(namespaceURI, attrName, attrValue);
508
// get a root XML document
509
var ownerDoc = elem.ownerDocument;
510
var attribute = ownerDoc.createNode(
517
attribute.nodeValue = attrValue;
520
elem.setAttributeNode(attribute);