3 // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
4 // Backbone may be freely distributed under the MIT license.
5 // For all details and documentation:
6 // http://backbonejs.org
7 (function(){var i
=this,r
=i
.Backbone
,s
=Array
.prototype.slice
,t
=Array
.prototype.splice
,g
;g
="undefined"!==typeof exports
?exports
:i
.Backbone
={};g
.VERSION
="0.9.1";var f
=i
._
;!f
&&"undefined"!==typeof require
&&(f
=require("underscore"));var h
=i
.jQuery
||i
.Zepto
||i
.ender
;g
.setDomLibrary=function(a
){h
=a
};g
.noConflict=function(){i
.Backbone
=r
;return this};g
.emulateHTTP
=!1;g
.emulateJSON
=!1;g
.Events
={on:function(a
,b
,c
){for(var d
,a
=a
.split(/\s+/),e
=this._callbacks
||(this._callbacks
={});d
=a
.shift();){d
=e
[d
]||(e
[d
]=
8 {});var f
=d
.tail
||(d
.tail
=d
.next
={});f
.callback
=b
;f
.context
=c
;d
.tail
=f
.next
={}}return this},off:function(a
,b
,c
){var d
,e
,f
;if(a
){if(e
=this._callbacks
)for(a
=a
.split(/\s+/);d
=a
.shift();)if(f
=e
[d
],delete e
[d
],b
&&f
)for(;(f
=f
.next
)&&f
.next
;)if(!(f
.callback
===b
&&(!c
||f
.context
===c
)))this.on(d
,f
.callback
,f
.context
)}else delete this._callbacks
;return this},trigger:function(a
){var b
,c
,d
,e
;if(!(d
=this._callbacks
))return this;e
=d
.all
;for((a
=a
.split(/\s+/)).push(null);b
=a
.shift();)e
&&a
.push({next
:e
.next
,tail
:e
.tail
,
9 event
:b
}),(c
=d
[b
])&&a
.push({next
:c
.next
,tail
:c
.tail
});for(e
=s
.call(arguments
,1);c
=a
.pop();){b
=c
.tail
;for(d
=c
.event
?[c
.event
].concat(e
):e
;(c
=c
.next
)!==b
;)c
.callback
.apply(c
.context
||this,d
)}return this}};g
.Events
.bind
=g
.Events
.on
;g
.Events
.unbind
=g
.Events
.off
;g
.Model=function(a
,b
){var c
;a
||(a
={});b
&&b
.parse
&&(a
=this.parse(a
));if(c
=j(this,"defaults"))a
=f
.extend({},c
,a
);b
&&b
.collection
&&(this.collection
=b
.collection
);this.attributes
={};this._escapedAttributes
={};this.cid
=f
.uniqueId("c");if(!this.set(a
,
10 {silent
:!0}))throw Error("Can't create an invalid model");delete this._changed
;this._previousAttributes
=f
.clone(this.attributes
);this.initialize
.apply(this,arguments
)};f
.extend(g
.Model
.prototype,g
.Events
,{idAttribute
:"id",initialize:function(){},toJSON:function(){return f
.clone(this.attributes
)},get:function(a
){return this.attributes
[a
]},escape:function(a
){var b
;if(b
=this._escapedAttributes
[a
])return b
;b
=this.attributes
[a
];return this._escapedAttributes
[a
]=f
.escape(null==b
?"":""+b
)},has:function(a
){return null!=
11 this.attributes
[a
]},set:function(a
,b
,c
){var d
,e
;f
.isObject(a
)||null==a
?(d
=a
,c
=b
):(d
={},d
[a
]=b
);c
||(c
={});if(!d
)return this;d
instanceof g
.Model
&&(d
=d
.attributes
);if(c
.unset
)for(e
in d
)d
[e
]=void 0;if(!this._validate(d
,c
))return!1;this.idAttribute
in d
&&(this.id
=d
[this.idAttribute
]);var b
=this.attributes
,k
=this._escapedAttributes
,n
=this._previousAttributes
||{},h
=this._setting
;this._changed
||(this._changed
={});this._setting
=!0;for(e
in d
)if(a
=d
[e
],f
.isEqual(b
[e
],a
)||delete k
[e
],c
.unset
?delete b
[e
]:b
[e
]=
12 a
,this._changing
&&!f
.isEqual(this._changed
[e
],a
)&&(this.trigger("change:"+e
,this,a
,c
),this._moreChanges
=!0),delete this._changed
[e
],!f
.isEqual(n
[e
],a
)||f
.has(b
,e
)!=f
.has(n
,e
))this._changed
[e
]=a
;h
||(!c
.silent
&&this.hasChanged()&&this.change(c
),this._setting
=!1);return this},unset:function(a
,b
){(b
||(b
={})).unset
=!0;return this.set(a
,null,b
)},clear:function(a
){(a
||(a
={})).unset
=!0;return this.set(f
.clone(this.attributes
),a
)},fetch:function(a
){var a
=a
?f
.clone(a
):{},b
=this,c
=a
.success
;a
.success=function(d
,
13 e
,f
){if(!b
.set(b
.parse(d
,f
),a
))return!1;c
&&c(b
,d
)};a
.error
=g
.wrapError(a
.error
,b
,a
);return(this.sync
||g
.sync
).call(this,"read",this,a
)},save:function(a
,b
,c
){var d
,e
;f
.isObject(a
)||null==a
?(d
=a
,c
=b
):(d
={},d
[a
]=b
);c
=c
?f
.clone(c
):{};c
.wait
&&(e
=f
.clone(this.attributes
));a
=f
.extend({},c
,{silent
:!0});if(d
&&!this.set(d
,c
.wait
?a
:c
))return!1;var k
=this,h
=c
.success
;c
.success=function(a
,b
,e
){b
=k
.parse(a
,e
);c
.wait
&&(b
=f
.extend(d
||{},b
));if(!k
.set(b
,c
))return!1;h
?h(k
,a
):k
.trigger("sync",k
,a
,c
)};c
.error
=g
.wrapError(c
.error
,
14 k
,c
);b
=this.isNew()?"create":"update";b
=(this.sync
||g
.sync
).call(this,b
,this,c
);c
.wait
&&this.set(e
,a
);return b
},destroy:function(a
){var a
=a
?f
.clone(a
):{},b
=this,c
=a
.success
,d=function(){b
.trigger("destroy",b
,b
.collection
,a
)};if(this.isNew())return d();a
.success=function(e
){a
.wait
&&d();c
?c(b
,e
):b
.trigger("sync",b
,e
,a
)};a
.error
=g
.wrapError(a
.error
,b
,a
);var e
=(this.sync
||g
.sync
).call(this,"delete",this,a
);a
.wait
||d();return e
},url:function(){var a
=j(this.collection
,"url")||j(this,"urlRoot")||o();return this.isNew()?
15 a
:a
+("/"==a
.charAt(a
.length
-1)?"":"/")+encodeURIComponent(this.id
)},parse:function(a
){return a
},clone:function(){return new this.constructor(this.attributes
)},isNew:function(){return null==this.id
},change:function(a
){if(this._changing
||!this.hasChanged())return this;this._moreChanges
=this._changing
=!0;for(var b
in this._changed
)this.trigger("change:"+b
,this,this._changed
[b
],a
);for(;this._moreChanges
;)this._moreChanges
=!1,this.trigger("change",this,a
);this._previousAttributes
=f
.clone(this.attributes
);
16 delete this._changed
;this._changing
=!1;return this},hasChanged:function(a
){return!arguments
.length
?!f
.isEmpty(this._changed
):this._changed
&&f
.has(this._changed
,a
)},changedAttributes:function(a
){if(!a
)return this.hasChanged()?f
.clone(this._changed
):!1;var b
,c
=!1,d
=this._previousAttributes
,e
;for(e
in a
)if(!f
.isEqual(d
[e
],b
=a
[e
]))(c
||(c
={}))[e
]=b
;return c
},previous:function(a
){return!arguments
.length
||!this._previousAttributes
?null:this._previousAttributes
[a
]},previousAttributes:function(){return f
.clone(this._previousAttributes
)},
17 isValid:function(){return!this.validate(this.attributes
)},_validate:function(a
,b
){if(b
.silent
||!this.validate
)return!0;var a
=f
.extend({},this.attributes
,a
),c
=this.validate(a
,b
);if(!c
)return!0;b
&&b
.error
?b
.error(this,c
,b
):this.trigger("error",this,c
,b
);return!1}});g
.Collection=function(a
,b
){b
||(b
={});b
.comparator
&&(this.comparator
=b
.comparator
);this._reset();this.initialize
.apply(this,arguments
);a
&&this.reset(a
,{silent
:!0,parse
:b
.parse
})};f
.extend(g
.Collection
.prototype,g
.Events
,{model
:g
.Model
,initialize:function(){},
18 toJSON:function(){return this.map(function(a
){return a
.toJSON()})},add:function(a
,b
){var c
,d
,e
,g
,h
,i
={},j
={};b
||(b
={});a
=f
.isArray(a
)?a
.slice():[a
];for(c
=0,d
=a
.length
;c
<d
;c
++){if(!(e
=a
[c
]=this._prepareModel(a
[c
],b
)))throw Error("Can't add an invalid model to a collection");if(i
[g
=e
.cid
]||this._byCid
[g
]||null!=(h
=e
.id
)&&(j
[h
]||this._byId
[h
]))throw Error("Can't add the same model to a collection twice");i
[g
]=j
[h
]=e
}for(c
=0;c
<d
;c
++)(e
=a
[c
]).on("all",this._onModelEvent
,this),this._byCid
[e
.cid
]=e
,null!=
19 e
.id
&&(this._byId
[e
.id
]=e
);this.length
+=d
;t
.apply(this.models
,[null!=b
.at
?b
.at
:this.models
.length
,0].concat(a
));this.comparator
&&this.sort({silent
:!0});if(b
.silent
)return this;for(c
=0,d
=this.models
.length
;c
<d
;c
++)if(i
[(e
=this.models
[c
]).cid
])b
.index
=c
,e
.trigger("add",e
,this,b
);return this},remove:function(a
,b
){var c
,d
,e
,g
;b
||(b
={});a
=f
.isArray(a
)?a
.slice():[a
];for(c
=0,d
=a
.length
;c
<d
;c
++)if(g
=this.getByCid(a
[c
])||this.get(a
[c
]))delete this._byId
[g
.id
],delete this._byCid
[g
.cid
],e
=this.indexOf(g
),this.models
.splice(e
,
20 1),this.length
--,b
.silent
||(b
.index
=e
,g
.trigger("remove",g
,this,b
)),this._removeReference(g
);return this},get:function(a
){return null==a
?null:this._byId
[null!=a
.id
?a
.id
:a
]},getByCid:function(a
){return a
&&this._byCid
[a
.cid
||a
]},at:function(a
){return this.models
[a
]},sort:function(a
){a
||(a
={});if(!this.comparator
)throw Error("Cannot sort a set without a comparator");var b
=f
.bind(this.comparator
,this);1==this.comparator
.length
?this.models
=this.sortBy(b
):this.models
.sort(b
);a
.silent
||this.trigger("reset",
21 this,a
);return this},pluck:function(a
){return f
.map(this.models
,function(b
){return b
.get(a
)})},reset:function(a
,b
){a
||(a
=[]);b
||(b
={});for(var c
=0,d
=this.models
.length
;c
<d
;c
++)this._removeReference(this.models
[c
]);this._reset();this.add(a
,{silent
:!0,parse
:b
.parse
});b
.silent
||this.trigger("reset",this,b
);return this},fetch:function(a
){a
=a
?f
.clone(a
):{};void 0===a
.parse
&&(a
.parse
=!0);var b
=this,c
=a
.success
;a
.success=function(d
,e
,f
){b
[a
.add
?"add":"reset"](b
.parse(d
,f
),a
);c
&&c(b
,d
)};a
.error
=g
.wrapError(a
.error
,
22 b
,a
);return(this.sync
||g
.sync
).call(this,"read",this,a
)},create:function(a
,b
){var c
=this,b
=b
?f
.clone(b
):{},a
=this._prepareModel(a
,b
);if(!a
)return!1;b
.wait
||c
.add(a
,b
);var d
=b
.success
;b
.success=function(e
,f
){b
.wait
&&c
.add(e
,b
);d
?d(e
,f
):e
.trigger("sync",a
,f
,b
)};a
.save(null,b
);return a
},parse:function(a
){return a
},chain:function(){return f(this.models
).chain()},_reset:function(){this.length
=0;this.models
=[];this._byId
={};this._byCid
={}},_prepareModel:function(a
,b
){a
instanceof g
.Model
?a
.collection
||
23 (a
.collection
=this):(b
.collection
=this,a
=new this.model(a
,b
),a
._validate(a
.attributes
,b
)||(a
=!1));return a
},_removeReference:function(a
){this==a
.collection
&&delete a
.collection
;a
.off("all",this._onModelEvent
,this)},_onModelEvent:function(a
,b
,c
,d
){("add"==a
||"remove"==a
)&&c
!=this||("destroy"==a
&&this.remove(b
,d
),b
&&a
==="change:"+b
.idAttribute
&&(delete this._byId
[b
.previous(b
.idAttribute
)],this._byId
[b
.id
]=b
),this.trigger
.apply(this,arguments
))}});f
.each("forEach,each,map,reduce,reduceRight,find,detect,filter,select,reject,every,all,some,any,include,contains,invoke,max,min,sortBy,sortedIndex,toArray,size,first,initial,rest,last,without,indexOf,shuffle,lastIndexOf,isEmpty,groupBy".split(","),
24 function(a
){g
.Collection
.prototype[a
]=function(){return f
[a
].apply(f
,[this.models
].concat(f
.toArray(arguments
)))}});g
.Router=function(a
){a
||(a
={});a
.routes
&&(this.routes
=a
.routes
);this._bindRoutes();this.initialize
.apply(this,arguments
)};var u
=/:\w+/g,v
=/\*\w+/g,w
=/[-[\]{}()+?.,\\^$|#\s]/g;f
.extend(g
.Router
.prototype,g
.Events
,{initialize:function(){},route:function(a
,b
,c
){g
.history
||(g
.history
=new g
.History
);f
.isRegExp(a
)||(a
=this._routeToRegExp(a
));c
||(c
=this[b
]);g
.history
.route(a
,f
.bind(function(d
){d
=
25 this._extractParameters(a
,d
);c
&&c
.apply(this,d
);this.trigger
.apply(this,["route:"+b
].concat(d
));g
.history
.trigger("route",this,b
,d
)},this));return this},navigate:function(a
,b
){g
.history
.navigate(a
,b
)},_bindRoutes:function(){if(this.routes
){var a
=[],b
;for(b
in this.routes
)a
.unshift([b
,this.routes
[b
]]);b
=0;for(var c
=a
.length
;b
<c
;b
++)this.route(a
[b
][0],a
[b
][1],this[a
[b
][1]])}},_routeToRegExp:function(a
){a
=a
.replace(w
,"\\$&").replace(u
,"([^/]+)").replace(v
,"(.*?)");return RegExp("^"+a
+"$")},_extractParameters:function(a
,
26 b
){return a
.exec(b
).slice(1)}});g
.History=function(){this.handlers
=[];f
.bindAll(this,"checkUrl")};var m
=/^[#\/]/,x
=/msie [\w.]+/,l
=!1;f
.extend(g
.History
.prototype,g
.Events
,{interval
:50,getFragment:function(a
,b
){if(null==a
)if(this._hasPushState
||b
){var a
=window
.location
.pathname
,c
=window
.location
.search
;c
&&(a
+=c
)}else a
=window
.location
.hash
;a
=decodeURIComponent(a
);a
.indexOf(this.options
.root
)||(a
=a
.substr(this.options
.root
.length
));return a
.replace(m
,"")},start:function(a
){if(l
)throw Error("Backbone.history has already been started");
27 this.options
=f
.extend({},{root
:"/"},this.options
,a
);this._wantsHashChange
=!1!==this.options
.hashChange
;this._wantsPushState
=!!this.options
.pushState
;this._hasPushState
=!(!this.options
.pushState
||!window
.history
||!window
.history
.pushState
);var a
=this.getFragment(),b
=document
.documentMode
;if(b
=x
.exec(navigator
.userAgent
.toLowerCase())&&(!b
||7>=b
))this.iframe
=h('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow
,this.navigate(a
);this._hasPushState
?h(window
).bind("popstate",
28 this.checkUrl
):this._wantsHashChange
&&"onhashchange"in window
&&!b
?h(window
).bind("hashchange",this.checkUrl
):this._wantsHashChange
&&(this._checkUrlInterval
=setInterval(this.checkUrl
,this.interval
));this.fragment
=a
;l
=!0;a
=window
.location
;b
=a
.pathname
==this.options
.root
;if(this._wantsHashChange
&&this._wantsPushState
&&!this._hasPushState
&&!b
)return this.fragment
=this.getFragment(null,!0),window
.location
.replace(this.options
.root
+"#"+this.fragment
),!0;this._wantsPushState
&&this._hasPushState
&&b
&&a
.hash
&&
29 (this.fragment
=a
.hash
.replace(m
,""),window
.history
.replaceState({},document
.title
,a
.protocol
+"//"+a
.host
+this.options
.root
+this.fragment
));if(!this.options
.silent
)return this.loadUrl()},stop:function(){h(window
).unbind("popstate",this.checkUrl
).unbind("hashchange",this.checkUrl
);clearInterval(this._checkUrlInterval
);l
=!1},route:function(a
,b
){this.handlers
.unshift({route
:a
,callback
:b
})},checkUrl:function(){var a
=this.getFragment();a
==this.fragment
&&this.iframe
&&(a
=this.getFragment(this.iframe
.location
.hash
));
30 if(a
==this.fragment
||a
==decodeURIComponent(this.fragment
))return!1;this.iframe
&&this.navigate(a
);this.loadUrl()||this.loadUrl(window
.location
.hash
)},loadUrl:function(a
){var b
=this.fragment
=this.getFragment(a
);return f
.any(this.handlers
,function(a
){if(a
.route
.test(b
))return a
.callback(b
),!0})},navigate:function(a
,b
){if(!l
)return!1;if(!b
||!0===b
)b
={trigger
:b
};var c
=(a
||"").replace(m
,"");this.fragment
==c
||this.fragment
==decodeURIComponent(c
)||(this._hasPushState
?(0!=c
.indexOf(this.options
.root
)&&(c
=
31 this.options
.root
+c
),this.fragment
=c
,window
.history
[b
.replace
?"replaceState":"pushState"]({},document
.title
,c
)):this._wantsHashChange
?(this.fragment
=c
,this._updateHash(window
.location
,c
,b
.replace
),this.iframe
&&c
!=this.getFragment(this.iframe
.location
.hash
)&&(b
.replace
||this.iframe
.document
.open().close(),this._updateHash(this.iframe
.location
,c
,b
.replace
))):window
.location
.assign(this.options
.root
+a
),b
.trigger
&&this.loadUrl(a
))},_updateHash:function(a
,b
,c
){c
?a
.replace(a
.toString().replace(/(javascript:|#).*$/,
32 "")+"#"+b
):a
.hash
=b
}});g
.View=function(a
){this.cid
=f
.uniqueId("view");this._configure(a
||{});this._ensureElement();this.initialize
.apply(this,arguments
);this.delegateEvents()};var y
=/^(\S+)\s*(.*)$/,p
="model,collection,el,id,attributes,className,tagName".split(",");f
.extend(g
.View
.prototype,g
.Events
,{tagName
:"div",$:function(a
){return this.$el
.find(a
)},initialize:function(){},render:function(){return this},remove:function(){this.$el
.remove();return this},make:function(a
,b
,c
){a
=document
.createElement(a
);
33 b
&&h(a
).attr(b
);c
&&h(a
).html(c
);return a
},setElement:function(a
,b
){this.$el
=h(a
);this.el
=this.$el
[0];!1!==b
&&this.delegateEvents();return this},delegateEvents:function(a
){if(a
||(a
=j(this,"events"))){this.undelegateEvents();for(var b
in a
){var c
=a
[b
];f
.isFunction(c
)||(c
=this[a
[b
]]);if(!c
)throw Error('Event "'+a
[b
]+'" does not exist');var d
=b
.match(y
),e
=d
[1],d
=d
[2],c
=f
.bind(c
,this),e
=e
+(".delegateEvents"+this.cid
);""===d
?this.$el
.bind(e
,c
):this.$el
.delegate(d
,e
,c
)}}},undelegateEvents:function(){this.$el
.unbind(".delegateEvents"+
34 this.cid
)},_configure:function(a
){this.options
&&(a
=f
.extend({},this.options
,a
));for(var b
=0,c
=p
.length
;b
<c
;b
++){var d
=p
[b
];a
[d
]&&(this[d
]=a
[d
])}this.options
=a
},_ensureElement:function(){if(this.el
)this.setElement(this.el
,!1);else{var a
=j(this,"attributes")||{};this.id
&&(a
.id
=this.id
);this.className
&&(a
["class"]=this.className
);this.setElement(this.make(this.tagName
,a
),!1)}}});g
.Model
.extend
=g
.Collection
.extend
=g
.Router
.extend
=g
.View
.extend=function(a
,b
){var c
=z(this,a
,b
);c
.extend
=this.extend
;return c
};
35 var A
={create
:"POST",update
:"PUT","delete":"DELETE",read
:"GET"};g
.sync=function(a
,b
,c
){var d
=A
[a
],e
={type
:d
,dataType
:"json"};c
.url
||(e
.url
=j(b
,"url")||o());if(!c
.data
&&b
&&("create"==a
||"update"==a
))e
.contentType
="application/json",e
.data
=JSON
.stringify(b
.toJSON());g
.emulateJSON
&&(e
.contentType
="application/x-www-form-urlencoded",e
.data
=e
.data
?{model
:e
.data
}:{});if(g
.emulateHTTP
&&("PUT"===d
||"DELETE"===d
))g
.emulateJSON
&&(e
.data
._method
=d
),e
.type
="POST",e
.beforeSend=function(a
){a
.setRequestHeader("X-HTTP-Method-Override",
36 d
)};"GET"!==e
.type
&&!g
.emulateJSON
&&(e
.processData
=!1);return h
.ajax(f
.extend(e
,c
))};g
.wrapError=function(a
,b
,c
){return function(d
,e
){e
=d
===b
?e
:d
;a
?a(b
,e
,c
):b
.trigger("error",b
,e
,c
)}};var q=function(){},z=function(a
,b
,c
){var d
;d
=b
&&b
.hasOwnProperty("constructor")?b
.constructor:function(){a
.apply(this,arguments
)};f
.extend(d
,a
);q
.prototype=a
.prototype;d
.prototype=new q
;b
&&f
.extend(d
.prototype,b
);c
&&f
.extend(d
,c
);d
.prototype.constructor=d
;d
.__super__
=a
.prototype;return d
},j=function(a
,b
){return!a
||!a
[b
]?
37 null:f
.isFunction(a
[b
])?a
[b
]():a
[b
]},o=function(){throw Error('A "url" property or function must be specified');}}).call(this);