summaryrefslogtreecommitdiff
path: root/lib/dojo/selector
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2012-08-14 18:59:10 +0400
committerAndrew Dolgov <[email protected]>2012-08-14 18:59:18 +0400
commit1354d17270961fff662d40f90521223f8fd0d73b (patch)
treee9266be71587e47c800303446e968a6d3565e2cf /lib/dojo/selector
parentd04f8c826f5283765f52cf6b98b42a1ed8f2d6bc (diff)
update dojo to 1.7.3
Diffstat (limited to 'lib/dojo/selector')
-rw-r--r--lib/dojo/selector/_loader.js8
-rw-r--r--lib/dojo/selector/_loader.js.uncompressed.js45
-rw-r--r--lib/dojo/selector/acme.js8
-rw-r--r--lib/dojo/selector/acme.js.uncompressed.js1480
-rw-r--r--lib/dojo/selector/lite.js8
-rw-r--r--lib/dojo/selector/lite.js.uncompressed.js264
6 files changed, 1813 insertions, 0 deletions
diff --git a/lib/dojo/selector/_loader.js b/lib/dojo/selector/_loader.js
new file mode 100644
index 000000000..68db99f00
--- /dev/null
+++ b/lib/dojo/selector/_loader.js
@@ -0,0 +1,8 @@
+/*
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
+ Available via Academic Free License >= 2.1 OR the modified BSD license.
+ see: http://dojotoolkit.org/license for details
+*/
+
+//>>built
+define("dojo/selector/_loader",["../has","require"],function(_1,_2){"use strict";var _3=document.createElement("div");_1.add("dom-qsa2.1",!!_3.querySelectorAll);_1.add("dom-qsa3",function(){try{_3.innerHTML="<p class='TEST'></p>";return _3.querySelectorAll(".TEST:empty").length==1;}catch(e){}});var _4;var _5="./acme",_6="./lite";return {load:function(id,_7,_8,_9){var _a=_2;id=id=="default"?_1("config-selectorEngine")||"css3":id;id=id=="css2"||id=="lite"?_6:id=="css2.1"?_1("dom-qsa2.1")?_6:_5:id=="css3"?_1("dom-qsa3")?_6:_5:id=="acme"?_5:(_a=_7)&&id;if(id.charAt(id.length-1)=="?"){id=id.substring(0,id.length-1);var _b=true;}if(_b&&(_1("dom-compliant-qsa")||_4)){return _8(_4);}_a([id],function(_c){if(id!="./lite"){_4=_c;}_8(_c);});}};}); \ No newline at end of file
diff --git a/lib/dojo/selector/_loader.js.uncompressed.js b/lib/dojo/selector/_loader.js.uncompressed.js
new file mode 100644
index 000000000..9543069e1
--- /dev/null
+++ b/lib/dojo/selector/_loader.js.uncompressed.js
@@ -0,0 +1,45 @@
+define("dojo/selector/_loader", ["../has", "require"],
+ function(has, require){
+// summary:
+// This module handles loading the appropriate selector engine for the given browser
+"use strict";
+var testDiv = document.createElement("div");
+has.add("dom-qsa2.1", !!testDiv.querySelectorAll);
+has.add("dom-qsa3", function(){
+ // test to see if we have a reasonable native selector engine available
+ try{
+ testDiv.innerHTML = "<p class='TEST'></p>"; // test kind of from sizzle
+ // Safari can't handle uppercase or unicode characters when
+ // in quirks mode, IE8 can't handle pseudos like :empty
+ return testDiv.querySelectorAll(".TEST:empty").length == 1;
+ }catch(e){}
+ });
+var fullEngine;
+var acme = "./acme", lite = "./lite";
+return {
+ load: function(id, parentRequire, loaded, config){
+ var req = require;
+ // here we implement the default logic for choosing a selector engine
+ id = id == "default" ? has("config-selectorEngine") || "css3" : id;
+ id = id == "css2" || id == "lite" ? lite :
+ id == "css2.1" ? has("dom-qsa2.1") ? lite : acme :
+ id == "css3" ? has("dom-qsa3") ? lite : acme :
+ id == "acme" ? acme : (req = parentRequire) && id;
+ if(id.charAt(id.length-1) == '?'){
+ id = id.substring(0,id.length - 1);
+ var optionalLoad = true;
+ }
+ // the query engine is optional, only load it if a native one is not available or existing one has not been loaded
+ if(optionalLoad && (has("dom-compliant-qsa") || fullEngine)){
+ return loaded(fullEngine);
+ }
+ // load the referenced selector engine
+ req([id], function(engine){
+ if(id != "./lite"){
+ fullEngine = engine;
+ }
+ loaded(engine);
+ });
+ }
+};
+});
diff --git a/lib/dojo/selector/acme.js b/lib/dojo/selector/acme.js
new file mode 100644
index 000000000..e75fbf0f4
--- /dev/null
+++ b/lib/dojo/selector/acme.js
@@ -0,0 +1,8 @@
+/*
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
+ Available via Academic Free License >= 2.1 OR the modified BSD license.
+ see: http://dojotoolkit.org/license for details
+*/
+
+//>>built
+define("dojo/selector/acme",["../_base/kernel","../has","../dom","../_base/sniff","../_base/array","../_base/lang","../_base/window"],function(_1,_2,_3){var _4=_1.trim;var _5=_1.forEach;var _6=function(){return _1.doc;};var _7=((_1.isWebKit||_1.isMozilla)&&((_6().compatMode)=="BackCompat"));var _8=">~+";var _9=false;var _a=function(){return true;};var _b=function(_c){if(_8.indexOf(_c.slice(-1))>=0){_c+=" * ";}else{_c+=" ";}var ts=function(s,e){return _4(_c.slice(s,e));};var _d=[];var _e=-1,_f=-1,_10=-1,_11=-1,_12=-1,_13=-1,_14=-1,lc="",cc="",_15;var x=0,ql=_c.length,_16=null,_17=null;var _18=function(){if(_14>=0){var tv=(_14==x)?null:ts(_14,x);_16[(_8.indexOf(tv)<0)?"tag":"oper"]=tv;_14=-1;}};var _19=function(){if(_13>=0){_16.id=ts(_13,x).replace(/\\/g,"");_13=-1;}};var _1a=function(){if(_12>=0){_16.classes.push(ts(_12+1,x).replace(/\\/g,""));_12=-1;}};var _1b=function(){_19();_18();_1a();};var _1c=function(){_1b();if(_11>=0){_16.pseudos.push({name:ts(_11+1,x)});}_16.loops=(_16.pseudos.length||_16.attrs.length||_16.classes.length);_16.oquery=_16.query=ts(_15,x);_16.otag=_16.tag=(_16["oper"])?null:(_16.tag||"*");if(_16.tag){_16.tag=_16.tag.toUpperCase();}if(_d.length&&(_d[_d.length-1].oper)){_16.infixOper=_d.pop();_16.query=_16.infixOper.query+" "+_16.query;}_d.push(_16);_16=null;};for(;lc=cc,cc=_c.charAt(x),x<ql;x++){if(lc=="\\"){continue;}if(!_16){_15=x;_16={query:null,pseudos:[],attrs:[],classes:[],tag:null,oper:null,id:null,getTag:function(){return (_9)?this.otag:this.tag;}};_14=x;}if(_e>=0){if(cc=="]"){if(!_17.attr){_17.attr=ts(_e+1,x);}else{_17.matchFor=ts((_10||_e+1),x);}var cmf=_17.matchFor;if(cmf){if((cmf.charAt(0)=="\"")||(cmf.charAt(0)=="'")){_17.matchFor=cmf.slice(1,-1);}}_16.attrs.push(_17);_17=null;_e=_10=-1;}else{if(cc=="="){var _1d=("|~^$*".indexOf(lc)>=0)?lc:"";_17.type=_1d+cc;_17.attr=ts(_e+1,x-_1d.length);_10=x+1;}}}else{if(_f>=0){if(cc==")"){if(_11>=0){_17.value=ts(_f+1,x);}_11=_f=-1;}}else{if(cc=="#"){_1b();_13=x+1;}else{if(cc=="."){_1b();_12=x;}else{if(cc==":"){_1b();_11=x;}else{if(cc=="["){_1b();_e=x;_17={};}else{if(cc=="("){if(_11>=0){_17={name:ts(_11+1,x),value:null};_16.pseudos.push(_17);}_f=x;}else{if((cc==" ")&&(lc!=cc)){_1c();}}}}}}}}}return _d;};var _1e=function(_1f,_20){if(!_1f){return _20;}if(!_20){return _1f;}return function(){return _1f.apply(window,arguments)&&_20.apply(window,arguments);};};var _21=function(i,arr){var r=arr||[];if(i){r.push(i);}return r;};var _22=function(n){return (1==n.nodeType);};var _23="";var _24=function(_25,_26){if(!_25){return _23;}if(_26=="class"){return _25.className||_23;}if(_26=="for"){return _25.htmlFor||_23;}if(_26=="style"){return _25.style.cssText||_23;}return (_9?_25.getAttribute(_26):_25.getAttribute(_26,2))||_23;};var _27={"*=":function(_28,_29){return function(_2a){return (_24(_2a,_28).indexOf(_29)>=0);};},"^=":function(_2b,_2c){return function(_2d){return (_24(_2d,_2b).indexOf(_2c)==0);};},"$=":function(_2e,_2f){return function(_30){var ea=" "+_24(_30,_2e);return (ea.lastIndexOf(_2f)==(ea.length-_2f.length));};},"~=":function(_31,_32){var _33=" "+_32+" ";return function(_34){var ea=" "+_24(_34,_31)+" ";return (ea.indexOf(_33)>=0);};},"|=":function(_35,_36){var _37=_36+"-";return function(_38){var ea=_24(_38,_35);return ((ea==_36)||(ea.indexOf(_37)==0));};},"=":function(_39,_3a){return function(_3b){return (_24(_3b,_39)==_3a);};}};var _3c=(typeof _6().firstChild.nextElementSibling=="undefined");var _3d=!_3c?"nextElementSibling":"nextSibling";var _3e=!_3c?"previousElementSibling":"previousSibling";var _3f=(_3c?_22:_a);var _40=function(_41){while(_41=_41[_3e]){if(_3f(_41)){return false;}}return true;};var _42=function(_43){while(_43=_43[_3d]){if(_3f(_43)){return false;}}return true;};var _44=function(_45){var _46=_45.parentNode;var i=0,_47=_46.children||_46.childNodes,ci=(_45["_i"]||-1),cl=(_46["_l"]||-1);if(!_47){return -1;}var l=_47.length;if(cl==l&&ci>=0&&cl>=0){return ci;}_46["_l"]=l;ci=-1;for(var te=_46["firstElementChild"]||_46["firstChild"];te;te=te[_3d]){if(_3f(te)){te["_i"]=++i;if(_45===te){ci=i;}}}return ci;};var _48=function(_49){return !((_44(_49))%2);};var _4a=function(_4b){return ((_44(_4b))%2);};var _4c={"checked":function(_4d,_4e){return function(_4f){return !!("checked" in _4f?_4f.checked:_4f.selected);};},"first-child":function(){return _40;},"last-child":function(){return _42;},"only-child":function(_50,_51){return function(_52){return _40(_52)&&_42(_52);};},"empty":function(_53,_54){return function(_55){var cn=_55.childNodes;var cnl=_55.childNodes.length;for(var x=cnl-1;x>=0;x--){var nt=cn[x].nodeType;if((nt===1)||(nt==3)){return false;}}return true;};},"contains":function(_56,_57){var cz=_57.charAt(0);if(cz=="\""||cz=="'"){_57=_57.slice(1,-1);}return function(_58){return (_58.innerHTML.indexOf(_57)>=0);};},"not":function(_59,_5a){var p=_b(_5a)[0];var _5b={el:1};if(p.tag!="*"){_5b.tag=1;}if(!p.classes.length){_5b.classes=1;}var ntf=_5c(p,_5b);return function(_5d){return (!ntf(_5d));};},"nth-child":function(_5e,_5f){var pi=parseInt;if(_5f=="odd"){return _4a;}else{if(_5f=="even"){return _48;}}if(_5f.indexOf("n")!=-1){var _60=_5f.split("n",2);var _61=_60[0]?((_60[0]=="-")?-1:pi(_60[0])):1;var idx=_60[1]?pi(_60[1]):0;var lb=0,ub=-1;if(_61>0){if(idx<0){idx=(idx%_61)&&(_61+(idx%_61));}else{if(idx>0){if(idx>=_61){lb=idx-idx%_61;}idx=idx%_61;}}}else{if(_61<0){_61*=-1;if(idx>0){ub=idx;idx=idx%_61;}}}if(_61>0){return function(_62){var i=_44(_62);return (i>=lb)&&(ub<0||i<=ub)&&((i%_61)==idx);};}else{_5f=idx;}}var _63=pi(_5f);return function(_64){return (_44(_64)==_63);};}};var _65=(_1.isIE&&(_1.isIE<9||_1.isQuirks))?function(_66){var clc=_66.toLowerCase();if(clc=="class"){_66="className";}return function(_67){return (_9?_67.getAttribute(_66):_67[_66]||_67[clc]);};}:function(_68){return function(_69){return (_69&&_69.getAttribute&&_69.hasAttribute(_68));};};var _5c=function(_6a,_6b){if(!_6a){return _a;}_6b=_6b||{};var ff=null;if(!("el" in _6b)){ff=_1e(ff,_22);}if(!("tag" in _6b)){if(_6a.tag!="*"){ff=_1e(ff,function(_6c){return (_6c&&(_6c.tagName==_6a.getTag()));});}}if(!("classes" in _6b)){_5(_6a.classes,function(_6d,idx,arr){var re=new RegExp("(?:^|\\s)"+_6d+"(?:\\s|$)");ff=_1e(ff,function(_6e){return re.test(_6e.className);});ff.count=idx;});}if(!("pseudos" in _6b)){_5(_6a.pseudos,function(_6f){var pn=_6f.name;if(_4c[pn]){ff=_1e(ff,_4c[pn](pn,_6f.value));}});}if(!("attrs" in _6b)){_5(_6a.attrs,function(_70){var _71;var a=_70.attr;if(_70.type&&_27[_70.type]){_71=_27[_70.type](a,_70.matchFor);}else{if(a.length){_71=_65(a);}}if(_71){ff=_1e(ff,_71);}});}if(!("id" in _6b)){if(_6a.id){ff=_1e(ff,function(_72){return (!!_72&&(_72.id==_6a.id));});}}if(!ff){if(!("default" in _6b)){ff=_a;}}return ff;};var _73=function(_74){return function(_75,ret,bag){while(_75=_75[_3d]){if(_3c&&(!_22(_75))){continue;}if((!bag||_76(_75,bag))&&_74(_75)){ret.push(_75);}break;}return ret;};};var _77=function(_78){return function(_79,ret,bag){var te=_79[_3d];while(te){if(_3f(te)){if(bag&&!_76(te,bag)){break;}if(_78(te)){ret.push(te);}}te=te[_3d];}return ret;};};var _7a=function(_7b){_7b=_7b||_a;return function(_7c,ret,bag){var te,x=0,_7d=_7c.children||_7c.childNodes;while(te=_7d[x++]){if(_3f(te)&&(!bag||_76(te,bag))&&(_7b(te,x))){ret.push(te);}}return ret;};};var _7e=function(_7f,_80){var pn=_7f.parentNode;while(pn){if(pn==_80){break;}pn=pn.parentNode;}return !!pn;};var _81={};var _82=function(_83){var _84=_81[_83.query];if(_84){return _84;}var io=_83.infixOper;var _85=(io?io.oper:"");var _86=_5c(_83,{el:1});var qt=_83.tag;var _87=("*"==qt);var ecs=_6()["getElementsByClassName"];if(!_85){if(_83.id){_86=(!_83.loops&&_87)?_a:_5c(_83,{el:1,id:1});_84=function(_88,arr){var te=_3.byId(_83.id,(_88.ownerDocument||_88));if(!te||!_86(te)){return;}if(9==_88.nodeType){return _21(te,arr);}else{if(_7e(te,_88)){return _21(te,arr);}}};}else{if(ecs&&/\{\s*\[native code\]\s*\}/.test(String(ecs))&&_83.classes.length&&!_7){_86=_5c(_83,{el:1,classes:1,id:1});var _89=_83.classes.join(" ");_84=function(_8a,arr,bag){var ret=_21(0,arr),te,x=0;var _8b=_8a.getElementsByClassName(_89);while((te=_8b[x++])){if(_86(te,_8a)&&_76(te,bag)){ret.push(te);}}return ret;};}else{if(!_87&&!_83.loops){_84=function(_8c,arr,bag){var ret=_21(0,arr),te,x=0;var _8d=_8c.getElementsByTagName(_83.getTag());while((te=_8d[x++])){if(_76(te,bag)){ret.push(te);}}return ret;};}else{_86=_5c(_83,{el:1,tag:1,id:1});_84=function(_8e,arr,bag){var ret=_21(0,arr),te,x=0;var _8f=_8e.getElementsByTagName(_83.getTag());while((te=_8f[x++])){if(_86(te,_8e)&&_76(te,bag)){ret.push(te);}}return ret;};}}}}else{var _90={el:1};if(_87){_90.tag=1;}_86=_5c(_83,_90);if("+"==_85){_84=_73(_86);}else{if("~"==_85){_84=_77(_86);}else{if(">"==_85){_84=_7a(_86);}}}}return _81[_83.query]=_84;};var _91=function(_92,_93){var _94=_21(_92),qp,x,te,qpl=_93.length,bag,ret;for(var i=0;i<qpl;i++){ret=[];qp=_93[i];x=_94.length-1;if(x>0){bag={};ret.nozip=true;}var gef=_82(qp);for(var j=0;(te=_94[j]);j++){gef(te,ret,bag);}if(!ret.length){break;}_94=ret;}return ret;};var _95={},_96={};var _97=function(_98){var _99=_b(_4(_98));if(_99.length==1){var tef=_82(_99[0]);return function(_9a){var r=tef(_9a,[]);if(r){r.nozip=true;}return r;};}return function(_9b){return _91(_9b,_99);};};var nua=navigator.userAgent;var wk="WebKit/";var _9c=(_1.isWebKit&&(nua.indexOf(wk)>0)&&(parseFloat(nua.split(wk)[1])>528));var _9d=_1.isIE?"commentStrip":"nozip";var qsa="querySelectorAll";var _9e=(!!_6()[qsa]&&(!_1.isSafari||(_1.isSafari>3.1)||_9c));var _9f=/n\+\d|([^ ])?([>~+])([^ =])?/g;var _a0=function(_a1,pre,ch,_a2){return ch?(pre?pre+" ":"")+ch+(_a2?" "+_a2:""):_a1;};var _a3=function(_a4,_a5){_a4=_a4.replace(_9f,_a0);if(_9e){var _a6=_96[_a4];if(_a6&&!_a5){return _a6;}}var _a7=_95[_a4];if(_a7){return _a7;}var qcz=_a4.charAt(0);var _a8=(-1==_a4.indexOf(" "));if((_a4.indexOf("#")>=0)&&(_a8)){_a5=true;}var _a9=(_9e&&(!_a5)&&(_8.indexOf(qcz)==-1)&&(!_1.isIE||(_a4.indexOf(":")==-1))&&(!(_7&&(_a4.indexOf(".")>=0)))&&(_a4.indexOf(":contains")==-1)&&(_a4.indexOf(":checked")==-1)&&(_a4.indexOf("|=")==-1));if(_a9){var tq=(_8.indexOf(_a4.charAt(_a4.length-1))>=0)?(_a4+" *"):_a4;return _96[_a4]=function(_aa){try{if(!((9==_aa.nodeType)||_a8)){throw "";}var r=_aa[qsa](tq);r[_9d]=true;return r;}catch(e){return _a3(_a4,true)(_aa);}};}else{var _ab=_a4.split(/\s*,\s*/);return _95[_a4]=((_ab.length<2)?_97(_a4):function(_ac){var _ad=0,ret=[],tp;while((tp=_ab[_ad++])){ret=ret.concat(_97(tp)(_ac));}return ret;});}};var _ae=0;var _af=_1.isIE?function(_b0){if(_9){return (_b0.getAttribute("_uid")||_b0.setAttribute("_uid",++_ae)||_ae);}else{return _b0.uniqueID;}}:function(_b1){return (_b1._uid||(_b1._uid=++_ae));};var _76=function(_b2,bag){if(!bag){return 1;}var id=_af(_b2);if(!bag[id]){return bag[id]=1;}return 0;};var _b3="_zipIdx";var _b4=function(arr){if(arr&&arr.nozip){return arr;}var ret=[];if(!arr||!arr.length){return ret;}if(arr[0]){ret.push(arr[0]);}if(arr.length<2){return ret;}_ae++;if(_1.isIE&&_9){var _b5=_ae+"";arr[0].setAttribute(_b3,_b5);for(var x=1,te;te=arr[x];x++){if(arr[x].getAttribute(_b3)!=_b5){ret.push(te);}te.setAttribute(_b3,_b5);}}else{if(_1.isIE&&arr.commentStrip){try{for(var x=1,te;te=arr[x];x++){if(_22(te)){ret.push(te);}}}catch(e){}}else{if(arr[0]){arr[0][_b3]=_ae;}for(var x=1,te;te=arr[x];x++){if(arr[x][_b3]!=_ae){ret.push(te);}te[_b3]=_ae;}}}return ret;};var _b6=function(_b7,_b8){_b8=_b8||_6();var od=_b8.ownerDocument||_b8.documentElement;_9=(_b8.contentType&&_b8.contentType=="application/xml")||(_1.isOpera&&(_b8.doctype||od.toString()=="[object XMLDocument]"))||(!!od)&&(_1.isIE?od.xml:(_b8.xmlVersion||od.xmlVersion));var r=_a3(_b7)(_b8);if(r&&r.nozip){return r;}return _b4(r);};_b6.filter=function(_b9,_ba,_bb){var _bc=[],_bd=_b(_ba),_be=(_bd.length==1&&!/[^\w#\.]/.test(_ba))?_5c(_bd[0]):function(_bf){return _1.query(_ba,_bb).indexOf(_bf)!=-1;};for(var x=0,te;te=_b9[x];x++){if(_be(te)){_bc.push(te);}}return _bc;};return _b6;}); \ No newline at end of file
diff --git a/lib/dojo/selector/acme.js.uncompressed.js b/lib/dojo/selector/acme.js.uncompressed.js
new file mode 100644
index 000000000..641478ec3
--- /dev/null
+++ b/lib/dojo/selector/acme.js.uncompressed.js
@@ -0,0 +1,1480 @@
+define("dojo/selector/acme", ["../_base/kernel", "../has", "../dom", "../_base/sniff", "../_base/array", "../_base/lang", "../_base/window"], function(dojo, has, dom){
+ // module:
+ // dojo/selector/acme
+ // summary:
+ // This module defines the Acme selector engine
+
+/*
+ acme architectural overview:
+
+ acme 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)
+ - native (FF3.1+, Safari 3.1+, IE 8+)
+ 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)
+ 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
+ - for native implementations, this may mean working around spec
+ bugs. So be it.
+ 5.) matched nodes are pruned to ensure they are unique (if necessary)
+*/
+
+
+ ////////////////////////////////////////////////////////////////////////
+ // Toolkit aliases
+ ////////////////////////////////////////////////////////////////////////
+
+ // if you are extracting acme for use in your own system, you will
+ // need to provide these methods and properties. No other porting should be
+ // necessary, save for configuring the system to use a class other than
+ // dojo.NodeList as the return instance instantiator
+ var trim = dojo.trim;
+ var each = dojo.forEach;
+ // d.isIE; // float
+ // d.isSafari; // float
+ // d.isOpera; // float
+ // d.isWebKit; // float
+ // d.doc ; // document element
+
+ var getDoc = function(){ return dojo.doc; };
+ // NOTE(alex): the spec is idiotic. CSS queries should ALWAYS be case-sensitive, but nooooooo
+ var cssCaseBug = ((dojo.isWebKit||dojo.isMozilla) && ((getDoc().compatMode) == "BackCompat"));
+
+ ////////////////////////////////////////////////////////////////////////
+ // Global utilities
+ ////////////////////////////////////////////////////////////////////////
+
+
+ var specials = ">~+";
+
+ // global thunk to determine whether we should treat the current query as
+ // case sensitive or not. This switch is flipped by the query evaluator
+ // based on the document passed as the context to search.
+ var caseSensitive = false;
+
+ // how high?
+ var yesman = function(){ return true; };
+
+ ////////////////////////////////////////////////////////////////////////
+ // Tokenizer
+ ////////////////////////////////////////////////////////////////////////
+
+ var getQueryParts = function(query){
+ // summary:
+ // state machine for query tokenization
+ // description:
+ // instead of using a brittle and slow regex-based CSS parser,
+ // acme implements an AST-style query representation. This
+ // representation is only generated once per query. For example,
+ // the same query run multiple times or under different root nodes
+ // does not re-parse the selector expression but instead uses the
+ // cached data structure. The state machine implemented here
+ // terminates on the last " " (space) character and returns an
+ // ordered array of query component structures (or "parts"). Each
+ // part represents an operator or a simple CSS filtering
+ // expression. The structure for parts is documented in the code
+ // below.
+
+
+ // NOTE:
+ // this code is designed to run fast and compress well. Sacrifices
+ // to readability and maintainability have been made. Your best
+ // bet when hacking the tokenizer is to put The Donnas on *really*
+ // loud (may we recommend their "Spend The Night" release?) and
+ // just assume you're gonna make mistakes. Keep the unit tests
+ // open and run them frequently. Knowing is half the battle ;-)
+ if(specials.indexOf(query.slice(-1)) >= 0){
+ // if we end with a ">", "+", or "~", that means we're implicitly
+ // searching all children, so make it explicit
+ query += " * "
+ }else{
+ // if you have not provided a terminator, one will be provided for
+ // you...
+ query += " ";
+ }
+
+ var ts = function(/*Integer*/ s, /*Integer*/ e){
+ // trim and slice.
+
+ // take an index to start a string slice from and an end position
+ // and return a trimmed copy of that sub-string
+ return trim(query.slice(s, e));
+ };
+
+ // the overall data graph of the full query, as represented by queryPart objects
+ var queryParts = [];
+
+
+ // state keeping vars
+ var inBrackets = -1, inParens = -1, inMatchFor = -1,
+ inPseudo = -1, inClass = -1, inId = -1, inTag = -1,
+ lc = "", cc = "", pStart;
+
+ // iteration vars
+ var x = 0, // index in the query
+ ql = query.length,
+ currentPart = null, // data structure representing the entire clause
+ _cp = null; // the current pseudo or attr matcher
+
+ // several temporary variables are assigned to this structure during a
+ // potential sub-expression match:
+ // attr:
+ // a string representing the current full attribute match in a
+ // bracket expression
+ // type:
+ // if there's an operator in a bracket expression, this is
+ // used to keep track of it
+ // value:
+ // the internals of parenthetical expression for a pseudo. for
+ // :nth-child(2n+1), value might be "2n+1"
+
+ var endTag = function(){
+ // called when the tokenizer hits the end of a particular tag name.
+ // Re-sets state variables for tag matching and sets up the matcher
+ // to handle the next type of token (tag or operator).
+ if(inTag >= 0){
+ var tv = (inTag == x) ? null : ts(inTag, x); // .toLowerCase();
+ currentPart[ (specials.indexOf(tv) < 0) ? "tag" : "oper" ] = tv;
+ inTag = -1;
+ }
+ };
+
+ var endId = function(){
+ // called when the tokenizer might be at the end of an ID portion of a match
+ if(inId >= 0){
+ currentPart.id = ts(inId, x).replace(/\\/g, "");
+ inId = -1;
+ }
+ };
+
+ var endClass = function(){
+ // called when the tokenizer might be at the end of a class name
+ // match. CSS allows for multiple classes, so we augment the
+ // current item with another class in its list
+ if(inClass >= 0){
+ currentPart.classes.push(ts(inClass + 1, x).replace(/\\/g, ""));
+ inClass = -1;
+ }
+ };
+
+ var endAll = function(){
+ // at the end of a simple fragment, so wall off the matches
+ endId();
+ endTag();
+ endClass();
+ };
+
+ var endPart = function(){
+ endAll();
+ if(inPseudo >= 0){
+ currentPart.pseudos.push({ name: ts(inPseudo + 1, x) });
+ }
+ // hint to the selector engine to tell it whether or not it
+ // needs to do any iteration. Many simple selectors don't, and
+ // we can avoid significant construction-time work by advising
+ // the system to skip them
+ currentPart.loops = (
+ currentPart.pseudos.length ||
+ currentPart.attrs.length ||
+ currentPart.classes.length );
+
+ currentPart.oquery = currentPart.query = ts(pStart, x); // save the full expression as a string
+
+
+ // otag/tag are hints to suggest to the system whether or not
+ // it's an operator or a tag. We save a copy of otag since the
+ // tag name is cast to upper-case in regular HTML matches. The
+ // system has a global switch to figure out if the current
+ // expression needs to be case sensitive or not and it will use
+ // otag or tag accordingly
+ currentPart.otag = currentPart.tag = (currentPart["oper"]) ? null : (currentPart.tag || "*");
+
+ if(currentPart.tag){
+ // if we're in a case-insensitive HTML doc, we likely want
+ // the toUpperCase when matching on element.tagName. If we
+ // do it here, we can skip the string op per node
+ // comparison
+ currentPart.tag = currentPart.tag.toUpperCase();
+ }
+
+ // add the part to the list
+ if(queryParts.length && (queryParts[queryParts.length-1].oper)){
+ // operators are always infix, so we remove them from the
+ // list and attach them to the next match. The evaluator is
+ // responsible for sorting out how to handle them.
+ currentPart.infixOper = queryParts.pop();
+ currentPart.query = currentPart.infixOper.query + " " + currentPart.query;
+ /*
+ console.debug( "swapping out the infix",
+ currentPart.infixOper,
+ "and attaching it to",
+ currentPart);
+ */
+ }
+ queryParts.push(currentPart);
+
+ currentPart = null;
+ };
+
+ // iterate over the query, character by character, building up a
+ // list of query part objects
+ for(; lc=cc, cc=query.charAt(x), x < ql; x++){
+ // cc: the current character in the match
+ // lc: the last character (if any)
+
+ // someone is trying to escape something, so don't try to match any
+ // fragments. We assume we're inside a literal.
+ if(lc == "\\"){ continue; }
+ if(!currentPart){ // a part was just ended or none has yet been created
+ // NOTE: I hate all this alloc, but it's shorter than writing tons of if's
+ pStart = x;
+ // rules describe full CSS sub-expressions, like:
+ // #someId
+ // .className:first-child
+ // but not:
+ // thinger > div.howdy[type=thinger]
+ // the indidual components of the previous query would be
+ // split into 3 parts that would be represented a structure
+ // like:
+ // [
+ // {
+ // query: "thinger",
+ // tag: "thinger",
+ // },
+ // {
+ // query: "div.howdy[type=thinger]",
+ // classes: ["howdy"],
+ // infixOper: {
+ // query: ">",
+ // oper: ">",
+ // }
+ // },
+ // ]
+ currentPart = {
+ query: null, // the full text of the part's rule
+ pseudos: [], // CSS supports multiple pseud-class matches in a single rule
+ attrs: [], // CSS supports multi-attribute match, so we need an array
+ classes: [], // class matches may be additive, e.g.: .thinger.blah.howdy
+ tag: null, // only one tag...
+ oper: null, // ...or operator per component. Note that these wind up being exclusive.
+ id: null, // the id component of a rule
+ getTag: function(){
+ return (caseSensitive) ? this.otag : this.tag;
+ }
+ };
+
+ // if we don't have a part, we assume we're going to start at
+ // the beginning of a match, which should be a tag name. This
+ // might fault a little later on, but we detect that and this
+ // iteration will still be fine.
+ inTag = x;
+ }
+
+ if(inBrackets >= 0){
+ // look for a the close first
+ if(cc == "]"){ // if we're in a [...] clause and we end, do assignment
+ if(!_cp.attr){
+ // no attribute match was previously begun, so we
+ // assume this is an attribute existence match in the
+ // form of [someAttributeName]
+ _cp.attr = ts(inBrackets+1, x);
+ }else{
+ // we had an attribute already, so we know that we're
+ // matching some sort of value, as in [attrName=howdy]
+ _cp.matchFor = ts((inMatchFor||inBrackets+1), x);
+ }
+ var cmf = _cp.matchFor;
+ if(cmf){
+ // try to strip quotes from the matchFor value. We want
+ // [attrName=howdy] to match the same
+ // as [attrName = 'howdy' ]
+ if( (cmf.charAt(0) == '"') || (cmf.charAt(0) == "'") ){
+ _cp.matchFor = cmf.slice(1, -1);
+ }
+ }
+ // end the attribute by adding it to the list of attributes.
+ currentPart.attrs.push(_cp);
+ _cp = null; // necessary?
+ inBrackets = inMatchFor = -1;
+ }else if(cc == "="){
+ // if the last char was an operator prefix, make sure we
+ // record it along with the "=" operator.
+ 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 we're in a parenthetical expression, we need to figure
+ // out if it's attached to a pseudo-selector rule like
+ // :nth-child(1)
+ if(cc == ")"){
+ if(inPseudo >= 0){
+ _cp.value = ts(inParens+1, x);
+ }
+ inPseudo = inParens = -1;
+ }
+ }else if(cc == "#"){
+ // start of an ID match
+ endAll();
+ inId = x+1;
+ }else if(cc == "."){
+ // start of a class match
+ endAll();
+ inClass = x;
+ }else if(cc == ":"){
+ // start of a pseudo-selector match
+ endAll();
+ inPseudo = x;
+ }else if(cc == "["){
+ // start of an attribute match.
+ endAll();
+ inBrackets = x;
+ // provide a new structure for the attribute match to fill-in
+ _cp = {
+ /*=====
+ attr: null, type: null, matchFor: null
+ =====*/
+ };
+ }else if(cc == "("){
+ // we really only care if we've entered a parenthetical
+ // expression if we're already inside a pseudo-selector match
+ if(inPseudo >= 0){
+ // provide a new structure for the pseudo match to fill-in
+ _cp = {
+ name: ts(inPseudo+1, x),
+ value: null
+ };
+ currentPart.pseudos.push(_cp);
+ }
+ inParens = x;
+ }else if(
+ (cc == " ") &&
+ // if it's a space char and the last char is too, consume the
+ // current one without doing more work
+ (lc != cc)
+ ){
+ endPart();
+ }
+ }
+ return queryParts;
+ };
+
+
+ ////////////////////////////////////////////////////////////////////////
+ // DOM query infrastructure
+ ////////////////////////////////////////////////////////////////////////
+
+ var agree = function(first, second){
+ // 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. If
+ // either are not passed, the other is used exclusively.
+ if(!first){ return second; }
+ if(!second){ return first; }
+
+ return function(){
+ return first.apply(window, arguments) && second.apply(window, arguments);
+ }
+ };
+
+ var getArr = function(i, arr){
+ // helps us avoid array alloc when we don't need it
+ var r = arr||[]; // FIXME: should this be 'new d._NodeListCtor()' ?
+ if(i){ r.push(i); }
+ return r;
+ };
+
+ var _isElement = function(n){ return (1 == n.nodeType); };
+
+ // FIXME: need to coalesce _getAttr with defaultGetter
+ var blank = "";
+ var _getAttr = function(elem, attr){
+ if(!elem){ return blank; }
+ if(attr == "class"){
+ return elem.className || blank;
+ }
+ if(attr == "for"){
+ return elem.htmlFor || blank;
+ }
+ if(attr == "style"){
+ return elem.style.cssText || blank;
+ }
+ return (caseSensitive ? elem.getAttribute(attr) : 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"
+ 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 = _getAttr(elem, attr);
+ return (
+ (ea == value) ||
+ (ea.indexOf(valueDash)==0)
+ );
+ }
+ },
+ "=": function(attr, value){
+ return function(elem){
+ return (_getAttr(elem, attr) == value);
+ }
+ }
+ };
+
+ // avoid testing for node type if we can. Defining this in the negative
+ // here to avoid negation in the fast path.
+ var _noNES = (typeof getDoc().firstChild.nextElementSibling == "undefined");
+ var _ns = !_noNES ? "nextElementSibling" : "nextSibling";
+ var _ps = !_noNES ? "previousElementSibling" : "previousSibling";
+ var _simpleNodeTest = (_noNES ? _isElement : yesman);
+
+ var _lookLeft = function(node){
+ // look left
+ while(node = node[_ps]){
+ if(_simpleNodeTest(node)){ return false; }
+ }
+ return true;
+ };
+
+ var _lookRight = function(node){
+ // look right
+ while(node = node[_ns]){
+ if(_simpleNodeTest(node)){ return false; }
+ }
+ return true;
+ };
+
+ var getNodeIndex = function(node){
+ var root = node.parentNode;
+ var i = 0,
+ tret = root.children || root.childNodes,
+ ci = (node["_i"]||-1),
+ cl = (root["_l"]||-1);
+
+ if(!tret){ return -1; }
+ var l = tret.length;
+
+ // we calculate the parent length as a cheap way to invalidate the
+ // cache. It's not 100% accurate, but it's much more honest than what
+ // other libraries do
+ if( cl == l && ci >= 0 && cl >= 0 ){
+ // if it's legit, tag and release
+ return ci;
+ }
+
+ // else re-key things
+ root["_l"] = l;
+ ci = -1;
+ for(var te = root["firstElementChild"]||root["firstChild"]; te; te = te[_ns]){
+ if(_simpleNodeTest(te)){
+ te["_i"] = ++i;
+ if(node === te){
+ // NOTE:
+ // shortcutting the return at this step in indexing works
+ // very well for benchmarking but we avoid it here since
+ // it leads to potential O(n^2) behavior in sequential
+ // getNodexIndex operations on a previously un-indexed
+ // parent. We may revisit this at a later time, but for
+ // now we just want to get the right answer more often
+ // than not.
+ ci = i;
+ }
+ }
+ }
+ return ci;
+ };
+
+ var isEven = function(elem){
+ return !((getNodeIndex(elem)) % 2);
+ };
+
+ var isOdd = function(elem){
+ return ((getNodeIndex(elem)) % 2);
+ };
+
+ var pseudos = {
+ "checked": function(name, condition){
+ return function(elem){
+ return !!("checked" in elem ? elem.checked : elem.selected);
+ }
+ },
+ "first-child": function(){ return _lookLeft; },
+ "last-child": function(){ return _lookRight; },
+ "only-child": function(name, condition){
+ return function(node){
+ return _lookLeft(node) && _lookRight(node);
+ };
+ },
+ "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){
+ var cz = condition.charAt(0);
+ if( cz == '"' || cz == "'" ){ //remove quote
+ condition = condition.slice(1, -1);
+ }
+ return function(elem){
+ return (elem.innerHTML.indexOf(condition) >= 0);
+ }
+ },
+ "not": function(name, condition){
+ var p = getQueryParts(condition)[0];
+ var ignores = { el: 1 };
+ if(p.tag != "*"){
+ ignores.tag = 1;
+ }
+ if(!p.classes.length){
+ ignores.classes = 1;
+ }
+ var ntf = getSimpleFilterFunc(p, ignores);
+ return function(elem){
+ return (!ntf(elem));
+ }
+ },
+ "nth-child": function(name, condition){
+ var pi = parseInt;
+ // avoid re-defining function objects if we can
+ if(condition == "odd"){
+ return isOdd;
+ }else if(condition == "even"){
+ return isEven;
+ }
+ // FIXME: can we shorten this?
+ if(condition.indexOf("n") != -1){
+ var tparts = condition.split("n", 2);
+ var pred = tparts[0] ? ((tparts[0] == '-') ? -1 : pi(tparts[0])) : 1;
+ var idx = tparts[1] ? pi(tparts[1]) : 0;
+ var lb = 0, ub = -1;
+ if(pred > 0){
+ if(idx < 0){
+ idx = (idx % pred) && (pred + (idx % pred));
+ }else if(idx>0){
+ if(idx >= pred){
+ lb = idx - idx % pred;
+ }
+ idx = idx % pred;
+ }
+ }else if(pred<0){
+ pred *= -1;
+ // idx has to be greater than 0 when pred is negative;
+ // shall we throw an error here?
+ if(idx > 0){
+ ub = idx;
+ idx = idx % pred;
+ }
+ }
+ if(pred > 0){
+ return function(elem){
+ var i = getNodeIndex(elem);
+ return (i>=lb) && (ub<0 || i<=ub) && ((i % pred) == idx);
+ }
+ }else{
+ condition = idx;
+ }
+ }
+ var ncount = pi(condition);
+ return function(elem){
+ return (getNodeIndex(elem) == ncount);
+ }
+ }
+ };
+
+ var defaultGetter = (dojo.isIE && (dojo.isIE < 9 || dojo.isQuirks)) ? function(cond){
+ var clc = cond.toLowerCase();
+ if(clc == "class"){ cond = "className"; }
+ return function(elem){
+ return (caseSensitive ? elem.getAttribute(cond) : elem[cond]||elem[clc]);
+ }
+ } : function(cond){
+ return function(elem){
+ return (elem && elem.getAttribute && elem.hasAttribute(cond));
+ }
+ };
+
+ var getSimpleFilterFunc = function(query, ignores){
+ // generates a node tester function based on the passed query part. The
+ // query part is one of the structures generated by the query parser
+ // when it creates the query AST. The "ignores" object specifies which
+ // (if any) tests to skip, allowing the system to avoid duplicating
+ // work where it may have already been taken into account by other
+ // factors such as how the nodes to test were fetched in the first
+ // place
+ if(!query){ return yesman; }
+ ignores = ignores||{};
+
+ var ff = null;
+
+ if(!("el" in ignores)){
+ ff = agree(ff, _isElement);
+ }
+
+ if(!("tag" in ignores)){
+ if(query.tag != "*"){
+ ff = agree(ff, function(elem){
+ return (elem && (elem.tagName == query.getTag()));
+ });
+ }
+ }
+
+ if(!("classes" in ignores)){
+ each(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 memoized in a cache, but it's VERY short
+ var re = new RegExp("(?:^|\\s)" + cname + (isWildcard ? ".*" : "") + "(?:\\s|$)");
+ */
+ var re = new RegExp("(?:^|\\s)" + cname + "(?:\\s|$)");
+ ff = agree(ff, function(elem){
+ return re.test(elem.className);
+ });
+ ff.count = idx;
+ });
+ }
+
+ if(!("pseudos" in ignores)){
+ each(query.pseudos, function(pseudo){
+ var pn = pseudo.name;
+ if(pseudos[pn]){
+ ff = agree(ff, pseudos[pn](pn, pseudo.value));
+ }
+ });
+ }
+
+ if(!("attrs" in ignores)){
+ each(query.attrs, function(attr){
+ var matcher;
+ var a = attr.attr;
+ // type, attr, matchFor
+ if(attr.type && attrs[attr.type]){
+ matcher = attrs[attr.type](a, attr.matchFor);
+ }else if(a.length){
+ matcher = defaultGetter(a);
+ }
+ if(matcher){
+ ff = agree(ff, matcher);
+ }
+ });
+ }
+
+ if(!("id" in ignores)){
+ if(query.id){
+ ff = agree(ff, function(elem){
+ return (!!elem && (elem.id == query.id));
+ });
+ }
+ }
+
+ if(!ff){
+ if(!("default" in ignores)){
+ ff = yesman;
+ }
+ }
+ return ff;
+ };
+
+ var _nextSibling = function(filterFunc){
+ return function(node, ret, bag){
+ while(node = node[_ns]){
+ if(_noNES && (!_isElement(node))){ continue; }
+ if(
+ (!bag || _isUnique(node, bag)) &&
+ filterFunc(node)
+ ){
+ ret.push(node);
+ }
+ break;
+ }
+ return ret;
+ }
+ };
+
+ var _nextSiblings = function(filterFunc){
+ return function(root, ret, bag){
+ var te = root[_ns];
+ while(te){
+ if(_simpleNodeTest(te)){
+ if(bag && !_isUnique(te, bag)){
+ break;
+ }
+ if(filterFunc(te)){
+ ret.push(te);
+ }
+ }
+ te = te[_ns];
+ }
+ return ret;
+ }
+ };
+
+ // get an array of child *elements*, skipping text and comment nodes
+ var _childElements = function(filterFunc){
+ filterFunc = filterFunc||yesman;
+ return function(root, ret, bag){
+ // get an array of child elements, skipping text and comment nodes
+ var te, x = 0, tret = root.children || root.childNodes;
+ while(te = tret[x++]){
+ if(
+ _simpleNodeTest(te) &&
+ (!bag || _isUnique(te, bag)) &&
+ (filterFunc(te, x))
+ ){
+ ret.push(te);
+ }
+ }
+ return ret;
+ };
+ };
+
+ /*
+ // thanks, Dean!
+ var itemIsAfterRoot = d.isIE ? function(item, root){
+ return (item.sourceIndex > root.sourceIndex);
+ } : function(item, root){
+ return (item.compareDocumentPosition(root) == 2);
+ };
+ */
+
+ // test to see if node is below root
+ var _isDescendant = function(node, root){
+ var pn = node.parentNode;
+ while(pn){
+ if(pn == root){
+ break;
+ }
+ pn = pn.parentNode;
+ }
+ return !!pn;
+ };
+
+ var _getElementsFuncCache = {};
+
+ var getElementsFunc = function(query){
+ var retFunc = _getElementsFuncCache[query.query];
+ // if we've got a cached dispatcher, just use that
+ if(retFunc){ return retFunc; }
+ // else, generate a new on
+
+ // NOTE:
+ // this function returns a function that searches for nodes and
+ // filters them. The search may be specialized by infix operators
+ // (">", "~", or "+") else it will default to searching all
+ // descendants (the " " selector). Once a group of children is
+ // found, a test function is applied to weed out the ones we
+ // don't want. Many common cases can be fast-pathed. We spend a
+ // lot of cycles to create a dispatcher that doesn't do more work
+ // than necessary at any point since, unlike this function, the
+ // dispatchers will be called every time. The logic of generating
+ // efficient dispatchers looks like this in pseudo code:
+ //
+ // # if it's a purely descendant query (no ">", "+", or "~" modifiers)
+ // if infixOperator == " ":
+ // if only(id):
+ // return def(root):
+ // return d.byId(id, root);
+ //
+ // elif id:
+ // return def(root):
+ // return filter(d.byId(id, root));
+ //
+ // elif cssClass && getElementsByClassName:
+ // return def(root):
+ // return filter(root.getElementsByClassName(cssClass));
+ //
+ // elif only(tag):
+ // return def(root):
+ // return root.getElementsByTagName(tagName);
+ //
+ // else:
+ // # search by tag name, then filter
+ // return def(root):
+ // return filter(root.getElementsByTagName(tagName||"*"));
+ //
+ // elif infixOperator == ">":
+ // # search direct children
+ // return def(root):
+ // return filter(root.children);
+ //
+ // elif infixOperator == "+":
+ // # search next sibling
+ // return def(root):
+ // return filter(root.nextElementSibling);
+ //
+ // elif infixOperator == "~":
+ // # search rightward siblings
+ // return def(root):
+ // return filter(nextSiblings(root));
+
+ var io = query.infixOper;
+ var oper = (io ? io.oper : "");
+ // the default filter func which tests for all conditions in the query
+ // part. This is potentially inefficient, so some optimized paths may
+ // re-define it to test fewer things.
+ var filterFunc = getSimpleFilterFunc(query, { el: 1 });
+ var qt = query.tag;
+ var wildcardTag = ("*" == qt);
+ var ecs = getDoc()["getElementsByClassName"];
+
+ if(!oper){
+ // if there's no infix operator, then it's a descendant query. ID
+ // and "elements by class name" variants can be accelerated so we
+ // call them out explicitly:
+ if(query.id){
+ // testing shows that the overhead of yesman() is acceptable
+ // and can save us some bytes vs. re-defining the function
+ // everywhere.
+ filterFunc = (!query.loops && wildcardTag) ?
+ yesman :
+ getSimpleFilterFunc(query, { el: 1, id: 1 });
+
+ retFunc = function(root, arr){
+ var te = dom.byId(query.id, (root.ownerDocument||root));
+ if(!te || !filterFunc(te)){ return; }
+ if(9 == root.nodeType){ // if root's a doc, we just return directly
+ return getArr(te, arr);
+ }else{ // otherwise check ancestry
+ if(_isDescendant(te, root)){
+ return getArr(te, arr);
+ }
+ }
+ }
+ }else if(
+ ecs &&
+ // isAlien check. Workaround for Prototype.js being totally evil/dumb.
+ /\{\s*\[native code\]\s*\}/.test(String(ecs)) &&
+ query.classes.length &&
+ !cssCaseBug
+ ){
+ // it's a class-based query and we've got a fast way to run it.
+
+ // ignore class and ID filters since we will have handled both
+ filterFunc = getSimpleFilterFunc(query, { el: 1, classes: 1, id: 1 });
+ var classesString = query.classes.join(" ");
+ retFunc = function(root, arr, bag){
+ var ret = getArr(0, arr), te, x=0;
+ var tret = root.getElementsByClassName(classesString);
+ while((te = tret[x++])){
+ if(filterFunc(te, root) && _isUnique(te, bag)){
+ ret.push(te);
+ }
+ }
+ return ret;
+ };
+
+ }else if(!wildcardTag && !query.loops){
+ // it's tag only. Fast-path it.
+ retFunc = function(root, arr, bag){
+ var ret = getArr(0, arr), te, x=0;
+ var tret = root.getElementsByTagName(query.getTag());
+ while((te = tret[x++])){
+ if(_isUnique(te, bag)){
+ ret.push(te);
+ }
+ }
+ return ret;
+ };
+ }else{
+ // the common case:
+ // a descendant selector without a fast path. By now it's got
+ // to have a tag selector, even if it's just "*" so we query
+ // by that and filter
+ filterFunc = getSimpleFilterFunc(query, { el: 1, tag: 1, id: 1 });
+ retFunc = function(root, arr, bag){
+ var ret = getArr(0, arr), te, x=0;
+ // we use getTag() to avoid case sensitivity issues
+ var tret = root.getElementsByTagName(query.getTag());
+ while((te = tret[x++])){
+ if(filterFunc(te, root) && _isUnique(te, bag)){
+ ret.push(te);
+ }
+ }
+ return ret;
+ };
+ }
+ }else{
+ // the query is scoped in some way. Instead of querying by tag we
+ // use some other collection to find candidate nodes
+ var skipFilters = { el: 1 };
+ if(wildcardTag){
+ skipFilters.tag = 1;
+ }
+ filterFunc = getSimpleFilterFunc(query, skipFilters);
+ if("+" == oper){
+ retFunc = _nextSibling(filterFunc);
+ }else if("~" == oper){
+ retFunc = _nextSiblings(filterFunc);
+ }else if(">" == oper){
+ retFunc = _childElements(filterFunc);
+ }
+ }
+ // cache it and return
+ return _getElementsFuncCache[query.query] = retFunc;
+ };
+
+ var filterDown = function(root, queryParts){
+ // NOTE:
+ // this is the guts of the DOM query system. It takes a list of
+ // parsed query parts and a root and finds children which match
+ // the selector represented by the parts
+ var candidates = getArr(root), qp, x, te, qpl = queryParts.length, bag, ret;
+
+ for(var i = 0; i < qpl; i++){
+ ret = [];
+ qp = queryParts[i];
+ x = candidates.length - 1;
+ if(x > 0){
+ // if we have more than one root at this level, provide a new
+ // hash to use for checking group membership but tell the
+ // system not to post-filter us since we will already have been
+ // gauranteed to be unique
+ bag = {};
+ ret.nozip = true;
+ }
+ var gef = getElementsFunc(qp);
+ for(var j = 0; (te = candidates[j]); j++){
+ // for every root, get the elements that match the descendant
+ // selector, adding them to the "ret" array and filtering them
+ // via membership in this level's bag. If there are more query
+ // parts, then this level's return will be used as the next
+ // level's candidates
+ gef(te, ret, bag);
+ }
+ if(!ret.length){ break; }
+ candidates = ret;
+ }
+ return ret;
+ };
+
+ ////////////////////////////////////////////////////////////////////////
+ // the query runner
+ ////////////////////////////////////////////////////////////////////////
+
+ // these are the primary caches for full-query results. The query
+ // dispatcher functions are generated then stored here for hash lookup in
+ // the future
+ var _queryFuncCacheDOM = {},
+ _queryFuncCacheQSA = {};
+
+ // 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 getStepQueryFunc = function(query){
+ var qparts = getQueryParts(trim(query));
+
+ // if it's trivial, avoid iteration and zipping costs
+ if(qparts.length == 1){
+ // we optimize this case here to prevent dispatch further down the
+ // chain, potentially slowing things down. We could more elegantly
+ // handle this in filterDown(), but it's slower for simple things
+ // that need to be fast (e.g., "#someId").
+ var tef = getElementsFunc(qparts[0]);
+ return function(root){
+ var r = tef(root, []);
+ if(r){ r.nozip = true; }
+ return r;
+ }
+ }
+
+ // otherwise, break it up and return a runner that iterates over the parts recursively
+ return function(root){
+ return filterDown(root, qparts);
+ }
+ };
+
+ // NOTES:
+ // * we can't trust QSA for anything but document-rooted queries, so
+ // caching is split into DOM query evaluators and QSA query evaluators
+ // * caching query results is dirty and leak-prone (or, at a minimum,
+ // prone to unbounded growth). Other toolkits may go this route, but
+ // they totally destroy their own ability to manage their memory
+ // footprint. If we implement it, it should only ever be with a fixed
+ // total element reference # limit and an LRU-style algorithm since JS
+ // has no weakref support. Caching compiled query evaluators is also
+ // potentially problematic, but even on large documents the size of the
+ // query evaluators is often < 100 function objects per evaluator (and
+ // LRU can be applied if it's ever shown to be an issue).
+ // * since IE's QSA support is currently only for HTML documents and even
+ // then only in IE 8's "standards mode", we have to detect our dispatch
+ // route at query time and keep 2 separate caches. Ugg.
+
+ // we need to determine if we think we can run a given query via
+ // querySelectorAll or if we'll need to fall back on DOM queries to get
+ // there. We need a lot of information about the environment and the query
+ // to make the determiniation (e.g. does it support QSA, does the query in
+ // question work in the native QSA impl, etc.).
+ var nua = navigator.userAgent;
+ // some versions of Safari provided QSA, but it was buggy and crash-prone.
+ // We need te detect the right "internal" webkit version to make this work.
+ var wk = "WebKit/";
+ var is525 = (
+ dojo.isWebKit &&
+ (nua.indexOf(wk) > 0) &&
+ (parseFloat(nua.split(wk)[1]) > 528)
+ );
+
+ // IE QSA queries may incorrectly include comment nodes, so we throw the
+ // zipping function into "remove" comments mode instead of the normal "skip
+ // it" which every other QSA-clued browser enjoys
+ var noZip = dojo.isIE ? "commentStrip" : "nozip";
+
+ var qsa = "querySelectorAll";
+ var qsaAvail = (
+ !!getDoc()[qsa] &&
+ // see #5832
+ (!dojo.isSafari || (dojo.isSafari > 3.1) || is525 )
+ );
+
+ //Don't bother with n+3 type of matches, IE complains if we modify those.
+ var infixSpaceRe = /n\+\d|([^ ])?([>~+])([^ =])?/g;
+ var infixSpaceFunc = function(match, pre, ch, post){
+ return ch ? (pre ? pre + " " : "") + ch + (post ? " " + post : "") : /*n+3*/ match;
+ };
+
+ var getQueryFunc = function(query, forceDOM){
+ //Normalize query. The CSS3 selectors spec allows for omitting spaces around
+ //infix operators, >, ~ and +
+ //Do the work here since detection for spaces is used as a simple "not use QSA"
+ //test below.
+ query = query.replace(infixSpaceRe, infixSpaceFunc);
+
+ if(qsaAvail){
+ // if we've got a cached variant and we think we can do it, run it!
+ var qsaCached = _queryFuncCacheQSA[query];
+ if(qsaCached && !forceDOM){ return qsaCached; }
+ }
+
+ // else if we've got a DOM cached variant, assume that we already know
+ // all we need to and use it
+ var domCached = _queryFuncCacheDOM[query];
+ if(domCached){ return domCached; }
+
+ // TODO:
+ // today we're caching DOM and QSA branches separately so we
+ // recalc useQSA every time. If we had a way to tag root+query
+ // efficiently, we'd be in good shape to do a global cache.
+
+ var qcz = query.charAt(0);
+ var nospace = (-1 == query.indexOf(" "));
+
+ // byId searches are wicked fast compared to QSA, even when filtering
+ // is required
+ if( (query.indexOf("#") >= 0) && (nospace) ){
+ forceDOM = true;
+ }
+
+ var useQSA = (
+ qsaAvail && (!forceDOM) &&
+ // as per CSS 3, we can't currently start w/ combinator:
+ // http://www.w3.org/TR/css3-selectors/#w3cselgrammar
+ (specials.indexOf(qcz) == -1) &&
+ // IE's QSA impl sucks on pseudos
+ (!dojo.isIE || (query.indexOf(":") == -1)) &&
+
+ (!(cssCaseBug && (query.indexOf(".") >= 0))) &&
+
+ // FIXME:
+ // need to tighten up browser rules on ":contains" and "|=" to
+ // figure out which aren't good
+ // Latest webkit (around 531.21.8) does not seem to do well with :checked on option
+ // elements, even though according to spec, selected options should
+ // match :checked. So go nonQSA for it:
+ // http://bugs.dojotoolkit.org/ticket/5179
+ (query.indexOf(":contains") == -1) && (query.indexOf(":checked") == -1) &&
+ (query.indexOf("|=") == -1) // some browsers don't grok it
+ );
+
+ // TODO:
+ // if we've got a descendant query (e.g., "> .thinger" instead of
+ // just ".thinger") in a QSA-able doc, but are passed a child as a
+ // root, it should be possible to give the item a synthetic ID and
+ // trivially rewrite the query to the form "#synid > .thinger" to
+ // use the QSA branch
+
+
+ if(useQSA){
+ var tq = (specials.indexOf(query.charAt(query.length-1)) >= 0) ?
+ (query + " *") : query;
+ return _queryFuncCacheQSA[query] = function(root){
+ try{
+ // the QSA system contains an egregious spec bug which
+ // limits us, effectively, to only running QSA queries over
+ // entire documents. See:
+ // http://ejohn.org/blog/thoughts-on-queryselectorall/
+ // despite this, we can also handle QSA runs on simple
+ // selectors, but we don't want detection to be expensive
+ // so we're just checking for the presence of a space char
+ // right now. Not elegant, but it's cheaper than running
+ // the query parser when we might not need to
+ if(!((9 == root.nodeType) || nospace)){ throw ""; }
+ var r = root[qsa](tq);
+ // skip expensive duplication checks and just wrap in a NodeList
+ r[noZip] = true;
+ return r;
+ }catch(e){
+ // else run the DOM branch on this query, ensuring that we
+ // default that way in the future
+ return getQueryFunc(query, true)(root);
+ }
+ }
+ }else{
+ // DOM branch
+ var parts = query.split(/\s*,\s*/);
+ return _queryFuncCacheDOM[query] = ((parts.length < 2) ?
+ // if not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher
+ getStepQueryFunc(query) :
+ // if it *is* a complex query, break it up into its
+ // constituent parts and return a dispatcher that will
+ // merge the parts when run
+ function(root){
+ var pindex = 0, // avoid array alloc for every invocation
+ ret = [],
+ tp;
+ while((tp = parts[pindex++])){
+ ret = ret.concat(getStepQueryFunc(tp)(root));
+ }
+ return ret;
+ }
+ );
+ }
+ };
+
+ var _zipIdx = 0;
+
+ // NOTE:
+ // this function is Moo inspired, but our own impl to deal correctly
+ // with XML in IE
+ var _nodeUID = dojo.isIE ? function(node){
+ if(caseSensitive){
+ // XML docs don't have uniqueID on their nodes
+ return (node.getAttribute("_uid") || node.setAttribute("_uid", ++_zipIdx) || _zipIdx);
+
+ }else{
+ return node.uniqueID;
+ }
+ } :
+ function(node){
+ return (node._uid || (node._uid = ++_zipIdx));
+ };
+
+ // determine if a node in is unique in a "bag". In this case we don't want
+ // to flatten a list of unique items, but rather just tell if the item in
+ // question is already in the bag. Normally we'd just use hash lookup to do
+ // this for us but IE's DOM is busted so we can't really count on that. On
+ // the upside, it gives us a built in unique ID function.
+ var _isUnique = function(node, bag){
+ if(!bag){ return 1; }
+ var id = _nodeUID(node);
+ if(!bag[id]){ return bag[id] = 1; }
+ return 0;
+ };
+
+ // attempt to efficiently determine if an item in a list is a dupe,
+ // returning a list of "uniques", hopefully in doucment order
+ var _zipIdxName = "_zipIdx";
+ var _zip = function(arr){
+ if(arr && arr.nozip){
+ return arr;
+ }
+ var ret = [];
+ if(!arr || !arr.length){ return ret; }
+ if(arr[0]){
+ ret.push(arr[0]);
+ }
+ if(arr.length < 2){ return ret; }
+
+ _zipIdx++;
+
+ // we have to fork here for IE and XML docs because we can't set
+ // expandos on their nodes (apparently). *sigh*
+ if(dojo.isIE && caseSensitive){
+ var szidx = _zipIdx+"";
+ arr[0].setAttribute(_zipIdxName, szidx);
+ for(var x = 1, te; te = arr[x]; x++){
+ if(arr[x].getAttribute(_zipIdxName) != szidx){
+ ret.push(te);
+ }
+ te.setAttribute(_zipIdxName, szidx);
+ }
+ }else if(dojo.isIE && arr.commentStrip){
+ try{
+ for(var x = 1, te; te = arr[x]; x++){
+ if(_isElement(te)){
+ ret.push(te);
+ }
+ }
+ }catch(e){ /* squelch */ }
+ }else{
+ if(arr[0]){ arr[0][_zipIdxName] = _zipIdx; }
+ for(var x = 1, te; te = arr[x]; x++){
+ if(arr[x][_zipIdxName] != _zipIdx){
+ ret.push(te);
+ }
+ te[_zipIdxName] = _zipIdx;
+ }
+ }
+ return ret;
+ };
+
+ // the main executor
+ var 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 array.
+ // 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:
+ // --------------------
+ //
+ // acme 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 preceded-by sibling selector
+ // * `+`, the immediately preceded-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`, and `:only-child` positional selectors
+ // * `:empty` content emtpy selector
+ // * `:checked` pseudo 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
+ // manipulation 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 reasonable 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`
+ // * `:*-of-type` pseudo selectors
+ //
+ // dojo.query and XML Documents:
+ // -----------------------------
+ //
+ // `dojo.query` (as of dojo 1.2) supports searching XML documents
+ // in a case-sensitive manner. If an HTML document is served with
+ // a doctype that forces case-sensitivity (e.g., XHTML 1.1
+ // Strict), dojo.query() will detect this and "do the right
+ // thing". Case sensitivity is dependent upon the document being
+ // searched and not the query used. It is therefore possible to
+ // use case-sensitive queries on strict sub-documents (iframes,
+ // etc.) or XML documents while still assuming case-insensitivity
+ // for a host/root document.
+ //
+ // Non-selector Queries:
+ // ---------------------
+ //
+ // If something other than a String is passed for the query,
+ // `dojo.query` will return a new `dojo.NodeList` instance
+ // 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: Array
+ // 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");
+ // | }
+ // | });
+ // | });
+
+ root = root||getDoc();
+ var od = root.ownerDocument||root.documentElement;
+
+ // throw the big case sensitivity switch
+
+ // NOTE:
+ // Opera in XHTML mode doesn't detect case-sensitivity correctly
+ // and it's not clear that there's any way to test for it
+ caseSensitive = (root.contentType && root.contentType=="application/xml") ||
+ (dojo.isOpera && (root.doctype || od.toString() == "[object XMLDocument]")) ||
+ (!!od) &&
+ (dojo.isIE ? od.xml : (root.xmlVersion || od.xmlVersion));
+
+ // NOTE:
+ // adding "true" as the 2nd argument to getQueryFunc is useful for
+ // testing the DOM branch without worrying about the
+ // behavior/performance of the QSA branch.
+ var r = getQueryFunc(query)(root);
+
+ // FIXME:
+ // need to investigate this branch WRT #8074 and #8075
+ if(r && r.nozip){
+ return r;
+ }
+ return _zip(r); // dojo.NodeList
+ };
+ query.filter = function(/*Node[]*/ nodeList, /*String*/ filter, /*String|DOMNode?*/ root){
+ // summary:
+ // function for filtering a NodeList based on a selector, optimized for simple selectors
+ var tmpNodeList = [],
+ parts = getQueryParts(filter),
+ filterFunc =
+ (parts.length == 1 && !/[^\w#\.]/.test(filter)) ?
+ getSimpleFilterFunc(parts[0]) :
+ function(node){
+ return dojo.query(filter, root).indexOf(node) != -1;
+ };
+ for(var x = 0, te; te = nodeList[x]; x++){
+ if(filterFunc(te)){ tmpNodeList.push(te); }
+ }
+ return tmpNodeList;
+ };
+ return query;
+});//end defineQuery
diff --git a/lib/dojo/selector/lite.js b/lib/dojo/selector/lite.js
new file mode 100644
index 000000000..c20fe724b
--- /dev/null
+++ b/lib/dojo/selector/lite.js
@@ -0,0 +1,8 @@
+/*
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
+ Available via Academic Free License >= 2.1 OR the modified BSD license.
+ see: http://dojotoolkit.org/license for details
+*/
+
+//>>built
+define("dojo/selector/lite",["../has","../_base/kernel"],function(_1,_2){"use strict";var _3=document.createElement("div");var _4=_3.matchesSelector||_3.webkitMatchesSelector||_3.mozMatchesSelector||_3.msMatchesSelector||_3.oMatchesSelector;var _5=_3.querySelectorAll;_1.add("dom-matches-selector",!!_4);_1.add("dom-qsa",!!_5);var _6=function(_7,_8){if(_9&&_7.indexOf(",")>-1){return _9(_7,_8);}var _a=(_5?/^([\w]*)#([\w\-]+$)|^(\.)([\w\-\*]+$)|^(\w+$)/:/^([\w]*)#([\w\-]+)(?:\s+(.*))?$|(?:^|(>|.+\s+))([\w\-\*]+)(\S*$)/).exec(_7);_8=_8||document;if(_a){if(_a[2]){var _b=_2.byId?_2.byId(_a[2]):document.getElementById(_a[2]);if(!_b||(_a[1]&&_a[1]!=_b.tagName.toLowerCase())){return [];}if(_8!=document){var _c=_b;while(_c!=_8){_c=_c.parentNode;if(!_c){return [];}}}return _a[3]?_6(_a[3],_b):[_b];}if(_a[3]&&_8.getElementsByClassName){return _8.getElementsByClassName(_a[4]);}var _b;if(_a[5]){_b=_8.getElementsByTagName(_a[5]);if(_a[4]||_a[6]){_7=(_a[4]||"")+_a[6];}else{return _b;}}}if(_5){if(_8.nodeType===1&&_8.nodeName.toLowerCase()!=="object"){return _d(_8,_7,_8.querySelectorAll);}else{return _8.querySelectorAll(_7);}}else{if(!_b){_b=_8.getElementsByTagName("*");}}var _e=[];for(var i=0,l=_b.length;i<l;i++){var _f=_b[i];if(_f.nodeType==1&&_10(_f,_7,_8)){_e.push(_f);}}return _e;};var _d=function(_11,_12,_13){var _14=_11,old=_11.getAttribute("id"),nid=old||"__dojo__",_15=_11.parentNode,_16=/^\s*[+~]/.test(_12);if(_16&&!_15){return [];}if(!old){_11.setAttribute("id",nid);}else{nid=nid.replace(/'/g,"\\$&");}if(_16&&_15){_11=_11.parentNode;}try{return _13.call(_11,"[id='"+nid+"'] "+_12);}finally{if(!old){_14.removeAttribute("id");}}};if(!_1("dom-matches-selector")){var _10=(function(){var _17=_3.tagName=="div"?"toLowerCase":"toUpperCase";function tag(_18){_18=_18[_17]();return function(_19){return _19.tagName==_18;};};function _1a(_1b){var _1c=" "+_1b+" ";return function(_1d){return _1d.className.indexOf(_1b)>-1&&(" "+_1d.className+" ").indexOf(_1c)>-1;};};var _1e={"^=":function(_1f,_20){return _1f.indexOf(_20)==0;},"*=":function(_21,_22){return _21.indexOf(_22)>-1;},"$=":function(_23,_24){return _23.substring(_23.length-_24.length,_23.length)==_24;},"~=":function(_25,_26){return (" "+_25+" ").indexOf(" "+_26+" ")>-1;},"|=":function(_27,_28){return (_27+"-").indexOf(_28+"-")==0;},"=":function(_29,_2a){return _29==_2a;},"":function(_2b,_2c){return true;}};function _2d(_2e,_2f,_30){if(_2f.match(/['"]/)){_2f=eval(_2f);}var _31=_1e[_30||""];return function(_32){var _33=_32.getAttribute(_2e);return _33&&_31(_33,_2f);};};function _34(_35){return function(_36,_37){while((_36=_36.parentNode)!=_37){if(_35(_36,_37)){return true;}}};};function _38(_39){return function(_3a,_3b){_3a=_3a.parentNode;return _39?_3a!=_3b&&_39(_3a,_3b):_3a==_3b;};};var _3c={};function and(_3d,_3e){return _3d?function(_3f,_40){return _3e(_3f)&&_3d(_3f,_40);}:_3e;};return function(_41,_42,_43){var _44=_3c[_42];if(!_44){if(_42.replace(/(?:\s*([> ])\s*)|(\.)?([\w-]+)|\[([\w-]+)\s*(.?=)?\s*([^\]]*)\]/g,function(t,_45,_46,_47,_48,_49,_4a){if(_47){if(_46=="."){_44=and(_44,_1a(_47));}else{_44=and(_44,tag(_47));}}else{if(_45){_44=(_45==" "?_34:_38)(_44);}else{if(_48){_44=and(_44,_2d(_48,_4a,_49));}}}return "";})){throw new Error("Syntax error in query");}if(!_44){return true;}_3c[_42]=_44;}return _44(_41,_43);};})();}if(!_1("dom-qsa")){var _9=function(_4b,_4c){_4b=_4b.split(/\s*,\s*/);var _4d=[];for(var i=0;i<_4b.length;i++){var _4e=_6(_4b[i],_4c);for(var j=0,l=_4e.length;j<l;j++){var _4f=_4e[j];_4d[_4f.sourceIndex]=_4f;}}var _50=[];for(i in _4d){_50.push(_4d[i]);}return _50;};}_6.match=_4?function(_51,_52,_53){if(_53){return _d(_53,_52,function(_54){return _4.call(_51,_54);});}return _4.call(_51,_52);}:_10;return _6;}); \ No newline at end of file
diff --git a/lib/dojo/selector/lite.js.uncompressed.js b/lib/dojo/selector/lite.js.uncompressed.js
new file mode 100644
index 000000000..374f7a2ad
--- /dev/null
+++ b/lib/dojo/selector/lite.js.uncompressed.js
@@ -0,0 +1,264 @@
+define("dojo/selector/lite", ["../has", "../_base/kernel"], function(has, dojo){
+"use strict";
+// summary:
+// A small lightweight query selector engine that implements CSS2.1 selectors
+// minus pseudo-classes and the sibling combinator, plus CSS3 attribute selectors
+var testDiv = document.createElement("div");
+var matchesSelector = testDiv.matchesSelector || testDiv.webkitMatchesSelector || testDiv.mozMatchesSelector || testDiv.msMatchesSelector || testDiv.oMatchesSelector; // IE9, WebKit, Firefox have this, but not Opera yet
+var querySelectorAll = testDiv.querySelectorAll;
+has.add("dom-matches-selector", !!matchesSelector);
+has.add("dom-qsa", !!querySelectorAll);
+
+// this is a simple query engine. It has handles basic selectors, and for simple
+// common selectors is extremely fast
+var liteEngine = function(selector, root){
+ if(combine && selector.indexOf(',') > -1){
+ return combine(selector, root);
+ }
+ var match = (querySelectorAll ?
+ /^([\w]*)#([\w\-]+$)|^(\.)([\w\-\*]+$)|^(\w+$)/ : // this one only matches on simple queries where we can beat qSA with specific methods
+ /^([\w]*)#([\w\-]+)(?:\s+(.*))?$|(?:^|(>|.+\s+))([\w\-\*]+)(\S*$)/) // this one matches parts of the query that we can use to speed up manual filtering
+ .exec(selector);
+ root = root || document;
+ if(match){
+ // fast path regardless of whether or not querySelectorAll exists
+ if(match[2]){
+ // an #id
+ // use dojo.byId if available as it fixes the id retrieval in IE
+ var found = dojo.byId ? dojo.byId(match[2]) : document.getElementById(match[2]);
+ if(!found || (match[1] && match[1] != found.tagName.toLowerCase())){
+ // if there is a tag qualifer and it doesn't match, no matches
+ return [];
+ }
+ if(root != document){
+ // there is a root element, make sure we are a child of it
+ var parent = found;
+ while(parent != root){
+ parent = parent.parentNode;
+ if(!parent){
+ return [];
+ }
+ }
+ }
+ return match[3] ?
+ liteEngine(match[3], found)
+ : [found];
+ }
+ if(match[3] && root.getElementsByClassName){
+ // a .class
+ return root.getElementsByClassName(match[4]);
+ }
+ var found;
+ if(match[5]){
+ // a tag
+ found = root.getElementsByTagName(match[5]);
+ if(match[4] || match[6]){
+ selector = (match[4] || "") + match[6];
+ }else{
+ // that was the entirety of the query, return results
+ return found;
+ }
+ }
+ }
+ if(querySelectorAll){
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ if (root.nodeType === 1 && root.nodeName.toLowerCase() !== "object"){
+ return useRoot(root, selector, root.querySelectorAll);
+ }else{
+ // we can use the native qSA
+ return root.querySelectorAll(selector);
+ }
+ }else if(!found){
+ // search all children and then filter
+ found = root.getElementsByTagName("*");
+ }
+ // now we filter the nodes that were found using the matchesSelector
+ var results = [];
+ for(var i = 0, l = found.length; i < l; i++){
+ var node = found[i];
+ if(node.nodeType == 1 && jsMatchesSelector(node, selector, root)){
+ // keep the nodes that match the selector
+ results.push(node);
+ }
+ }
+ return results;
+};
+var useRoot = function(context, query, method){
+ // this function creates a temporary id so we can do rooted qSA queries, this is taken from sizzle
+ var oldContext = context,
+ old = context.getAttribute( "id" ),
+ nid = old || "__dojo__",
+ hasParent = context.parentNode,
+ relativeHierarchySelector = /^\s*[+~]/.test( query );
+
+ if(relativeHierarchySelector && !hasParent){
+ return [];
+ }
+ if(!old){
+ context.setAttribute("id", nid);
+ }else{
+ nid = nid.replace(/'/g, "\\$&");
+ }
+ if(relativeHierarchySelector && hasParent){
+ context = context.parentNode;
+ }
+
+ try {
+ return method.call(context, "[id='" + nid + "'] " + query );
+ } finally {
+ if ( !old ) {
+ oldContext.removeAttribute( "id" );
+ }
+ }
+};
+
+if(!has("dom-matches-selector")){
+ var jsMatchesSelector = (function(){
+ // a JS implementation of CSS selector matching, first we start with the various handlers
+ var caseFix = testDiv.tagName == "div" ? "toLowerCase" : "toUpperCase";
+ function tag(tagName){
+ tagName = tagName[caseFix]();
+ return function(node){
+ return node.tagName == tagName;
+ }
+ }
+ function className(className){
+ var classNameSpaced = ' ' + className + ' ';
+ return function(node){
+ return node.className.indexOf(className) > -1 && (' ' + node.className + ' ').indexOf(classNameSpaced) > -1;
+ }
+ }
+ var attrComparators = {
+ "^=": function(attrValue, value){
+ return attrValue.indexOf(value) == 0;
+ },
+ "*=": function(attrValue, value){
+ return attrValue.indexOf(value) > -1;
+ },
+ "$=": function(attrValue, value){
+ return attrValue.substring(attrValue.length - value.length, attrValue.length) == value;
+ },
+ "~=": function(attrValue, value){
+ return (' ' + attrValue + ' ').indexOf(' ' + value + ' ') > -1;
+ },
+ "|=": function(attrValue, value){
+ return (attrValue + '-').indexOf(value + '-') == 0;
+ },
+ "=": function(attrValue, value){
+ return attrValue == value;
+ },
+ "": function(attrValue, value){
+ return true;
+ }
+ };
+ function attr(name, value, type){
+ if(value.match(/['"]/)){
+ // it is quoted, do an eval to parse the string (CSS and JS parsing are close enough)
+ value = eval(value);
+ }
+ var comparator = attrComparators[type || ""];
+ return function(node){
+ var attrValue = node.getAttribute(name);
+ return attrValue && comparator(attrValue, value);
+ }
+ }
+ function ancestor(matcher){
+ return function(node, root){
+ while((node = node.parentNode) != root){
+ if(matcher(node, root)){
+ return true;
+ }
+ }
+ };
+ }
+ function parent(matcher){
+ return function(node, root){
+ node = node.parentNode;
+ return matcher ?
+ node != root && matcher(node, root)
+ : node == root;
+ };
+ }
+ var cache = {};
+ function and(matcher, next){
+ return matcher ?
+ function(node, root){
+ return next(node) && matcher(node, root);
+ }
+ : next;
+ }
+ return function(node, selector, root){
+ // this returns true or false based on if the node matches the selector (optionally within the given root)
+ var matcher = cache[selector]; // check to see if we have created a matcher function for the given selector
+ if(!matcher){
+ // create a matcher function for the given selector
+ // parse the selectors
+ if(selector.replace(/(?:\s*([> ])\s*)|(\.)?([\w-]+)|\[([\w-]+)\s*(.?=)?\s*([^\]]*)\]/g, function(t, combinator, type, value, attrName, attrType, attrValue){
+ if(value){
+ if(type == "."){
+ matcher = and(matcher, className(value));
+ }
+ else{
+ matcher = and(matcher, tag(value));
+ }
+ }
+ else if(combinator){
+ matcher = (combinator == " " ? ancestor : parent)(matcher);
+ }
+ else if(attrName){
+ matcher = and(matcher, attr(attrName, attrValue, attrType));
+ }
+ return "";
+ })){
+ throw new Error("Syntax error in query");
+ }
+ if(!matcher){
+ return true;
+ }
+ cache[selector] = matcher;
+ }
+ // now run the matcher function on the node
+ return matcher(node, root);
+ };
+ })();
+}
+if(!has("dom-qsa")){
+ var combine = function(selector, root){
+ // combined queries
+ selector = selector.split(/\s*,\s*/);
+ var indexed = [];
+ // add all results and keep unique ones, this only runs in IE, so we take advantage
+ // of known IE features, particularly sourceIndex which is unique and allows us to
+ // order the results
+ for(var i = 0; i < selector.length; i++){
+ var results = liteEngine(selector[i], root);
+ for(var j = 0, l = results.length; j < l; j++){
+ var node = results[j];
+ indexed[node.sourceIndex] = node;
+ }
+ }
+ // now convert from a sparse array to a dense array
+ var totalResults = [];
+ for(i in indexed){
+ totalResults.push(indexed[i]);
+ }
+ return totalResults;
+ };
+}
+
+liteEngine.match = matchesSelector ? function(node, selector, root){
+ if(root){
+ // doesn't support three args, use rooted id trick
+ return useRoot(root, selector, function(query){
+ return matchesSelector.call(node, query);
+ });
+ }
+ // we have a native matchesSelector, use that
+ return matchesSelector.call(node, selector);
+} : jsMatchesSelector; // otherwise use the JS matches impl
+
+return liteEngine;
+});