Browse files

v2.0 release

  • Loading branch information...
1 parent 349d2be commit edb9fed40dc224bc03c338be938cb586ef397fa6 @getify committed Jul 12, 2011
Showing with 2,873 additions and 968 deletions.
  1. +1 −1 {next → }/LAB-debug.min.js
  2. +1 −1 {next → }/LAB.js
  3. +2 −2 LAB.min.js
  4. +458 −313 LAB.src.js
  5. +26 −6 README.TXT
  6. +1 −1 fLAB.src.js
  7. +0 −5 next/LAB.min.js
  8. +0 −513 next/LAB.src.js
  9. +0 −9 next/mLAB/anothermodule.js
  10. +0 −33 next/mLAB/example.html
  11. +0 −41 next/mLAB/mLAB.src.js
  12. +0 −18 next/mLAB/mymodule.js
  13. +0 −7 next/mLAB/someothermodule.js
  14. +0 −8 next/mLAB/yetanothermodule.js
  15. BIN tests/img1.jpg
  16. BIN tests/img2.jpg
  17. +0 −10 tests/test-1.html
  18. +58 −0 tests/test-LABjs-preloading-1.html
  19. +59 −0 tests/test-LABjs-preloading-10.html
  20. +59 −0 tests/test-LABjs-preloading-11.html
  21. +79 −0 tests/test-LABjs-preloading-12a.html
  22. +83 −0 tests/test-LABjs-preloading-12b.html
  23. +84 −0 tests/test-LABjs-preloading-12c.html
  24. +85 −0 tests/test-LABjs-preloading-12d.html
  25. +89 −0 tests/test-LABjs-preloading-12e.html
  26. +89 −0 tests/test-LABjs-preloading-12f.html
  27. +89 −0 tests/test-LABjs-preloading-12g.html
  28. +78 −0 tests/test-LABjs-preloading-13a.html
  29. +82 −0 tests/test-LABjs-preloading-13b.html
  30. +83 −0 tests/test-LABjs-preloading-13c.html
  31. +84 −0 tests/test-LABjs-preloading-13d.html
  32. +87 −0 tests/test-LABjs-preloading-13e.html
  33. +89 −0 tests/test-LABjs-preloading-13f.html
  34. +89 −0 tests/test-LABjs-preloading-13g.html
  35. +72 −0 tests/test-LABjs-preloading-14a.html
  36. +70 −0 tests/test-LABjs-preloading-14b.html
  37. +73 −0 tests/test-LABjs-preloading-14c.html
  38. +74 −0 tests/test-LABjs-preloading-14d.html
  39. +77 −0 tests/test-LABjs-preloading-14e.html
  40. +59 −0 tests/test-LABjs-preloading-15.html
  41. +59 −0 tests/test-LABjs-preloading-16.html
  42. +60 −0 tests/test-LABjs-preloading-2.html
  43. +58 −0 tests/test-LABjs-preloading-3.html
  44. +61 −0 tests/test-LABjs-preloading-4.html
  45. +58 −0 tests/test-LABjs-preloading-5.html
  46. +55 −0 tests/test-LABjs-preloading-6.html
  47. +56 −0 tests/test-LABjs-preloading-7.html
  48. +83 −0 tests/test-LABjs-preloading-8.html
  49. +59 −0 tests/test-LABjs-preloading-9.html
  50. +6 −0 tests/testscript1.js
  51. +6 −0 tests/testscript2.js
  52. +7 −0 tests/testscript3.js
  53. +6 −0 tests/testscript3b.js
  54. +6 −0 tests/testscript4.js
  55. +6 −0 tests/testscript5.js
  56. +7 −0 tests/testscript6.js
