<html>\r
<head>\r
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> \r
<title>The source code</title>\r
<link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
<script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
<li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>\r
<li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>\r
<li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>\r
+ <li> <b>E:any(S1|S2|S2)</b> an E element which matches any of the simple selectors S1, S2 or S3//\\</li>\r
</ul>\r
<h4>CSS Value Selectors:</h4>\r
<ul class="list">\r
nthRe = /(\d*)n\+?(\d*)/, \r
nthRe2 = /\D/,\r
// This is for IE MSXML which does not support expandos.\r
- // IE runs the same speed using setAttribute, however FF slows way down\r
- // and Safari completely fails so they need to continue to use expandos.\r
- isIE = window.ActiveXObject ? true : false,\r
- isOpera = Ext.isOpera,\r
- key = 30803;\r
- \r
+ // IE runs the same speed using setAttribute, however FF slows way down\r
+ // and Safari completely fails so they need to continue to use expandos.\r
+ isIE = window.ActiveXObject ? true : false,\r
+ key = 30803;\r
+ \r
// this eval is stop the compressor from\r
- // renaming the variable to something shorter\r
- eval("var batch = 30803;"); \r
+ // renaming the variable to something shorter\r
+ eval("var batch = 30803;"); \r
\r
- function child(p, index){\r
+ // Retrieve the child node from a particular\r
+ // parent at the specified index.\r
+ function child(parent, index){\r
var i = 0,\r
- n = p.firstChild;\r
+ n = parent.firstChild;\r
while(n){\r
if(n.nodeType == 1){\r
if(++i == index){\r
n = n.nextSibling;\r
}\r
return null;\r
- };\r
+ }\r
\r
- function next(n){\r
+ // retrieve the next element node\r
+ function next(n){ \r
while((n = n.nextSibling) && n.nodeType != 1);\r
return n;\r
- };\r
+ }\r
\r
+ // retrieve the previous element node \r
function prev(n){\r
while((n = n.previousSibling) && n.nodeType != 1);\r
return n;\r
- };\r
+ }\r
+\r
+ // Mark each child node with a nodeIndex skipping and\r
+ // removing empty text nodes.\r
+ function children(parent){\r
+ var n = parent.firstChild,\r
+ nodeIndex = -1,\r
+ nextNode;\r
+ while(n){\r
+ nextNode = n.nextSibling;\r
+ // clean worthless empty nodes.\r
+ if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){\r
+ parent.removeChild(n);\r
+ }else{\r
+ // add an expando nodeIndex\r
+ n.nodeIndex = ++nodeIndex;\r
+ }\r
+ n = nextNode;\r
+ }\r
+ return this;\r
+ }\r
\r
- function children(d){\r
- var n = d.firstChild, ni = -1,\r
- nx;\r
- while(n){\r
- nx = n.nextSibling;\r
- if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){\r
- d.removeChild(n);\r
- }else{\r
- n.nodeIndex = ++ni;\r
- }\r
- n = nx;\r
- }\r
- return this;\r
- };\r
-\r
- function byClassName(c, a, v){\r
- if(!v){\r
- return c;\r
- }\r
- var r = [], ri = -1, cn;\r
- for(var i = 0, ci; ci = c[i]; i++){\r
- if((' '+ci.className+' ').indexOf(v) != -1){\r
- r[++ri] = ci;\r
+\r
+ // nodeSet - array of nodes\r
+ // cls - CSS Class\r
+ function byClassName(nodeSet, cls){\r
+ if(!cls){\r
+ return nodeSet;\r
+ }\r
+ var result = [], ri = -1;\r
+ for(var i = 0, ci; ci = nodeSet[i]; i++){\r
+ if((' '+ci.className+' ').indexOf(cls) != -1){\r
+ result[++ri] = ci;\r
}\r
}\r
- return r;\r
+ return result;\r
};\r
\r
function attrValue(n, attr){\r
+ // if its an array, use the first node.\r
if(!n.tagName && typeof n.length != "undefined"){\r
n = n[0];\r
}\r
if(!n){\r
return null;\r
}\r
+\r
if(attr == "for"){\r
return n.htmlFor;\r
}\r
\r
};\r
\r
+\r
+ // ns - nodes\r
+ // mode - false, /, >, +, ~\r
+ // tagName - defaults to "*"\r
function getNodes(ns, mode, tagName){\r
var result = [], ri = -1, cs;\r
if(!ns){\r
return result;\r
}\r
tagName = tagName || "*";\r
+ // convert to array\r
if(typeof ns.getElementsByTagName != "undefined"){\r
ns = [ns];\r
}\r
+ \r
+ // no mode specified, grab all elements by tagName\r
+ // at any depth\r
if(!mode){\r
for(var i = 0, ni; ni = ns[i]; i++){\r
cs = ni.getElementsByTagName(tagName);\r
result[++ri] = ci;\r
}\r
}\r
- }else if(mode == "/" || mode == ">"){\r
+ // Direct Child mode (/ or >)\r
+ // E > F or E/F all direct children elements of E that have the tag \r
+ } else if(mode == "/" || mode == ">"){\r
var utag = tagName.toUpperCase();\r
for(var i = 0, ni, cn; ni = ns[i]; i++){\r
- cn = isOpera ? ni.childNodes : (ni.children || ni.childNodes);\r
+ cn = ni.childNodes;\r
for(var j = 0, cj; cj = cn[j]; j++){\r
if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){\r
result[++ri] = cj;\r
}\r
}\r
}\r
+ // Immediately Preceding mode (+)\r
+ // E + F all elements with the tag F that are immediately preceded by an element with the tag E\r
}else if(mode == "+"){\r
var utag = tagName.toUpperCase();\r
for(var i = 0, n; n = ns[i]; i++){\r
result[++ri] = n;\r
}\r
}\r
+ // Sibling mode (~)\r
+ // E ~ F all elements with the tag F that are preceded by a sibling element with the tag E\r
}else if(mode == "~"){\r
var utag = tagName.toUpperCase();\r
for(var i = 0, n; n = ns[i]; i++){\r
}\r
}\r
return result;\r
- };\r
+ }\r
\r
function concat(a, b){\r
if(b.slice){\r
if(!tagName){\r
return cs;\r
}\r
- var r = [], ri = -1;\r
+ var result = [], ri = -1;\r
tagName = tagName.toLowerCase();\r
for(var i = 0, ci; ci = cs[i]; i++){\r
- if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){\r
- r[++ri] = ci;\r
+ if(ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName){\r
+ result[++ri] = ci;\r
}\r
}\r
- return r;\r
- };\r
+ return result;\r
+ }\r
\r
- function byId(cs, attr, id){\r
+ function byId(cs, id){\r
if(cs.tagName || cs == document){\r
cs = [cs];\r
}\r
if(!id){\r
return cs;\r
}\r
- var r = [], ri = -1;\r
- for(var i = 0,ci; ci = cs[i]; i++){\r
+ var result = [], ri = -1;\r
+ for(var i = 0, ci; ci = cs[i]; i++){\r
if(ci && ci.id == id){\r
- r[++ri] = ci;\r
- return r;\r
+ result[++ri] = ci;\r
+ return result;\r
}\r
}\r
- return r;\r
- };\r
+ return result;\r
+ }\r
\r
+ // operators are =, !=, ^=, $=, *=, %=, |= and ~=\r
+ // custom can be "{"\r
function byAttribute(cs, attr, value, op, custom){\r
- var r = [], \r
- ri = -1, \r
- st = custom=="{",\r
- f = Ext.DomQuery.operators[op];\r
+ var result = [], \r
+ ri = -1, \r
+ useGetStyle = custom == "{", \r
+ fn = Ext.DomQuery.operators[op], \r
+ a, \r
+ innerHTML;\r
for(var i = 0, ci; ci = cs[i]; i++){\r
+ // skip non-element nodes.\r
if(ci.nodeType != 1){\r
continue;\r
}\r
- var a;\r
- if(st){\r
- a = Ext.DomQuery.getStyle(ci, attr);\r
- }\r
- else if(attr == "class" || attr == "className"){\r
- a = ci.className;\r
- }else if(attr == "for"){\r
- a = ci.htmlFor;\r
- }else if(attr == "href"){\r
- a = ci.getAttribute("href", 2);\r
+ \r
+ innerHTML = ci.innerHTML;\r
+ // we only need to change the property names if we're dealing with html nodes, not XML\r
+ if(innerHTML !== null && innerHTML !== undefined){\r
+ if(useGetStyle){\r
+ a = Ext.DomQuery.getStyle(ci, attr);\r
+ } else if (attr == "class" || attr == "className"){\r
+ a = ci.className;\r
+ } else if (attr == "for"){\r
+ a = ci.htmlFor;\r
+ } else if (attr == "href"){\r
+ // getAttribute href bug\r
+ // http://www.glennjones.net/Post/809/getAttributehrefbug.htm\r
+ a = ci.getAttribute("href", 2);\r
+ } else{\r
+ a = ci.getAttribute(attr);\r
+ }\r
}else{\r
a = ci.getAttribute(attr);\r
}\r
- if((f && f(a, value)) || (!f && a)){\r
- r[++ri] = ci;\r
+ if((fn && fn(a, value)) || (!fn && a)){\r
+ result[++ri] = ci;\r
}\r
}\r
- return r;\r
- };\r
+ return result;\r
+ }\r
\r
function byPseudo(cs, name, value){\r
return Ext.DomQuery.pseudos[name](cs, value);\r
- };\r
+ }\r
\r
function nodupIEXml(cs){\r
var d = ++key, \r
- r;\r
+ r;\r
cs[0].setAttribute("_nodup", d);\r
r = [cs[0]];\r
for(var i = 1, len = cs.length; i < len; i++){\r
\r
function quickDiffIEXml(c1, c2){\r
var d = ++key,\r
- r = [];\r
+ r = [];\r
for(var i = 0, len = c1.length; i < len; i++){\r
c1[i].setAttribute("_qdiff", d);\r
} \r
if(!len1){\r
return c2;\r
}\r
- if(isIE && c1[0].selectSingleNode){\r
+ if(isIE && typeof c1[0].selectSingleNode != "undefined"){\r
return quickDiffIEXml(c1, c2);\r
} \r
for(var i = 0; i < len1; i++){\r
return d.getElementById(id);\r
}\r
ns = getNodes(ns, mode, "*");\r
- return byId(ns, null, id);\r
+ return byId(ns, id);\r
}\r
\r
return {\r
compile : function(path, type){\r
type = type || "select";\r
\r
+ // setup fn preamble\r
var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"],\r
- q = path, mode, lq,\r
- tk = Ext.DomQuery.matchers,\r
- tklen = tk.length,\r
- mm,\r
+ mode, \r
+ lastPath,\r
+ matchers = Ext.DomQuery.matchers,\r
+ matchersLn = matchers.length,\r
+ modeMatch,\r
// accept leading mode switch\r
- lmode = q.match(modeRe);\r
+ lmode = path.match(modeRe);\r
\r
if(lmode && lmode[1]){\r
fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';\r
- q = q.replace(lmode[1], "");\r
+ path = path.replace(lmode[1], "");\r
}\r
+ \r
// strip leading slashes\r
while(path.substr(0, 1)=="/"){\r
path = path.substr(1);\r
}\r
\r
- while(q && lq != q){\r
- lq = q;\r
- var tm = q.match(tagTokenRe);\r
+ while(path && lastPath != path){\r
+ lastPath = path;\r
+ var tokenMatch = path.match(tagTokenRe);\r
if(type == "select"){\r
- if(tm){\r
- if(tm[1] == "#"){\r
- fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';\r
+ if(tokenMatch){\r
+ // ID Selector\r
+ if(tokenMatch[1] == "#"){\r
+ fn[fn.length] = 'n = quickId(n, mode, root, "'+tokenMatch[2]+'");'; \r
}else{\r
- fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';\r
+ fn[fn.length] = 'n = getNodes(n, mode, "'+tokenMatch[2]+'");';\r
}\r
- q = q.replace(tm[0], "");\r
- }else if(q.substr(0, 1) != '@'){\r
+ path = path.replace(tokenMatch[0], "");\r
+ }else if(path.substr(0, 1) != '@'){\r
fn[fn.length] = 'n = getNodes(n, mode, "*");';\r
}\r
+ // type of "simple"\r
}else{\r
- if(tm){\r
- if(tm[1] == "#"){\r
- fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';\r
+ if(tokenMatch){\r
+ if(tokenMatch[1] == "#"){\r
+ fn[fn.length] = 'n = byId(n, "'+tokenMatch[2]+'");';\r
}else{\r
- fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';\r
+ fn[fn.length] = 'n = byTag(n, "'+tokenMatch[2]+'");';\r
}\r
- q = q.replace(tm[0], "");\r
+ path = path.replace(tokenMatch[0], "");\r
}\r
}\r
- while(!(mm = q.match(modeRe))){\r
+ while(!(modeMatch = path.match(modeRe))){\r
var matched = false;\r
- for(var j = 0; j < tklen; j++){\r
- var t = tk[j];\r
- var m = q.match(t.re);\r
+ for(var j = 0; j < matchersLn; j++){\r
+ var t = matchers[j];\r
+ var m = path.match(t.re);\r
if(m){\r
fn[fn.length] = t.select.replace(tplRe, function(x, i){\r
- return m[i];\r
- });\r
- q = q.replace(m[0], "");\r
+ return m[i];\r
+ });\r
+ path = path.replace(m[0], "");\r
matched = true;\r
break;\r
}\r
}\r
// prevent infinite loop on bad selector\r
if(!matched){\r
- throw 'Error parsing selector, parsing failed at "' + q + '"';\r
+ throw 'Error parsing selector, parsing failed at "' + path + '"';\r
}\r
}\r
- if(mm[1]){\r
- fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';\r
- q = q.replace(mm[1], "");\r
+ if(modeMatch[1]){\r
+ fn[fn.length] = 'mode="'+modeMatch[1].replace(trimRe, "")+'";';\r
+ path = path.replace(modeMatch[1], "");\r
}\r
}\r
+ // close fn out\r
fn[fn.length] = "return nodup(n);\n}";\r
+ \r
+ // eval fn and return it\r
eval(fn.join(""));\r
return f;\r
},\r
\r
- <div id="method-Ext.DomQuery-select"></div>/**\r
+ <div id="method-Ext.DomQuery-jsSelect"></div>/**\r
* Selects a group of elements.\r
* @param {String} selector The selector/xpath query (can be a comma separated list of selectors)\r
- * @param {Node} root (optional) The start of the query (defaults to document).\r
+ * @param {Node/String} root (optional) The start of the query (defaults to document).\r
* @return {Array} An Array of DOM elements which match the selector. If there are\r
* no matches, and empty Array is returned.\r
*/\r
- select : function(path, root, type){\r
- if(!root || root == document){\r
- root = document;\r
- }\r
+ jsSelect: function(path, root, type){\r
+ // set root to doc if not specified.\r
+ root = root || document;\r
+ \r
if(typeof root == "string"){\r
root = document.getElementById(root);\r
}\r
var paths = path.split(","),\r
results = [];\r
- for(var i = 0, len = paths.length; i < len; i++){\r
- var p = paths[i].replace(trimRe, "");\r
- if(!cache[p]){\r
- cache[p] = Ext.DomQuery.compile(p);\r
- if(!cache[p]){\r
- throw p + " is not a valid selector";\r
+ \r
+ // loop over each selector\r
+ for(var i = 0, len = paths.length; i < len; i++){ \r
+ var subPath = paths[i].replace(trimRe, "");\r
+ // compile and place in cache\r
+ if(!cache[subPath]){\r
+ cache[subPath] = Ext.DomQuery.compile(subPath);\r
+ if(!cache[subPath]){\r
+ throw subPath + " is not a valid selector";\r
}\r
}\r
- var result = cache[p](root);\r
+ var result = cache[subPath](root);\r
if(result && result != document){\r
results = results.concat(result);\r
}\r
}\r
+ \r
+ // if there were multiple selectors, make sure dups\r
+ // are eliminated\r
if(paths.length > 1){\r
return nodup(results);\r
}\r
return results;\r
},\r
+ isXml: function(el) {\r
+ var docEl = (el ? el.ownerDocument || el : 0).documentElement;\r
+ return docEl ? docEl.nodeName !== "HTML" : false;\r
+ },\r
+ select : document.querySelectorAll ? function(path, root, type) {\r
+ root = root || document;\r
+ if (!Ext.DomQuery.isXml(root)) {\r
+ try {\r
+ var cs = root.querySelectorAll(path);\r
+ return Ext.toArray(cs);\r
+ }\r
+ catch (ex) {} \r
+ } \r
+ return Ext.DomQuery.jsSelect.call(this, path, root, type);\r
+ } : function(path, root, type) {\r
+ return Ext.DomQuery.jsSelect.call(this, path, root, type);\r
+ },\r
\r
<div id="method-Ext.DomQuery-selectNode"></div>/**\r
* Selects a single element.\r
if(!valueCache[path]){\r
valueCache[path] = Ext.DomQuery.compile(path, "select");\r
}\r
- var n = valueCache[path](root),\r
- v;\r
+ var n = valueCache[path](root), v;\r
n = n[0] ? n[0] : n;\r
+ \r
+ // overcome a limitation of maximum textnode size\r
+ // Rumored to potentially crash IE6 but has not been confirmed.\r
+ // http://reference.sitepoint.com/javascript/Node/normalize\r
+ // https://developer.mozilla.org/En/DOM/Node.normalize \r
+ if (typeof n.normalize == 'function') n.normalize();\r
+ \r
v = (n && n.firstChild ? n.firstChild.nodeValue : null);\r
return ((v === null||v === undefined||v==='') ? defaultValue : v);\r
},\r
\r
<div id="prop-Ext.DomQuery-matchers"></div>/**\r
* Collection of matching regular expressions and code snippets.\r
+ * Each capture group within () will be replace the {} in the select\r
+ * statement as specified by their index.\r
*/\r
matchers : [{\r
re: /^\.([\w-]+)/,\r
- select: 'n = byClassName(n, null, " {1} ");'\r
+ select: 'n = byClassName(n, " {1} ");'\r
}, {\r
re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,\r
select: 'n = byPseudo(n, "{1}", "{2}");'\r
select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'\r
}, {\r
re: /^#([\w-]+)/,\r
- select: 'n = byId(n, null, "{1}");'\r
+ select: 'n = byId(n, "{1}");'\r
},{\r
re: /^@([\w-]+)/,\r
select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'\r
},\r
\r
<div id="prop-Ext.DomQuery-pseudos"></div>/**\r
- * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)\r
- * and the argument (if any) supplied in the selector.\r
+ * <p>Object hash of "pseudo class" filter functions which are used when filtering selections. Each function is passed\r
+ * two parameters:</p><div class="mdetail-params"><ul>\r
+ * <li><b>c</b> : Array<div class="sub-desc">An Array of DOM elements to filter.</div></li>\r
+ * <li><b>v</b> : String<div class="sub-desc">The argument (if any) supplied in the selector.</div></li>\r
+ * </ul></div>\r
+ * <p>A filter function returns an Array of DOM elements which conform to the pseudo class.</p>\r
+ * <p>In addition to the provided pseudo classes listed above such as <code>first-child</code> and <code>nth-child</code>,\r
+ * developers may add additional, custom psuedo class filters to select elements according to application-specific requirements.</p>\r
+ * <p>For example, to filter <code><a></code> elements to only return links to <i>external</i> resources:</p>\r
+ * <code><pre>\r
+Ext.DomQuery.pseudos.external = function(c, v){\r
+ var r = [], ri = -1;\r
+ for(var i = 0, ci; ci = c[i]; i++){\r
+// Include in result set only if it's a link to an external resource\r
+ if(ci.hostname != location.hostname){\r
+ r[++ri] = ci;\r
+ }\r
+ }\r
+ return r;\r
+};</pre></code>\r
+ * Then external links could be gathered with the following statement:<code><pre>\r
+var externalLinks = Ext.select("a:external");\r
+</code></pre>\r
*/\r
pseudos : {\r
"first-child" : function(c){\r