Skip to content
Browse files

adding LABjs script loading chain

  • Loading branch information...
1 parent 43a2192 commit c3ca67d6b8349db10479e55f6ab90e517edf771a @addyosmani committed
Showing with 232 additions and 188 deletions.
  1. +2 −2 app/application.js
  2. +15 −11 index.html
  3. +5 −0 lib/LAB.min.js
  4. +210 −175 lib/spine.js
View
4 app/application.js
@@ -27,7 +27,7 @@ jQuery(function($){
},
render: function(){
- this.el.html(this.template(this.item.reload()));
+ this.el.html(this.template(this.item));
return this;
},
@@ -100,7 +100,7 @@ jQuery(function($){
render: function(){
if ( !this.item ) return;
- this.el.html(this.template(this.item.reload()));
+ this.el.html(this.template(this.item));
},
change: function(item){
View
26 index.html
@@ -3,17 +3,21 @@
<head>
<link rel="stylesheet" href="css/application.css" type="text/css" charset="utf-8">
- <script src="lib/json2.js" type="text/javascript" charset="utf-8"></script>
- <script src="lib/jquery.js" type="text/javascript" charset="utf-8"></script>
- <script src="lib/jquery.tmpl.js" type="text/javascript" charset="utf-8"></script>
- <script src="lib/jquery.bitly.js" type="text/javascript" charset="utf-8"></script>
- <script src="lib/store.min.js" type="text/javascript" charset="utf-8"></script>
- <script src="lib/spine.js" type="text/javascript" charset="utf-8"></script>
- <script src="lib/spine.model.local.js" type="text/javascript" charset="utf-8"></script>
- <script src="lib/spine.controller.manager.js" type="text/javascript" charset="utf-8"></script>
- <script src="lib/spine.route.js" type="text/javascript" charset="utf-8"></script>
- <script src="app/models/url.js" type="text/javascript" charset="utf-8"></script>
- <script src="app/application.js" type="text/javascript" charset="utf-8"></script>
+ <script src="lib/LAB.min.js" type="text/javascript" charset="utf-8"></script>
+ <script type="text/javascript">
+ $LAB
+ .script("lib/json.js")
+ .script("lib/jquery.js")
+ .script("lib/jquery.tmpl.js")
+ .script("lib/jquery.bitly.js")
+ .script("lib/store.min.js")
+ .script("lib/spine.js")
+ .script("lib/spine.model.local.js")
+ .script("lib/spine.controller.manager.js")
+ .script("lib/spine.route.js")
+ .script("app/models/url.js")
+ .script("app/application.js");
+ </script>
<script type="text/x-jquery-tmpl" id="urlTemplate">
<div class="item">
View
5 lib/LAB.min.js
@@ -0,0 +1,5 @@
+/*! LAB.js (LABjs :: Loading And Blocking JavaScript)
+ v1.2.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);
View
385 lib/spine.js
@@ -15,6 +15,15 @@
return Array.prototype.slice.call(args, 0);
};
+ // Shim Array, as these functions aren't in IE
+ if (typeof Array.prototype.indexOf === "undefined")
+ Array.prototype.indexOf = function(value){
+ for ( var i = 0; i < this.length; i++ )
+ if ( this[ i ] === value )
+ return i;
+ return -1;
+ };
+
var Events = Spine.Events = {
bind: function(ev, callback) {
var evs = ev.split(" ");
@@ -31,13 +40,14 @@
var ev = args.shift();
var list, calls, i, l;
- if (!(calls = this._callbacks)) return this;
- if (!(list = this._callbacks[ev])) return this;
+ if (!(calls = this._callbacks)) return false;
+ if (!(list = this._callbacks[ev])) return false;
for (i = 0, l = list.length; i < l; i++)
if (list[i].apply(this, args) === false)
- return false;
- return this;
+ break;
+
+ return true;
},
unbind: function(ev, callback){
@@ -50,12 +60,16 @@
if (!(calls = this._callbacks)) return this;
if (!(list = this._callbacks[ev])) return this;
- for (i = 0, l = list.length; i < l; i++) {
+ if ( !callback ) {
+ delete this._callbacks[ev];
+ return this;
+ }
+
+ for (i = 0, l = list.length; i < l; i++)
if (callback === list[i]) {
list.splice(i, 1);
break;
}
- }
return this;
}
@@ -89,6 +103,7 @@
var Class = Spine.Class = {
inherited: function(){},
+ created: function(){},
prototype: {
initializer: function(){},
@@ -103,6 +118,7 @@
if (include) object.include(include);
if (extend) object.extend(extend);
+ object.created();
this.inherited(object);
return object;
},
@@ -153,6 +169,7 @@
Class.prototype.proxy = Class.proxy;
Class.prototype.proxyAll = Class.proxyAll;
Class.inst = Class.init;
+ Class.sub = Class.create;
// Models
@@ -167,154 +184,164 @@
Model.extend(Events);
- // Alias create
- Model.createSub = Model.create;
- Model.setup = function(name, atts){
- var model = Model.createSub();
- if (name) model.name = name;
- if (atts) model.attributes = atts;
- return model;
- };
-
Model.extend({
- inherited: function(sub){
- sub.records = {};
- sub.attributes = [];
-
- sub.bind("create", this.proxy(function(record){
- sub.trigger("change", "create", record);
- }));
- sub.bind("update", this.proxy(function(record){
- sub.trigger("change", "update", record);
- }));
- sub.bind("destroy", this.proxy(function(record){
- sub.trigger("change", "destroy", record);
- }));
- },
-
- find: function(id){
- var record = this.records[id];
- if ( !record ) throw("Unknown record");
- return record.dup();
- },
-
- exists: function(id){
- try {
- return this.find(id);
- } catch (e) {
- return false;
- }
- },
-
- refresh: function(values){
- this.records = {};
-
- for (var i=0, il = values.length; i < il; i++) {
- var record = this.init(values[i]);
- record.newRecord = false;
- this.records[record.id] = record;
- }
-
- this.trigger("refresh");
- },
-
- select: function(callback){
- var result = [];
-
- for (var key in this.records)
- if (callback(this.records[key]))
- result.push(this.records[key]);
-
- return this.dupArray(result);
- },
-
- findByAttribute: function(name, value){
- for (var key in this.records)
- if (this.records[key][name] == value)
- return this.records[key].dup();
- },
-
- findAllByAttribute: function(name, value){
- return(this.select(function(item){
- return(item[name] == value);
- }));
- },
-
- each: function(callback){
- for (var key in this.records)
- callback(this.records[key]);
- },
-
- all: function(){
- return this.dupArray(this.recordsValues());
- },
-
- first: function(){
- var record = this.recordsValues()[0];
- return(record && record.dup());
- },
-
- last: function(){
- var values = this.recordsValues()
- var record = values[values.length - 1];
- return(record && record.dup());
- },
-
- count: function(){
- return this.recordsValues().length;
- },
-
- deleteAll: function(){
- for (var key in this.records)
- delete this.records[key];
- },
-
- destroyAll: function(){
- for (var key in this.records)
- this.records[key].destroy();
- },
-
- update: function(id, atts){
- this.find(id).updateAttributes(atts);
- },
-
- create: function(atts){
- var record = this.init(atts);
- record.save();
- return record;
- },
-
- destroy: function(id){
- this.find(id).destroy();
- },
-
- sync: function(callback){
- this.bind("change", callback);
- },
-
- fetch: function(callback){
- callback ? this.bind("fetch", callback) : this.trigger("fetch");
- },
-
- toJSON: function(){
- return this.recordsValues();
- },
-
- // Private
-
- recordsValues: function(){
- var result = [];
- for (var key in this.records)
- result.push(this.records[key]);
- return result;
- },
-
- dupArray: function(array){
- var result = [];
- for (var i=0; i < array.length; i++)
- result.push(array[i].dup());
- return result;
- }
+ setup: function(name, atts){
+ var model = Model.sub();
+ if (name) model.name = name;
+ if (atts) model.attributes = atts;
+ return model;
+ },
+
+ created: function(sub){
+ this.records = {};
+ this.attributes = [];
+
+ this.bind("create", this.proxy(function(record){
+ this.trigger("change", "create", record);
+ }));
+ this.bind("update", this.proxy(function(record){
+ this.trigger("change", "update", record);
+ }));
+ this.bind("destroy", this.proxy(function(record){
+ this.trigger("change", "destroy", record);
+ }));
+ },
+
+ find: function(id){
+ var record = this.records[id];
+ if ( !record ) throw("Unknown record");
+ return record.clone();
+ },
+
+ exists: function(id){
+ try {
+ return this.find(id);
+ } catch (e) {
+ return false;
+ }
+ },
+
+ refresh: function(values){
+ this.records = {};
+
+ for (var i=0, il = values.length; i < il; i++) {
+ var record = this.init(values[i]);
+ record.newRecord = false;
+ this.records[record.id] = record;
+ }
+
+ this.trigger("refresh");
+ },
+
+ select: function(callback){
+ var result = [];
+
+ for (var key in this.records)
+ if (callback(this.records[key]))
+ result.push(this.records[key]);
+
+ return this.cloneArray(result);
+ },
+
+ findByAttribute: function(name, value){
+ for (var key in this.records)
+ if (this.records[key][name] == value)
+ return this.records[key].clone();
+ },
+
+ findAllByAttribute: function(name, value){
+ return(this.select(function(item){
+ return(item[name] == value);
+ }));
+ },
+
+ each: function(callback){
+ for (var key in this.records)
+ callback(this.records[key]);
+ },
+
+ all: function(){
+ return this.cloneArray(this.recordsValues());
+ },
+
+ first: function(){
+ var record = this.recordsValues()[0];
+ return(record && record.clone());
+ },
+
+ last: function(){
+ var values = this.recordsValues()
+ var record = values[values.length - 1];
+ return(record && record.clone());
+ },
+
+ count: function(){
+ return this.recordsValues().length;
+ },
+
+ deleteAll: function(){
+ for (var key in this.records)
+ delete this.records[key];
+ },
+
+ destroyAll: function(){
+ for (var key in this.records)
+ this.records[key].destroy();
+ },
+
+ update: function(id, atts){
+ this.find(id).updateAttributes(atts);
+ },
+
+ create: function(atts){
+ var record = this.init(atts);
+ record.save();
+ return record;
+ },
+
+ destroy: function(id){
+ this.find(id).destroy();
+ },
+
+ sync: function(callback){
+ this.bind("change", callback);
+ },
+
+ fetch: function(callback){
+ callback ? this.bind("fetch", callback) : this.trigger("fetch");
+ },
+
+ toJSON: function(){
+ return this.recordsValues();
+ },
+
+ fromJSON: function(objects){
+ var self = this;
+ if (typeof objects == "string")
+ objects = JSON.parse(objects)
+ if (typeof objects == "array")
+ return($.map(objects, function(){
+ return self.init(this);
+ }));
+ else
+ return this.init(objects);
+ },
+
+ // Private
+
+ recordsValues: function(){
+ var result = [];
+ for (var key in this.records)
+ result.push(this.records[key]);
+ return result;
+ },
+
+ cloneArray: function(array){
+ var result = [];
+ for (var i=0; i < array.length; i++)
+ result.push(array[i].dup());
+ return result;
+ }
});
Model.include({
@@ -354,13 +381,14 @@
save: function(){
var error = this.validate();
if (error) {
- if ( !this.trigger("error", error) )
+ if ( !this.trigger("error", this, error) )
throw("Validation failed: " + error);
}
- this.trigger("beforeSave");
+ this.trigger("beforeSave", this);
this.newRecord ? this.create() : this.update();
- this.trigger("save");
+ this.trigger("save", this);
+ return this;
},
updateAttribute: function(name, value){
@@ -374,9 +402,9 @@
},
destroy: function(){
- this.trigger("beforeDestroy");
+ this.trigger("beforeDestroy", this);
delete this.parent.records[this.id];
- this.trigger("destroy");
+ this.trigger("destroy", this);
},
dup: function(){
@@ -384,9 +412,16 @@
result.newRecord = this.newRecord;
return result;
},
+
+ clone: function(){
+ return Object.create(this);
+ },
reload: function(){
- return(this.parent.find(this.id));
+ if ( this.newRecord ) return this;
+ var original = this.parent.find(this.id);
+ this.load(original.attributes());
+ return original;
},
toJSON: function(){
@@ -400,30 +435,30 @@
// Private
update: function(){
- this.trigger("beforeUpdate");
- this.parent.records[this.id] = this.dup();
- this.trigger("update");
+ this.trigger("beforeUpdate", this);
+ var records = this.parent.records;
+ records[this.id].load(this.attributes());
+ this.trigger("update", records[this.id].clone());
},
create: function(){
- this.trigger("beforeCreate");
+ this.trigger("beforeCreate", this);
if ( !this.id ) this.id = Spine.guid();
- this.newRecord = false;
- this.parent.records[this.id] = this.dup();
- this.trigger("create");
+ this.newRecord = false;
+ var records = this.parent.records;
+ records[this.id] = this.dup();
+ this.trigger("create", records[this.id].clone());
},
bind: function(events, callback){
- this.parent.bind(events, this.proxy(function(record){
+ return this.parent.bind(events, this.proxy(function(record){
if ( record && this.eql(record) )
callback.apply(this, arguments);
}));
},
- trigger: function(events){
- var args = makeArray(arguments);
- args.splice(1, 0, this);
- this.parent.trigger.apply(this.parent, args);
+ trigger: function(){
+ return this.parent.trigger.apply(this.parent, arguments);
}
});
@@ -436,16 +471,16 @@
initializer: function(options){
this.options = options;
-
+
for (var key in this.options)
this[key] = this.options[key];
-
+
if (!this.el) this.el = document.createElement(this.tag);
this.el = $(this.el);
-
+
if ( !this.events ) this.events = this.parent.events;
if ( !this.elements ) this.elements = this.parent.elements;
-
+
if (this.events) this.delegateEvents();
if (this.elements) this.refreshElements();
if (this.proxied) this.proxyAll.apply(this, this.proxied);

0 comments on commit c3ca67d

Please sign in to comment.
Something went wrong with that request. Please try again.