View
2 next/LAB-debug.min.js → LAB-debug.min.js
@@ -1,5 +1,5 @@
/*! LAB.js (LABjs :: Loading And Blocking JavaScript)
- v2.0b3 (c) Kyle Simpson
+ v2.0 (c) Kyle Simpson
MIT License
*/
(function(j){var N=j.$LAB,A="UseLocalXHR",B="AlwaysPreserveOrder",w="AllowDuplicates",C="CacheBust",l="Debug",D="BasePath",E=/^[^?#]*\//.exec(location.href)[0],F=/^\w+\:\/\/\/?[^\/]+/.exec(E)[0],i=document.head||document.getElementsByTagName("head"),O=(j.opera&&Object.prototype.toString.call(j.opera)=="[object Opera]")||("MozAppearance"in document.documentElement.style),m=function(){},G=m,s=document.createElement("script"),H=typeof s.preload=="boolean",t=H||(s.readyState&&s.readyState=="uninitialized"),I=!t&&s.async===true,P=!t&&!I&&!O;if(j.console&&j.console.log){if(!j.console.error)j.console.error=j.console.log;m=function(a){j.console.log(a)};G=function(a,c){j.console.error(a,c)}}function J(a){return Object.prototype.toString.call(a)=="[object Function]"}function K(a){return Object.prototype.toString.call(a)=="[object Array]"}function Q(a,c){var b=/^\w+\:\/\//;if(/^\/\/\/?/.test(a)){a=location.protocol+a}else if(!b.test(a)&&a[0]!="/"){a=(c||"")+a}return b.test(a)?a:((a[0]=="/"?F:E)+a)}function u(a,c){for(var b in a){if(a.hasOwnProperty(b)){c[b]=a[b]}}return c}function R(a){var c=false;for(var b=0;b<a.scripts.length;b++){if(a.scripts[b].ready&&a.scripts[b].exec_trigger){c=true;a.scripts[b].exec_trigger();a.scripts[b].exec_trigger=null}}return c}function v(a,c,b,d){a.onload=a.onreadystatechange=function(){if((a.readyState&&a.readyState!="complete"&&a.readyState!="loaded")||c[b])return;a.onload=a.onreadystatechange=null;d()}}function L(a){a.ready=a.finished=true;for(var c=0;c<a.finished_listeners.length;c++){setTimeout(a.finished_listeners[c],0)}a.ready_listeners=[];a.finished_listeners=[]}function S(d,g,e,f,h){setTimeout(function(){var a,c=g.real_src,b;if("item"in i){if(!i[0]){setTimeout(arguments.callee,25);return}i=i[0]}a=document.createElement("script");if(g.type)a.type=g.type;if(g.charset)a.charset=g.charset;if(h){if(t){if(d[l])m("start script preload: "+c);e.elem=a;if(H){a.preload=true;a.onpreload=f}else{a.onreadystatechange=function(){if(a.readyState=="loaded")f();a.onreadystatechange=null}}a.src=c}else if(h&&c.indexOf(F)==0&&d[A]){b=new XMLHttpRequest();if(d[l])m("start script preload (xhr): "+c);b.onreadystatechange=function(){if(b.readyState==4){b.onreadystatechange=function(){};e.text=b.responseText+"\n//@ sourceURL="+c;f()}};b.open("GET",c);b.send()}else{if(d[l])m("start script preload (cache): "+c);a.type="text/cache-script";v(a,e,"ready",function(){i.removeChild(a);f()});a.src=c;i.insertBefore(a,i.firstChild)}}else if(I){if(d[l])m("start script load (ordered async): "+c);a.async=false;v(a,e,"finished",f);a.src=c;i.insertBefore(a,i.firstChild)}else{if(d[l])m("start script load: "+c);v(a,e,"finished",f);a.src=c;i.insertBefore(a,i.firstChild)}},0)}function M(){var o={},T=t||P,q=[],r={},p;o[A]=true;o[B]=false;o[w]=false;o[C]=false;o[l]=false;o[D]="";function U(a,c,b){var d;function g(){if(d!=null){L(b);d=null}}if(r[c.src].finished)return;if(!a[w])r[c.src].finished=true;d=b.elem||document.createElement("script");if(c.type)d.type=c.type;if(c.charset)d.charset=c.charset;v(d,b,"finished",g);if(b.elem){b.elem=null}else if(b.text){d.onload=d.onreadystatechange=null;d.text=b.text}else{d.src=c.real_src}i.insertBefore(d,i.firstChild);if(b.text){g()}}function V(c,b,d,g){var e,f,h=function(){b.ready_cb(b,function(){U(c,b,e)})},k=function(){b.finished_cb(b,d)};b.src=Q(b.src,c[D]);b.real_src=b.src+(c[C]?((/\?.*$/.test(b.src)?"&_":"?_")+~~(Math.random()*1E9)+"="):"");if(!r[b.src])r[b.src]={items:[],finished:false};f=r[b.src].items;if(c[w]||f.length==0){e=f[f.length]={ready:false,finished:false,ready_listeners:[h],finished_listeners:[k]};S(c,b,e,((g)?function(){e.ready=true;for(var a=0;a<e.ready_listeners.length;a++){setTimeout(e.ready_listeners[a],0)}e.ready_listeners=[]}:function(){L(e)}),g)}else{e=f[0];if(e.finished){setTimeout(k,0)}else{e.finished_listeners.push(k)}}}function x(){var e,f=u(o,{}),h=[],k=0,y=false,n;function W(a,c){if(f[l])m("script preload finished: "+a.real_src);a.ready=true;a.exec_trigger=c;z()}function X(a,c){if(f[l])m("script execution finished: "+a.real_src);a.ready=a.finished=true;a.exec_trigger=null;for(var b=0;b<c.scripts.length;b++){if(!c.scripts[b].finished)return}c.finished=true;z()}function z(){while(k<h.length){if(J(h[k])){if(f[l])m("$LAB.wait() executing: "+h[k]);try{h[k]()}catch(err){if(f[l])G("$LAB.wait() error caught: ",err)}}else if(!h[k].finished){if(R(h[k]))continue;break}k++}if(k==h.length){y=false;n=false}}function Y(){if(!n||!n.scripts){h.push(n={scripts:[],finished:true})}}e={script:function(){for(var g=0;g<arguments.length;g++){(function(a,c){var b;if(!K(a)){c=[a]}for(var d=0;d<c.length;d++){Y();a=c[d];if(J(a))a=a();if(!a)continue;if(K(a)){b=[].slice.call(a);b.push(d,1);c.splice.call(c,b);d--;continue}if(typeof a=="string")a={src:a};a=u(a,{ready:false,ready_cb:W,finished:false,finished_cb:X});n.finished=false;n.scripts.push(a);V(f,a,n,(T&&y));y=true;if(f[B])e.wait()}})(arguments[g],arguments[g])}return e},wait:function(){if(arguments.length>0){for(var a=0;a<arguments.length;a++){h.push(arguments[a])}n=h[h.length-1]}else n=false;z();return e}};return{script:e.script,wait:e.wait,setOptions:function(a){u(a,f);return e}}}p={setGlobalDefaults:function(a){u(a,o);return p},setOptions:function(){return x().setOptions.apply(null,arguments)},script:function(){return x().script.apply(null,arguments)},wait:function(){return x().wait.apply(null,arguments)},queueScript:function(){q[q.length]={type:"script",args:[].slice.call(arguments)};return p},queueWait:function(){q[q.length]={type:"wait",args:[].slice.call(arguments)};return p},runQueue:function(){var a=p,c=q.length,b=c,d;for(;--b>=0;){d=q.shift();a=a[d.type].apply(null,d.args)}return a},noConflict:function(){j.$LAB=N;return p},sandbox:function(){return M()}};return p}j.$LAB=M();(function(a,c,b){if(document.readyState==null&&document[a]){document.readyState="loading";document[a](c,b=function(){document.removeEventListener(c,b,false);document.readyState="complete"},false)}})("addEventListener","DOMContentLoaded")})(this);
View
2 next/LAB.js → LAB.js
@@ -1,5 +1,5 @@
/*! LAB.js (LABjs :: Loading And Blocking JavaScript)
- v2.0b3 (c) Kyle Simpson
+ v2.0 (c) Kyle Simpson
MIT License
*/
(function(o){var K=o.$LAB,y="UseLocalXHR",z="AlwaysPreserveOrder",u="AllowDuplicates",A="CacheBust",B="BasePath",C=/^[^?#]*\//.exec(location.href)[0],D=/^\w+\:\/\/\/?[^\/]+/.exec(C)[0],i=document.head||document.getElementsByTagName("head"),L=(o.opera&&Object.prototype.toString.call(o.opera)=="[object Opera]")||("MozAppearance"in document.documentElement.style),q=document.createElement("script"),E=typeof q.preload=="boolean",r=E||(q.readyState&&q.readyState=="uninitialized"),F=!r&&q.async===true,M=!r&&!F&&!L;function G(a){return Object.prototype.toString.call(a)=="[object Function]"}function H(a){return Object.prototype.toString.call(a)=="[object Array]"}function N(a,c){var b=/^\w+\:\/\//;if(/^\/\/\/?/.test(a)){a=location.protocol+a}else if(!b.test(a)&&a[0]!="/"){a=(c||"")+a}return b.test(a)?a:((a[0]=="/"?D:C)+a)}function s(a,c){for(var b in a){if(a.hasOwnProperty(b)){c[b]=a[b]}}return c}function O(a){var c=false;for(var b=0;b<a.scripts.length;b++){if(a.scripts[b].ready&&a.scripts[b].exec_trigger){c=true;a.scripts[b].exec_trigger();a.scripts[b].exec_trigger=null}}return c}function t(a,c,b,d){a.onload=a.onreadystatechange=function(){if((a.readyState&&a.readyState!="complete"&&a.readyState!="loaded")||c[b])return;a.onload=a.onreadystatechange=null;d()}}function I(a){a.ready=a.finished=true;for(var c=0;c<a.finished_listeners.length;c++){setTimeout(a.finished_listeners[c],0)}a.ready_listeners=[];a.finished_listeners=[]}function P(d,f,e,g,h){setTimeout(function(){var a,c=f.real_src,b;if("item"in i){if(!i[0]){setTimeout(arguments.callee,25);return}i=i[0]}a=document.createElement("script");if(f.type)a.type=f.type;if(f.charset)a.charset=f.charset;if(h){if(r){e.elem=a;if(E){a.preload=true;a.onpreload=g}else{a.onreadystatechange=function(){if(a.readyState=="loaded")g();a.onreadystatechange=null}}a.src=c}else if(h&&c.indexOf(D)==0&&d[y]){b=new XMLHttpRequest();b.onreadystatechange=function(){if(b.readyState==4){b.onreadystatechange=function(){};e.text=b.responseText+"\n//@ sourceURL="+c;g()}};b.open("GET",c);b.send()}else{a.type="text/cache-script";t(a,e,"ready",function(){i.removeChild(a);g()});a.src=c;i.insertBefore(a,i.firstChild)}}else if(F){a.async=false;t(a,e,"finished",g);a.src=c;i.insertBefore(a,i.firstChild)}else{t(a,e,"finished",g);a.src=c;i.insertBefore(a,i.firstChild)}},0)}function J(){var l={},Q=r||M,n=[],p={},m;l[y]=true;l[z]=false;l[u]=false;l[A]=false;l[B]="";function R(a,c,b){var d;function f(){if(d!=null){I(b);d=null}}if(p[c.src].finished)return;if(!a[u])p[c.src].finished=true;d=b.elem||document.createElement("script");if(c.type)d.type=c.type;if(c.charset)d.charset=c.charset;t(d,b,"finished",f);if(b.elem){b.elem=null}else if(b.text){d.onload=d.onreadystatechange=null;d.text=b.text}else{d.src=c.real_src}i.insertBefore(d,i.firstChild);if(b.text){f()}}function S(c,b,d,f){var e,g,h=function(){b.ready_cb(b,function(){R(c,b,e)})},j=function(){b.finished_cb(b,d)};b.src=N(b.src,c[B]);b.real_src=b.src+(c[A]?((/\?.*$/.test(b.src)?"&_":"?_")+~~(Math.random()*1E9)+"="):"");if(!p[b.src])p[b.src]={items:[],finished:false};g=p[b.src].items;if(c[u]||g.length==0){e=g[g.length]={ready:false,finished:false,ready_listeners:[h],finished_listeners:[j]};P(c,b,e,((f)?function(){e.ready=true;for(var a=0;a<e.ready_listeners.length;a++){setTimeout(e.ready_listeners[a],0)}e.ready_listeners=[]}:function(){I(e)}),f)}else{e=g[0];if(e.finished){setTimeout(j,0)}else{e.finished_listeners.push(j)}}}function v(){var e,g=s(l,{}),h=[],j=0,w=false,k;function T(a,c){a.ready=true;a.exec_trigger=c;x()}function U(a,c){a.ready=a.finished=true;a.exec_trigger=null;for(var b=0;b<c.scripts.length;b++){if(!c.scripts[b].finished)return}c.finished=true;x()}function x(){while(j<h.length){if(G(h[j])){try{h[j]()}catch(err){}}else if(!h[j].finished){if(O(h[j]))continue;break}j++}if(j==h.length){w=false;k=false}}function V(){if(!k||!k.scripts){h.push(k={scripts:[],finished:true})}}e={script:function(){for(var f=0;f<arguments.length;f++){(function(a,c){var b;if(!H(a)){c=[a]}for(var d=0;d<c.length;d++){V();a=c[d];if(G(a))a=a();if(!a)continue;if(H(a)){b=[].slice.call(a);b.push(d,1);c.splice.call(c,b);d--;continue}if(typeof a=="string")a={src:a};a=s(a,{ready:false,ready_cb:T,finished:false,finished_cb:U});k.finished=false;k.scripts.push(a);S(g,a,k,(Q&&w));w=true;if(g[z])e.wait()}})(arguments[f],arguments[f])}return e},wait:function(){if(arguments.length>0){for(var a=0;a<arguments.length;a++){h.push(arguments[a])}k=h[h.length-1]}else k=false;x();return e}};return{script:e.script,wait:e.wait,setOptions:function(a){s(a,g);return e}}}m={setGlobalDefaults:function(a){s(a,l);return m},setOptions:function(){return v().setOptions.apply(null,arguments)},script:function(){return v().script.apply(null,arguments)},wait:function(){return v().wait.apply(null,arguments)},queueScript:function(){n[n.length]={type:"script",args:[].slice.call(arguments)};return m},queueWait:function(){n[n.length]={type:"wait",args:[].slice.call(arguments)};return m},runQueue:function(){var a=m,c=n.length,b=c,d;for(;--b>=0;){d=n.shift();a=a[d.type].apply(null,d.args)}return a},noConflict:function(){o.$LAB=K;return m},sandbox:function(){return J()}};return m}o.$LAB=J();(function(a,c,b){if(document.readyState==null&&document[a]){document.readyState="loading";document[a](c,b=function(){document.removeEventListener(c,b,false);document.readyState="complete"},false)}})("addEventListener","DOMContentLoaded")})(this);
View
4 LAB.min.js
@@ -1,5 +1,5 @@
/*! LAB.js (LABjs :: Loading And Blocking JavaScript)
- v1.2.0 (c) Kyle Simpson
+ v2.0 (c) Kyle Simpson
MIT License
*/
-(function(p){var q="string",w="head",L="body",M="script",u="readyState",j="preloaddone",x="loadtrigger",N="srcuri",E="preload",Z="complete",y="done",z="which",O="preserve",F="onreadystatechange",ba="onload",P="hasOwnProperty",bb="script/cache",Q="[object ",bw=Q+"Function]",bx=Q+"Array]",e=null,h=true,i=false,k=p.document,bc=p.location,bd=p.ActiveXObject,A=p.setTimeout,be=p.clearTimeout,R=function(a){return k.getElementsByTagName(a)},S=Object.prototype.toString,G=function(){},r={},T={},bf=/^[^?#]*\//.exec(bc.href)[0],bg=/^\w+\:\/\/\/?[^\/]+/.exec(bf)[0],by=R(M),bh=p.opera&&S.call(p.opera)==Q+"Opera]",bi=("MozAppearance"in k.documentElement.style),bj=(k.createElement(M).async===true),v={cache:!(bi||bh),order:bi||bh||bj,xhr:h,dupe:h,base:"",which:w};v[O]=i;v[E]=h;r[w]=k.head||R(w);r[L]=R(L);function B(a){return S.call(a)===bw}function U(a,b){var c=/^\w+\:\/\//,d;if(typeof a!=q)a="";if(typeof b!=q)b="";d=((/^\/\//.test(a))?bc.protocol:"")+a;d=(c.test(d)?"":b)+d;return((c.test(d)?"":(d.charAt(0)==="/"?bg:bf))+d)}function bz(a){return(U(a).indexOf(bg)===0)}function bA(a){var b,c=-1;while(b=by[++c]){if(typeof b.src==q&&a===U(b.src)&&b.type!==bb)return h}return i}function H(t,l){t=!(!t);if(l==e)l=v;var bk=i,C=t&&l[E],bl=C&&l.cache,I=C&&l.order,bm=C&&l.xhr,bB=l[O],bC=l.which,bD=l.base,bn=G,J=i,D,s=h,m={},K=[],V=e;C=bl||bm||I;function bo(a,b){if((a[u]&&a[u]!==Z&&a[u]!=="loaded")||b[y]){return i}a[ba]=a[F]=e;return h}function W(a,b,c){c=!(!c);if(!c&&!(bo(a,b)))return;b[y]=h;for(var d in m){if(m[P](d)&&!(m[d][y]))return}bk=h;bn()}function bp(a){if(B(a[x])){a[x]();a[x]=e}}function bE(a,b){if(!bo(a,b))return;b[j]=h;A(function(){r[b[z]].removeChild(a);bp(b)},0)}function bF(a,b){if(a[u]===4){a[F]=G;b[j]=h;A(function(){bp(b)},0)}}function X(b,c,d,g,f,n){var o=b[z];A(function(){if("item"in r[o]){if(!r[o][0]){A(arguments.callee,25);return}r[o]=r[o][0]}var a=k.createElement(M);if(typeof d==q)a.type=d;if(typeof g==q)a.charset=g;if(B(f)){a[ba]=a[F]=function(){f(a,b)};a.src=c;if(bj){a.async=i}}r[o].insertBefore(a,(o===w?r[o].firstChild:e));if(typeof n==q){a.text=n;W(a,b,h)}},0)}function bq(a,b,c,d){T[a[N]]=h;X(a,b,c,d,W)}function br(a,b,c,d){var g=arguments;if(s&&a[j]==e){a[j]=i;X(a,b,bb,d,bE)}else if(!s&&a[j]!=e&&!a[j]){a[x]=function(){br.apply(e,g)}}else if(!s){bq.apply(e,g)}}function bs(a,b,c,d){var g=arguments,f;if(s&&a[j]==e){a[j]=i;f=a.xhr=(bd?new bd("Microsoft.XMLHTTP"):new p.XMLHttpRequest());f[F]=function(){bF(f,a)};f.open("GET",b);f.send("")}else if(!s&&a[j]!=e&&!a[j]){a[x]=function(){bs.apply(e,g)}}else if(!s){T[a[N]]=h;X(a,b,c,d,e,a.xhr.responseText);a.xhr=e}}function bt(a){if(typeof a=="undefined"||!a)return;if(a.allowDup==e)a.allowDup=l.dupe;var b=a.src,c=a.type,d=a.charset,g=a.allowDup,f=U(b,bD),n,o=bz(f);if(typeof d!=q)d=e;g=!(!g);if(!g&&((T[f]!=e)||(s&&m[f])||bA(f))){if(m[f]!=e&&m[f][j]&&!m[f][y]&&o){W(e,m[f],h)}return}if(m[f]==e)m[f]={};n=m[f];if(n[z]==e)n[z]=bC;n[y]=i;n[N]=f;J=h;if(!I&&bm&&o)bs(n,f,c,d);else if(!I&&bl)br(n,f,c,d);else bq(n,f,c,d)}function Y(a){if(t&&!I)K.push(a);if(!t||C)a()}function bu(a){var b=[],c;for(c=-1;++c<a.length;){if(S.call(a[c])===bx)b=b.concat(bu(a[c]));else b[b.length]=a[c]}return b}D={script:function(){be(V);var a=bu(arguments),b=D,c;if(bB){for(c=-1;++c<a.length;){if(B(a[c]))a[c]=a[c]();if(c===0){Y(function(){bt((typeof a[0]==q)?{src:a[0]}:a[0])})}else b=b.script(a[c]);b=b.wait()}}else{for(c=-1;++c<a.length;){if(B(a[c]))a[c]=a[c]()}Y(function(){for(c=-1;++c<a.length;){bt((typeof a[c]==q)?{src:a[c]}:a[c])}})}V=A(function(){s=i},5);return b},wait:function(a){be(V);s=i;if(!B(a))a=G;var b=H(t||J,l),c=b.trigger,d=function(){try{a()}catch(err){}c()};delete b.trigger;var g=function(){if(J&&!bk)bn=d;else d()};if(t&&!J)K.push(g);else Y(g);return b}};if(t){D.trigger=function(){var a,b=-1;while(a=K[++b])a();K=[]}}else D.trigger=G;return D}function bv(a){var b,c={},d={"UseCachePreload":"cache","UseLocalXHR":"xhr","UsePreloading":E,"AlwaysPreserveOrder":O,"AllowDuplicates":"dupe"},g={"AppendTo":z,"BasePath":"base"};for(b in d)g[b]=d[b];c.order=!(!v.order);for(b in g){if(g[P](b)&&v[g[b]]!=e)c[g[b]]=(a[b]!=e)?a[b]:v[g[b]]}for(b in d){if(d[P](b))c[d[b]]=!(!c[d[b]])}if(!c[E])c.cache=c.order=c.xhr=i;c.which=(c.which===w||c.which===L)?c.which:w;return c}p.$LAB={setGlobalDefaults:function(a){v=bv(a)},setOptions:function(a){return H(i,bv(a))},script:function(){return H().script.apply(e,arguments)},wait:function(){return H().wait.apply(e,arguments)}};(function(a,b,c){if(k[u]==e&&k[a]){k[u]="loading";k[a](b,c=function(){k.removeEventListener(b,c,i);k[u]=Z},i)}})("addEventListener","DOMContentLoaded")})(window);
+(function(o){var K=o.$LAB,y="UseLocalXHR",z="AlwaysPreserveOrder",u="AllowDuplicates",A="CacheBust",B="BasePath",C=/^[^?#]*\//.exec(location.href)[0],D=/^\w+\:\/\/\/?[^\/]+/.exec(C)[0],i=document.head||document.getElementsByTagName("head"),L=(o.opera&&Object.prototype.toString.call(o.opera)=="[object Opera]")||("MozAppearance"in document.documentElement.style),q=document.createElement("script"),E=typeof q.preload=="boolean",r=E||(q.readyState&&q.readyState=="uninitialized"),F=!r&&q.async===true,M=!r&&!F&&!L;function G(a){return Object.prototype.toString.call(a)=="[object Function]"}function H(a){return Object.prototype.toString.call(a)=="[object Array]"}function N(a,c){var b=/^\w+\:\/\//;if(/^\/\/\/?/.test(a)){a=location.protocol+a}else if(!b.test(a)&&a[0]!="/"){a=(c||"")+a}return b.test(a)?a:((a[0]=="/"?D:C)+a)}function s(a,c){for(var b in a){if(a.hasOwnProperty(b)){c[b]=a[b]}}return c}function O(a){var c=false;for(var b=0;b<a.scripts.length;b++){if(a.scripts[b].ready&&a.scripts[b].exec_trigger){c=true;a.scripts[b].exec_trigger();a.scripts[b].exec_trigger=null}}return c}function t(a,c,b,d){a.onload=a.onreadystatechange=function(){if((a.readyState&&a.readyState!="complete"&&a.readyState!="loaded")||c[b])return;a.onload=a.onreadystatechange=null;d()}}function I(a){a.ready=a.finished=true;for(var c=0;c<a.finished_listeners.length;c++){setTimeout(a.finished_listeners[c],0)}a.ready_listeners=[];a.finished_listeners=[]}function P(d,f,e,g,h){setTimeout(function(){var a,c=f.real_src,b;if("item"in i){if(!i[0]){setTimeout(arguments.callee,25);return}i=i[0]}a=document.createElement("script");if(f.type)a.type=f.type;if(f.charset)a.charset=f.charset;if(h){if(r){e.elem=a;if(E){a.preload=true;a.onpreload=g}else{a.onreadystatechange=function(){if(a.readyState=="loaded")g();a.onreadystatechange=null}}a.src=c}else if(h&&c.indexOf(D)==0&&d[y]){b=new XMLHttpRequest();b.onreadystatechange=function(){if(b.readyState==4){b.onreadystatechange=function(){};e.text=b.responseText+"\n//@ sourceURL="+c;g()}};b.open("GET",c);b.send()}else{a.type="text/cache-script";t(a,e,"ready",function(){i.removeChild(a);g()});a.src=c;i.insertBefore(a,i.firstChild)}}else if(F){a.async=false;t(a,e,"finished",g);a.src=c;i.insertBefore(a,i.firstChild)}else{t(a,e,"finished",g);a.src=c;i.insertBefore(a,i.firstChild)}},0)}function J(){var l={},Q=r||M,n=[],p={},m;l[y]=true;l[z]=false;l[u]=false;l[A]=false;l[B]="";function R(a,c,b){var d;function f(){if(d!=null){I(b);d=null}}if(p[c.src].finished)return;if(!a[u])p[c.src].finished=true;d=b.elem||document.createElement("script");if(c.type)d.type=c.type;if(c.charset)d.charset=c.charset;t(d,b,"finished",f);if(b.elem){b.elem=null}else if(b.text){d.onload=d.onreadystatechange=null;d.text=b.text}else{d.src=c.real_src}i.insertBefore(d,i.firstChild);if(b.text){f()}}function S(c,b,d,f){var e,g,h=function(){b.ready_cb(b,function(){R(c,b,e)})},j=function(){b.finished_cb(b,d)};b.src=N(b.src,c[B]);b.real_src=b.src+(c[A]?((/\?.*$/.test(b.src)?"&_":"?_")+~~(Math.random()*1E9)+"="):"");if(!p[b.src])p[b.src]={items:[],finished:false};g=p[b.src].items;if(c[u]||g.length==0){e=g[g.length]={ready:false,finished:false,ready_listeners:[h],finished_listeners:[j]};P(c,b,e,((f)?function(){e.ready=true;for(var a=0;a<e.ready_listeners.length;a++){setTimeout(e.ready_listeners[a],0)}e.ready_listeners=[]}:function(){I(e)}),f)}else{e=g[0];if(e.finished){setTimeout(j,0)}else{e.finished_listeners.push(j)}}}function v(){var e,g=s(l,{}),h=[],j=0,w=false,k;function T(a,c){a.ready=true;a.exec_trigger=c;x()}function U(a,c){a.ready=a.finished=true;a.exec_trigger=null;for(var b=0;b<c.scripts.length;b++){if(!c.scripts[b].finished)return}c.finished=true;x()}function x(){while(j<h.length){if(G(h[j])){try{h[j]()}catch(err){}}else if(!h[j].finished){if(O(h[j]))continue;break}j++}if(j==h.length){w=false;k=false}}function V(){if(!k||!k.scripts){h.push(k={scripts:[],finished:true})}}e={script:function(){for(var f=0;f<arguments.length;f++){(function(a,c){var b;if(!H(a)){c=[a]}for(var d=0;d<c.length;d++){V();a=c[d];if(G(a))a=a();if(!a)continue;if(H(a)){b=[].slice.call(a);b.push(d,1);c.splice.call(c,b);d--;continue}if(typeof a=="string")a={src:a};a=s(a,{ready:false,ready_cb:T,finished:false,finished_cb:U});k.finished=false;k.scripts.push(a);S(g,a,k,(Q&&w));w=true;if(g[z])e.wait()}})(arguments[f],arguments[f])}return e},wait:function(){if(arguments.length>0){for(var a=0;a<arguments.length;a++){h.push(arguments[a])}k=h[h.length-1]}else k=false;x();return e}};return{script:e.script,wait:e.wait,setOptions:function(a){s(a,g);return e}}}m={setGlobalDefaults:function(a){s(a,l);return m},setOptions:function(){return v().setOptions.apply(null,arguments)},script:function(){return v().script.apply(null,arguments)},wait:function(){return v().wait.apply(null,arguments)},queueScript:function(){n[n.length]={type:"script",args:[].slice.call(arguments)};return m},queueWait:function(){n[n.length]={type:"wait",args:[].slice.call(arguments)};return m},runQueue:function(){var a=m,c=n.length,b=c,d;for(;--b>=0;){d=n.shift();a=a[d.type].apply(null,d.args)}return a},noConflict:function(){o.$LAB=K;return m},sandbox:function(){return J()}};return m}o.$LAB=J();(function(a,c,b){if(document.readyState==null&&document[a]){document.readyState="loading";document[a](c,b=function(){document.removeEventListener(c,b,false);document.readyState="complete"},false)}})("addEventListener","DOMContentLoaded")})(this);
View
771 LAB.src.js
@@ -1,351 +1,496 @@
/*! LAB.js (LABjs :: Loading And Blocking JavaScript)
- v1.2.0 (c) Kyle Simpson
+ v2.0 (c) Kyle Simpson
MIT License
*/
(function(global){
- var sSTRING = "string", // constants used for compression optimization
- sHEAD = "head",
- sBODY = "body",
- sSCRIPT = "script",
- sREADYSTATE = "readyState",
- sPRELOADDONE = "preloaddone",
- sLOADTRIGGER = "loadtrigger",
- sSRCURI = "srcuri",
- sPRELOAD = "preload",
- sCOMPLETE = "complete",
- sDONE = "done",
- sWHICH = "which",
- sPRESERVE = "preserve",
- sONREADYSTATECHANGE = "onreadystatechange",
- sONLOAD = "onload",
- sHASOWNPROPERTY = "hasOwnProperty",
- sSCRIPTCACHE = "script/cache",
- sTYPEOBJ = "[object ",
- sTYPEFUNC = sTYPEOBJ+"Function]",
- sTYPEARRAY = sTYPEOBJ+"Array]",
- nNULL = null,
- bTRUE = true,
- bFALSE = false,
- oDOC = global.document,
- oWINLOC = global.location,
- oACTIVEX = global.ActiveXObject,
- fSETTIMEOUT = global.setTimeout,
- fCLEARTIMEOUT = global.clearTimeout,
- fGETELEMENTSBYTAGNAME = function(tn){return oDOC.getElementsByTagName(tn);},
- fOBJTOSTRING = Object.prototype.toString,
- fNOOP = function(){},
- append_to = {},
- all_scripts = {},
- PAGEROOT = /^[^?#]*\//.exec(oWINLOC.href)[0], // these ROOTs do not support file:/// usage, only http:// type usage
- DOCROOT = /^\w+\:\/\/\/?[^\/]+/.exec(PAGEROOT)[0], // optional third / in the protocol portion of this regex so that LABjs doesn't blow up when used in file:/// usage
- docScripts = fGETELEMENTSBYTAGNAME(sSCRIPT),
-
- // Ah-ha hush that fuss, feature inference is used to detect specific browsers
- // because the techniques used in LABjs have no known feature detection. If
- // you know of a feature test please contact me ASAP. Feature inference is used
- // instead of user agent sniffing because the UA string can be easily
- // spoofed and is not adequate for such a mission critical part of the code.
- is_opera = global.opera && fOBJTOSTRING.call(global.opera) == sTYPEOBJ+"Opera]",
- is_gecko = ("MozAppearance" in oDOC.documentElement.style),
+ var _$LAB = global.$LAB,
+
+ // constants for the valid keys of the options object
+ _UseLocalXHR = "UseLocalXHR",
+ _AlwaysPreserveOrder = "AlwaysPreserveOrder",
+ _AllowDuplicates = "AllowDuplicates",
+ _CacheBust = "CacheBust",
+ /*!START_DEBUG*/_Debug = "Debug",/*!END_DEBUG*/
+ _BasePath = "BasePath",
- // the following is a feature sniff for the ability to set async=false on dynamically created script elements, as proposed to the W3C
- // RE: http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
- is_script_async = (oDOC.createElement(sSCRIPT).async === true),
+ // stateless variables used across all $LAB instances
+ root_page = /^[^?#]*\//.exec(location.href)[0],
+ root_domain = /^\w+\:\/\/\/?[^\/]+/.exec(root_page)[0],
+ append_to = document.head || document.getElementsByTagName("head"),
+
+ // inferences... ick, but still necessary
+ opera_or_gecko = (global.opera && Object.prototype.toString.call(global.opera) == "[object Opera]") || ("MozAppearance" in document.documentElement.style),
- global_defs = {
- cache:!(is_gecko||is_opera), // browsers like IE/Safari/Chrome can use the "cache" trick to preload
- order:is_gecko||is_opera||is_script_async, // FF(prior to FF4) & Opera preserve execution order with script tags automatically,
- // so just add all scripts as fast as possible. FF4 has async=false to do the same
- xhr:bTRUE, // use XHR trick to preload local scripts
- dupe:bTRUE, // allow duplicate scripts? defaults to true now 'cause is slightly more performant that way (less checks)
- base:"", // base path to prepend to all non-absolute-path scripts
- which:sHEAD // which DOM object ("head" or "body") to append scripts to
- }
+/*!START_DEBUG*/
+ // console.log() and console.error() wrappers
+ log_msg = function(){},
+ log_error = log_msg,
+/*!END_DEBUG*/
+
+ // feature sniffs (yay!)
+ test_script_elem = document.createElement("script"),
+ explicit_preloading = typeof test_script_elem.preload == "boolean", // http://wiki.whatwg.org/wiki/Script_Execution_Control#Proposal_1_.28Nicholas_Zakas.29
+ real_preloading = explicit_preloading || (test_script_elem.readyState && test_script_elem.readyState == "uninitialized"), // will a script preload with `src` set before DOM append?
+ script_ordered_async = !real_preloading && test_script_elem.async === true, // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
+
+ // XHR preloading (same-domain) and cache-preloading (remote-domain) are the fallbacks (for some browsers)
+ xhr_or_cache_preloading = !real_preloading && !script_ordered_async && !opera_or_gecko
;
- global_defs[sPRESERVE] = bFALSE; // force preserve execution order of all loaded scripts (regardless of preloading)
- global_defs[sPRELOAD] = bTRUE; // use various tricks for "preloading" scripts
-
- append_to[sHEAD] = oDOC.head || fGETELEMENTSBYTAGNAME(sHEAD);
- append_to[sBODY] = fGETELEMENTSBYTAGNAME(sBODY);
-
- function isFunc(func) { return fOBJTOSTRING.call(func) === sTYPEFUNC; }
- function canonicalScriptURI(src,base_path) {
- var regex = /^\w+\:\/\//, ret;
- if (typeof src != sSTRING) src = "";
- if (typeof base_path != sSTRING) base_path = "";
- ret = ((/^\/\//.test(src)) ? oWINLOC.protocol : "") + src;
- ret = (regex.test(ret) ? "" : base_path) + ret;
- return ((regex.test(ret) ? "" : (ret.charAt(0) === "/" ? DOCROOT : PAGEROOT)) + ret);
- }
- function sameDomain(src) { return (canonicalScriptURI(src).indexOf(DOCROOT) === 0); }
- function scriptTagExists(uri) { // checks if a script uri has ever been loaded into this page's DOM
- var script, idx=-1;
- while (script = docScripts[++idx]) {
- if (typeof script.src == sSTRING && uri === canonicalScriptURI(script.src) && script.type !== sSCRIPTCACHE) return bTRUE;
- }
- return bFALSE;
+
+/*!START_DEBUG*/
+ // define console wrapper functions if applicable
+ if (global.console && global.console.log) {
+ if (!global.console.error) global.console.error = global.console.log;
+ log_msg = function(msg) { global.console.log(msg); };
+ log_error = function(msg,err) { global.console.error(msg,err); };
}
- function engine(queueExec,opts) {
- queueExec = !(!queueExec);
- if (opts == nNULL) opts = global_defs;
-
- var ready = bFALSE,
- _use_preload = queueExec && opts[sPRELOAD],
- _use_cache_preload = _use_preload && opts.cache,
- _use_script_order = _use_preload && opts.order,
- _use_xhr_preload = _use_preload && opts.xhr,
- _auto_wait = opts[sPRESERVE],
- _which = opts.which,
- _base_path = opts.base,
- waitFunc = fNOOP,
- scripts_loading = bFALSE,
- publicAPI,
+/*!END_DEBUG*/
- first_pass = bTRUE,
- scripts = {},
- exec = [],
- end_of_chain_check_interval = nNULL
- ;
-
- _use_preload = _use_cache_preload || _use_xhr_preload || _use_script_order; // if all flags are turned off, preload is moot so disable it
+ // test for function
+ function is_func(func) { return Object.prototype.toString.call(func) == "[object Function]"; }
+
+ // test for array
+ function is_array(arr) { return Object.prototype.toString.call(arr) == "[object Array]"; }
+
+ // make script URL absolute/canonical
+ function canonical_uri(src,base_path) {
+ var absolute_regex = /^\w+\:\/\//;
- function isScriptLoaded(elem,scriptentry) {
- if ((elem[sREADYSTATE] && elem[sREADYSTATE]!==sCOMPLETE && elem[sREADYSTATE]!=="loaded") || scriptentry[sDONE]) { return bFALSE; }
- elem[sONLOAD] = elem[sONREADYSTATECHANGE] = nNULL; // prevent memory leak
- return bTRUE;
+ // is `src` is protocol-relative (begins with // or ///), prepend protocol
+ if (/^\/\/\/?/.test(src)) {
+ src = location.protocol + src;
}
- function handleScriptLoad(elem,scriptentry,skipReadyCheck) {
- skipReadyCheck = !(!skipReadyCheck); // used to override ready check when script text was injected from XHR preload
- if (!skipReadyCheck && !(isScriptLoaded(elem,scriptentry))) return;
- scriptentry[sDONE] = bTRUE;
-
- for (var key in scripts) {
- if (scripts[sHASOWNPROPERTY](key) && !(scripts[key][sDONE])) return;
- }
- ready = bTRUE;
- waitFunc();
+ // is `src` page-relative? (not an absolute URL, and not a domain-relative path, beginning with /)
+ else if (!absolute_regex.test(src) && src[0] != "/") {
+ // prepend `base_path`, if any
+ src = (base_path || "") + src;
}
- function loadTriggerExecute(scriptentry) {
- if (isFunc(scriptentry[sLOADTRIGGER])) {
- scriptentry[sLOADTRIGGER]();
- scriptentry[sLOADTRIGGER] = nNULL; // prevent memory leak
+ // make sure to return `src` as absolute
+ return absolute_regex.test(src) ? src : ((src[0] == "/" ? root_domain : root_page) + src);
+ }
+
+ // merge `source` into `target`
+ function merge_objs(source,target) {
+ for (var k in source) { if (source.hasOwnProperty(k)) {
+ target[k] = source[k]; // TODO: does this need to be recursive for our purposes?
+ }}
+ return target;
+ }
+
+ // does the chain group have any ready-to-execute scripts?
+ function check_chain_group_scripts_ready(chain_group) {
+ var any_scripts_ready = false;
+ for (var i=0; i<chain_group.scripts.length; i++) {
+ if (chain_group.scripts[i].ready && chain_group.scripts[i].exec_trigger) {
+ any_scripts_ready = true;
+ chain_group.scripts[i].exec_trigger();
+ chain_group.scripts[i].exec_trigger = null;
}
}
- function handleScriptPreload(elem,scriptentry) {
- if (!isScriptLoaded(elem,scriptentry)) return;
- scriptentry[sPRELOADDONE] = bTRUE;
- fSETTIMEOUT(function(){
- append_to[scriptentry[sWHICH]].removeChild(elem); // remove preload script node
- loadTriggerExecute(scriptentry);
- },0);
+ return any_scripts_ready;
+ }
+
+ // creates a script load listener
+ function create_script_load_listener(elem,registry_item,flag,onload) {
+ elem.onload = elem.onreadystatechange = function() {
+ if ((elem.readyState && elem.readyState != "complete" && elem.readyState != "loaded") || registry_item[flag]) return;
+ elem.onload = elem.onreadystatechange = null;
+ onload();
+ };
+ }
+
+ // script executed handler
+ function script_executed(registry_item) {
+ registry_item.ready = registry_item.finished = true;
+ for (var i=0; i<registry_item.finished_listeners.length; i++) {
+ setTimeout(registry_item.finished_listeners[i],0);
}
- function handleXHRPreload(xhr,scriptentry) {
- if (xhr[sREADYSTATE] === 4) {
- xhr[sONREADYSTATECHANGE] = fNOOP; // fix a memory leak in IE
- scriptentry[sPRELOADDONE] = bTRUE;
- fSETTIMEOUT(function(){ loadTriggerExecute(scriptentry); },0);
+ registry_item.ready_listeners = [];
+ registry_item.finished_listeners = [];
+ }
+
+ // make the request for a scriptha
+ function request_script(chain_opts,script_obj,registry_item,onload,preload_this_script) {
+ // setTimeout() "yielding" prevents some weird race/crash conditions in older browsers
+ setTimeout(function(){
+ var script, src = script_obj.real_src, xhr;
+
+ // don't proceed until `append_to` is ready to append to
+ if ("item" in append_to) { // check if `append_to` ref is still a live node list
+ if (!append_to[0]) { // `append_to` node not yet ready
+ // try again in a little bit -- note: will re-call the anonymous function in the outer setTimeout, not the parent `request_script()`
+ setTimeout(arguments.callee,25);
+ return;
+ }
+ // reassign from live node list ref to pure node ref -- avoids nasty IE bug where changes to DOM invalidate live node lists
+ append_to = append_to[0];
}
- }
- function createScriptTag(scriptentry,src,type,charset,onload,scriptText) {
- var _script_which = scriptentry[sWHICH];
- fSETTIMEOUT(function() { // this setTimeout waiting "hack" prevents a nasty race condition browser hang (IE) when the document.write("<script defer=true>") type dom-ready hack is present in the page
- if ("item" in append_to[_script_which]) { // check if ref is still a live node list
- if (!append_to[_script_which][0]) { // append_to node not yet ready
- fSETTIMEOUT(arguments.callee,25); // try again in a little bit -- note, will recall the anonymous function in the outer setTimeout, not the parent createScriptTag()
- return;
+ script = document.createElement("script");
+ if (script_obj.type) script.type = script_obj.type;
+ if (script_obj.charset) script.charset = script_obj.charset;
+
+ // should preloading be used for this script?
+ if (preload_this_script) {
+ // real script preloading?
+ if (real_preloading) {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload: "+src);/*!END_DEBUG*/
+ registry_item.elem = script;
+ if (explicit_preloading) { // explicit preloading (aka, Zakas' proposal)
+ script.preload = true;
+ script.onpreload = onload;
}
- append_to[_script_which] = append_to[_script_which][0]; // reassign from live node list ref to pure node ref -- avoids nasty IE bug where changes to DOM invalidate live node lists
- }
- var scriptElem = oDOC.createElement(sSCRIPT);
- if (typeof type == sSTRING) scriptElem.type = type;
- if (typeof charset == sSTRING) scriptElem.charset = charset;
- if (isFunc(onload)) { // load script via 'src' attribute, set onload/onreadystatechange listeners
- scriptElem[sONLOAD] = scriptElem[sONREADYSTATECHANGE] = function(){onload(scriptElem,scriptentry);};
- scriptElem.src = src;
- if (is_script_async) {
- scriptElem.async = bFALSE;
+ else {
+ script.onreadystatechange = function(){
+ if (script.readyState == "loaded") onload();
+ script.onreadystatechange = null;
+ };
}
+ script.src = src;
+ // NOTE: no append to DOM yet, appending will happen when ready to execute
}
- // only for appending to <head>, fix a bug in IE6 if <base> tag is present -- otherwise, insertBefore(...,null) acts just like appendChild()
- append_to[_script_which].insertBefore(scriptElem,(_script_which===sHEAD?append_to[_script_which].firstChild:nNULL));
- if (typeof scriptText == sSTRING) { // script text already avaiable from XHR preload, so just inject it
- scriptElem.text = scriptText;
- handleScriptLoad(scriptElem,scriptentry,bTRUE); // manually call 'load' callback function, skipReadyCheck=true
+ // same-domain and XHR allowed? use XHR preloading
+ else if (preload_this_script && src.indexOf(root_domain) == 0 && chain_opts[_UseLocalXHR]) {
+ xhr = new XMLHttpRequest(); // note: IE never uses XHR (it supports true preloading), so no more need for ActiveXObject fallback for IE <= 7
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload (xhr): "+src);/*!END_DEBUG*/
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ xhr.onreadystatechange = function(){}; // fix a memory leak in IE
+ registry_item.text = xhr.responseText + "\n//@ sourceURL=" + src; // http://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/
+ onload();
+ }
+ };
+ xhr.open("GET",src);
+ xhr.send();
+ }
+ // as a last resort, use cache-preloading
+ else {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload (cache): "+src);/*!END_DEBUG*/
+ script.type = "text/cache-script";
+ create_script_load_listener(script,registry_item,"ready",function() {
+ append_to.removeChild(script);
+ onload();
+ });
+ script.src = src;
+ append_to.insertBefore(script,append_to.firstChild);
}
- },0);
- }
- function loadScriptElem(scriptentry,src,type,charset) {
- all_scripts[scriptentry[sSRCURI]] = bTRUE;
- createScriptTag(scriptentry,src,type,charset,handleScriptLoad);
- }
- function loadScriptCache(scriptentry,src,type,charset) {
- var args = arguments;
- if (first_pass && scriptentry[sPRELOADDONE] == nNULL) { // need to preload into cache
- scriptentry[sPRELOADDONE] = bFALSE;
- createScriptTag(scriptentry,src,sSCRIPTCACHE,charset,handleScriptPreload); // fake mimetype causes a fetch into cache, but no execution
}
- else if (!first_pass && scriptentry[sPRELOADDONE] != nNULL && !scriptentry[sPRELOADDONE]) { // preload still in progress, make sure trigger is set for execution later
- scriptentry[sLOADTRIGGER] = function(){loadScriptCache.apply(nNULL,args);};
+ // use async=false for ordered async? parallel-load-serial-execute http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
+ else if (script_ordered_async) {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script load (ordered async): "+src);/*!END_DEBUG*/
+ script.async = false;
+ create_script_load_listener(script,registry_item,"finished",onload);
+ script.src = src;
+ append_to.insertBefore(script,append_to.firstChild);
}
- else if (!first_pass) { // preload done, so reload (from cache, hopefully!) as regular script element
- loadScriptElem.apply(nNULL,args);
+ // otherwise, just a normal script element
+ else {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script load: "+src);/*!END_DEBUG*/
+ create_script_load_listener(script,registry_item,"finished",onload);
+ script.src = src;
+ append_to.insertBefore(script,append_to.firstChild);
}
- }
- function loadScriptXHR(scriptentry,src,type,charset) {
- var args = arguments, xhr;
- if (first_pass && scriptentry[sPRELOADDONE] == nNULL) { // need to preload
- scriptentry[sPRELOADDONE] = bFALSE;
- xhr = scriptentry.xhr = (oACTIVEX ? new oACTIVEX("Microsoft.XMLHTTP") : new global.XMLHttpRequest());
- xhr[sONREADYSTATECHANGE] = function(){handleXHRPreload(xhr,scriptentry);};
- xhr.open("GET",src);
- xhr.send("");
+ },0);
+ }
+
+ // create a clean instance of $LAB
+ function create_sandbox() {
+ var global_defaults = {},
+ can_use_preloading = real_preloading || xhr_or_cache_preloading,
+ queue = [],
+ registry = {},
+ instanceAPI
+ ;
+
+ // global defaults
+ global_defaults[_UseLocalXHR] = true;
+ global_defaults[_AlwaysPreserveOrder] = false;
+ global_defaults[_AllowDuplicates] = false;
+ global_defaults[_CacheBust] = false;
+ /*!START_DEBUG*/global_defaults[_Debug] = false;/*!END_DEBUG*/
+ global_defaults[_BasePath] = "";
+
+ // execute a script that has been preloaded already
+ function execute_preloaded_script(chain_opts,script_obj,registry_item) {
+ var script;
+
+ function preload_execute_finished() {
+ if (script != null) { // make sure this only ever fires once
+ script_executed(registry_item);
+ script = null;
+ }
+ }
+
+ if (registry[script_obj.src].finished) return;
+ if (!chain_opts[_AllowDuplicates]) registry[script_obj.src].finished = true;
+
+ script = registry_item.elem || document.createElement("script");
+ if (script_obj.type) script.type = script_obj.type;
+ if (script_obj.charset) script.charset = script_obj.charset;
+ create_script_load_listener(script,registry_item,"finished",preload_execute_finished);
+
+ // script elem was real-preloaded
+ if (registry_item.elem) {
+ registry_item.elem = null;
}
- else if (!first_pass && scriptentry[sPRELOADDONE] != nNULL && !scriptentry[sPRELOADDONE]) { // preload XHR still in progress, make sure trigger is set for execution later
- scriptentry[sLOADTRIGGER] = function(){loadScriptXHR.apply(nNULL,args);};
+ // script was XHR preloaded
+ else if (registry_item.text) {
+ script.onload = script.onreadystatechange = null; // script injection doesn't fire these events
+ script.text = registry_item.text;
}
- else if (!first_pass) { // preload done, so "execute" script via injection
- all_scripts[scriptentry[sSRCURI]] = bTRUE;
- createScriptTag(scriptentry,src,type,charset,nNULL,scriptentry.xhr.responseText);
- scriptentry.xhr = nNULL;
+ // script was cache-preloaded
+ else {
+ script.src = script_obj.real_src;
+ }
+ append_to.insertBefore(script,append_to.firstChild);
+
+ // manually fire execution callback for injected scripts, since events don't fire
+ if (registry_item.text) {
+ preload_execute_finished();
}
}
- function loadScript(o) {
- if (typeof o == "undefined" || !o) return; // skip over this script call if there's nothing to load
- if (o.allowDup == nNULL) o.allowDup = opts.dupe;
- var src = o.src, type = o.type, charset = o.charset, allowDup = o.allowDup,
- src_uri = canonicalScriptURI(src,_base_path), scriptentry, same_domain = sameDomain(src_uri);
- if (typeof charset != sSTRING) charset = nNULL;
- allowDup = !(!allowDup);
- if (!allowDup &&
- (
- (all_scripts[src_uri] != nNULL) || (first_pass && scripts[src_uri]) || scriptTagExists(src_uri)
- )
- ) {
- if (scripts[src_uri] != nNULL && scripts[src_uri][sPRELOADDONE] && !scripts[src_uri][sDONE] && same_domain) {
- // this script was preloaded via XHR, but is a duplicate, and dupes are not allowed
- handleScriptLoad(nNULL,scripts[src_uri],bTRUE); // mark the entry as done and check if chain group is done
+
+ // process the script request setup
+ function do_script(chain_opts,script_obj,chain_group,preload_this_script) {
+ var registry_item,
+ registry_items,
+ ready_cb = function(){ script_obj.ready_cb(script_obj,function(){ execute_preloaded_script(chain_opts,script_obj,registry_item); }); },
+ finished_cb = function(){ script_obj.finished_cb(script_obj,chain_group); }
+ ;
+
+ script_obj.src = canonical_uri(script_obj.src,chain_opts[_BasePath]);
+ script_obj.real_src = script_obj.src +
+ // append cache-bust param to URL?
+ (chain_opts[_CacheBust] ? ((/\?.*$/.test(script_obj.src) ? "&_" : "?_") + ~~(Math.random()*1E9) + "=") : "")
+ ;
+
+ if (!registry[script_obj.src]) registry[script_obj.src] = {items:[],finished:false};
+ registry_items = registry[script_obj.src].items;
+
+ // allowing duplicates, or is this the first recorded load of this script?
+ if (chain_opts[_AllowDuplicates] || registry_items.length == 0) {
+ registry_item = registry_items[registry_items.length] = {
+ ready:false,
+ finished:false,
+ ready_listeners:[ready_cb],
+ finished_listeners:[finished_cb]
+ };
+
+ request_script(chain_opts,script_obj,registry_item,
+ // which callback type to pass?
+ (
+ (preload_this_script) ? // depends on script-preloading
+ function(){
+ registry_item.ready = true;
+ for (var i=0; i<registry_item.ready_listeners.length; i++) {
+ setTimeout(registry_item.ready_listeners[i],0);
+ }
+ registry_item.ready_listeners = [];
+ } :
+ function(){ script_executed(registry_item); }
+ ),
+ // signal if script-preloading should be used or not
+ preload_this_script
+ );
+ }
+ else {
+ registry_item = registry_items[0];
+ if (registry_item.finished) {
+ setTimeout(finished_cb,0);
+ }
+ else {
+ registry_item.finished_listeners.push(finished_cb);
}
- return;
}
- if (scripts[src_uri] == nNULL) scripts[src_uri] = {};
- scriptentry = scripts[src_uri];
- if (scriptentry[sWHICH] == nNULL) scriptentry[sWHICH] = _which;
- scriptentry[sDONE] = bFALSE;
- scriptentry[sSRCURI] = src_uri;
- scripts_loading = bTRUE;
-
- if (!_use_script_order && _use_xhr_preload && same_domain) loadScriptXHR(scriptentry,src_uri,type,charset);
- else if (!_use_script_order && _use_cache_preload) loadScriptCache(scriptentry,src_uri,type,charset);
- else loadScriptElem(scriptentry,src_uri,type,charset);
- }
- function queueAndExecute(execBody) { // helper for publicAPI functions below
- if (queueExec && !_use_script_order) exec.push(execBody);
- if (!queueExec || _use_preload) execBody(); // if engine is either not queueing, or is queuing in preload mode, go ahead and execute
}
- function serializeArgs(args) {
- var sargs = [], idx;
- for (idx=-1; ++idx<args.length;) {
- if (fOBJTOSTRING.call(args[idx]) === sTYPEARRAY) sargs = sargs.concat(serializeArgs(args[idx]));
- else sargs[sargs.length] = args[idx];
+
+ // creates a closure for each separate chain spawned from this $LAB instance, to keep state cleanly separated between chains
+ function create_chain() {
+ var chainedAPI,
+ chain_opts = merge_objs(global_defaults,{}),
+ chain = [],
+ exec_cursor = 0,
+ scripts_currently_loading = false,
+ group
+ ;
+
+ // called when a script has finished preloading
+ function chain_script_ready(script_obj,exec_trigger) {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("script preload finished: "+script_obj.real_src);/*!END_DEBUG*/
+ script_obj.ready = true;
+ script_obj.exec_trigger = exec_trigger;
+ advance_exec_cursor(); // will only check for 'ready' scripts to be executed
}
- return sargs;
- }
-
- publicAPI = {
- script:function() {
- fCLEARTIMEOUT(end_of_chain_check_interval);
- var args = serializeArgs(arguments), use_engine = publicAPI, idx;
- if (_auto_wait) {
- for (idx=-1; ++idx<args.length;) {
- if (isFunc(args[idx])) args[idx] = args[idx](); // if a function is found, call/evaluate it first
- if (idx===0) {
- queueAndExecute(function(){
- loadScript((typeof args[0] == sSTRING) ? {src:args[0]} : args[0]);
- });
+
+ // called when a script has finished executing
+ function chain_script_executed(script_obj,chain_group) {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("script execution finished: "+script_obj.real_src);/*!END_DEBUG*/
+ script_obj.ready = script_obj.finished = true;
+ script_obj.exec_trigger = null;
+ // check if chain group is all finished
+ for (var i=0; i<chain_group.scripts.length; i++) {
+ if (!chain_group.scripts[i].finished) return;
+ }
+ // chain_group is all finished if we get this far
+ chain_group.finished = true;
+ advance_exec_cursor();
+ }
+
+ // main driver for executing each part of the chain
+ function advance_exec_cursor() {
+ while (exec_cursor < chain.length) {
+ if (is_func(chain[exec_cursor])) {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("$LAB.wait() executing: "+chain[exec_cursor]);/*!END_DEBUG*/
+ try { chain[exec_cursor](); } catch (err) {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_error("$LAB.wait() error caught: ",err);/*!END_DEBUG*/
}
- else use_engine = use_engine.script(args[idx]);
- use_engine = use_engine.wait();
}
+ else if (!chain[exec_cursor].finished) {
+ if (check_chain_group_scripts_ready(chain[exec_cursor])) continue;
+ break;
+ }
+ exec_cursor++;
}
- else {
- for (idx=-1; ++idx<args.length;) {
- if (isFunc(args[idx])) args[idx] = args[idx](); // if a function is found, call/evaluate it first
+ // we've reached the end of the chain (so far)
+ if (exec_cursor == chain.length) {
+ scripts_currently_loading = false;
+ group = false;
+ }
+ }
+
+ // setup next chain script group
+ function init_script_chain_group() {
+ if (!group || !group.scripts) {
+ chain.push(group = {scripts:[],finished:true});
+ }
+ }
+
+ // API for $LAB chains
+ chainedAPI = {
+ // start loading one or more scripts
+ script:function(){
+ for (var i=0; i<arguments.length; i++) {
+ (function(script_obj,script_list){
+ var splice_args;
+
+ if (!is_array(script_obj)) {
+ script_list = [script_obj];
+ }
+ for (var j=0; j<script_list.length; j++) {
+ init_script_chain_group();
+ script_obj = script_list[j];
+
+ if (is_func(script_obj)) script_obj = script_obj();
+ if (!script_obj) continue;
+ if (is_array(script_obj)) {
+ splice_args = [].slice.call(script_obj);
+ splice_args.push(j,1);
+ script_list.splice.call(script_list,splice_args);
+ j--;
+ continue;
+ }
+ if (typeof script_obj == "string") script_obj = {src:script_obj};
+ script_obj = merge_objs(script_obj,{
+ ready:false,
+ ready_cb:chain_script_ready,
+ finished:false,
+ finished_cb:chain_script_executed
+ });
+ group.finished = false;
+ group.scripts.push(script_obj);
+
+ do_script(chain_opts,script_obj,group,(can_use_preloading && scripts_currently_loading));
+ scripts_currently_loading = true;
+
+ if (chain_opts[_AlwaysPreserveOrder]) chainedAPI.wait();
+ }
+ })(arguments[i],arguments[i]);
}
- queueAndExecute(function(){
- for (idx=-1; ++idx<args.length;) {
- loadScript((typeof args[idx] == sSTRING) ? {src:args[idx]} : args[idx]);
+ return chainedAPI;
+ },
+ // force LABjs to pause in execution at this point in the chain, until the execution thus far finishes, before proceeding
+ wait:function(){
+ if (arguments.length > 0) {
+ for (var i=0; i<arguments.length; i++) {
+ chain.push(arguments[i]);
}
- });
+ group = chain[chain.length-1];
+ }
+ else group = false;
+
+ advance_exec_cursor();
+
+ return chainedAPI;
}
- end_of_chain_check_interval = fSETTIMEOUT(function(){first_pass = bFALSE;},5); // hack to "detect" the end of the chain if a wait() is not the last call
- return use_engine;
+ };
+
+ // the first chain link API (includes `setOptions` only this first time)
+ return {
+ script:chainedAPI.script,
+ wait:chainedAPI.wait,
+ setOptions:function(opts){
+ merge_objs(opts,chain_opts);
+ return chainedAPI;
+ }
+ };
+ }
+
+ // API for each initial $LAB instance (before chaining starts)
+ instanceAPI = {
+ // main API functions
+ setGlobalDefaults:function(opts){
+ merge_objs(opts,global_defaults);
+ return instanceAPI;
+ },
+ setOptions:function(){
+ return create_chain().setOptions.apply(null,arguments);
+ },
+ script:function(){
+ return create_chain().script.apply(null,arguments);
+ },
+ wait:function(){
+ return create_chain().wait.apply(null,arguments);
+ },
+
+ // built-in queuing for $LAB `script()` and `wait()` calls
+ // useful for building up a chain programmatically across various script locations, and simulating
+ // execution of the chain
+ queueScript:function(){
+ queue[queue.length] = {type:"script", args:[].slice.call(arguments)};
+ return instanceAPI;
+ },
+ queueWait:function(){
+ queue[queue.length] = {type:"wait", args:[].slice.call(arguments)};
+ return instanceAPI;
+ },
+ runQueue:function(){
+ var $L = instanceAPI, len=queue.length, i=len, val;
+ for (;--i>=0;) {
+ val = queue.shift();
+ $L = $L[val.type].apply(null,val.args);
+ }
+ return $L;
},
- wait:function(func) {
- fCLEARTIMEOUT(end_of_chain_check_interval);
- first_pass = bFALSE;
- if (!isFunc(func)) func = fNOOP;
- // On this current chain's waitFunc function, tack on call to trigger the queue for the *next* engine
- // in the chain, which will be executed when the current chain finishes loading
- var e = engine(queueExec||scripts_loading,opts), // if already in queuing, or if scripts now loading, keep queuing
- triggerNextChain = e.trigger, // store ref to e's trigger function for use by 'wfunc'
- wfunc = function(){ try { func(); } catch(err) {} triggerNextChain(); };
- delete e.trigger; // remove the 'trigger' property from e's public API, since only used internally
- var fn = function(){
- if (scripts_loading && !ready) waitFunc = wfunc;
- else wfunc();
- };
- if (queueExec && !scripts_loading) exec.push(fn);
- else queueAndExecute(fn);
- return e;
+ // rollback `[global].$LAB` to what it was before this file was loaded, the return this current instance of $LAB
+ noConflict:function(){
+ global.$LAB = _$LAB;
+ return instanceAPI;
+ },
+
+ // create another clean instance of $LAB
+ sandbox:function(){
+ return create_sandbox();
}
};
- if (queueExec) {
- // if queueing, return a function that the previous chain's waitFunc function can use to trigger this
- // engine's queue. NOTE: this trigger function is captured and removed from the public chain API before return
- publicAPI.trigger = function() {
- var fn, idx=-1;
- while (fn = exec[++idx]) fn();
- exec = [];
- };
- }
- else publicAPI.trigger = fNOOP; // no-op trigger function because this chain is not in queuing mode, so nothing to trigger
- return publicAPI;
- }
- function processOpts(opts) {
- var k, newOpts = {},
- boolOpts = {"UseCachePreload":"cache","UseLocalXHR":"xhr","UsePreloading":sPRELOAD,"AlwaysPreserveOrder":sPRESERVE,"AllowDuplicates":"dupe"},
- allOpts = {"AppendTo":sWHICH,"BasePath":"base"}
- ;
- for (k in boolOpts) allOpts[k] = boolOpts[k];
- newOpts.order = !(!global_defs.order);
- for (k in allOpts) {
- if (allOpts[sHASOWNPROPERTY](k) && global_defs[allOpts[k]] != nNULL) newOpts[allOpts[k]] = (opts[k] != nNULL) ? opts[k] : global_defs[allOpts[k]];
- }
- for (k in boolOpts) { // normalize bool props to actual boolean values if not already
- if (boolOpts[sHASOWNPROPERTY](k)) newOpts[boolOpts[k]] = !(!newOpts[boolOpts[k]]);
- }
- if (!newOpts[sPRELOAD]) newOpts.cache = newOpts.order = newOpts.xhr = bFALSE; // turn off all flags if preloading is disabled
- newOpts.which = (newOpts.which === sHEAD || newOpts.which === sBODY) ? newOpts.which : sHEAD;
- return newOpts;
+
+ return instanceAPI;
}
-
- global.$LAB = {
- setGlobalDefaults:function(gdefs) { // intentionally does not return an "engine" instance -- must call as stand-alone function call on $LAB
- global_defs = processOpts(gdefs);
- },
- setOptions:function(opts){ // set options per chain
- return engine(bFALSE,processOpts(opts));
- },
- script:function(){ // will load one or more scripts
- return engine().script.apply(nNULL,arguments);
- },
- wait:function(){ // will ensure that the chain's previous scripts are executed before execution of scripts in subsequent chain links
- return engine().wait.apply(nNULL,arguments);
- }
- };
-
+
+ // create the main instance of $LAB
+ global.$LAB = create_sandbox();
+
+
/* The following "hack" was suggested by Andrea Giammarchi and adapted from: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
NOTE: this hack only operates in FF and then only in versions where document.readyState is not present (FF < 3.6?).
@@ -356,13 +501,13 @@
fixed by this hack, and should therefore **not** be lazy-loaded by script loader tools such as LABjs.
*/
(function(addEvent,domLoaded,handler){
- if (oDOC[sREADYSTATE] == nNULL && oDOC[addEvent]){
- oDOC[sREADYSTATE] = "loading";
- oDOC[addEvent](domLoaded,handler = function(){
- oDOC.removeEventListener(domLoaded,handler,bFALSE);
- oDOC[sREADYSTATE] = sCOMPLETE;
- },bFALSE);
+ if (document.readyState == null && document[addEvent]){
+ document.readyState = "loading";
+ document[addEvent](domLoaded,handler = function(){
+ document.removeEventListener(domLoaded,handler,false);
+ document.readyState = "complete";
+ },false);
}
})("addEventListener","DOMContentLoaded");
-
-})(window);
+
+})(this);
View
32 README.TXT
@@ -54,17 +54,13 @@ would tell just this particular $LAB chain to do the same.
The configuration options available are:
-* UseCachePreload:true/false (default true): uses the mime-type cache trick (in browsers that support it) for preloading scripts from remote (cross-domain) locations
-
* UseLocalXHR:true/false (default true): use XHR to preload scripts from local (same-domain) locations
-* UsePreloading:true/false (default true): use the cache and xhr tricks for preloading scripts in parallel
-
* AlwaysPreserveOrder:true/false (default false): whether to insert an implicit .wait() call after each script load request... if turned on, prevents immediate execution of loaded files and instead executes all scripts in order
-* AllowDuplicates:true/false (default true): whether to inspect the current page and $LAB loading cache to see if the same script URL has already been requested and allow (true) or ignore (false) if so. NOTE: because $LAB chains are independent, may not necessarily work well across different chains if preloading is in effect.
+* AllowDuplicates:true/false (default true): whether to inspect the current page and $LAB loading cache to see if the same script URL has already been requested and allow (true) or ignore (false) if so. NOTE: in v1.2.0 and before, this didn't work correctly across multiple $LAB chains, but as of v2.0, it works correctly.
-* AppendTo:"head"/"body" (default "head"): which document element to append script elements to
+* CacheBust:true/false (default false): adds a cache-busting parameter (random number) to the end of a script URL
* BasePath:{string} (default ""): a path string to prepend to every script request's URL
@@ -76,3 +72,27 @@ Browsers have long supported "protocol-relative URLs", which basically means lea
LABjs now supports specifying such URLs to any script URL setting. NOTE: This is the recommended way to specify URLs for script resources if: a) the page you're serving can be viewed in both HTTP and HTTPS; and b) the script resource you're linking to can be accessed using the exact same domain/path with exception to the protocol.
A common example of such a resource is the CDN locations on the Google Ajax API, where popular frameworks like jQuery and Dojo are hosted. If you are linking to such CDN resources, you are strongly encouraged to change to using protocol-relative URLs, like "//ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" instead of "http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" or "https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js".
+
+
+New in v2.0:
+
+* `AllowDuplicates` now actually works across chains. This is very important for those who want to use multiple/nested $LAB chains as part of a shared-dependency loading mechanism.
+
+* Chains are now fully resumable, meaning you can save the return value from the last call to a chained function, and then use that saved value later as the starting point to resume the chain from where it left off.
+
+* Queueing is now built-in, with `queueScript`, `queueWait` and `runQueue` -- this important for those who want to build up the chain across multiple files or inline <script> elements (like in the CMS case), but want to defer starting the loading of the code starting until later (usually at the bottom of the page).
+
+* LABjs now supports `noConflict` (for rolling back to a previous version/copy of $LAB on the page) and `sandbox` (for creating a new pristine sandboxed copy of the current $LAB)
+
+* LABjs now relies on feature-testing for `async=false` and implicit/explicit "true preloading" (currently only IE, but in the spec process). Ugly/hacky "cache preloading" is now only used for "older webkit" (before March 2011 nightlies, etc), and even then, only for remote files.
+
+* For XHR preloading (only used in "older webkit" for local files, by default), to support better debugability, "// @sourceURL=..." is appended to the end of the code, to map the XHR/injected code to a real file name. Currently, browsers only support this for eval() (not script injection, like LABjs uses). It is hoped that browsers will soon support this annotation for their developer-tools.
+
+* Speaking of debugging, LABjs now supports a DEBUG mode (only if you use the source file, or if you use the LABjs-debug.min.js production file) *and* enable the "Debug" config option, which captures all the inner workings (and any errors in .wait() calls) to the browser's console.log, if present.
+
+* LABjs now supports a "CacheBust" config option, which will attempt to make sure all loaded scripts are forcibly loaded new on each page refresh, by auto-appending a random number parameter to each URL. ****This is really only practical/advised for DEV environments, where you want to ensure that the code reloads every time. Doing so in production would be really bad for user performance.*****
+
+* As part of LABjs' rewrite, the code style is now significantly improved in readability (most "minification" hacks have been removed), and it's also using more memory-savvy code, such as far fewer closures. As a result, LABjs should run leaner and faster, if only by a little bit. The goal is to get LABjs out of the way so your scripts load and run as fast as possible.
+
+* "AppendTo", "UsePreloading", and "UseCachePreloading" options were removed as they are no longer useful. This is the only backwards-incompatible change (no actual API changes, just config), and the change should just cause older usage code to continue to operate as normal while ignoring the no longer supported options. Still, test your code carefully if you've been using either of those 3 config options before.
+
View
2 fLAB.src.js
@@ -1,4 +1,4 @@
-// fLAB.js (file:// protocol adapter for LABjs 1.0+)
+// fLAB.js (file:// protocol adapter for LABjs 1.x only)
// v0.2 (c) Kyle Simpson
// MIT License
View
5 next/LAB.min.js
@@ -1,5 +0,0 @@
-/*! LAB.js (LABjs :: Loading And Blocking JavaScript)
- v2.0b3 (c) Kyle Simpson
- MIT License
-*/
-(function(o){var K=o.$LAB,y="UseLocalXHR",z="AlwaysPreserveOrder",u="AllowDuplicates",A="CacheBust",B="BasePath",C=/^[^?#]*\//.exec(location.href)[0],D=/^\w+\:\/\/\/?[^\/]+/.exec(C)[0],i=document.head||document.getElementsByTagName("head"),L=(o.opera&&Object.prototype.toString.call(o.opera)=="[object Opera]")||("MozAppearance"in document.documentElement.style),q=document.createElement("script"),E=typeof q.preload=="boolean",r=E||(q.readyState&&q.readyState=="uninitialized"),F=!r&&q.async===true,M=!r&&!F&&!L;function G(a){return Object.prototype.toString.call(a)=="[object Function]"}function H(a){return Object.prototype.toString.call(a)=="[object Array]"}function N(a,c){var b=/^\w+\:\/\//;if(/^\/\/\/?/.test(a)){a=location.protocol+a}else if(!b.test(a)&&a[0]!="/"){a=(c||"")+a}return b.test(a)?a:((a[0]=="/"?D:C)+a)}function s(a,c){for(var b in a){if(a.hasOwnProperty(b)){c[b]=a[b]}}return c}function O(a){var c=false;for(var b=0;b<a.scripts.length;b++){if(a.scripts[b].ready&&a.scripts[b].exec_trigger){c=true;a.scripts[b].exec_trigger();a.scripts[b].exec_trigger=null}}return c}function t(a,c,b,d){a.onload=a.onreadystatechange=function(){if((a.readyState&&a.readyState!="complete"&&a.readyState!="loaded")||c[b])return;a.onload=a.onreadystatechange=null;d()}}function I(a){a.ready=a.finished=true;for(var c=0;c<a.finished_listeners.length;c++){setTimeout(a.finished_listeners[c],0)}a.ready_listeners=[];a.finished_listeners=[]}function P(d,f,e,g,h){setTimeout(function(){var a,c=f.real_src,b;if("item"in i){if(!i[0]){setTimeout(arguments.callee,25);return}i=i[0]}a=document.createElement("script");if(f.type)a.type=f.type;if(f.charset)a.charset=f.charset;if(h){if(r){e.elem=a;if(E){a.preload=true;a.onpreload=g}else{a.onreadystatechange=function(){if(a.readyState=="loaded")g();a.onreadystatechange=null}}a.src=c}else if(h&&c.indexOf(D)==0&&d[y]){b=new XMLHttpRequest();b.onreadystatechange=function(){if(b.readyState==4){b.onreadystatechange=function(){};e.text=b.responseText+"\n//@ sourceURL="+c;g()}};b.open("GET",c);b.send()}else{a.type="text/cache-script";t(a,e,"ready",function(){i.removeChild(a);g()});a.src=c;i.insertBefore(a,i.firstChild)}}else if(F){a.async=false;t(a,e,"finished",g);a.src=c;i.insertBefore(a,i.firstChild)}else{t(a,e,"finished",g);a.src=c;i.insertBefore(a,i.firstChild)}},0)}function J(){var l={},Q=r||M,n=[],p={},m;l[y]=true;l[z]=false;l[u]=false;l[A]=false;l[B]="";function R(a,c,b){var d;function f(){if(d!=null){I(b);d=null}}if(p[c.src].finished)return;if(!a[u])p[c.src].finished=true;d=b.elem||document.createElement("script");if(c.type)d.type=c.type;if(c.charset)d.charset=c.charset;t(d,b,"finished",f);if(b.elem){b.elem=null}else if(b.text){d.onload=d.onreadystatechange=null;d.text=b.text}else{d.src=c.real_src}i.insertBefore(d,i.firstChild);if(b.text){f()}}function S(c,b,d,f){var e,g,h=function(){b.ready_cb(b,function(){R(c,b,e)})},j=function(){b.finished_cb(b,d)};b.src=N(b.src,c[B]);b.real_src=b.src+(c[A]?((/\?.*$/.test(b.src)?"&_":"?_")+~~(Math.random()*1E9)+"="):"");if(!p[b.src])p[b.src]={items:[],finished:false};g=p[b.src].items;if(c[u]||g.length==0){e=g[g.length]={ready:false,finished:false,ready_listeners:[h],finished_listeners:[j]};P(c,b,e,((f)?function(){e.ready=true;for(var a=0;a<e.ready_listeners.length;a++){setTimeout(e.ready_listeners[a],0)}e.ready_listeners=[]}:function(){I(e)}),f)}else{e=g[0];if(e.finished){setTimeout(j,0)}else{e.finished_listeners.push(j)}}}function v(){var e,g=s(l,{}),h=[],j=0,w=false,k;function T(a,c){a.ready=true;a.exec_trigger=c;x()}function U(a,c){a.ready=a.finished=true;a.exec_trigger=null;for(var b=0;b<c.scripts.length;b++){if(!c.scripts[b].finished)return}c.finished=true;x()}function x(){while(j<h.length){if(G(h[j])){try{h[j]()}catch(err){}}else if(!h[j].finished){if(O(h[j]))continue;break}j++}if(j==h.length){w=false;k=false}}function V(){if(!k||!k.scripts){h.push(k={scripts:[],finished:true})}}e={script:function(){for(var f=0;f<arguments.length;f++){(function(a,c){var b;if(!H(a)){c=[a]}for(var d=0;d<c.length;d++){V();a=c[d];if(G(a))a=a();if(!a)continue;if(H(a)){b=[].slice.call(a);b.push(d,1);c.splice.call(c,b);d--;continue}if(typeof a=="string")a={src:a};a=s(a,{ready:false,ready_cb:T,finished:false,finished_cb:U});k.finished=false;k.scripts.push(a);S(g,a,k,(Q&&w));w=true;if(g[z])e.wait()}})(arguments[f],arguments[f])}return e},wait:function(){if(arguments.length>0){for(var a=0;a<arguments.length;a++){h.push(arguments[a])}k=h[h.length-1]}else k=false;x();return e}};return{script:e.script,wait:e.wait,setOptions:function(a){s(a,g);return e}}}m={setGlobalDefaults:function(a){s(a,l);return m},setOptions:function(){return v().setOptions.apply(null,arguments)},script:function(){return v().script.apply(null,arguments)},wait:function(){return v().wait.apply(null,arguments)},queueScript:function(){n[n.length]={type:"script",args:[].slice.call(arguments)};return m},queueWait:function(){n[n.length]={type:"wait",args:[].slice.call(arguments)};return m},runQueue:function(){var a=m,c=n.length,b=c,d;for(;--b>=0;){d=n.shift();a=a[d.type].apply(null,d.args)}return a},noConflict:function(){o.$LAB=K;return m},sandbox:function(){return J()}};return m}o.$LAB=J();(function(a,c,b){if(document.readyState==null&&document[a]){document.readyState="loading";document[a](c,b=function(){document.removeEventListener(c,b,false);document.readyState="complete"},false)}})("addEventListener","DOMContentLoaded")})(this);
View
513 next/LAB.src.js
@@ -1,513 +0,0 @@
-/*! LAB.js (LABjs :: Loading And Blocking JavaScript)
- v2.0b3 (c) Kyle Simpson
- MIT License
-*/
-
-(function(global){
- var _$LAB = global.$LAB,
-
- // constants for the valid keys of the options object
- _UseLocalXHR = "UseLocalXHR",
- _AlwaysPreserveOrder = "AlwaysPreserveOrder",
- _AllowDuplicates = "AllowDuplicates",
- _CacheBust = "CacheBust",
- /*!START_DEBUG*/_Debug = "Debug",/*!END_DEBUG*/
- _BasePath = "BasePath",
-
- // stateless variables used across all $LAB instances
- root_page = /^[^?#]*\//.exec(location.href)[0],
- root_domain = /^\w+\:\/\/\/?[^\/]+/.exec(root_page)[0],
- append_to = document.head || document.getElementsByTagName("head"),
-
- // inferences... ick, but still necessary
- opera_or_gecko = (global.opera && Object.prototype.toString.call(global.opera) == "[object Opera]") || ("MozAppearance" in document.documentElement.style),
-
-/*!START_DEBUG*/
- // console.log() and console.error() wrappers
- log_msg = function(){},
- log_error = log_msg,
-/*!END_DEBUG*/
-
- // feature sniffs (yay!)
- test_script_elem = document.createElement("script"),
- explicit_preloading = typeof test_script_elem.preload == "boolean", // http://wiki.whatwg.org/wiki/Script_Execution_Control#Proposal_1_.28Nicholas_Zakas.29
- real_preloading = explicit_preloading || (test_script_elem.readyState && test_script_elem.readyState == "uninitialized"), // will a script preload with `src` set before DOM append?
- script_ordered_async = !real_preloading && test_script_elem.async === true, // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
-
- // XHR preloading (same-domain) and cache-preloading (remote-domain) are the fallbacks (for some browsers)
- xhr_or_cache_preloading = !real_preloading && !script_ordered_async && !opera_or_gecko
- ;
-
-/*!START_DEBUG*/
- // define console wrapper functions if applicable
- if (global.console && global.console.log) {
- if (!global.console.error) global.console.error = global.console.log;
- log_msg = function(msg) { global.console.log(msg); };
- log_error = function(msg,err) { global.console.error(msg,err); };
- }
-/*!END_DEBUG*/
-
- // test for function
- function is_func(func) { return Object.prototype.toString.call(func) == "[object Function]"; }
-
- // test for array
- function is_array(arr) { return Object.prototype.toString.call(arr) == "[object Array]"; }
-
- // make script URL absolute/canonical
- function canonical_uri(src,base_path) {
- var absolute_regex = /^\w+\:\/\//;
-
- // is `src` is protocol-relative (begins with // or ///), prepend protocol
- if (/^\/\/\/?/.test(src)) {
- src = location.protocol + src;
- }
- // is `src` page-relative? (not an absolute URL, and not a domain-relative path, beginning with /)
- else if (!absolute_regex.test(src) && src[0] != "/") {
- // prepend `base_path`, if any
- src = (base_path || "") + src;
- }
- // make sure to return `src` as absolute
- return absolute_regex.test(src) ? src : ((src[0] == "/" ? root_domain : root_page) + src);
- }
-
- // merge `source` into `target`
- function merge_objs(source,target) {
- for (var k in source) { if (source.hasOwnProperty(k)) {
- target[k] = source[k]; // TODO: does this need to be recursive for our purposes?
- }}
- return target;
- }
-
- // does the chain group have any ready-to-execute scripts?
- function check_chain_group_scripts_ready(chain_group) {
- var any_scripts_ready = false;
- for (var i=0; i<chain_group.scripts.length; i++) {
- if (chain_group.scripts[i].ready && chain_group.scripts[i].exec_trigger) {
- any_scripts_ready = true;
- chain_group.scripts[i].exec_trigger();
- chain_group.scripts[i].exec_trigger = null;
- }
- }
- return any_scripts_ready;
- }
-
- // creates a script load listener
- function create_script_load_listener(elem,registry_item,flag,onload) {
- elem.onload = elem.onreadystatechange = function() {
- if ((elem.readyState && elem.readyState != "complete" && elem.readyState != "loaded") || registry_item[flag]) return;
- elem.onload = elem.onreadystatechange = null;
- onload();
- };
- }
-
- // script executed handler
- function script_executed(registry_item) {
- registry_item.ready = registry_item.finished = true;
- for (var i=0; i<registry_item.finished_listeners.length; i++) {
- setTimeout(registry_item.finished_listeners[i],0);
- }
- registry_item.ready_listeners = [];
- registry_item.finished_listeners = [];
- }
-
- // make the request for a scriptha
- function request_script(chain_opts,script_obj,registry_item,onload,preload_this_script) {
- // setTimeout() "yielding" prevents some weird race/crash conditions in older browsers
- setTimeout(function(){
- var script, src = script_obj.real_src, xhr;
-
- // don't proceed until `append_to` is ready to append to
- if ("item" in append_to) { // check if `append_to` ref is still a live node list
- if (!append_to[0]) { // `append_to` node not yet ready
- // try again in a little bit -- note: will re-call the anonymous function in the outer setTimeout, not the parent `request_script()`
- setTimeout(arguments.callee,25);
- return;
- }
- // reassign from live node list ref to pure node ref -- avoids nasty IE bug where changes to DOM invalidate live node lists
- append_to = append_to[0];
- }
- script = document.createElement("script");
- if (script_obj.type) script.type = script_obj.type;
- if (script_obj.charset) script.charset = script_obj.charset;
-
- // should preloading be used for this script?
- if (preload_this_script) {
- // real script preloading?
- if (real_preloading) {
- /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload: "+src);/*!END_DEBUG*/
- registry_item.elem = script;
- if (explicit_preloading) { // explicit preloading (aka, Zakas' proposal)
- script.preload = true;
- script.onpreload = onload;
- }
- else {
- script.onreadystatechange = function(){
- if (script.readyState == "loaded") onload();
- script.onreadystatechange = null;
- };
- }
- script.src = src;
- // NOTE: no append to DOM yet, appending will happen when ready to execute
- }
- // same-domain and XHR allowed? use XHR preloading
- else if (preload_this_script && src.indexOf(root_domain) == 0 && chain_opts[_UseLocalXHR]) {
- xhr = new XMLHttpRequest(); // note: IE never uses XHR (it supports true preloading), so no more need for ActiveXObject fallback for IE <= 7
- /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload (xhr): "+src);/*!END_DEBUG*/
- xhr.onreadystatechange = function() {
- if (xhr.readyState == 4) {
- xhr.onreadystatechange = function(){}; // fix a memory leak in IE
- registry_item.text = xhr.responseText + "\n//@ sourceURL=" + src; // http://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/
- onload();
- }
- };
- xhr.open("GET",src);
- xhr.send();
- }
- // as a last resort, use cache-preloading
- else {
- /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload (cache): "+src);/*!END_DEBUG*/
- script.type = "text/cache-script";
- create_script_load_listener(script,registry_item,"ready",function() {
- append_to.removeChild(script);
- onload();
- });
- script.src = src;
- append_to.insertBefore(script,append_to.firstChild);
- }
- }
- // use async=false for ordered async? parallel-load-serial-execute http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
- else if (script_ordered_async) {
- /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script load (ordered async): "+src);/*!END_DEBUG*/
- script.async = false;
- create_script_load_listener(script,registry_item,"finished",onload);
- script.src = src;
- append_to.insertBefore(script,append_to.firstChild);
- }
- // otherwise, just a normal script element
- else {
- /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script load: "+src);/*!END_DEBUG*/
- create_script_load_listener(script,registry_item,"finished",onload);
- script.src = src;
- append_to.insertBefore(script,append_to.firstChild);
- }
- },0);
- }
-
- // create a clean instance of $LAB
- function create_sandbox() {
- var global_defaults = {},
- can_use_preloading = real_preloading || xhr_or_cache_preloading,
- queue = [],
- registry = {},
- instanceAPI
- ;
-
- // global defaults
- global_defaults[_UseLocalXHR] = true;
- global_defaults[_AlwaysPreserveOrder] = false;
- global_defaults[_AllowDuplicates] = false;
- global_defaults[_CacheBust] = false;
- /*!START_DEBUG*/global_defaults[_Debug] = false;/*!END_DEBUG*/
- global_defaults[_BasePath] = "";
-
- // execute a script that has been preloaded already
- function execute_preloaded_script(chain_opts,script_obj,registry_item) {
- var script;
-
- function preload_execute_finished() {
- if (script != null) { // make sure this only ever fires once
- script_executed(registry_item);
- script = null;
- }
- }
-
- if (registry[script_obj.src].finished) return;
- if (!chain_opts[_AllowDuplicates]) registry[script_obj.src].finished = true;
-
- script = registry_item.elem || document.createElement("script");
- if (script_obj.type) script.type = script_obj.type;
- if (script_obj.charset) script.charset = script_obj.charset;
- create_script_load_listener(script,registry_item,"finished",preload_execute_finished);
-
- // script elem was real-preloaded
- if (registry_item.elem) {
- registry_item.elem = null;
- }
- // script was XHR preloaded
- else if (registry_item.text) {
- script.onload = script.onreadystatechange = null; // script injection doesn't fire these events
- script.text = registry_item.text;
- }
- // script was cache-preloaded
- else {
- script.src = script_obj.real_src;
- }
- append_to.insertBefore(script,append_to.firstChild);
-
- // manually fire execution callback for injected scripts, since events don't fire
- if (registry_item.text) {
- preload_execute_finished();
- }
- }
-
- // process the script request setup
- function do_script(chain_opts,script_obj,chain_group,preload_this_script) {
- var registry_item,
- registry_items,
- ready_cb = function(){ script_obj.ready_cb(script_obj,function(){ execute_preloaded_script(chain_opts,script_obj,registry_item); }); },
- finished_cb = function(){ script_obj.finished_cb(script_obj,chain_group); }
- ;
-
- script_obj.src = canonical_uri(script_obj.src,chain_opts[_BasePath]);
- script_obj.real_src = script_obj.src +
- // append cache-bust param to URL?
- (chain_opts[_CacheBust] ? ((/\?.*$/.test(script_obj.src) ? "&_" : "?_") + ~~(Math.random()*1E9) + "=") : "")
- ;
-
- if (!registry[script_obj.src]) registry[script_obj.src] = {items:[],finished:false};
- registry_items = registry[script_obj.src].items;
-
- // allowing duplicates, or is this the first recorded load of this script?
- if (chain_opts[_AllowDuplicates] || registry_items.length == 0) {
- registry_item = registry_items[registry_items.length] = {
- ready:false,
- finished:false,
- ready_listeners:[ready_cb],
- finished_listeners:[finished_cb]
- };
-
- request_script(chain_opts,script_obj,registry_item,
- // which callback type to pass?
- (
- (preload_this_script) ? // depends on script-preloading
- function(){
- registry_item.ready = true;
- for (var i=0; i<registry_item.ready_listeners.length; i++) {
- setTimeout(registry_item.ready_listeners[i],0);
- }
- registry_item.ready_listeners = [];
- } :
- function(){ script_executed(registry_item); }
- ),
- // signal if script-preloading should be used or not
- preload_this_script
- );
- }
- else {
- registry_item = registry_items[0];
- if (registry_item.finished) {
- setTimeout(finished_cb,0);
- }
- else {
- registry_item.finished_listeners.push(finished_cb);
- }
- }
- }
-
- // creates a closure for each separate chain spawned from this $LAB instance, to keep state cleanly separated between chains
- function create_chain() {
- var chainedAPI,
- chain_opts = merge_objs(global_defaults,{}),
- chain = [],
- exec_cursor = 0,
- scripts_currently_loading = false,
- group
- ;
-
- // called when a script has finished preloading
- function chain_script_ready(script_obj,exec_trigger) {
- /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("script preload finished: "+script_obj.real_src);/*!END_DEBUG*/
- script_obj.ready = true;
- script_obj.exec_trigger = exec_trigger;
- advance_exec_cursor(); // will only check for 'ready' scripts to be executed
- }
-
- // called when a script has finished executing
- function chain_script_executed(script_obj,chain_group) {
- /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("script execution finished: "+script_obj.real_src);/*!END_DEBUG*/
- script_obj.ready = script_obj.finished = true;
- script_obj.exec_trigger = null;
- // check if chain group is all finished
- for (var i=0; i<chain_group.scripts.length; i++) {
- if (!chain_group.scripts[i].finished) return;
- }
- // chain_group is all finished if we get this far
- chain_group.finished = true;
- advance_exec_cursor();
- }
-
- // main driver for executing each part of the chain
- function advance_exec_cursor() {
- while (exec_cursor < chain.length) {
- if (is_func(chain[exec_cursor])) {
- /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("$LAB.wait() executing: "+chain[exec_cursor]);/*!END_DEBUG*/
- try { chain[exec_cursor](); } catch (err) {
- /*!START_DEBUG*/if (chain_opts[_Debug]) log_error("$LAB.wait() error caught: ",err);/*!END_DEBUG*/
- }
- }
- else if (!chain[exec_cursor].finished) {
- if (check_chain_group_scripts_ready(chain[exec_cursor])) continue;
- break;
- }
- exec_cursor++;
- }
- // we've reached the end of the chain (so far)
- if (exec_cursor == chain.length) {
- scripts_currently_loading = false;
- group = false;
- }
- }
-
- // setup next chain script group
- function init_script_chain_group() {
- if (!group || !group.scripts) {
- chain.push(group = {scripts:[],finished:true});
- }
- }
-
- // API for $LAB chains
- chainedAPI = {
- // start loading one or more scripts
- script:function(){
- for (var i=0; i<arguments.length; i++) {
- (function(script_obj,script_list){
- var splice_args;
-
- if (!is_array(script_obj)) {
- script_list = [script_obj];
- }
- for (var j=0; j<script_list.length; j++) {
- init_script_chain_group();
- script_obj = script_list[j];
-
- if (is_func(script_obj)) script_obj = script_obj();
- if (!script_obj) continue;
- if (is_array(script_obj)) {
- splice_args = [].slice.call(script_obj);
- splice_args.push(j,1);
- script_list.splice.call(script_list,splice_args);
- j--;
- continue;
- }
- if (typeof script_obj == "string") script_obj = {src:script_obj};
- script_obj = merge_objs(script_obj,{
- ready:false,
- ready_cb:chain_script_ready,
- finished:false,
- finished_cb:chain_script_executed
- });
- group.finished = false;
- group.scripts.push(script_obj);
-
- do_script(chain_opts,script_obj,group,(can_use_preloading && scripts_currently_loading));
- scripts_currently_loading = true;
-
- if (chain_opts[_AlwaysPreserveOrder]) chainedAPI.wait();
- }
- })(arguments[i],arguments[i]);
- }
- return chainedAPI;
- },
- // force LABjs to pause in execution at this point in the chain, until the execution thus far finishes, before proceeding
- wait:function(){
- if (arguments.length > 0) {
- for (var i=0; i<arguments.length; i++) {
- chain.push(arguments[i]);
- }
- group = chain[chain.length-1];
- }
- else group = false;
-
- advance_exec_cursor();
-
- return chainedAPI;
- }
- };
-
- // the first chain link API (includes `setOptions` only this first time)
- return {
- script:chainedAPI.script,
- wait:chainedAPI.wait,
- setOptions:function(opts){
- merge_objs(opts,chain_opts);
- return chainedAPI;
- }
- };
- }
-
- // API for each initial $LAB instance (before chaining starts)
- instanceAPI = {
- // main API functions
- setGlobalDefaults:function(opts){
- merge_objs(opts,global_defaults);
- return instanceAPI;
- },
- setOptions:function(){
- return create_chain().setOptions.apply(null,arguments);
- },
- script:function(){
- return create_chain().script.apply(null,arguments);
- },
- wait:function(){
- return create_chain().wait.apply(null,arguments);
- },
-
- // built-in queuing for $LAB `script()` and `wait()` calls
- // useful for building up a chain programmatically across various script locations, and simulating
- // execution of the chain
- queueScript:function(){
- queue[queue.length] = {type:"script", args:[].slice.call(arguments)};
- return instanceAPI;
- },
- queueWait:function(){
- queue[queue.length] = {type:"wait", args:[].slice.call(arguments)};
- return instanceAPI;
- },
- runQueue:function(){
- var $L = instanceAPI, len=queue.length, i=len, val;
- for (;--i>=0;) {
- val = queue.shift();
- $L = $L[val.type].apply(null,val.args);
- }
- return $L;
- },
-
- // rollback `[global].$LAB` to what it was before this file was loaded, the return this current instance of $LAB
- noConflict:function(){
- global.$LAB = _$LAB;
- return instanceAPI;
- },
-
- // create another clean instance of $LAB
- sandbox:function(){
- return create_sandbox();
- }
- };
-
- return instanceAPI;
- }
-
- // create the main instance of $LAB
- global.$LAB = create_sandbox();
-
-
- /* The following "hack" was suggested by Andrea Giammarchi and adapted from: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
- NOTE: this hack only operates in FF and then only in versions where document.readyState is not present (FF < 3.6?).
-
- The hack essentially "patches" the **page** that LABjs is loaded onto so that it has a proper conforming document.readyState, so that if a script which does
- proper and safe dom-ready detection is loaded onto a page, after dom-ready has passed, it will still be able to detect this state, by inspecting the now hacked
- document.readyState property. The loaded script in question can then immediately trigger any queued code executions that were waiting for the DOM to be ready.
- For instance, jQuery 1.4+ has been patched to take advantage of document.readyState, which is enabled by this hack. But 1.3.2 and before are **not** safe or
- fixed by this hack, and should therefore **not** be lazy-loaded by script loader tools such as LABjs.
- */
- (function(addEvent,domLoaded,handler){
- if (document.readyState == null && document[addEvent]){
- document.readyState = "loading";
- document[addEvent](domLoaded,handler = function(){
- document.removeEventListener(domLoaded,handler,false);
- document.readyState = "complete";
- },false);
- }
- })("addEventListener","DOMContentLoaded");
-
-})(this);
View
9 next/mLAB/anothermodule.js
@@ -1,9 +0,0 @@
-$MLAB.module()
-
-.require({"yetanother":"http://domain.tld/yetanothermodule.js"})
-
-.define("another", function($M){
- return {
- bar:function() { return 5 * $M.yetanother.yum(5); }
- };
-});
View
33 next/mLAB/example.html
@@ -1,33 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-
-<script src="MLAB.js"></script>
-<script>
-
-$MLAB
-.require({"my":"http://domain.tld/mymodule.js"})
-.then(function($M){
- console.log($M.my.foobarbaz());
-});
-
-</script>
-
-</head>
-<body>
-
-<h1>Module-LABjs example</h1>
-
-</body>
-
-
-<script>
-
-// look, I can still use LABjs if I want!
-$LAB.script("google-analytics.js").wait(function(){
- // init GA
-});
-
-</script>
-
-</html>
View
41 next/mLAB/mLAB.src.js
@@ -1,41 +0,0 @@
-/*! mLAB.js (Module-LABjs :: Loading And Blocking JavaScript Modules)
- v0.1a (c) Kyle Simpson
- MIT License
-*/
-
-(function(global){
- var modules = [],
- module_chains = [],
- module_registry = {},
-
- current_chain_id = 0
- ;
-
- function create_chain() {
- var chain_id = modules.length,
- chain_group_id = 0,
- publicAPI
- ;
-
- modules[chain_id] = [];
-
- module_chains[chain_id] = publicAPI = {
- require:function(){ return publicAPI; },
- define:function(){ return; }
- };
- return publicAPI;
- }
-
- global.$MLAB = {
- require:function(){
- return global.$MLAB;
- },
- then:function(){
- return global.$MLAB;
- },
- module:function(){
- return module_chains[current_chain_id];
- }
- };
-
-})(window);
View
18 next/mLAB/mymodule.js
@@ -1,18 +0,0 @@
-$MLAB.module()
-
-.require("someother")
-.require({"another":"http://domain.tld/anothermodule.js"})
-.require("yetanother")
-
-.define("my", function($M){
- var someother = $M.someother,
- another = $M.another,
- yetanother = $M.yetanother,
- ;
-
- return {
- foobarbaz:function(){
- return someother.foo() + another.bar() + yetanother.baz();
- }
- };
-})
View
7 next/mLAB/someothermodule.js
@@ -1,7 +0,0 @@
-$MLAB.module()
-
-.define("someother", function($M){
- return {
- foo:function() { return 10; }
- };
-});
View
8 next/mLAB/yetanothermodule.js
@@ -1,8 +0,0 @@
-$MLAB.module()
-
-.define("yetanother", function($M){
- return {
- baz:function() { return 30; },
- yum:function(val) { return val - 1; }
- };
-});
View
BIN tests/img1.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN tests/img2.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
10 tests/test-1.html
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="LAB.src.js"></script>
-</head>
-<body>
-<script>
-$LAB.script("test1script.php");
-</script>
-</html>
View
58 tests/test-LABjs-preloading-1.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>LABjs tests (LABjs with preloading #1)</title>
+<script type="text/javascript" src="../js/LAB.js"></script>
+<script>
+
+var timeDiff = function(){
+ var d, time=(new Date()).getTime();
+ return {
+ setStartTime:function (){
+ d = new Date();
+ time = d.getTime();
+ },
+ getDiff:function (){
+ d = new Date();
+ return (d.getTime()-time);
+ }
+ };
+}();
+
+function done() {
+ var log_value_text = "Loading/Execution Time: "+timeDiff.getDiff()+"\nVerification: "+script3+"\n";
+ (function fn(){
+ var load_log = document.getElementById("load_log");
+ if (load_log !== null) load_log.value += log_value_text;
+ else setTimeout(fn,10);
+ })();
+}
+
+timeDiff.setStartTime();
+
+
+$LAB
+.setOptions({AlwaysPreserveOrder:true,UseLocalXHR:false,BasePath:"/test_suite/"})
+.script("//labjs.xhr.me/test_suite/testscript1.php?delay=5") // testing protocol-relative pathing
+.script("/test_suite/testscript2.php?delay=3")
+.script("testscript3.php?delay=1")
+.wait(done);
+
+</script>
+</head>
+
+<body>
+
+<h1>LABjs tests (LABjs with preloading #1)</h1>
+
+<img src="img1.jpg" width="100" hspace="5" alt="image 1" title="size: 379kb" />
+<img src="img2.jpg" width="100" hspace="5" alt="image 2" title="size: 20kb" />
+
+<br />
+<form name="log_form">
+<textarea id="load_log" name="load_log" cols="80" rows="10"></textarea>
+</form>
+
+</body>
+</html>
View
59 tests/test-LABjs-preloading-10.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>LABjs tests (LABjs with preloading #10)</title>
+<script type="text/javascript" src="../js/LAB.js"></script>
+<script>
+
+var timeDiff = function(){
+ var d, time;
+ return {
+ setStartTime:function (){
+ d = new Date();
+ time = d.getTime();
+ },
+ getDiff:function (){
+ d = new Date();
+ return (d.getTime()-time);
+ }
+ };
+}();
+
+function done() {
+ var log_value_text = "Loading/Execution Time: "+timeDiff.getDiff()+"\nVerification: "+script3+"\n";
+ (function fn(){
+ var load_log = document.getElementById("load_log");
+ if (load_log !== null) load_log.value += log_value_text;
+ else setTimeout(fn,10);
+ })();
+}
+
+timeDiff.setStartTime();
+
+$LAB
+.setOptions({AlwaysPreserveOrder:true})
+.script("http://labjs.xhr.me/test_suite/testscript1.php?delay=5") // dupe scripts, only one will be preloaded/loaded
+.script("http://labjs.xhr.me/test_suite/testscript1.php?delay=5")
+.script("testscript2.php?delay=3")
+.script("testscript2.php?delay=7") // 7 second load of script will be long poll for final "done" (~7 secs)
+.script("http://labjs.xhr.me/test_suite/testscript3.php?delay=1")
+.wait(done);
+
+</script>
+</head>
+
+<body>
+
+<h1>LABjs tests (LABjs with preloading #10)</h1>
+
+<img src="img1.jpg" width="100" hspace="5" alt="image 1" title="size: 379kb" />
+<img src="img2.jpg" width="100" hspace="5" alt="image 2" title="size: 20kb" />
+
+<br />
+<form name="log_form">
+<textarea id="load_log" name="load_log" cols="80" rows="10"></textarea>
+</form>
+
+</body>
+</html>
View
59 tests/test-LABjs-preloading-11.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>LABjs tests (LABjs with preloading #11)</title>
+<script type="text/javascript" src="../js/LAB.js"></script>
+<script>
+
+var timeDiff = function(){
+ var d, time;
+ return {
+ setStartTime:function (){
+ d = new Date();
+ time = d.getTime();
+ },
+ getDiff:function (){
+ d = new Date();
+ return (d.getTime()-time);
+ }
+ };
+}();
+
+function done() {
+ var log_value_text = "Loading/Execution Time: "+timeDiff.getDiff()+"\nVerification: "+script3+"\n";
+ (function fn(){
+ var load_log = document.getElementById("load_log");
+ if (load_log !== null) load_log.value += log_value_text;
+ else setTimeout(fn,10);
+ })();
+}
+
+timeDiff.setStartTime();
+
+$LAB
+.setOptions({AlwaysPreserveOrder:true,AllowDuplicates:true})
+.script("http://labjs.xhr.me/test_suite/testscript1.php?delay=5")
+.script("http://labjs.xhr.me/test_suite/testscript1.php?delay=5") // will be allowed since duplicates are allowed
+.script("testscript2.php?delay=3")
+.script("testscript2.php?delay=3") // will be allowed since duplicates are allowed
+.script("http://labjs.xhr.me/test_suite/testscript3.php?delay=1")
+.wait(done);
+
+</script>
+</head>
+
+<body>
+
+<h1>LABjs tests (LABjs with preloading #11)</h1>
+
+<img src="img1.jpg" width="100" hspace="5" alt="image 1" title="size: 379kb" />
+<img src="img2.jpg" width="100" hspace="5" alt="image 2" title="size: 20kb" />
+
+<br />
+<form name="log_form">
+<textarea id="load_log" name="load_log" cols="80" rows="10"></textarea>
+</form>
+
+</body>
+</html>
View
79 tests/test-LABjs-preloading-12a.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>LABjs tests (LABjs with preloading #12a)</title>
+
+<!-- testing conditional chaining -->
+
+<script type="text/javascript" src="../js/LAB.js"></script>
+<script>
+
+var timeDiff = function(){
+ var d, time;
+ return {
+ setStartTime:function (){
+ d = new Date();
+ time = d.getTime();
+ },
+ getDiff:function (){
+ d = new Date();
+ return (d.getTime()-time);
+ }
+ };
+}();
+
+function done() {
+ var log_value_text = "Loading/Execution Time: "+timeDiff.getDiff()+"\nVerification: "+script3+"\n";
+ (function fn(){
+ var load_log = document.getElementById("load_log");
+ if (load_log !== null) load_log.value += log_value_text;
+ else setTimeout(fn,10);
+ })();
+}
+
+timeDiff.setStartTime();
+
+$LAB
+.script(function(){
+ if (typeof script1 == "undefined") return "http://labjs.xhr.me/test_suite/testscript1.php?delay=5";
+ else return false;
+})
+.wait()
+.script(function(){
+ if (typeof script2 == "undefined") return "testscript2.php?delay=3";
+ else return false;
+})
+.wait()
+.script(function(){
+ if (typeof script3 == "undefined") return {src:"http://labjs.xhr.me/test_suite/testscript3.php?delay=1"};
+ else return false;
+})
+.wait(done);
+
+</script>
+</head>
+
+<body>
+
+<h1>LABjs tests (LABjs with preloading #12a)</h1>
+<ul>
+<li><a href="test-LABjs-preloading-12a.html">test 12a</a></li>
+<li><a href="test-LABjs-preloading-12b.html">test 12b</a></li>
+<li><a href="test-LABjs-preloading-12c.html">test 12c</a></li>
+<li><a href="test-LABjs-preloading-12d.html">test 12d</a></li>
+<li><a href="test-LABjs-preloading-12e.html">test 12e</a></li>
+<li><a href="test-LABjs-preloading-12f.html">test 12f</a></li>
+<li><a href="test-LABjs-preloading-12g.html">test 12g</a></li>
+</ul>
+
+<img src="img1.jpg" width="100" hspace="5" alt="image 1" title="size: 379kb" />
+<img src="img2.jpg" width="100" hspace="5" alt="image 2" title="size: 20kb" />
+
+<br />
+<form name="log_form">
+<textarea id="load_log" name="load_log" cols="80" rows="10"></textarea>
+</form>
+
+</body>
+</html>
View
83 tests/test-LABjs-preloading-12b.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>LABjs tests (LABjs with preloading #12b)</title>
+
+<!-- testing conditional chaining -->
+
+<script type="text/javascript" src="../js/LAB.js"></script>
+<script>
+
+var timeDiff = function(){
+ var d, time;
+ return {
+ setStartTime:function (){
+ d = new Date();
+ time = d.getTime();
+ },
+ getDiff:function (){
+ d = new Date();
+ return (d.getTime()-time);
+ }
+ };
+}();
+
+function done() {
+ var log_value_text = "Loading/Execution Time: "+timeDiff.getDiff()+"\nVerification: "+script3+"\n";
+ (function fn(){
+ var load_log = document.getElementById("load_log");
+ if (load_log !== null) load_log.value += log_value_text;
+ else setTimeout(fn,10);
+ })();
+}
+
+timeDiff.setStartTime();
+
+</script>
+<script src="http://labjs.xhr.me/test_suite/testscript1.php?delay=1"></script>
+<script>
+
+$LAB
+.script(function(){
+ if (typeof script1 == "undefined") return "http://labjs.xhr.me/test_suite/testscript1.php?delay=5";
+ else return false;
+})
+.wait()
+.script(function(){
+ if (typeof script2 == "undefined") return "testscript2.php?delay=3";
+ else return false;
+})
+.wait()
+.script(function(){
+ if (typeof script3 == "undefined") return {src:"http://labjs.xhr.me/test_suite/testscript3.php?delay=1"};
+ else return false;
+})
+.wait(done);
+
+</script>
+</head>
+
+<body>
+
+<h1>LABjs tests (LABjs with preloading #12b)</h1>
+<ul>
+<li><a href="test-LABjs-preloading-12a.html">test 12a</a></li>
+<li><a href="test-LABjs-preloading-12b.html">test 12b</a></li>
+<li><a href="test-LABjs-preloading-12c.html">test 12c</a></li>
+<li><a href="test-LABjs-preloading-12d.html">test 12d</a></li>
+<li><a href="test-LABjs-preloading-12e.html">test 12e</a></li>
+<li><a href="test-LABjs-preloading-12f.html">test 12f</a></li>
+<li><a href="test-LABjs-preloading-12g.html">test 12g</a></li>
+</ul>
+
+<img src="img1.jpg" width="100" hspace="5" alt="image 1" title="size: 379kb" />
+<img src="img2.jpg" width="100" hspace="5" alt="image 2" title="size: 20kb" />
+
+<br />
+<form name="log_form">
+<textarea id="load_log" name="load_log" cols="80" rows="10"></textarea>
+</form>
+
+</body>
+</html>
View
84 tests/test-LABjs-preloading-12c.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>LABjs tests (LABjs with preloading #12c)</title>
+
+<!-- testing conditional chaining -->
+
+<script type="text/javascript" src="../js/LAB.js"></script>
+<script>
+
+var timeDiff = function(){
+ var d, time;
+ return {
+ setStartTime:function (){
+ d = new Date();
+ time = d.getTime();
+ },
+ getDiff:function (){
+ d = new Date();
+ return (d.getTime()-time);
+ }
+ };
+}();
+
+function done() {
+ var log_value_text = "Loading/Execution Time: "+timeDiff.getDiff()+"\nVerification: "+script3+"\n";
+ (function fn(){
+ var load_log = document.getElementById("load_log");
+ if (load_log !== null) load_log.value += log_value_text;
+ else setTimeout(fn,10);
+ })();
+}
+
+timeDiff.setStartTime();
+
+</script>
+<script src="http://labjs.xhr.me/test_suite/testscript1.php?delay=1"></script>
+<script src="testscript2.php?delay=1"></script>
+<script>
+
+$LAB
+.script(function(){
+ if (typeof script1 == "undefined") return "http://labjs.xhr.me/test_suite/testscript1.php?delay=5";
+ else return false;
+})
+.wait()
+.script(function(){
+ if (typeof script2 == "undefined") return "testscript2.php?delay=3";
+ else return false;
+})
+.wait()
+.script(function(){
+ if (typeof script3 == "undefined") return {src:"http://labjs.xhr.me/test_suite/testscript3.php?delay=1"};
+ else return false;
+})
+.wait(done);
+
+</script>
+</head>
+
+<body>
+
+<h1>LABjs tests (LABjs with preloading #12c)</h1>
+<ul>
+<li><a href="test-LABjs-preloading-12a.html">test 12a</a></li>
+<li><a href="test-LABjs-preloading-12b.html">test 12b</a></li>
+<li><a href="test-LABjs-preloading-12c.html">test 12c</a></li>
+<li><a href="test-LABjs-preloading-12d.html">test 12d</a></li>
+<li><a href="test-LABjs-preloading-12e.html">test 12e</a></li>
+<li><a href="test-LABjs-preloading-12f.html">test 12f</a></li>
+<li><a href="test-LABjs-preloading-12g.html">test 12g</a></li>
+</ul>
+
+<img src="img1.jpg" width="100" hspace="5" alt="image 1" title="size: 379kb" />
+<img src="img2.jpg" width="100" hspace="5" alt="image 2" title="size: 20kb" />
+
+<br />
+<form name="log_form">
+<textarea id="load_log" name="load_log" cols="80" rows="10"></textarea>
+</form>
+
+</body>
+</html>
View
85 tests/test-LABjs-preloading-12d.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>LABjs tests (LABjs with preloading #12d)</title>
+
+<!-- testing conditional chaining -->
+
+<script type="text/javascript" src="../js/LAB.js"></script>
+<script>