X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/6a7e4474cba9d8be4b2ec445e10f1691f7277c50..f562e4c6e5fac7bcb445985b99acbea4d706e6f0:/docs/source/DomQuery.html?ds=sidebyside diff --git a/docs/source/DomQuery.html b/docs/source/DomQuery.html index 9572dcd1..f576a44a 100644 --- a/docs/source/DomQuery.html +++ b/docs/source/DomQuery.html @@ -1,103 +1,109 @@ + - + The source code - - + + + + - -
/*!
- * Ext JS Library 3.2.0
- * Copyright(c) 2006-2010 Ext JS, Inc.
- * licensing@extjs.com
- * http://www.extjs.com/license
- */
-/*
+
+  
/*
  * This is code is also distributed under MIT license for use
  * with jQuery and prototype JavaScript libraries.
  */
-
/** - * @class Ext.DomQuery +/** + * @class Ext.DomQuery Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in). -

-DomQuery supports most of the CSS3 selectors spec, along with some custom selectors and basic XPath.

- -

-All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure. -

-

Element Selectors:

- -

Attribute Selectors:

-

The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.

- -

Pseudo Classes:

- -

CSS Value Selectors:

- +<p> +DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/#selectors">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p> + +<p> +All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure. +</p> +<h4>Element Selectors:</h4> +<ul class="list"> + <li> <b>*</b> any element</li> + <li> <b>E</b> an element with the tag E</li> + <li> <b>E F</b> All descendent elements of E that have the tag F</li> + <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li> + <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li> + <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li> +</ul> +<h4>Attribute Selectors:</h4> +<p>The use of &#64; and quotes are optional. For example, div[&#64;foo='bar'] is also a valid attribute selector.</p> +<ul class="list"> + <li> <b>E[foo]</b> has an attribute "foo"</li> + <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li> + <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li> + <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li> + <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li> + <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li> + <li> <b>E[foo!=bar]</b> attribute "foo" does not equal "bar"</li> +</ul> +<h4>Pseudo Classes:</h4> +<ul class="list"> + <li> <b>E:first-child</b> E is the first child of its parent</li> + <li> <b>E:last-child</b> E is the last child of its parent</li> + <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li> + <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li> + <li> <b>E:nth-child(even)</b> E is an even child of its parent</li> + <li> <b>E:only-child</b> E is the only child of its parent</li> + <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li> + <li> <b>E:first</b> the first E in the resultset</li> + <li> <b>E:last</b> the last E in the resultset</li> + <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li> + <li> <b>E:odd</b> shortcut for :nth-child(odd)</li> + <li> <b>E:even</b> shortcut for :nth-child(even)</li> + <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li> + <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li> + <li> <b>E:not(S)</b> an E element that does not match simple selector S</li> + <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li> + <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li> + <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li> + <li> <b>E:any(S1|S2|S2)</b> an E element which matches any of the simple selectors S1, S2 or S3//\\</li> +</ul> +<h4>CSS Value Selectors:</h4> +<ul class="list"> + <li> <b>E{display=none}</b> css value "display" that equals "none"</li> + <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li> + <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li> + <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li> + <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li> + <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li> +</ul> * @singleton */ -Ext.DomQuery = function(){ - var cache = {}, - simpleCache = {}, - valueCache = {}, - nonSpace = /\S/, - trimRe = /^\s+|\s+$/g, - tplRe = /\{(\d+)\}/g, - modeRe = /^(\s?[\/>+~]\s?|\s|$)/, - tagTokenRe = /^(#)?([\w-\*]+)/, - nthRe = /(\d*)n\+?(\d*)/, - nthRe2 = /\D/, - // This is for IE MSXML which does not support expandos. - // IE runs the same speed using setAttribute, however FF slows way down - // and Safari completely fails so they need to continue to use expandos. - isIE = window.ActiveXObject ? true : false, - key = 30803; - +Ext.ns('Ext.core'); + +Ext.core.DomQuery = Ext.DomQuery = function(){ + var cache = {}, + simpleCache = {}, + valueCache = {}, + nonSpace = /\S/, + trimRe = /^\s+|\s+$/g, + tplRe = /\{(\d+)\}/g, + modeRe = /^(\s?[\/>+~]\s?|\s|$)/, + tagTokenRe = /^(#)?([\w-\*]+)/, + nthRe = /(\d*)n\+?(\d*)/, + nthRe2 = /\D/, + startIdRe = /^\s*\#/, + // This is for IE MSXML which does not support expandos. + // IE runs the same speed using setAttribute, however FF slows way down + // and Safari completely fails so they need to continue to use expandos. + isIE = window.ActiveXObject ? true : false, + key = 30803; + // this eval is stop the compressor from // renaming the variable to something shorter - eval("var batch = 30803;"); + eval("var batch = 30803;"); // Retrieve the child node from a particular // parent at the specified index. @@ -116,14 +122,14 @@ Ext.DomQuery = function(){ } // retrieve the next element node - function next(n){ - while((n = n.nextSibling) && n.nodeType != 1); + function next(n){ + while((n = n.nextSibling) && n.nodeType != 1); return n; } - // retrieve the previous element node + // retrieve the previous element node function prev(n){ - while((n = n.previousSibling) && n.nodeType != 1); + while((n = n.previousSibling) && n.nodeType != 1); return n; } @@ -131,20 +137,20 @@ Ext.DomQuery = function(){ // removing empty text nodes. function children(parent){ var n = parent.firstChild, - nodeIndex = -1, - nextNode; - while(n){ - nextNode = n.nextSibling; - // clean worthless empty nodes. - if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){ - parent.removeChild(n); - }else{ - // add an expando nodeIndex - n.nodeIndex = ++nodeIndex; - } - n = nextNode; - } - return this; + nodeIndex = -1, + nextNode; + while(n){ + nextNode = n.nextSibling; + // clean worthless empty nodes. + if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){ + parent.removeChild(n); + }else{ + // add an expando nodeIndex + n.nodeIndex = ++nodeIndex; + } + n = nextNode; + } + return this; } @@ -164,18 +170,18 @@ Ext.DomQuery = function(){ }; function attrValue(n, attr){ - // if its an array, use the first node. - if(!n.tagName && typeof n.length != "undefined"){ + // if its an array, use the first node. + if(!n.tagName && typeof n.length != "undefined"){ n = n[0]; } if(!n){ return null; } - if(attr == "for"){ + if(attr == "for"){ return n.htmlFor; } - if(attr == "class" || attr == "className"){ + if(attr == "class" || attr == "className"){ return n.className; } return n.getAttribute(attr) || n[attr]; @@ -184,21 +190,21 @@ Ext.DomQuery = function(){ // ns - nodes - // mode - false, /, >, +, ~ - // tagName - defaults to "*" + // mode - false, /, >, +, ~ + // tagName - defaults to "*" function getNodes(ns, mode, tagName){ var result = [], ri = -1, cs; if(!ns){ return result; } - tagName = tagName || "*"; - // convert to array - if(typeof ns.getElementsByTagName != "undefined"){ + tagName = tagName || "*"; + // convert to array + if(typeof ns.getElementsByTagName != "undefined"){ ns = [ns]; } - - // no mode specified, grab all elements by tagName - // at any depth + + // no mode specified, grab all elements by tagName + // at any depth if(!mode){ for(var i = 0, ni; ni = ns[i]; i++){ cs = ni.getElementsByTagName(tagName); @@ -206,9 +212,9 @@ Ext.DomQuery = function(){ result[++ri] = ci; } } - // Direct Child mode (/ or >) - // E > F or E/F all direct children elements of E that have the tag - } else if(mode == "/" || mode == ">"){ + // Direct Child mode (/ or >) + // E > F or E/F all direct children elements of E that have the tag + } else if(mode == "/" || mode == ">"){ var utag = tagName.toUpperCase(); for(var i = 0, ni, cn; ni = ns[i]; i++){ cn = ni.childNodes; @@ -218,19 +224,19 @@ Ext.DomQuery = function(){ } } } - // Immediately Preceding mode (+) - // E + F all elements with the tag F that are immediately preceded by an element with the tag E - }else if(mode == "+"){ + // Immediately Preceding mode (+) + // E + F all elements with the tag F that are immediately preceded by an element with the tag E + }else if(mode == "+"){ var utag = tagName.toUpperCase(); for(var i = 0, n; n = ns[i]; i++){ - while((n = n.nextSibling) && n.nodeType != 1); - if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){ + while((n = n.nextSibling) && n.nodeType != 1); + if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){ result[++ri] = n; } } - // Sibling mode (~) - // E ~ F all elements with the tag F that are preceded by a sibling element with the tag E - }else if(mode == "~"){ + // Sibling mode (~) + // E ~ F all elements with the tag F that are preceded by a sibling element with the tag E + }else if(mode == "~"){ var utag = tagName.toUpperCase(); for(var i = 0, n; n = ns[i]; i++){ while((n = n.nextSibling)){ @@ -247,7 +253,7 @@ Ext.DomQuery = function(){ if(b.slice){ return a.concat(b); } - for(var i = 0, l = b.length; i < l; i++){ + for(var i = 0, l = b.length; i < l; i++){ a[a.length] = b[i]; } return a; @@ -263,7 +269,7 @@ Ext.DomQuery = function(){ var result = [], ri = -1; tagName = tagName.toLowerCase(); for(var i = 0, ci; ci = cs[i]; i++){ - if(ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName){ + if(ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName){ result[++ri] = ci; } } @@ -279,7 +285,7 @@ Ext.DomQuery = function(){ } var result = [], ri = -1; for(var i = 0, ci; ci = cs[i]; i++){ - if(ci && ci.id == id){ + if(ci && ci.id == id){ result[++ri] = ci; return result; } @@ -288,40 +294,46 @@ Ext.DomQuery = function(){ } // operators are =, !=, ^=, $=, *=, %=, |= and ~= - // custom can be "{" + // custom can be "{" function byAttribute(cs, attr, value, op, custom){ - var result = [], - ri = -1, - useGetStyle = custom == "{", - fn = Ext.DomQuery.operators[op], - a, - innerHTML; + var result = [], + ri = -1, + useGetStyle = custom == "{", + fn = Ext.DomQuery.operators[op], + a, + xml, + hasXml; + for(var i = 0, ci; ci = cs[i]; i++){ - // skip non-element nodes. + // skip non-element nodes. if(ci.nodeType != 1){ continue; } - - innerHTML = ci.innerHTML; + // only need to do this for the first node + if(!hasXml){ + xml = Ext.DomQuery.isXml(ci); + hasXml = true; + } + // we only need to change the property names if we're dealing with html nodes, not XML - if(innerHTML !== null && innerHTML !== undefined){ + if(!xml){ if(useGetStyle){ a = Ext.DomQuery.getStyle(ci, attr); - } else if (attr == "class" || attr == "className"){ + } else if (attr == "class" || attr == "className"){ a = ci.className; - } else if (attr == "for"){ + } else if (attr == "for"){ a = ci.htmlFor; - } else if (attr == "href"){ - // getAttribute href bug - // http://www.glennjones.net/Post/809/getAttributehrefbug.htm - a = ci.getAttribute("href", 2); + } else if (attr == "href"){ + // getAttribute href bug + // http://www.glennjones.net/Post/809/getAttributehrefbug.htm + a = ci.getAttribute("href", 2); } else{ a = ci.getAttribute(attr); } }else{ a = ci.getAttribute(attr); } - if((fn && fn(a, value)) || (!fn && a)){ + if((fn && fn(a, value)) || (!fn && a)){ result[++ri] = ci; } } @@ -333,19 +345,19 @@ Ext.DomQuery = function(){ } function nodupIEXml(cs){ - var d = ++key, + var d = ++key, r; - cs[0].setAttribute("_nodup", d); + cs[0].setAttribute("_nodup", d); r = [cs[0]]; - for(var i = 1, len = cs.length; i < len; i++){ + for(var i = 1, len = cs.length; i < len; i++){ var c = cs[i]; - if(!c.getAttribute("_nodup") != d){ - c.setAttribute("_nodup", d); + if(!c.getAttribute("_nodup") != d){ + c.setAttribute("_nodup", d); r[r.length] = c; } } - for(var i = 0, len = cs.length; i < len; i++){ - cs[i].removeAttribute("_nodup"); + for(var i = 0, len = cs.length; i < len; i++){ + cs[i].removeAttribute("_nodup"); } return r; } @@ -355,10 +367,10 @@ Ext.DomQuery = function(){ return []; } var len = cs.length, c, i, r = cs, cj, ri = -1; - if(!len || typeof cs.nodeType != "undefined" || len == 1){ + if(!len || typeof cs.nodeType != "undefined" || len == 1){ return cs; } - if(isIE && typeof cs[0].selectSingleNode != "undefined"){ + if(isIE && typeof cs[0].selectSingleNode != "undefined"){ return nodupIEXml(cs); } var d = ++key; @@ -368,7 +380,7 @@ Ext.DomQuery = function(){ c._nodup = d; }else{ r = []; - for(var j = 0; j < i; j++){ + for(var j = 0; j < i; j++){ r[++ri] = cs[j]; } for(j = i+1; cj = cs[j]; j++){ @@ -386,34 +398,34 @@ Ext.DomQuery = function(){ function quickDiffIEXml(c1, c2){ var d = ++key, r = []; - for(var i = 0, len = c1.length; i < len; i++){ - c1[i].setAttribute("_qdiff", d); - } - for(var i = 0, len = c2.length; i < len; i++){ - if(c2[i].getAttribute("_qdiff") != d){ + for(var i = 0, len = c1.length; i < len; i++){ + c1[i].setAttribute("_qdiff", d); + } + for(var i = 0, len = c2.length; i < len; i++){ + if(c2[i].getAttribute("_qdiff") != d){ r[r.length] = c2[i]; } } - for(var i = 0, len = c1.length; i < len; i++){ - c1[i].removeAttribute("_qdiff"); + for(var i = 0, len = c1.length; i < len; i++){ + c1[i].removeAttribute("_qdiff"); } return r; } function quickDiff(c1, c2){ var len1 = c1.length, - d = ++key, - r = []; + d = ++key, + r = []; if(!len1){ return c2; } - if(isIE && typeof c1[0].selectSingleNode != "undefined"){ + if(isIE && typeof c1[0].selectSingleNode != "undefined"){ return quickDiffIEXml(c1, c2); - } - for(var i = 0; i < len1; i++){ + } + for(var i = 0; i < len1; i++){ c1[i]._qdiff = d; - } - for(var i = 0, len = c2.length; i < len; i++){ + } + for(var i = 0, len = c2.length; i < len; i++){ if(c2[i]._qdiff != d){ r[r.length] = c2[i]; } @@ -426,7 +438,7 @@ Ext.DomQuery = function(){ var d = root.ownerDocument || root; return d.getElementById(id); } - ns = getNodes(ns, mode, "*"); + ns = getNodes(ns, mode, "*"); return byId(ns, id); } @@ -434,192 +446,245 @@ Ext.DomQuery = function(){ getStyle : function(el, name){ return Ext.fly(el).getStyle(name); }, -
/** - * Compiles a selector/xpath query into a reusable function. The returned function - * takes one parameter "root" (optional), which is the context node from where the query should start. + /** + * Compiles a selector/xpath query into a reusable function. The returned function + * takes one parameter "root" (optional), which is the context node from where the query should start. * @param {String} selector The selector/xpath query - * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match + * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match * @return {Function} */ compile : function(path, type){ - type = type || "select"; - - // setup fn preamble - var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"], - mode, - lastPath, - matchers = Ext.DomQuery.matchers, - matchersLn = matchers.length, - modeMatch, - // accept leading mode switch - lmode = path.match(modeRe); - - if(lmode && lmode[1]){ - fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";'; - path = path.replace(lmode[1], ""); + type = type || "select"; + + // setup fn preamble + var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"], + mode, + lastPath, + matchers = Ext.DomQuery.matchers, + matchersLn = matchers.length, + modeMatch, + // accept leading mode switch + lmode = path.match(modeRe); + + if(lmode && lmode[1]){ + fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";'; + path = path.replace(lmode[1], ""); } - + // strip leading slashes - while(path.substr(0, 1)=="/"){ + while(path.substr(0, 1)=="/"){ path = path.substr(1); } - while(path && lastPath != path){ + while(path && lastPath != path){ lastPath = path; var tokenMatch = path.match(tagTokenRe); - if(type == "select"){ + if(type == "select"){ if(tokenMatch){ - // ID Selector - if(tokenMatch[1] == "#"){ - fn[fn.length] = 'n = quickId(n, mode, root, "'+tokenMatch[2]+'");'; + // ID Selector + if(tokenMatch[1] == "#"){ + fn[fn.length] = 'n = quickId(n, mode, root, "'+tokenMatch[2]+'");'; }else{ - fn[fn.length] = 'n = getNodes(n, mode, "'+tokenMatch[2]+'");'; + fn[fn.length] = 'n = getNodes(n, mode, "'+tokenMatch[2]+'");'; } - path = path.replace(tokenMatch[0], ""); + path = path.replace(tokenMatch[0], ""); }else if(path.substr(0, 1) != '@'){ - fn[fn.length] = 'n = getNodes(n, mode, "*");'; + fn[fn.length] = 'n = getNodes(n, mode, "*");'; } - // type of "simple" + // type of "simple" }else{ if(tokenMatch){ - if(tokenMatch[1] == "#"){ - fn[fn.length] = 'n = byId(n, "'+tokenMatch[2]+'");'; + if(tokenMatch[1] == "#"){ + fn[fn.length] = 'n = byId(n, "'+tokenMatch[2]+'");'; }else{ - fn[fn.length] = 'n = byTag(n, "'+tokenMatch[2]+'");'; + fn[fn.length] = 'n = byTag(n, "'+tokenMatch[2]+'");'; } - path = path.replace(tokenMatch[0], ""); + path = path.replace(tokenMatch[0], ""); } } while(!(modeMatch = path.match(modeRe))){ var matched = false; - for(var j = 0; j < matchersLn; j++){ + for(var j = 0; j < matchersLn; j++){ var t = matchers[j]; var m = path.match(t.re); if(m){ fn[fn.length] = t.select.replace(tplRe, function(x, i){ - return m[i]; - }); - path = path.replace(m[0], ""); + return m[i]; + }); + path = path.replace(m[0], ""); matched = true; break; } } // prevent infinite loop on bad selector if(!matched){ - throw 'Error parsing selector, parsing failed at "' + path + '"'; + //<debug> + Ext.Error.raise({ + sourceClass: 'Ext.DomQuery', + sourceMethod: 'compile', + msg: 'Error parsing selector. Parsing failed at "' + path + '"' + }); + //</debug> } } if(modeMatch[1]){ - fn[fn.length] = 'mode="'+modeMatch[1].replace(trimRe, "")+'";'; - path = path.replace(modeMatch[1], ""); + fn[fn.length] = 'mode="'+modeMatch[1].replace(trimRe, "")+'";'; + path = path.replace(modeMatch[1], ""); } } - // close fn out - fn[fn.length] = "return nodup(n);\n}"; - - // eval fn and return it - eval(fn.join("")); + // close fn out + fn[fn.length] = "return nodup(n);\n}"; + + // eval fn and return it + eval(fn.join("")); return f; }, -
/** - * Selects a group of elements. + /** + * Selects an array of DOM nodes using JavaScript-only implementation. + * + * Use {@link #select} to take advantage of browsers built-in support for CSS selectors. + * * @param {String} selector The selector/xpath query (can be a comma separated list of selectors) - * @param {Node/String} root (optional) The start of the query (defaults to document). - * @return {Array} An Array of DOM elements which match the selector. If there are + * @param {HTMLElement/String} root (optional) The start of the query (defaults to document). + * @return {HTMLElement[]} An Array of DOM elements which match the selector. If there are * no matches, and empty Array is returned. */ - jsSelect: function(path, root, type){ - // set root to doc if not specified. - root = root || document; - - if(typeof root == "string"){ + jsSelect: function(path, root, type){ + // set root to doc if not specified. + root = root || document; + + if(typeof root == "string"){ root = document.getElementById(root); } - var paths = path.split(","), - results = []; - - // loop over each selector - for(var i = 0, len = paths.length; i < len; i++){ - var subPath = paths[i].replace(trimRe, ""); - // compile and place in cache + var paths = path.split(","), + results = []; + + // loop over each selector + for(var i = 0, len = paths.length; i < len; i++){ + var subPath = paths[i].replace(trimRe, ""); + // compile and place in cache if(!cache[subPath]){ cache[subPath] = Ext.DomQuery.compile(subPath); if(!cache[subPath]){ - throw subPath + " is not a valid selector"; + //<debug> + Ext.Error.raise({ + sourceClass: 'Ext.DomQuery', + sourceMethod: 'jsSelect', + msg: subPath + ' is not a valid selector' + }); + //</debug> } } var result = cache[subPath](root); - if(result && result != document){ + if(result && result != document){ results = results.concat(result); } } - - // if there were multiple selectors, make sure dups - // are eliminated - if(paths.length > 1){ + + // if there were multiple selectors, make sure dups + // are eliminated + if(paths.length > 1){ return nodup(results); } return results; }, - isXml: function(el) { - var docEl = (el ? el.ownerDocument || el : 0).documentElement; - return docEl ? docEl.nodeName !== "HTML" : false; - }, + + isXml: function(el) { + var docEl = (el ? el.ownerDocument || el : 0).documentElement; + return docEl ? docEl.nodeName !== "HTML" : false; + }, + + /** + * Selects an array of DOM nodes by CSS/XPath selector. + * + * Uses [document.querySelectorAll][0] if browser supports that, otherwise falls back to + * {@link Ext.DomQuery#jsSelect} to do the work. + * + * Aliased as {@link Ext#query}. + * + * [0]: https://developer.mozilla.org/en/DOM/document.querySelectorAll + * + * @param {String} path The selector/xpath query + * @param {HTMLElement} root (optional) The start of the query (defaults to document). + * @return {HTMLElement[]} An array of DOM elements (not a NodeList as returned by `querySelectorAll`). + * Empty array when no matches. + * @method + */ select : document.querySelectorAll ? function(path, root, type) { - root = root || document; - if (!Ext.DomQuery.isXml(root)) { - try { - var cs = root.querySelectorAll(path); - return Ext.toArray(cs); - } - catch (ex) {} - } - return Ext.DomQuery.jsSelect.call(this, path, root, type); - } : function(path, root, type) { - return Ext.DomQuery.jsSelect.call(this, path, root, type); - }, - -
/** - * Selects a single element. + root = root || document; + /* + * Safari 3.x can't handle uppercase or unicode characters when in quirks mode. + */ + if (!Ext.DomQuery.isXml(root) && !(Ext.isSafari3 && !Ext.isStrict)) { + try { + /* + * This checking here is to "fix" the behaviour of querySelectorAll + * for non root document queries. The way qsa works is intentional, + * however it's definitely not the expected way it should work. + * More info: http://ejohn.org/blog/thoughts-on-queryselectorall/ + * + * We only modify the path for single selectors (ie, no multiples), + * without a full parser it makes it difficult to do this correctly. + */ + var isDocumentRoot = root.nodeType === 9, + _path = path, + _root = root; + + if (!isDocumentRoot && path.indexOf(',') === -1 && !startIdRe.test(path)) { + _path = '#' + Ext.id(root) + ' ' + path; + _root = root.parentNode; + } + return Ext.Array.toArray(_root.querySelectorAll(_path)); + } + catch (e) { + } + } + return Ext.DomQuery.jsSelect.call(this, path, root, type); + } : function(path, root, type) { + return Ext.DomQuery.jsSelect.call(this, path, root, type); + }, + + /** + * Selects a single element. * @param {String} selector The selector/xpath query - * @param {Node} root (optional) The start of the query (defaults to document). - * @return {Element} The DOM element which matched the selector. + * @param {HTMLElement} root (optional) The start of the query (defaults to document). + * @return {HTMLElement} The DOM element which matched the selector. */ selectNode : function(path, root){ return Ext.DomQuery.select(path, root)[0]; }, -
/** - * Selects the value of a node, optionally replacing null with the defaultValue. + /** + * Selects the value of a node, optionally replacing null with the defaultValue. * @param {String} selector The selector/xpath query - * @param {Node} root (optional) The start of the query (defaults to document). - * @param {String} defaultValue + * @param {HTMLElement} root (optional) The start of the query (defaults to document). + * @param {String} defaultValue (optional) When specified, this is return as empty value. * @return {String} */ selectValue : function(path, root, defaultValue){ - path = path.replace(trimRe, ""); + path = path.replace(trimRe, ""); if(!valueCache[path]){ - valueCache[path] = Ext.DomQuery.compile(path, "select"); + valueCache[path] = Ext.DomQuery.compile(path, "select"); } var n = valueCache[path](root), v; n = n[0] ? n[0] : n; - - // overcome a limitation of maximum textnode size - // Rumored to potentially crash IE6 but has not been confirmed. - // http://reference.sitepoint.com/javascript/Node/normalize - // https://developer.mozilla.org/En/DOM/Node.normalize + + // overcome a limitation of maximum textnode size + // Rumored to potentially crash IE6 but has not been confirmed. + // http://reference.sitepoint.com/javascript/Node/normalize + // https://developer.mozilla.org/En/DOM/Node.normalize if (typeof n.normalize == 'function') n.normalize(); - - v = (n && n.firstChild ? n.firstChild.nodeValue : null); + + v = (n && n.firstChild ? n.firstChild.nodeValue : null); return ((v === null||v === undefined||v==='') ? defaultValue : v); }, -
/** - * Selects the value of a node, parsing integers and floats. Returns the defaultValue, or 0 if none is specified. + /** + * Selects the value of a node, parsing integers and floats. Returns the defaultValue, or 0 if none is specified. * @param {String} selector The selector/xpath query - * @param {Node} root (optional) The start of the query (defaults to document). - * @param {Number} defaultValue + * @param {HTMLElement} root (optional) The start of the query (defaults to document). + * @param {Number} defaultValue (optional) When specified, this is return as empty value. * @return {Number} */ selectNumber : function(path, root, defaultValue){ @@ -627,123 +692,131 @@ Ext.DomQuery = function(){ return parseFloat(v); }, -
/** - * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child) - * @param {String/HTMLElement/Array} el An element id, element or array of elements + /** + * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child) + * @param {String/HTMLElement/HTMLElement[]} el An element id, element or array of elements * @param {String} selector The simple selector to test * @return {Boolean} */ is : function(el, ss){ - if(typeof el == "string"){ + if(typeof el == "string"){ el = document.getElementById(el); } var isArray = Ext.isArray(el), - result = Ext.DomQuery.filter(isArray ? el : [el], ss); - return isArray ? (result.length == el.length) : (result.length > 0); + result = Ext.DomQuery.filter(isArray ? el : [el], ss); + return isArray ? (result.length == el.length) : (result.length > 0); }, -
/** - * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child) - * @param {Array} el An array of elements to filter + /** + * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child) + * @param {HTMLElement[]} el An array of elements to filter * @param {String} selector The simple selector to test * @param {Boolean} nonMatches If true, it returns the elements that DON'T match * the selector instead of the ones that match - * @return {Array} An Array of DOM elements which match the selector. If there are + * @return {HTMLElement[]} An Array of DOM elements which match the selector. If there are * no matches, and empty Array is returned. */ filter : function(els, ss, nonMatches){ - ss = ss.replace(trimRe, ""); + ss = ss.replace(trimRe, ""); if(!simpleCache[ss]){ - simpleCache[ss] = Ext.DomQuery.compile(ss, "simple"); + simpleCache[ss] = Ext.DomQuery.compile(ss, "simple"); } var result = simpleCache[ss](els); return nonMatches ? quickDiff(result, els) : result; }, -
/** - * Collection of matching regular expressions and code snippets. + /** + * Collection of matching regular expressions and code snippets. * Each capture group within () will be replace the {} in the select * statement as specified by their index. */ matchers : [{ re: /^\.([\w-]+)/, - select: 'n = byClassName(n, " {1} ");' + select: 'n = byClassName(n, " {1} ");' }, { - re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/, - select: 'n = byPseudo(n, "{1}", "{2}");' + re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/, + select: 'n = byPseudo(n, "{1}", "{2}");' },{ - re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/, - select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");' + re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/, + select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");' }, { re: /^#([\w-]+)/, - select: 'n = byId(n, "{1}");' + select: 'n = byId(n, "{1}");' },{ re: /^@([\w-]+)/, - select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};' + select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};' } ], -
/** - * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=. - * New operators can be added as long as the match the format c= where c is any character other than space, > <. + /** + * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=. + * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, &gt; &lt;. */ operators : { - "=" : function(a, v){ + "=" : function(a, v){ return a == v; }, - "!=" : function(a, v){ + "!=" : function(a, v){ return a != v; }, - "^=" : function(a, v){ - return a && a.substr(0, v.length) == v; + "^=" : function(a, v){ + return a && a.substr(0, v.length) == v; }, - "$=" : function(a, v){ - return a && a.substr(a.length-v.length) == v; + "$=" : function(a, v){ + return a && a.substr(a.length-v.length) == v; }, - "*=" : function(a, v){ - return a && a.indexOf(v) !== -1; + "*=" : function(a, v){ + return a && a.indexOf(v) !== -1; }, - "%=" : function(a, v){ + "%=" : function(a, v){ return (a % v) == 0; }, - "|=" : function(a, v){ - return a && (a == v || a.substr(0, v.length+1) == v+'-'); + "|=" : function(a, v){ + return a && (a == v || a.substr(0, v.length+1) == v+'-'); }, - "~=" : function(a, v){ - return a && (' '+a+' ').indexOf(' '+v+' ') != -1; + "~=" : function(a, v){ + return a && (' '+a+' ').indexOf(' '+v+' ') != -1; } }, -
/** - *

Object hash of "pseudo class" filter functions which are used when filtering selections. Each function is passed - * two parameters:

    - *
  • c : Array
    An Array of DOM elements to filter.
  • - *
  • v : String
    The argument (if any) supplied in the selector.
  • - *
- *

A filter function returns an Array of DOM elements which conform to the pseudo class.

- *

In addition to the provided pseudo classes listed above such as first-child and nth-child, - * developers may add additional, custom psuedo class filters to select elements according to application-specific requirements.

- *

For example, to filter <a> elements to only return links to external resources:

- *
-Ext.DomQuery.pseudos.external = function(c, v){
-    var r = [], ri = -1;
-    for(var i = 0, ci; ci = c[i]; i++){
-//      Include in result set only if it's a link to an external resource
-        if(ci.hostname != location.hostname){
-            r[++ri] = ci;
+        /**
+Object hash of "pseudo class" filter functions which are used when filtering selections.
+Each function is passed two parameters:
+
+- **c** : Array
+    An Array of DOM elements to filter.
+
+- **v** : String
+    The argument (if any) supplied in the selector.
+
+A filter function returns an Array of DOM elements which conform to the pseudo class.
+In addition to the provided pseudo classes listed above such as `first-child` and `nth-child`,
+developers may add additional, custom psuedo class filters to select elements according to application-specific requirements.
+
+For example, to filter `a` elements to only return links to __external__ resources:
+
+    Ext.DomQuery.pseudos.external = function(c, v){
+        var r = [], ri = -1;
+        for(var i = 0, ci; ci = c[i]; i++){
+            // Include in result set only if it's a link to an external resource
+            if(ci.hostname != location.hostname){
+                r[++ri] = ci;
+            }
         }
-    }
-    return r;
-};
- * Then external links could be gathered with the following statement:
-var externalLinks = Ext.select("a:external");
-
- */ + return r; + }; + +Then external links could be gathered with the following statement: + + var externalLinks = Ext.select("a:external"); + + * @markdown + */ pseudos : { - "first-child" : function(c){ + "first-child" : function(c){ var r = [], ri = -1, n; for(var i = 0, ci; ci = n = c[i]; i++){ - while((n = n.previousSibling) && n.nodeType != 1); + while((n = n.previousSibling) && n.nodeType != 1); if(!n){ r[++ri] = ci; } @@ -751,10 +824,10 @@ var externalLinks = Ext.select("a:external"); return r; }, - "last-child" : function(c){ + "last-child" : function(c){ var r = [], ri = -1, n; for(var i = 0, ci; ci = n = c[i]; i++){ - while((n = n.nextSibling) && n.nodeType != 1); + while((n = n.nextSibling) && n.nodeType != 1); if(!n){ r[++ri] = ci; } @@ -762,10 +835,10 @@ var externalLinks = Ext.select("a:external"); return r; }, - "nth-child" : function(c, a) { + "nth-child" : function(c, a) { var r = [], ri = -1, - m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a), - f = (m[1] || 1) - 0, l = m[2] - 0; + m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a), + f = (m[1] || 1) - 0, l = m[2] - 0; for(var i = 0, n; n = c[i]; i++){ var pn = n.parentNode; if (batch != pn._batch) { @@ -789,17 +862,17 @@ var externalLinks = Ext.select("a:external"); return r; }, - "only-child" : function(c){ + "only-child" : function(c){ var r = [], ri = -1;; for(var i = 0, ci; ci = c[i]; i++){ - if(!prev(ci) && !next(ci)){ + if(!prev(ci) && !next(ci)){ r[++ri] = ci; } } return r; }, - "empty" : function(c){ + "empty" : function(c){ var r = [], ri = -1; for(var i = 0, ci; ci = c[i]; i++){ var cns = ci.childNodes, j = 0, cn, empty = true; @@ -817,7 +890,7 @@ var externalLinks = Ext.select("a:external"); return r; }, - "contains" : function(c, v){ + "contains" : function(c, v){ var r = [], ri = -1; for(var i = 0, ci; ci = c[i]; i++){ if((ci.textContent||ci.innerText||'').indexOf(v) != -1){ @@ -827,17 +900,17 @@ var externalLinks = Ext.select("a:external"); return r; }, - "nodeValue" : function(c, v){ + "nodeValue" : function(c, v){ var r = [], ri = -1; for(var i = 0, ci; ci = c[i]; i++){ - if(ci.firstChild && ci.firstChild.nodeValue == v){ + if(ci.firstChild && ci.firstChild.nodeValue == v){ r[++ri] = ci; } } return r; }, - "checked" : function(c){ + "checked" : function(c){ var r = [], ri = -1; for(var i = 0, ci; ci = c[i]; i++){ if(ci.checked == true){ @@ -847,13 +920,13 @@ var externalLinks = Ext.select("a:external"); return r; }, - "not" : function(c, ss){ + "not" : function(c, ss){ return Ext.DomQuery.filter(c, ss, true); }, - "any" : function(c, selectors){ + "any" : function(c, selectors){ var ss = selectors.split('|'), - r = [], ri = -1, s; + r = [], ri = -1, s; for(var i = 0, ci; ci = c[i]; i++){ for(var j = 0; s = ss[j]; j++){ if(Ext.DomQuery.is(ci, s)){ @@ -865,55 +938,55 @@ var externalLinks = Ext.select("a:external"); return r; }, - "odd" : function(c){ - return this["nth-child"](c, "odd"); + "odd" : function(c){ + return this["nth-child"](c, "odd"); }, - "even" : function(c){ - return this["nth-child"](c, "even"); + "even" : function(c){ + return this["nth-child"](c, "even"); }, - "nth" : function(c, a){ + "nth" : function(c, a){ return c[a-1] || []; }, - "first" : function(c){ + "first" : function(c){ return c[0] || []; }, - "last" : function(c){ + "last" : function(c){ return c[c.length-1] || []; }, - "has" : function(c, ss){ + "has" : function(c, ss){ var s = Ext.DomQuery.select, - r = [], ri = -1; + r = [], ri = -1; for(var i = 0, ci; ci = c[i]; i++){ - if(s(ss, ci).length > 0){ + if(s(ss, ci).length > 0){ r[++ri] = ci; } } return r; }, - "next" : function(c, ss){ + "next" : function(c, ss){ var is = Ext.DomQuery.is, - r = [], ri = -1; + r = [], ri = -1; for(var i = 0, ci; ci = c[i]; i++){ var n = next(ci); - if(n && is(n, ss)){ + if(n && is(n, ss)){ r[++ri] = ci; } } return r; }, - "prev" : function(c, ss){ + "prev" : function(c, ss){ var is = Ext.DomQuery.is, - r = [], ri = -1; + r = [], ri = -1; for(var i = 0, ci; ci = c[i]; i++){ var n = prev(ci); - if(n && is(n, ss)){ + if(n && is(n, ss)){ r[++ri] = ci; } } @@ -923,15 +996,13 @@ var externalLinks = Ext.select("a:external"); }; }(); -
/** - * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Ext.DomQuery#select} - * @param {String} path The selector/xpath query - * @param {Node} root (optional) The start of the query (defaults to document). - * @return {Array} +/** + * Shorthand of {@link Ext.DomQuery#select} * @member Ext * @method query + * @alias Ext.DomQuery#select */ Ext.query = Ext.DomQuery.select; -
+
- \ No newline at end of file +