From f0cfe83e3725f9a3928da97a6e3085e79cb25309 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Mon, 18 Mar 2013 10:26:24 +0400 Subject: upgrade dojo to 1.8.3 (refs #570) --- lib/dojo/selector/_loader.js | 2 +- lib/dojo/selector/_loader.js.uncompressed.js | 47 + lib/dojo/selector/acme.js | 4 +- lib/dojo/selector/acme.js.uncompressed.js | 1493 ++++++++++++++++++++++++++ lib/dojo/selector/lite.js | 4 +- lib/dojo/selector/lite.js.uncompressed.js | 283 +++++ 6 files changed, 1828 insertions(+), 5 deletions(-) create mode 100644 lib/dojo/selector/_loader.js.uncompressed.js create mode 100644 lib/dojo/selector/acme.js.uncompressed.js create mode 100644 lib/dojo/selector/lite.js.uncompressed.js (limited to 'lib/dojo/selector') diff --git a/lib/dojo/selector/_loader.js b/lib/dojo/selector/_loader.js index 68db99f00..94472f0b8 100644 --- a/lib/dojo/selector/_loader.js +++ b/lib/dojo/selector/_loader.js @@ -1,5 +1,5 @@ /* - Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2012, 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 */ diff --git a/lib/dojo/selector/_loader.js.uncompressed.js b/lib/dojo/selector/_loader.js.uncompressed.js new file mode 100644 index 000000000..8c165c386 --- /dev/null +++ b/lib/dojo/selector/_loader.js.uncompressed.js @@ -0,0 +1,47 @@ +define("dojo/selector/_loader", ["../has", "require"], + function(has, require){ + +"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 = "

"; // 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 { + // summary: + // This module handles loading the appropriate selector engine for the given browser + + 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 index e75fbf0f4..baebc93f5 100644 --- a/lib/dojo/selector/acme.js +++ b/lib/dojo/selector/acme.js @@ -1,8 +1,8 @@ /* - Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2012, 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=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;i0){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 +define("dojo/selector/acme",["../dom","../sniff","../_base/array","../_base/lang","../_base/window"],function(_1,_2,_3,_4,_5){var _6=_4.trim;var _7=_3.forEach;var _8=function(){return _5.doc;};var _9=(_8().compatMode)=="BackCompat";var _a=">~+";var _b=false;var _c=function(){return true;};var _d=function(_e){if(_a.indexOf(_e.slice(-1))>=0){_e+=" * ";}else{_e+=" ";}var ts=function(s,e){return _6(_e.slice(s,e));};var _f=[];var _10=-1,_11=-1,_12=-1,_13=-1,_14=-1,_15=-1,_16=-1,_17,lc="",cc="",_18;var x=0,ql=_e.length,_19=null,_1a=null;var _1b=function(){if(_16>=0){var tv=(_16==x)?null:ts(_16,x);_19[(_a.indexOf(tv)<0)?"tag":"oper"]=tv;_16=-1;}};var _1c=function(){if(_15>=0){_19.id=ts(_15,x).replace(/\\/g,"");_15=-1;}};var _1d=function(){if(_14>=0){_19.classes.push(ts(_14+1,x).replace(/\\/g,""));_14=-1;}};var _1e=function(){_1c();_1b();_1d();};var _1f=function(){_1e();if(_13>=0){_19.pseudos.push({name:ts(_13+1,x)});}_19.loops=(_19.pseudos.length||_19.attrs.length||_19.classes.length);_19.oquery=_19.query=ts(_18,x);_19.otag=_19.tag=(_19["oper"])?null:(_19.tag||"*");if(_19.tag){_19.tag=_19.tag.toUpperCase();}if(_f.length&&(_f[_f.length-1].oper)){_19.infixOper=_f.pop();_19.query=_19.infixOper.query+" "+_19.query;}_f.push(_19);_19=null;};for(;lc=cc,cc=_e.charAt(x),x=0){if(cc=="]"){if(!_1a.attr){_1a.attr=ts(_10+1,x);}else{_1a.matchFor=ts((_12||_10+1),x);}var cmf=_1a.matchFor;if(cmf){if((cmf.charAt(0)=="\"")||(cmf.charAt(0)=="'")){_1a.matchFor=cmf.slice(1,-1);}}if(_1a.matchFor){_1a.matchFor=_1a.matchFor.replace(/\\/g,"");}_19.attrs.push(_1a);_1a=null;_10=_12=-1;}else{if(cc=="="){var _20=("|~^$*".indexOf(lc)>=0)?lc:"";_1a.type=_20+cc;_1a.attr=ts(_10+1,x-_20.length);_12=x+1;}}}else{if(_11>=0){if(cc==")"){if(_13>=0){_1a.value=ts(_11+1,x);}_13=_11=-1;}}else{if(cc=="#"){_1e();_15=x+1;}else{if(cc=="."){_1e();_14=x;}else{if(cc==":"){_1e();_13=x;}else{if(cc=="["){_1e();_10=x;_1a={};}else{if(cc=="("){if(_13>=0){_1a={name:ts(_13+1,x),value:null};_19.pseudos.push(_1a);}_11=x;}else{if((cc==" ")&&(lc!=cc)){_1f();}}}}}}}}}return _f;};var _21=function(_22,_23){if(!_22){return _23;}if(!_23){return _22;}return function(){return _22.apply(window,arguments)&&_23.apply(window,arguments);};};var _24=function(i,arr){var r=arr||[];if(i){r.push(i);}return r;};var _25=function(n){return (1==n.nodeType);};var _26="";var _27=function(_28,_29){if(!_28){return _26;}if(_29=="class"){return _28.className||_26;}if(_29=="for"){return _28.htmlFor||_26;}if(_29=="style"){return _28.style.cssText||_26;}return (_b?_28.getAttribute(_29):_28.getAttribute(_29,2))||_26;};var _2a={"*=":function(_2b,_2c){return function(_2d){return (_27(_2d,_2b).indexOf(_2c)>=0);};},"^=":function(_2e,_2f){return function(_30){return (_27(_30,_2e).indexOf(_2f)==0);};},"$=":function(_31,_32){return function(_33){var ea=" "+_27(_33,_31);var _34=ea.lastIndexOf(_32);return _34>-1&&(_34==(ea.length-_32.length));};},"~=":function(_35,_36){var _37=" "+_36+" ";return function(_38){var ea=" "+_27(_38,_35)+" ";return (ea.indexOf(_37)>=0);};},"|=":function(_39,_3a){var _3b=_3a+"-";return function(_3c){var ea=_27(_3c,_39);return ((ea==_3a)||(ea.indexOf(_3b)==0));};},"=":function(_3d,_3e){return function(_3f){return (_27(_3f,_3d)==_3e);};}};var _40=(typeof _8().firstChild.nextElementSibling=="undefined");var _41=!_40?"nextElementSibling":"nextSibling";var _42=!_40?"previousElementSibling":"previousSibling";var _43=(_40?_25:_c);var _44=function(_45){while(_45=_45[_42]){if(_43(_45)){return false;}}return true;};var _46=function(_47){while(_47=_47[_41]){if(_43(_47)){return false;}}return true;};var _48=function(_49){var _4a=_49.parentNode;_4a=_4a.nodeType!=7?_4a:_4a.nextSibling;var i=0,_4b=_4a.children||_4a.childNodes,ci=(_49["_i"]||_49.getAttribute("_i")||-1),cl=(_4a["_l"]||(typeof _4a.getAttribute!=="undefined"?_4a.getAttribute("_l"):-1));if(!_4b){return -1;}var l=_4b.length;if(cl==l&&ci>=0&&cl>=0){return ci;}if(_2("ie")&&typeof _4a.setAttribute!=="undefined"){_4a.setAttribute("_l",l);}else{_4a["_l"]=l;}ci=-1;for(var te=_4a["firstElementChild"]||_4a["firstChild"];te;te=te[_41]){if(_43(te)){if(_2("ie")){te.setAttribute("_i",++i);}else{te["_i"]=++i;}if(_49===te){ci=i;}}}return ci;};var _4c=function(_4d){return !((_48(_4d))%2);};var _4e=function(_4f){return ((_48(_4f))%2);};var _50={"checked":function(_51,_52){return function(_53){return !!("checked" in _53?_53.checked:_53.selected);};},"disabled":function(_54,_55){return function(_56){return _56.disabled;};},"enabled":function(_57,_58){return function(_59){return !_59.disabled;};},"first-child":function(){return _44;},"last-child":function(){return _46;},"only-child":function(_5a,_5b){return function(_5c){return _44(_5c)&&_46(_5c);};},"empty":function(_5d,_5e){return function(_5f){var cn=_5f.childNodes;var cnl=_5f.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(_60,_61){var cz=_61.charAt(0);if(cz=="\""||cz=="'"){_61=_61.slice(1,-1);}return function(_62){return (_62.innerHTML.indexOf(_61)>=0);};},"not":function(_63,_64){var p=_d(_64)[0];var _65={el:1};if(p.tag!="*"){_65.tag=1;}if(!p.classes.length){_65.classes=1;}var ntf=_66(p,_65);return function(_67){return (!ntf(_67));};},"nth-child":function(_68,_69){var pi=parseInt;if(_69=="odd"){return _4e;}else{if(_69=="even"){return _4c;}}if(_69.indexOf("n")!=-1){var _6a=_69.split("n",2);var _6b=_6a[0]?((_6a[0]=="-")?-1:pi(_6a[0])):1;var idx=_6a[1]?pi(_6a[1]):0;var lb=0,ub=-1;if(_6b>0){if(idx<0){idx=(idx%_6b)&&(_6b+(idx%_6b));}else{if(idx>0){if(idx>=_6b){lb=idx-idx%_6b;}idx=idx%_6b;}}}else{if(_6b<0){_6b*=-1;if(idx>0){ub=idx;idx=idx%_6b;}}}if(_6b>0){return function(_6c){var i=_48(_6c);return (i>=lb)&&(ub<0||i<=ub)&&((i%_6b)==idx);};}else{_69=idx;}}var _6d=pi(_69);return function(_6e){return (_48(_6e)==_6d);};}};var _6f=(_2("ie")<9||_2("ie")==9&&_2("quirks"))?function(_70){var clc=_70.toLowerCase();if(clc=="class"){_70="className";}return function(_71){return (_b?_71.getAttribute(_70):_71[_70]||_71[clc]);};}:function(_72){return function(_73){return (_73&&_73.getAttribute&&_73.hasAttribute(_72));};};var _66=function(_74,_75){if(!_74){return _c;}_75=_75||{};var ff=null;if(!("el" in _75)){ff=_21(ff,_25);}if(!("tag" in _75)){if(_74.tag!="*"){ff=_21(ff,function(_76){return (_76&&((_b?_76.tagName:_76.tagName.toUpperCase())==_74.getTag()));});}}if(!("classes" in _75)){_7(_74.classes,function(_77,idx,arr){var re=new RegExp("(?:^|\\s)"+_77+"(?:\\s|$)");ff=_21(ff,function(_78){return re.test(_78.className);});ff.count=idx;});}if(!("pseudos" in _75)){_7(_74.pseudos,function(_79){var pn=_79.name;if(_50[pn]){ff=_21(ff,_50[pn](pn,_79.value));}});}if(!("attrs" in _75)){_7(_74.attrs,function(_7a){var _7b;var a=_7a.attr;if(_7a.type&&_2a[_7a.type]){_7b=_2a[_7a.type](a,_7a.matchFor);}else{if(a.length){_7b=_6f(a);}}if(_7b){ff=_21(ff,_7b);}});}if(!("id" in _75)){if(_74.id){ff=_21(ff,function(_7c){return (!!_7c&&(_7c.id==_74.id));});}}if(!ff){if(!("default" in _75)){ff=_c;}}return ff;};var _7d=function(_7e){return function(_7f,ret,bag){while(_7f=_7f[_41]){if(_40&&(!_25(_7f))){continue;}if((!bag||_80(_7f,bag))&&_7e(_7f)){ret.push(_7f);}break;}return ret;};};var _81=function(_82){return function(_83,ret,bag){var te=_83[_41];while(te){if(_43(te)){if(bag&&!_80(te,bag)){break;}if(_82(te)){ret.push(te);}}te=te[_41];}return ret;};};var _84=function(_85){_85=_85||_c;return function(_86,ret,bag){var te,x=0,_87=_86.children||_86.childNodes;while(te=_87[x++]){if(_43(te)&&(!bag||_80(te,bag))&&(_85(te,x))){ret.push(te);}}return ret;};};var _88=function(_89,_8a){var pn=_89.parentNode;while(pn){if(pn==_8a){break;}pn=pn.parentNode;}return !!pn;};var _8b={};var _8c=function(_8d){var _8e=_8b[_8d.query];if(_8e){return _8e;}var io=_8d.infixOper;var _8f=(io?io.oper:"");var _90=_66(_8d,{el:1});var qt=_8d.tag;var _91=("*"==qt);var ecs=_8()["getElementsByClassName"];if(!_8f){if(_8d.id){_90=(!_8d.loops&&_91)?_c:_66(_8d,{el:1,id:1});_8e=function(_92,arr){var te=_1.byId(_8d.id,(_92.ownerDocument||_92));if(!te||!_90(te)){return;}if(9==_92.nodeType){return _24(te,arr);}else{if(_88(te,_92)){return _24(te,arr);}}};}else{if(ecs&&/\{\s*\[native code\]\s*\}/.test(String(ecs))&&_8d.classes.length&&!_9){_90=_66(_8d,{el:1,classes:1,id:1});var _93=_8d.classes.join(" ");_8e=function(_94,arr,bag){var ret=_24(0,arr),te,x=0;var _95=_94.getElementsByClassName(_93);while((te=_95[x++])){if(_90(te,_94)&&_80(te,bag)){ret.push(te);}}return ret;};}else{if(!_91&&!_8d.loops){_8e=function(_96,arr,bag){var ret=_24(0,arr),te,x=0;var tag=_8d.getTag(),_97=tag?_96.getElementsByTagName(tag):[];while((te=_97[x++])){if(_80(te,bag)){ret.push(te);}}return ret;};}else{_90=_66(_8d,{el:1,tag:1,id:1});_8e=function(_98,arr,bag){var ret=_24(0,arr),te,x=0;var tag=_8d.getTag(),_99=tag?_98.getElementsByTagName(tag):[];while((te=_99[x++])){if(_90(te,_98)&&_80(te,bag)){ret.push(te);}}return ret;};}}}}else{var _9a={el:1};if(_91){_9a.tag=1;}_90=_66(_8d,_9a);if("+"==_8f){_8e=_7d(_90);}else{if("~"==_8f){_8e=_81(_90);}else{if(">"==_8f){_8e=_84(_90);}}}}return _8b[_8d.query]=_8e;};var _9b=function(_9c,_9d){var _9e=_24(_9c),qp,x,te,qpl=_9d.length,bag,ret;for(var i=0;i0){bag={};ret.nozip=true;}var gef=_8c(qp);for(var j=0;(te=_9e[j]);j++){gef(te,ret,bag);}if(!ret.length){break;}_9e=ret;}return ret;};var _9f={},_a0={};var _a1=function(_a2){var _a3=_d(_6(_a2));if(_a3.length==1){var tef=_8c(_a3[0]);return function(_a4){var r=tef(_a4,[]);if(r){r.nozip=true;}return r;};}return function(_a5){return _9b(_a5,_a3);};};var _a6=_2("ie")?"commentStrip":"nozip";var qsa="querySelectorAll";var _a7=!!_8()[qsa];var _a8=/\\[>~+]|n\+\d|([^ \\])?([>~+])([^ =])?/g;var _a9=function(_aa,pre,ch,_ab){return ch?(pre?pre+" ":"")+ch+(_ab?" "+_ab:""):_aa;};var _ac=/([^[]*)([^\]]*])?/g;var _ad=function(_ae,_af,att){return _af.replace(_a8,_a9)+(att||"");};var _b0=function(_b1,_b2){_b1=_b1.replace(_ac,_ad);if(_a7){var _b3=_a0[_b1];if(_b3&&!_b2){return _b3;}}var _b4=_9f[_b1];if(_b4){return _b4;}var qcz=_b1.charAt(0);var _b5=(-1==_b1.indexOf(" "));if((_b1.indexOf("#")>=0)&&(_b5)){_b2=true;}var _b6=(_a7&&(!_b2)&&(_a.indexOf(qcz)==-1)&&(!_2("ie")||(_b1.indexOf(":")==-1))&&(!(_9&&(_b1.indexOf(".")>=0)))&&(_b1.indexOf(":contains")==-1)&&(_b1.indexOf(":checked")==-1)&&(_b1.indexOf("|=")==-1));if(_b6){var tq=(_a.indexOf(_b1.charAt(_b1.length-1))>=0)?(_b1+" *"):_b1;return _a0[_b1]=function(_b7){try{if(!((9==_b7.nodeType)||_b5)){throw "";}var r=_b7[qsa](tq);r[_a6]=true;return r;}catch(e){return _b0(_b1,true)(_b7);}};}else{var _b8=_b1.match(/([^\s,](?:"(?:\\.|[^"])+"|'(?:\\.|[^'])+'|[^,])*)/g);return _9f[_b1]=((_b8.length<2)?_a1(_b1):function(_b9){var _ba=0,ret=[],tp;while((tp=_b8[_ba++])){ret=ret.concat(_a1(tp)(_b9));}return ret;});}};var _bb=0;var _bc=_2("ie")?function(_bd){if(_b){return (_bd.getAttribute("_uid")||_bd.setAttribute("_uid",++_bb)||_bb);}else{return _bd.uniqueID;}}:function(_be){return (_be._uid||(_be._uid=++_bb));};var _80=function(_bf,bag){if(!bag){return 1;}var id=_bc(_bf);if(!bag[id]){return bag[id]=1;}return 0;};var _c0="_zipIdx";var _c1=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;}_bb++;var x,te;if(_2("ie")&&_b){var _c2=_bb+"";arr[0].setAttribute(_c0,_c2);for(x=1;te=arr[x];x++){if(arr[x].getAttribute(_c0)!=_c2){ret.push(te);}te.setAttribute(_c0,_c2);}}else{if(_2("ie")&&arr.commentStrip){try{for(x=1;te=arr[x];x++){if(_25(te)){ret.push(te);}}}catch(e){}}else{if(arr[0]){arr[0][_c0]=_bb;}for(x=1;te=arr[x];x++){if(arr[x][_c0]!=_bb){ret.push(te);}te[_c0]=_bb;}}}return ret;};var _c3=function(_c4,_c5){_c5=_c5||_8();var od=_c5.ownerDocument||_c5;_b=(od.createElement("div").tagName==="div");var r=_b0(_c4)(_c5);if(r&&r.nozip){return r;}return _c1(r);};_c3.filter=function(_c6,_c7,_c8){var _c9=[],_ca=_d(_c7),_cb=(_ca.length==1&&!/[^\w#\.]/.test(_c7))?_66(_ca[0]):function(_cc){return _3.indexOf(_c3(_c7,_1.byId(_c8)),_cc)!=-1;};for(var x=0,te;te=_c6[x];x++){if(_cb(te)){_c9.push(te);}}return _c9;};return _c3;}); \ 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..6adebb0e5 --- /dev/null +++ b/lib/dojo/selector/acme.js.uncompressed.js @@ -0,0 +1,1493 @@ +define("dojo/selector/acme", [ + "../dom", "../sniff", "../_base/array", "../_base/lang", "../_base/window" +], function(dom, has, array, lang, win){ + + // module: + // dojo/selector/acme + +/* + 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 = lang.trim; + var each = array.forEach; + + var getDoc = function(){ return win.doc; }; + // NOTE(alex): the spec is idiotic. CSS queries should ALWAYS be case-sensitive, but nooooooo + var cssCaseBug = (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, currentQuoteChar, + 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; + } + + // Skip processing all quoted characters. + // If we are inside quoted text then currentQuoteChar stores the character that began the quote, + // thus that character that will end it. + if(currentQuoteChar){ + if(cc == currentQuoteChar){ + currentQuoteChar = null; + } + continue; + }else if (cc == "'" || cc == '"'){ + currentQuoteChar = cc; + continue; + } + + 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); + } + } + // remove backslash escapes from an attribute match, since DOM + // querying will get attribute values without backslashes + if(_cp.matchFor){ + _cp.matchFor = _cp.matchFor.replace(/\\/g, ""); + } + + // 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); + var lastIndex = ea.lastIndexOf(value); + return lastIndex > -1 && (lastIndex==(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; + root = root.nodeType != 7 ? root : root.nextSibling; // PROCESSING_INSTRUCTION_NODE + var i = 0, + tret = root.children || root.childNodes, + ci = (node["_i"]||node.getAttribute("_i")||-1), + cl = (root["_l"]|| (typeof root.getAttribute !== "undefined" ? root.getAttribute("_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 + if(has("ie") && typeof root.setAttribute !== "undefined"){ + root.setAttribute("_l", l); + }else{ + root["_l"] = l; + } + ci = -1; + for(var te = root["firstElementChild"]||root["firstChild"]; te; te = te[_ns]){ + if(_simpleNodeTest(te)){ + if(has("ie")){ + te.setAttribute("_i", ++i); + }else{ + 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); + }; + }, + "disabled": function(name, condition){ + return function(elem){ + return elem.disabled; + }; + }, + "enabled": function(name, condition){ + return function(elem){ + return !elem.disabled; + }; + }, + "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 = (has("ie") < 9 || has("ie") == 9 && has("quirks")) ? 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 && ((caseSensitive ? elem.tagName : elem.tagName.toUpperCase()) == 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; + }; + }; + + // 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 tag = query.getTag(), + tret = tag ? root.getElementsByTagName(tag) : []; + 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 tag = query.getTag(), + tret = tag ? root.getElementsByTagName(tag) : []; + 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 + // guaranteed 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 splitting, 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 determination (e.g. does it support QSA, does the query in + // question work in the native QSA impl, etc.). + + // 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 = has("ie") ? "commentStrip" : "nozip"; + + var qsa = "querySelectorAll"; + var qsaAvail = !!getDoc()[qsa]; + + //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; + }; + + //Don't apply the infixSpaceRe to attribute value selectors + var attRe = /([^[]*)([^\]]*])?/g; + var attFunc = function(match, nonAtt, att){ + return nonAtt.replace(infixSpaceRe, infixSpaceFunc) + (att||""); + }; + 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(attRe, attFunc); + + 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 + (!has("ie") || (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.match(/([^\s,](?:"(?:\\.|[^"])+"|'(?:\\.|[^'])+'|[^,])*)/g); + 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 = has("ie") ? 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 document 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* + var x, te; + if(has("ie") && caseSensitive){ + var szidx = _zipIdx+""; + arr[0].setAttribute(_zipIdxName, szidx); + for(x = 1; te = arr[x]; x++){ + if(arr[x].getAttribute(_zipIdxName) != szidx){ + ret.push(te); + } + te.setAttribute(_zipIdxName, szidx); + } + }else if(has("ie") && arr.commentStrip){ + try{ + for(x = 1; te = arr[x]; x++){ + if(_isElement(te)){ + ret.push(te); + } + } + }catch(e){ /* squelch */ } + }else{ + if(arr[0]){ arr[0][_zipIdxName] = _zipIdx; } + for(x = 1; 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 pseudo-selectors which don't get a lot of day-to-day use: + // - `:root`, `:lang()`, `:target`, `:focus` + // - all visual and state selectors: + // - `:root`, `:active`, `:hover`, `:visited`, `: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 + // 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: + // | + // | + // |

+ // example: + // search the entire document for elements with the classes "foo" *and* "bar": + // | dojo.query(".foo.bar"); + // these elements will match: + // | + // while these will not: + // | + // |

+ // example: + // find `` elements which are descendants of paragraphs and + // which have a "highlighted" class: + // | dojo.query("p span.highlighted"); + // the innermost span in this fragment matches: + // |

+ // | ... + // | ... + // | + // |

+ // 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(); + + // throw the big case sensitivity switch + var od = root.ownerDocument || root; // root is either Document or a node inside the document + caseSensitive = (od.createElement("div").tagName === "div"); + + // 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 array.indexOf(query(filter, dom.byId(root)), node) != -1; + }; + for(var x = 0, te; te = nodeList[x]; x++){ + if(filterFunc(te)){ tmpNodeList.push(te); } + } + return tmpNodeList; + }; + return query; +}); diff --git a/lib/dojo/selector/lite.js b/lib/dojo/selector/lite.js index c20fe724b..881c64ed2 100644 --- a/lib/dojo/selector/lite.js +++ b/lib/dojo/selector/lite.js @@ -1,8 +1,8 @@ /* - Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2012, 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-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-1){return _a(_8,_9);}var _b=_9?_9.ownerDocument||_9:_2.doc||document,_c=(_5?/^([\w]*)#([\w\-]+$)|^(\.)([\w\-\*]+$)|^(\w+$)/:/^([\w]*)#([\w\-]+)(?:\s+(.*))?$|(?:^|(>|.+\s+))([\w\-\*]+)(\S*$)/).exec(_8);_9=_9||_b;if(_c){if(_c[2]){var _d=_2.byId?_2.byId(_c[2]):_b.getElementById(_c[2]);if(!_d||(_c[1]&&_c[1]!=_d.tagName.toLowerCase())){return [];}if(_9!=_b){var _e=_d;while(_e!=_9){_e=_e.parentNode;if(!_e){return [];}}}return _c[3]?_7(_c[3],_d):[_d];}if(_c[3]&&_9.getElementsByClassName){return _9.getElementsByClassName(_c[4]);}var _d;if(_c[5]){_d=_9.getElementsByTagName(_c[5]);if(_c[4]||_c[6]){_8=(_c[4]||"")+_c[6];}else{return _d;}}}if(_5){if(_9.nodeType===1&&_9.nodeName.toLowerCase()!=="object"){return _f(_9,_8,_9.querySelectorAll);}else{return _9.querySelectorAll(_8);}}else{if(!_d){_d=_9.getElementsByTagName("*");}}var _10=[];for(var i=0,l=_d.length;i-1&&(" "+_20.className+" ").indexOf(_1f)>-1;};},"#":function(id){return function(_21){return _21.id==id;};}};var _22={"^=":function(_23,_24){return _23.indexOf(_24)==0;},"*=":function(_25,_26){return _25.indexOf(_26)>-1;},"$=":function(_27,_28){return _27.substring(_27.length-_28.length,_27.length)==_28;},"~=":function(_29,_2a){return (" "+_29+" ").indexOf(" "+_2a+" ")>-1;},"|=":function(_2b,_2c){return (_2b+"-").indexOf(_2c+"-")==0;},"=":function(_2d,_2e){return _2d==_2e;},"":function(_2f,_30){return true;}};function _31(_32,_33,_34){var _35=_33.charAt(0);if(_35=="\""||_35=="'"){_33=_33.slice(1,-1);}_33=_33.replace(/\\/g,"");var _36=_22[_34||""];return function(_37){var _38=_37.getAttribute(_32);return _38&&_36(_38,_33);};};function _39(_3a){return function(_3b,_3c){while((_3b=_3b.parentNode)!=_3c){if(_3a(_3b,_3c)){return true;}}};};function _3d(_3e){return function(_3f,_40){_3f=_3f.parentNode;return _3e?_3f!=_40&&_3e(_3f,_40):_3f==_40;};};var _41={};function and(_42,_43){return _42?function(_44,_45){return _43(_44)&&_42(_44,_45);}:_43;};return function(_46,_47,_48){var _49=_41[_47];if(!_49){if(_47.replace(/(?:\s*([> ])\s*)|(#|\.)?((?:\\.|[\w-])+)|\[\s*([\w-]+)\s*(.?=)?\s*("(?:\\.|[^"])+"|'(?:\\.|[^'])+'|(?:\\.|[^\]])*)\s*\]/g,function(t,_4a,_4b,_4c,_4d,_4e,_4f){if(_4c){_49=and(_49,_1b[_4b||""](_4c.replace(/\\/g,"")));}else{if(_4a){_49=(_4a==" "?_39:_3d)(_49);}else{if(_4d){_49=and(_49,_31(_4d,_4f,_4e));}}}return "";})){throw new Error("Syntax error in query");}if(!_49){return true;}_41[_47]=_49;}return _49(_46,_48);};})();}if(!_1("dom-qsa")){var _a=function(_50,_51){var _52=_50.match(_6);var _53=[];for(var i=0;i<_52.length;i++){_50=new String(_52[i].replace(/\s*$/,""));_50.indexOf=escape;var _54=_7(_50,_51);for(var j=0,l=_54.length;j -1){ + return combine(selector, root); + } + // use the root's ownerDocument if provided, otherwise try to use dojo.doc. Note + // that we don't use dojo/_base/window's doc to reduce dependencies, and + // fallback to plain document if dojo.doc hasn't been defined (by dojo/_base/window). + // presumably we will have a better way to do this in 2.0 + var doc = root ? root.ownerDocument || root : dojo.doc || document, + 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 || doc; + 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, note that we can't use the dojo namespace in 2.0, but if there is a conditional module use, we will use that + var found = dojo.byId ? dojo.byId(match[2]) : doc.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 != doc){ + // 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; + } + var selectors = query.match(unionSplit); + for(var i = 0; i < selectors.length; i++){ + selectors[i] = "[id='" + nid + "'] " + selectors[i]; + } + query = selectors.join(","); + + try{ + return method.call(context, 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"; + var selectorTypes = { + "": function(tagName){ + tagName = tagName[caseFix](); + return function(node){ + return node.tagName == tagName; + }; + }, + ".": function(className){ + var classNameSpaced = ' ' + className + ' '; + return function(node){ + return node.className.indexOf(className) > -1 && (' ' + node.className + ' ').indexOf(classNameSpaced) > -1; + }; + }, + "#": function(id){ + return function(node){ + return node.id == id; + }; + } + }; + 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){ + var firstChar = value.charAt(0); + if(firstChar == '"' || firstChar == "'"){ + // it is quoted, remove the quotes + value = value.slice(1, -1); + } + value = value.replace(/\\/g,''); + 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-])+)|\[\s*([\w-]+)\s*(.?=)?\s*("(?:\\.|[^"])+"|'(?:\\.|[^'])+'|(?:\\.|[^\]])*)\s*\]/g, function(t, combinator, type, value, attrName, attrType, attrValue){ + if(value){ + matcher = and(matcher, selectorTypes[type || ""](value.replace(/\\/g, ''))); + } + 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 + var selectors = selector.match(unionSplit); + 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 < selectors.length; i++){ + selector = new String(selectors[i].replace(/\s*$/,'')); + selector.indexOf = escape; // keep it from recursively entering combine + var results = liteEngine(selector, 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 && root.nodeType != 9){ + // 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; +}); -- cgit v1.2.3