]> git.pond.sub.org Git - eow/blobdiff - static/dojo-release-1.1.1/dojo/_base/query.js
Replace Dojo with jQuery
[eow] / static / dojo-release-1.1.1 / dojo / _base / query.js
diff --git a/static/dojo-release-1.1.1/dojo/_base/query.js b/static/dojo-release-1.1.1/dojo/_base/query.js
deleted file mode 100644 (file)
index 8743df8..0000000
+++ /dev/null
@@ -1,1191 +0,0 @@
-if(!dojo._hasResource["dojo._base.query"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.query"] = true;
-dojo.provide("dojo._base.query");
-dojo.require("dojo._base.NodeList");
-
-/*
-       dojo.query() architectural overview:
-
-               dojo.query is a relatively full-featured CSS3 query library. It is
-               designed to take any valid CSS3 selector and return the nodes matching
-               the selector. To do this quickly, it processes queries in several
-               steps, applying caching where profitable.
-               
-               The steps (roughly in reverse order of the way they appear in the code):
-                       1.) check to see if we already have a "query dispatcher"
-                               - if so, use that with the given parameterization. Skip to step 4.
-                       2.) attempt to determine which branch to dispatch the query to:
-                               - JS (optimized DOM iteration)
-                               - xpath (for browsers that support it and where it's fast)
-                               - native (not available in any browser yet)
-                       3.) tokenize and convert to executable "query dispatcher"
-                               - this is where the lion's share of the complexity in the
-                                 system lies. In the DOM version, the query dispatcher is
-                                 assembled as a chain of "yes/no" test functions pertaining to
-                                 a section of a simple query statement (".blah:nth-child(odd)"
-                                 but not "div div", which is 2 simple statements). Individual
-                                 statement dispatchers are cached (to prevent re-definition)
-                                 as are entire dispatch chains (to make re-execution of the
-                                 same query fast)
-                               - in the xpath path, tokenization yeilds a concatenation of
-                                 parameterized xpath selectors. As with the DOM version, both
-                                 simple selector blocks and overall evaluators are cached to
-                                 prevent re-defintion
-                       4.) the resulting query dispatcher is called in the passed scope (by default the top-level document)
-                               - for DOM queries, this results in a recursive, top-down
-                                 evaluation of nodes based on each simple query section
-                               - xpath queries can, thankfully, be executed in one shot
-                       5.) matched nodes are pruned to ensure they are unique
-*/
-
-;(function(){
-       // define everything in a closure for compressability reasons. "d" is an
-       // alias to "dojo" since it's so frequently used. This seems a
-       // transformation that the build system could perform on a per-file basis.
-
-       ////////////////////////////////////////////////////////////////////////
-       // Utility code
-       ////////////////////////////////////////////////////////////////////////
-
-       var d = dojo;
-       var childNodesName = dojo.isIE ? "children" : "childNodes";
-       var caseSensitive = false;
-
-       var getQueryParts = function(query){
-               // summary: state machine for query tokenization
-               if(">~+".indexOf(query.charAt(query.length-1)) >= 0){
-                       query += " *"
-               }
-               query += " "; // ensure that we terminate the state machine
-
-               var ts = function(s, e){
-                       return d.trim(query.slice(s, e));
-               }
-
-               // the overall data graph of the full query, as represented by queryPart objects
-               var qparts = []; 
-               // state keeping vars
-               var inBrackets = -1;
-               var inParens = -1;
-               var inMatchFor = -1;
-               var inPseudo = -1;
-               var inClass = -1;
-               var inId = -1;
-               var inTag = -1;
-               var lc = ""; // the last character
-               var cc = ""; // the current character
-               var pStart;
-               // iteration vars
-               var x = 0; // index in the query
-               var ql = query.length;
-               var currentPart = null; // data structure representing the entire clause
-               var _cp = null; // the current pseudo or attr matcher
-
-               var endTag = function(){
-                       if(inTag >= 0){
-                               var tv = (inTag == x) ? null : ts(inTag, x).toLowerCase();
-                               currentPart[ (">~+".indexOf(tv) < 0) ? "tag" : "oper" ] = tv;
-                               inTag = -1;
-                       }
-               }
-
-               var endId = function(){
-                       if(inId >= 0){
-                               currentPart.id = ts(inId, x).replace(/\\/g, "");
-                               inId = -1;
-                       }
-               }
-
-               var endClass = function(){
-                       if(inClass >= 0){
-                               currentPart.classes.push(ts(inClass+1, x).replace(/\\/g, ""));
-                               inClass = -1;
-                       }
-               }
-
-               var endAll = function(){
-                       endId(); endTag(); endClass();
-               }
-
-               for(; lc=cc, cc=query.charAt(x),x<ql; x++){
-                       if(lc == "\\"){ continue; }
-                       if(!currentPart){
-                               // NOTE: I hate all this alloc, but it's shorter than writing tons of if's
-                               pStart = x;
-                               currentPart = {
-                                       query: null,
-                                       pseudos: [],
-                                       attrs: [],
-                                       classes: [],
-                                       tag: null,
-                                       oper: null,
-                                       id: null
-                               };
-                               inTag = x;
-                       }
-
-                       if(inBrackets >= 0){
-                               // look for a the close first
-                               if(cc == "]"){
-                                       if(!_cp.attr){
-                                               _cp.attr = ts(inBrackets+1, x);
-                                       }else{
-                                               _cp.matchFor = ts((inMatchFor||inBrackets+1), x);
-                                       }
-                                       var cmf = _cp.matchFor;
-                                       if(cmf){
-                                               if(     (cmf.charAt(0) == '"') || (cmf.charAt(0)  == "'") ){
-                                                       _cp.matchFor = cmf.substring(1, cmf.length-1);
-                                               }
-                                       }
-                                       currentPart.attrs.push(_cp);
-                                       _cp = null; // necessaray?
-                                       inBrackets = inMatchFor = -1;
-                               }else if(cc == "="){
-                                       var addToCc = ("|~^$*".indexOf(lc) >=0 ) ? lc : "";
-                                       _cp.type = addToCc+cc;
-                                       _cp.attr = ts(inBrackets+1, x-addToCc.length);
-                                       inMatchFor = x+1;
-                               }
-                               // now look for other clause parts
-                       }else if(inParens >= 0){
-                               if(cc == ")"){
-                                       if(inPseudo >= 0){
-                                               _cp.value = ts(inParens+1, x);
-                                       }
-                                       inPseudo = inParens = -1;
-                               }
-                       }else if(cc == "#"){
-                               endAll();
-                               inId = x+1;
-                       }else if(cc == "."){
-                               endAll();
-                               inClass = x;
-                       }else if(cc == ":"){
-                               endAll();
-                               inPseudo = x;
-                       }else if(cc == "["){
-                               endAll();
-                               inBrackets = x;
-                               _cp = {
-                                       /*=====
-                                       attr: null, type: null, matchFor: null
-                                       =====*/
-                               };
-                       }else if(cc == "("){
-                               if(inPseudo >= 0){
-                                       _cp = { 
-                                               name: ts(inPseudo+1, x), 
-                                               value: null
-                                       }
-                                       currentPart.pseudos.push(_cp);
-                               }
-                               inParens = x;
-                       }else if(cc == " " && lc != cc){
-                               // note that we expect the string to be " " terminated
-                               endAll();
-                               if(inPseudo >= 0){
-                                       currentPart.pseudos.push({ name: ts(inPseudo+1, x) });
-                               }
-                               currentPart.hasLoops = (        
-                                               currentPart.pseudos.length || 
-                                               currentPart.attrs.length || 
-                                               currentPart.classes.length      );
-                               currentPart.query = ts(pStart, x);
-                               currentPart.tag = (currentPart["oper"]) ? null : (currentPart.tag || "*");
-                               qparts.push(currentPart);
-                               currentPart = null;
-                       }
-               }
-               return qparts;
-       };
-       
-
-       ////////////////////////////////////////////////////////////////////////
-       // XPath query code
-       ////////////////////////////////////////////////////////////////////////
-
-       // this array is a lookup used to generate an attribute matching function.
-       // There is a similar lookup/generator list for the DOM branch with similar
-       // calling semantics.
-       var xPathAttrs = {
-               "*=": function(attr, value){
-                       return "[contains(@"+attr+", '"+ value +"')]";
-               },
-               "^=": function(attr, value){
-                       return "[starts-with(@"+attr+", '"+ value +"')]";
-               },
-               "$=": function(attr, value){
-                       return "[substring(@"+attr+", string-length(@"+attr+")-"+(value.length-1)+")='"+value+"']";
-               },
-               "~=": function(attr, value){
-                       return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
-               },
-               "|=": function(attr, value){
-                       return "[contains(concat(' ',@"+attr+",' '), ' "+ value +"-')]";
-               },
-               "=": function(attr, value){
-                       return "[@"+attr+"='"+ value +"']";
-               }
-       };
-
-       // takes a list of attribute searches, the overall query, a function to
-       // generate a default matcher, and a closure-bound method for providing a
-       // matching function that generates whatever type of yes/no distinguisher
-       // the query method needs. The method is a bit tortured and hard to read
-       // because it needs to be used in both the XPath and DOM branches.
-       var handleAttrs = function(     attrList, 
-                                                               query, 
-                                                               getDefault, 
-                                                               handleMatch){
-               d.forEach(query.attrs, function(attr){
-                       var matcher;
-                       // type, attr, matchFor
-                       if(attr.type && attrList[attr.type]){
-                               matcher = attrList[attr.type](attr.attr, attr.matchFor);
-                       }else if(attr.attr.length){
-                               matcher = getDefault(attr.attr);
-                       }
-                       if(matcher){ handleMatch(matcher); }
-               });
-       }
-
-       var buildPath = function(query){
-               var xpath = ".";
-               var qparts = getQueryParts(d.trim(query));
-               while(qparts.length){
-                       var tqp = qparts.shift();
-                       var prefix;
-                       var postfix = "";
-                       if(tqp.oper == ">"){
-                               prefix = "/";
-                               // prefix = "/child::*";
-                               tqp = qparts.shift();
-                       }else if(tqp.oper == "~"){
-                               prefix = "/following-sibling::"; // get element following siblings
-                               tqp = qparts.shift();
-                       }else if(tqp.oper == "+"){
-                               // FIXME: 
-                               //              fails when selecting subsequent siblings by node type
-                               //              because the position() checks the position in the list
-                               //              of matching elements and not the localized siblings
-                               prefix = "/following-sibling::";
-                               postfix = "[position()=1]";
-                               tqp = qparts.shift();
-                       }else{
-                               prefix = "//";
-                               // prefix = "/descendant::*"
-                       }
-
-                       // get the tag name (if any)
-
-                       xpath += prefix + tqp.tag + postfix;
-                       
-                       // check to see if it's got an id. Needs to come first in xpath.
-                       if(tqp.id){
-                               xpath += "[@id='"+tqp.id+"'][1]";
-                       }
-
-                       d.forEach(tqp.classes, function(cn){
-                               var cnl = cn.length;
-                               var padding = " ";
-                               if(cn.charAt(cnl-1) == "*"){
-                                       padding = ""; cn = cn.substr(0, cnl-1);
-                               }
-                               xpath += 
-                                       "[contains(concat(' ',@class,' '), ' "+
-                                       cn + padding + "')]";
-                       });
-
-                       handleAttrs(xPathAttrs, tqp, 
-                               function(condition){
-                                               return "[@"+condition+"]";
-                               },
-                               function(matcher){
-                                       xpath += matcher;
-                               }
-                       );
-
-                       // FIXME: need to implement pseudo-class checks!!
-               };
-               return xpath;
-       };
-
-       var _xpathFuncCache = {};
-       var getXPathFunc = function(path){
-               if(_xpathFuncCache[path]){
-                       return _xpathFuncCache[path];
-               }
-
-               var doc = d.doc;
-               // don't need to memoize. The closure scope handles it for us.
-               var xpath = buildPath(path);
-
-               var tf = function(parent){
-                       // XPath query strings are memoized.
-                       var ret = [];
-                       var xpathResult;
-                       try{
-                               xpathResult = doc.evaluate(xpath, parent, null, 
-                                                                                               // XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
-                                                                                               XPathResult.ANY_TYPE, null);
-                       }catch(e){
-                               console.debug("failure in exprssion:", xpath, "under:", parent);
-                               console.debug(e);
-                       }
-                       var result = xpathResult.iterateNext();
-                       while(result){
-                               ret.push(result);
-                               result = xpathResult.iterateNext();
-                       }
-                       return ret;
-               }
-               return _xpathFuncCache[path] = tf;
-       };
-
-       /*
-       d.xPathMatch = function(query){
-               // XPath based DOM query system. Handles a small subset of CSS
-               // selectors, subset is identical to the non-XPath version of this
-               // function. 
-
-               return getXPathFunc(query)();
-       }
-       */
-
-       ////////////////////////////////////////////////////////////////////////
-       // DOM query code
-       ////////////////////////////////////////////////////////////////////////
-
-       var _filtersCache = {};
-       var _simpleFiltersCache = {};
-
-       // the basic building block of the yes/no chaining system. agree(f1, f2)
-       // generates a new function which returns the boolean results of both of
-       // the passed functions to a single logical-anded result.
-       var agree = function(first, second){
-               if(!first){ return second; }
-               if(!second){ return first; }
-
-               return function(){
-                       return first.apply(window, arguments) && second.apply(window, arguments);
-               }
-       }
-
-       var _childElements = function(root){
-               var ret = [];
-               var te, x=0, tret = root[childNodesName];
-               while(te=tret[x++]){
-                       if(te.nodeType == 1){ ret.push(te); }
-               }
-               return ret;
-       }
-
-       var _nextSiblings = function(root, single){
-               var ret = [];
-               var te = root;
-               while(te = te.nextSibling){
-                       if(te.nodeType == 1){
-                               ret.push(te);
-                               if(single){ break; }
-                       }
-               }
-               return ret;
-       }
-
-       var _filterDown = function(element, queryParts, matchArr, idx){
-               // NOTE:
-               //              in the fast path! this function is called recursively and for
-               //              every run of a query.
-               var nidx = idx+1;
-               var isFinal = (queryParts.length == nidx);
-               var tqp = queryParts[idx];
-
-               // see if we can constrain our next level to direct children
-               if(tqp.oper){
-                       var ecn = (tqp.oper == ">") ? 
-                               _childElements(element) :
-                               _nextSiblings(element, (tqp.oper == "+"));
-
-                       if(!ecn || !ecn.length){
-                               return;
-                       }
-                       nidx++;
-                       isFinal = (queryParts.length == nidx);
-                       // kinda janky, too much array alloc
-                       var tf = getFilterFunc(queryParts[idx+1]);
-                       // for(var x=ecn.length-1, te; x>=0, te=ecn[x]; x--){
-                       for(var x=0, ecnl=ecn.length, te; x<ecnl, te=ecn[x]; x++){
-                               if(tf(te)){
-                                       if(isFinal){
-                                               matchArr.push(te);
-                                       }else{
-                                               _filterDown(te, queryParts, matchArr, nidx);
-                                       }
-                               }
-                               /*
-                               if(x==0){
-                                       break;
-                               }
-                               */
-                       }
-               }
-
-               // otherwise, keep going down, unless we'er at the end
-               var candidates = getElementsFunc(tqp)(element);
-               if(isFinal){
-                       while(candidates.length){
-                               matchArr.push(candidates.shift());
-                       }
-                       /*
-                       candidates.unshift(0, matchArr.length-1);
-                       matchArr.splice.apply(matchArr, candidates);
-                       */
-               }else{
-                       // if we're not yet at the bottom, keep going!
-                       while(candidates.length){
-                               _filterDown(candidates.shift(), queryParts, matchArr, nidx);
-                       }
-               }
-       }
-
-       var filterDown = function(elements, queryParts){
-               var ret = [];
-
-               // for every root, get the elements that match the descendant selector
-               // for(var x=elements.length-1, te; x>=0, te=elements[x]; x--){
-               var x = elements.length - 1, te;
-               while(te = elements[x--]){
-                       _filterDown(te, queryParts, ret, 0);
-               }
-               return ret;
-       }
-
-       var getFilterFunc = function(q){
-               // note: query can't have spaces!
-               if(_filtersCache[q.query]){
-                       return _filtersCache[q.query];
-               }
-               var ff = null;
-
-               // does it have a tagName component?
-               if(q.tag){
-                       if(q.tag == "*"){
-                               ff = agree(ff, 
-                                       function(elem){
-                                               return (elem.nodeType == 1);
-                                       }
-                               );
-                       }else{
-                               // tag name match
-                               ff = agree(ff, 
-                                       function(elem){
-                                               return (
-                                                       (elem.nodeType == 1) &&
-                                                       (q.tag == elem.tagName.toLowerCase())
-                                               );
-                                               // return isTn;
-                                       }
-                               );
-                       }
-               }
-
-               // does the node have an ID?
-               if(q.id){
-                       ff = agree(ff, 
-                               function(elem){
-                                       return (
-                                               (elem.nodeType == 1) &&
-                                               (elem.id == q.id)
-                                       );
-                               }
-                       );
-               }
-
-               if(q.hasLoops){
-                       // if we have other query param parts, make sure we add them to the
-                       // filter chain
-                       ff = agree(ff, getSimpleFilterFunc(q));
-               }
-
-               return _filtersCache[q.query] = ff;
-       }
-
-       var getNodeIndex = function(node){
-               // NOTE: 
-               //              we could have a more accurate caching mechanism by invalidating
-               //              caches after the query has finished, but I think that'd lead to
-               //              significantly more cache churn than the cache would provide
-               //              value for in the common case. Generally, we're more
-               //              conservative (and therefore, more accurate) than jQuery and
-               //              DomQuery WRT node node indexes, but there may be corner cases
-               //              in which we fall down.  How much we care about them is TBD.
-
-               var pn = node.parentNode;
-               var pnc = pn.childNodes;
-
-               // check to see if we can trust the cache. If not, re-key the whole
-               // thing and return our node match from that.
-
-               var nidx = -1;
-               var child = pn.firstChild;
-               if(!child){
-                       return nidx;
-               }
-
-               var ci = node["__cachedIndex"];
-               var cl = pn["__cachedLength"];
-
-               // only handle cache building if we've gone out of sync
-               if(((typeof cl == "number")&&(cl != pnc.length))||(typeof ci != "number")){
-                       // rip though the whole set, building cache indexes as we go
-                       pn["__cachedLength"] = pnc.length;
-                       var idx = 1;
-                       do{
-                               // we only assign indexes for nodes with nodeType == 1, as per:
-                               //              http://www.w3.org/TR/css3-selectors/#nth-child-pseudo
-                               // only elements are counted in the search order, and they
-                               // begin at 1 for the first child's index
-
-                               if(child === node){
-                                       nidx = idx;
-                               }
-                               if(child.nodeType == 1){
-                                       child["__cachedIndex"] = idx;
-                                       idx++;
-                               }
-                               child = child.nextSibling;
-                       }while(child);
-               }else{
-                       // NOTE: 
-                       //              could be incorrect in some cases (node swaps involving the
-                       //              passed node, etc.), but we ignore those due to the relative
-                       //              unlikelihood of that occuring
-                       nidx = ci;
-               }
-               return nidx;
-       }
-
-       var firedCount = 0;
-
-       var blank = "";
-       var _getAttr = function(elem, attr){
-               if(attr == "class"){
-                       return elem.className || blank;
-               }
-               if(attr == "for"){
-                       return elem.htmlFor || blank;
-               }
-               return elem.getAttribute(attr, 2) || blank;
-       }
-
-       var attrs = {
-               "*=": function(attr, value){
-                       return function(elem){
-                               // E[foo*="bar"]
-                               //              an E element whose "foo" attribute value contains
-                               //              the substring "bar"
-                               return (_getAttr(elem, attr).indexOf(value)>=0);
-                       }
-               },
-               "^=": function(attr, value){
-                       // E[foo^="bar"]
-                       //              an E element whose "foo" attribute value begins exactly
-                       //              with the string "bar"
-                       return function(elem){
-                               return (_getAttr(elem, attr).indexOf(value)==0);
-                       }
-               },
-               "$=": function(attr, value){
-                       // E[foo$="bar"]        
-                       //              an E element whose "foo" attribute value ends exactly
-                       //              with the string "bar"
-                       var tval = " "+value;
-                       return function(elem){
-                               var ea = " "+_getAttr(elem, attr);
-                               return (ea.lastIndexOf(value)==(ea.length-value.length));
-                       }
-               },
-               "~=": function(attr, value){
-                       // E[foo~="bar"]        
-                       //              an E element whose "foo" attribute value is a list of
-                       //              space-separated values, one of which is exactly equal
-                       //              to "bar"
-
-                       // return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
-                       var tval = " "+value+" ";
-                       return function(elem){
-                               var ea = " "+_getAttr(elem, attr)+" ";
-                               return (ea.indexOf(tval)>=0);
-                       }
-               },
-               "|=": function(attr, value){
-                       // E[hreflang|="en"]
-                       //              an E element whose "hreflang" attribute has a
-                       //              hyphen-separated list of values beginning (from the
-                       //              left) with "en"
-                       var valueDash = " "+value+"-";
-                       return function(elem){
-                               var ea = " "+(elem.getAttribute(attr, 2) || "");
-                               return (
-                                       (ea == value) ||
-                                       (ea.indexOf(valueDash)==0)
-                               );
-                       }
-               },
-               "=": function(attr, value){
-                       return function(elem){
-                               return (_getAttr(elem, attr) == value);
-                       }
-               }
-       };
-
-       var pseudos = {
-               "first-child": function(name, condition){
-                       return function(elem){
-                               if(elem.nodeType != 1){ return false; }
-                               // check to see if any of the previous siblings are elements
-                               var fc = elem.previousSibling;
-                               while(fc && (fc.nodeType != 1)){
-                                       fc = fc.previousSibling;
-                               }
-                               return (!fc);
-                       }
-               },
-               "last-child": function(name, condition){
-                       return function(elem){
-                               if(elem.nodeType != 1){ return false; }
-                               // check to see if any of the next siblings are elements
-                               var nc = elem.nextSibling;
-                               while(nc && (nc.nodeType != 1)){
-                                       nc = nc.nextSibling;
-                               }
-                               return (!nc);
-                       }
-               },
-               "empty": function(name, condition){
-                       return function(elem){
-                               // DomQuery and jQuery get this wrong, oddly enough.
-                               // The CSS 3 selectors spec is pretty explicit about
-                               // it, too.
-                               var cn = elem.childNodes;
-                               var cnl = elem.childNodes.length;
-                               // if(!cnl){ return true; }
-                               for(var x=cnl-1; x >= 0; x--){
-                                       var nt = cn[x].nodeType;
-                                       if((nt == 1)||(nt == 3)){ return false; }
-                               }
-                               return true;
-                       }
-               },
-               "contains": function(name, condition){
-                       return function(elem){
-                               // FIXME: I dislike this version of "contains", as
-                               // whimsical attribute could set it off. An inner-text
-                               // based version might be more accurate, but since
-                               // jQuery and DomQuery also potentially get this wrong,
-                               // I'm leaving it for now.
-                               return (elem.innerHTML.indexOf(condition) >= 0);
-                       }
-               },
-               "not": function(name, condition){
-                       var ntf = getFilterFunc(getQueryParts(condition)[0]);
-                       return function(elem){
-                               return (!ntf(elem));
-                       }
-               },
-               "nth-child": function(name, condition){
-                       var pi = parseInt;
-                       if(condition == "odd"){
-                               return function(elem){
-                                       return (
-                                               ((getNodeIndex(elem)) % 2) == 1
-                                       );
-                               }
-                       }else if((condition == "2n")||
-                               (condition == "even")){
-                               return function(elem){
-                                       return ((getNodeIndex(elem) % 2) == 0);
-                               }
-                       }else if(condition.indexOf("0n+") == 0){
-                               var ncount = pi(condition.substr(3));
-                               return function(elem){
-                                       return (elem.parentNode[childNodesName][ncount-1] === elem);
-                               }
-                       }else if(       (condition.indexOf("n+") > 0) &&
-                                               (condition.length > 3) ){
-                               var tparts = condition.split("n+", 2);
-                               var pred = pi(tparts[0]);
-                               var idx = pi(tparts[1]);
-                               return function(elem){
-                                       return ((getNodeIndex(elem) % pred) == idx);
-                               }
-                       }else if(condition.indexOf("n") == -1){
-                               var ncount = pi(condition);
-                               return function(elem){
-                                       return (getNodeIndex(elem) == ncount);
-                               }
-                       }
-               }
-       };
-
-       var defaultGetter = (d.isIE) ? function(cond){
-               var clc = cond.toLowerCase();
-               return function(elem){
-                       return elem[cond]||elem[clc];
-               }
-       } : function(cond){
-               return function(elem){
-                       return (elem && elem.getAttribute && elem.hasAttribute(cond));
-               }
-       };
-
-       var getSimpleFilterFunc = function(query){
-
-               var fcHit = (_simpleFiltersCache[query.query]||_filtersCache[query.query]);
-               if(fcHit){ return fcHit; }
-
-               var ff = null;
-
-               // the only case where we'll need the tag name is if we came from an ID query
-               if(query.id){ // do we have an ID component?
-                       if(query.tag != "*"){
-                               ff = agree(ff, function(elem){
-                                       return (elem.tagName.toLowerCase() == query.tag);
-                               });
-                       }
-               }
-
-               // if there's a class in our query, generate a match function for it
-               d.forEach(query.classes, function(cname, idx, arr){
-                       // get the class name
-                       var isWildcard = cname.charAt(cname.length-1) == "*";
-                       if(isWildcard){
-                               cname = cname.substr(0, cname.length-1);
-                       }
-                       // I dislike the regex thing, even if memozied in a cache, but it's VERY short
-                       var re = new RegExp("(?:^|\\s)" + cname + (isWildcard ? ".*" : "") + "(?:\\s|$)");
-                       ff = agree(ff, function(elem){
-                               return re.test(elem.className);
-                       });
-                       ff.count = idx;
-               });
-
-               d.forEach(query.pseudos, function(pseudo){
-                       if(pseudos[pseudo.name]){
-                               ff = agree(ff, pseudos[pseudo.name](pseudo.name, pseudo.value));
-                       }
-               });
-
-               handleAttrs(attrs, query, defaultGetter,
-                       function(tmatcher){ ff = agree(ff, tmatcher); }
-               );
-               if(!ff){
-                       ff = function(){ return true; };
-               }
-               return _simpleFiltersCache[query.query] = ff;
-       }
-
-       var _getElementsFuncCache = { };
-
-       var getElementsFunc = function(query, root){
-               var fHit = _getElementsFuncCache[query.query];
-               if(fHit){ return fHit; }
-
-               // NOTE: this function is in the fast path! not memoized!!!
-
-               // the query doesn't contain any spaces, so there's only so many
-               // things it could be
-
-               if(query.id && !query.hasLoops && !query.tag){
-                       // ID-only query. Easy.
-                       return _getElementsFuncCache[query.query] = function(root){
-                               // FIXME: if root != document, check for parenting!
-                               return [ d.byId(query.id) ];
-                       }
-               }
-
-               var filterFunc = getSimpleFilterFunc(query);
-
-               var retFunc;
-               if(query.tag && query.id && !query.hasLoops){
-                       // we got a filtered ID search (e.g., "h4#thinger")
-                       retFunc = function(root){
-                               var te = d.byId(query.id);
-                               if(filterFunc(te)){
-                                       return [ te ];
-                               }
-                       }
-               }else{
-                       var tret;
-
-                       if(!query.hasLoops){
-                               // it's just a plain-ol elements-by-tag-name query from the root
-                               retFunc = function(root){
-                                       var ret = [];
-                                       var te, x=0, tret = root.getElementsByTagName(query.tag);
-                                       while(te=tret[x++]){
-                                               ret.push(te);
-                                       }
-                                       return ret;
-                               }
-                       }else{
-                               retFunc = function(root){
-                                       var ret = [];
-                                       var te, x=0, tret = root.getElementsByTagName(query.tag);
-                                       while(te=tret[x++]){
-                                               if(filterFunc(te)){
-                                                       ret.push(te);
-                                               }
-                                       }
-                                       return ret;
-                               }
-                       }
-               }
-               return _getElementsFuncCache[query.query] = retFunc;
-       }
-
-       var _partsCache = {};
-
-       ////////////////////////////////////////////////////////////////////////
-       // the query runner
-       ////////////////////////////////////////////////////////////////////////
-
-       // this is the second level of spliting, from full-length queries (e.g.,
-       // "div.foo .bar") into simple query expressions (e.g., ["div.foo",
-       // ".bar"])
-       var _queryFuncCache = {
-               "*": d.isIE ? 
-                       function(root){ 
-                                       return root.all;
-                       } : 
-                       function(root){
-                                return root.getElementsByTagName("*");
-                       },
-               "~": _nextSiblings,
-               "+": function(root){ return _nextSiblings(root, true); },
-               ">": _childElements
-       };
-
-       var getStepQueryFunc = function(query){
-               // if it's trivial, get a fast-path dispatcher
-               var qparts = getQueryParts(d.trim(query));
-               // if(query[query.length-1] == ">"){ query += " *"; }
-               if(qparts.length == 1){
-                       var tt = getElementsFunc(qparts[0]);
-                       tt.nozip = true;
-                       return tt;
-               }
-
-               // otherwise, break it up and return a runner that iterates over the parts recursively
-               var sqf = function(root){
-                       var localQueryParts = qparts.slice(0); // clone the src arr
-                       var candidates;
-                       if(localQueryParts[0].oper == ">"){ // FIXME: what if it's + or ~?
-                               candidates = [ root ];
-                               // root = document;
-                       }else{
-                               candidates = getElementsFunc(localQueryParts.shift())(root);
-                       }
-                       return filterDown(candidates, localQueryParts);
-               }
-               return sqf;
-       }
-
-       // a specialized method that implements our primoridal "query optimizer".
-       // This allows us to dispatch queries to the fastest subsystem we can get.
-       var _getQueryFunc = (
-               // NOTE: 
-               //              XPath on the Webkit nighlies is slower than it's DOM iteration
-               //              for most test cases
-               // FIXME: 
-               //              we should try to capture some runtime speed data for each query
-               //              function to determine on the fly if we should stick w/ the
-               //              potentially optimized variant or if we should try something
-               //              new.
-               (document["evaluate"] && !d.isSafari) ? 
-               function(query){
-                       // has xpath support that's faster than DOM
-                       var qparts = query.split(" ");
-                       // can we handle it?
-                       if(     (document["evaluate"])&&
-                               (query.indexOf(":") == -1)&&
-                               (query.indexOf("+") == -1) // skip direct sibling matches. See line ~344
-                       ){
-                               // dojo.debug(query);
-                               // should we handle it?
-
-                               // kind of a lame heuristic, but it works
-                               if(     
-                                       // a "div div div" style query
-                                       ((qparts.length > 2)&&(query.indexOf(">") == -1))||
-                                       // or something else with moderate complexity. kinda janky
-                                       (qparts.length > 3)||
-                                       (query.indexOf("[")>=0)||
-                                       // or if it's a ".thinger" query
-                                       ((1 == qparts.length)&&(0 <= query.indexOf(".")))
-
-                               ){
-                                       // use get and cache a xpath runner for this selector
-                                       return getXPathFunc(query);
-                               }
-                       }
-
-                       // fallthrough
-                       return getStepQueryFunc(query);
-               } : getStepQueryFunc
-       );
-       // uncomment to disable XPath for testing and tuning the DOM path
-       // _getQueryFunc = getStepQueryFunc;
-
-       // FIXME: we've got problems w/ the NodeList query()/filter() functions if we go XPath for everything
-
-       // uncomment to disable DOM queries for testing and tuning XPath
-       // _getQueryFunc = getXPathFunc;
-
-       // this is the primary caching for full-query results. The query dispatcher
-       // functions are generated here and then pickled for hash lookup in the
-       // future
-       var getQueryFunc = function(query){
-               // return a cached version if one is available
-               var qcz = query.charAt(0);
-               if(d.doc["querySelectorAll"] && 
-                       ( (!d.isSafari) || (d.isSafari > 3.1) ) && // see #5832
-                       // as per CSS 3, we can't currently start w/ combinator:
-                       //              http://www.w3.org/TR/css3-selectors/#w3cselgrammar
-                       (">+~".indexOf(qcz) == -1)
-               ){
-                       return function(root){
-                               var r = root.querySelectorAll(query);
-                               r.nozip = true; // skip expensive duplication checks and just wrap in a NodeList
-                               return r;
-                       };
-               }
-               if(_queryFuncCache[query]){ return _queryFuncCache[query]; }
-               if(0 > query.indexOf(",")){
-                       // if it's not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher
-                       return _queryFuncCache[query] = _getQueryFunc(query);
-               }else{
-                       // if it's a complex query, break it up into it's constituent parts
-                       // and return a dispatcher that will merge the parts when run
-
-                       // var parts = query.split(", ");
-                       var parts = query.split(/\s*,\s*/);
-                       var tf = function(root){
-                               var pindex = 0; // avoid array alloc for every invocation
-                               var ret = [];
-                               var tp;
-                               while(tp = parts[pindex++]){
-                                       ret = ret.concat(_getQueryFunc(tp, tp.indexOf(" "))(root));
-                               }
-                               return ret;
-                       }
-                       // ...cache and return
-                       return _queryFuncCache[query] = tf;
-               }
-       }
-
-       // FIXME: 
-       //              Dean's Base2 uses a system whereby queries themselves note if
-       //              they'll need duplicate filtering. We need to get on that plan!!
-
-       // attempt to efficiently determine if an item in a list is a dupe,
-       // returning a list of "uniques", hopefully in doucment order
-       var _zipIdx = 0;
-       var _zip = function(arr){
-               if(arr && arr.nozip){ return d.NodeList._wrap(arr); }
-               var ret = new d.NodeList();
-               if(!arr){ return ret; }
-               if(arr[0]){
-                       ret.push(arr[0]);
-               }
-               if(arr.length < 2){ return ret; }
-               _zipIdx++;
-               arr[0]["_zipIdx"] = _zipIdx;
-               for(var x=1, te; te = arr[x]; x++){
-                       if(arr[x]["_zipIdx"] != _zipIdx){ 
-                               ret.push(te);
-                       }
-                       te["_zipIdx"] = _zipIdx;
-               }
-               // FIXME: should we consider stripping these properties?
-               return ret;
-       }
-
-       // the main executor
-       d.query = function(/*String*/ query, /*String|DOMNode?*/ root){
-               //      summary:
-               //              Returns nodes which match the given CSS3 selector, searching the
-               //              entire document by default but optionally taking a node to scope
-               //              the search by. Returns an instance of dojo.NodeList.
-               //      description:
-               //              dojo.query() is the swiss army knife of DOM node manipulation in
-               //              Dojo. Much like Prototype's "$$" (bling-bling) function or JQuery's
-               //              "$" function, dojo.query provides robust, high-performance
-               //              CSS-based node selector support with the option of scoping searches
-               //              to a particular sub-tree of a document.
-               //
-               //              Supported Selectors:
-               //              --------------------
-               //
-               //              dojo.query() supports a rich set of CSS3 selectors, including:
-               //
-               //                      * class selectors (e.g., `.foo`)
-               //                      * node type selectors like `span`
-               //                      * ` ` descendant selectors
-               //                      * `>` child element selectors 
-               //                      * `#foo` style ID selectors
-               //                      * `*` universal selector
-               //                      * `~`, the immediately preceeded-by sibling selector
-               //                      * `+`, the preceeded-by sibling selector
-               //                      * attribute queries:
-               //                      |       * `[foo]` attribute presence selector
-               //                      |       * `[foo='bar']` attribute value exact match
-               //                      |       * `[foo~='bar']` attribute value list item match
-               //                      |       * `[foo^='bar']` attribute start match
-               //                      |       * `[foo$='bar']` attribute end match
-               //                      |       * `[foo*='bar']` attribute substring match
-               //                      * `:first-child`, `:last-child` positional selectors
-               //                      * `:empty` content emtpy selector
-               //                      * `:empty` content emtpy selector
-               //                      * `:nth-child(n)`, `:nth-child(2n+1)` style positional calculations
-               //                      * `:nth-child(even)`, `:nth-child(odd)` positional selectors
-               //                      * `:not(...)` negation pseudo selectors
-               //
-               //              Any legal combination of these selectors will work with
-               //              `dojo.query()`, including compound selectors ("," delimited).
-               //              Very complex and useful searches can be constructed with this
-               //              palette of selectors and when combined with functions for
-               //              maniplation presented by dojo.NodeList, many types of DOM
-               //              manipulation operations become very straightforward.
-               //              
-               //              Unsupported Selectors:
-               //              ----------------------
-               //
-               //              While dojo.query handles many CSS3 selectors, some fall outside of
-               //              what's resaonable for a programmatic node querying engine to
-               //              handle. Currently unsupported selectors include:
-               //              
-               //                      * namespace-differentiated selectors of any form
-               //                      * all `::` pseduo-element selectors
-               //                      * certain pseduo-selectors which don't get a lot of day-to-day use:
-               //                      |       * `:root`, `:lang()`, `:target`, `:focus`
-               //                      * all visual and state selectors:
-               //                      |       * `:root`, `:active`, `:hover`, `:visisted`, `:link`,
-               //                                `:enabled`, `:disabled`, `:checked`
-               //                      * `:*-of-type` pseudo selectors
-               //              
-               //              dojo.query and XML Documents:
-               //              -----------------------------
-               //              
-               //              `dojo.query` currently only supports searching XML documents
-               //              whose tags and attributes are 100% lower-case. This is a known
-               //              limitation and will [be addressed soon](http://trac.dojotoolkit.org/ticket/3866)
-               //              Non-selector Queries:
-               //              ---------------------
-               //
-               //              If something other than a String is passed for the query,
-               //              `dojo.query` will return a new `dojo.NodeList` constructed from
-               //              that parameter alone and all further processing will stop. This
-               //              means that if you have a reference to a node or NodeList, you
-               //              can quickly construct a new NodeList from the original by
-               //              calling `dojo.query(node)` or `dojo.query(list)`.
-               //
-               //      query:
-               //              The CSS3 expression to match against. For details on the syntax of
-               //              CSS3 selectors, see <http://www.w3.org/TR/css3-selectors/#selectors>
-               //      root:
-               //              A DOMNode (or node id) to scope the search from. Optional.
-               //      returns: dojo.NodeList
-               //              An instance of `dojo.NodeList`. Many methods are available on
-               //              NodeLists for searching, iterating, manipulating, and handling
-               //              events on the matched nodes in the returned list.
-               //      example:
-               //              search the entire document for elements with the class "foo":
-               //      |       dojo.query(".foo");
-               //              these elements will match:
-               //      |       <span class="foo"></span>
-               //      |       <span class="foo bar"></span>
-               //      |       <p class="thud foo"></p>
-               //      example:
-               //              search the entire document for elements with the classes "foo" *and* "bar":
-               //      |       dojo.query(".foo.bar");
-               //              these elements will match:
-               //      |       <span class="foo bar"></span>
-               //              while these will not:
-               //      |       <span class="foo"></span>
-               //      |       <p class="thud foo"></p>
-               //      example:
-               //              find `<span>` elements which are descendants of paragraphs and
-               //              which have a "highlighted" class:
-               //      |       dojo.query("p span.highlighted");
-               //              the innermost span in this fragment matches:
-               //      |       <p class="foo">
-               //      |               <span>...
-               //      |                       <span class="highlighted foo bar">...</span>
-               //      |               </span>
-               //      |       </p>
-               //      example:
-               //              set an "odd" class on all odd table rows inside of the table
-               //              `#tabular_data`, using the `>` (direct child) selector to avoid
-               //              affecting any nested tables:
-               //      |       dojo.query("#tabular_data > tbody > tr:nth-child(odd)").addClass("odd");
-               //      example:
-               //              remove all elements with the class "error" from the document
-               //              and store them in a list:
-               //      |       var errors = dojo.query(".error").orphan();
-               //      example:
-               //              add an onclick handler to every submit button in the document
-               //              which causes the form to be sent via Ajax instead:
-               //      |       dojo.query("input[type='submit']").onclick(function(e){
-               //      |               dojo.stopEvent(e); // prevent sending the form
-               //      |               var btn = e.target;
-               //      |               dojo.xhrPost({
-               //      |                       form: btn.form,
-               //      |                       load: function(data){
-               //      |                               // replace the form with the response
-               //      |                               var div = dojo.doc.createElement("div");
-               //      |                               dojo.place(div, btn.form, "after");
-               //      |                               div.innerHTML = data;
-               //      |                               dojo.style(btn.form, "display", "none");
-               //      |                       }
-               //      |               });
-               //      |       });
-
-
-               // NOTE: elementsById is not currently supported
-               // NOTE: ignores xpath-ish queries for now
-
-               if(query.constructor == d.NodeList){
-                       return query;
-               }
-               if(!d.isString(query)){
-                       return new d.NodeList(query); // dojo.NodeList
-               }
-               if(d.isString(root)){
-                       root = d.byId(root);
-               }
-
-               return _zip(getQueryFunc(query)(root||d.doc)); // dojo.NodeList
-       }
-
-       /*
-       // exposing this was a mistake
-       d.query.attrs = attrs;
-       */
-       // exposing this because new pseudo matches are only executed through the
-       // DOM query path (never through the xpath optimizing branch)
-       d.query.pseudos = pseudos;
-
-       // one-off function for filtering a NodeList based on a simple selector
-       d._filterQueryResult = function(nodeList, simpleFilter){
-               var tnl = new d.NodeList();
-               var ff = (simpleFilter) ? getFilterFunc(getQueryParts(simpleFilter)[0]) : function(){ return true; };
-               for(var x=0, te; te = nodeList[x]; x++){
-                       if(ff(te)){ tnl.push(te); }
-               }
-               return tnl;
-       }
-})();
-
-}