diff options
author | Arthur Schiwon <blizzz@owncloud.com> | 2015-08-06 00:00:40 +0200 |
---|---|---|
committer | Arthur Schiwon <blizzz@owncloud.com> | 2015-08-06 00:00:40 +0200 |
commit | dc04afbe29375091eeb10bfb18aac42ed62dcccc (patch) | |
tree | f233f57a576e719d604ad71db5866a317d981927 /core/vendor | |
parent | 7f44b0fd18771842bba8957dae4a50c5483a7280 (diff) | |
download | nextcloud-server-dc04afbe29375091eeb10bfb18aac42ed62dcccc.tar.gz nextcloud-server-dc04afbe29375091eeb10bfb18aac42ed62dcccc.zip |
add backbone.js
Diffstat (limited to 'core/vendor')
-rw-r--r-- | core/vendor/backbone/.bower.json | 33 | ||||
-rw-r--r-- | core/vendor/backbone/LICENSE | 22 | ||||
-rw-r--r-- | core/vendor/backbone/backbone-min.js | 2 | ||||
-rw-r--r-- | core/vendor/backbone/backbone-min.map | 1 | ||||
-rw-r--r-- | core/vendor/backbone/backbone.js | 1873 |
5 files changed, 1931 insertions, 0 deletions
diff --git a/core/vendor/backbone/.bower.json b/core/vendor/backbone/.bower.json new file mode 100644 index 00000000000..578c8ffb669 --- /dev/null +++ b/core/vendor/backbone/.bower.json @@ -0,0 +1,33 @@ +{ + "name": "backbone", + "version": "1.2.1", + "main": "backbone.js", + "dependencies": { + "underscore": ">=1.7.0" + }, + "ignore": [ + "docs", + "examples", + "test", + "*.yml", + "*.html", + "*.ico", + "*.md", + "CNAME", + ".*", + "karma.*", + "component.json", + "package.json" + ], + "homepage": "https://github.com/jashkenas/backbone", + "_release": "1.2.1", + "_resolution": { + "type": "version", + "tag": "1.2.1", + "commit": "938a8ff934fd4de4f0009f68d43f500f5920b490" + }, + "_source": "git://github.com/jashkenas/backbone.git", + "_target": "~1.2.1", + "_originalSource": "backbone", + "_direct": true +}
\ No newline at end of file diff --git a/core/vendor/backbone/LICENSE b/core/vendor/backbone/LICENSE new file mode 100644 index 00000000000..184d1b99645 --- /dev/null +++ b/core/vendor/backbone/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2010-2015 Jeremy Ashkenas, DocumentCloud + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/core/vendor/backbone/backbone-min.js b/core/vendor/backbone/backbone-min.js new file mode 100644 index 00000000000..f29903b1ae6 --- /dev/null +++ b/core/vendor/backbone/backbone-min.js @@ -0,0 +1,2 @@ +(function(t){var e=typeof self=="object"&&self.self==self&&self||typeof global=="object"&&global.global==global&&global;if(typeof define==="function"&&define.amd){define(["underscore","jquery","exports"],function(i,r,s){e.Backbone=t(e,s,i,r)})}else if(typeof exports!=="undefined"){var i=require("underscore"),r;try{r=require("jquery")}catch(s){}t(e,exports,i,r)}else{e.Backbone=t(e,{},e._,e.jQuery||e.Zepto||e.ender||e.$)}})(function(t,e,i,r){var s=t.Backbone;var n=[].slice;e.VERSION="1.2.1";e.$=r;e.noConflict=function(){t.Backbone=s;return this};e.emulateHTTP=false;e.emulateJSON=false;var a=function(t,e,r){switch(t){case 1:return function(){return i[e](this[r])};case 2:return function(t){return i[e](this[r],t)};case 3:return function(t,s){return i[e](this[r],t,s)};case 4:return function(t,s,n){return i[e](this[r],t,s,n)};default:return function(){var t=n.call(arguments);t.unshift(this[r]);return i[e].apply(i,t)}}};var o=function(t,e,r){i.each(e,function(e,s){if(i[s])t.prototype[s]=a(e,s,r)})};var h=e.Events={};var u=/\s+/;var l=function(t,e,r,s,n){var a=0,o;if(r&&typeof r==="object"){if(s!==void 0&&"context"in n&&n.context===void 0)n.context=s;for(o=i.keys(r);a<o.length;a++){e=t(e,o[a],r[o[a]],n)}}else if(r&&u.test(r)){for(o=r.split(u);a<o.length;a++){e=t(e,o[a],s,n)}}else{e=t(e,r,s,n)}return e};h.on=function(t,e,i){return c(this,t,e,i)};var c=function(t,e,i,r,s){t._events=l(f,t._events||{},e,i,{context:r,ctx:t,listening:s});if(s){var n=t._listeners||(t._listeners={});n[s.id]=s}return t};h.listenTo=function(t,e,r){if(!t)return this;var s=t._listenId||(t._listenId=i.uniqueId("l"));var n=this._listeningTo||(this._listeningTo={});var a=n[s];if(!a){var o=this._listenId||(this._listenId=i.uniqueId("l"));a=n[s]={obj:t,objId:s,id:o,listeningTo:n,count:0}}c(t,e,r,this,a);return this};var f=function(t,e,i,r){if(i){var s=t[e]||(t[e]=[]);var n=r.context,a=r.ctx,o=r.listening;if(o)o.count++;s.push({callback:i,context:n,ctx:n||a,listening:o})}return t};h.off=function(t,e,i){if(!this._events)return this;this._events=l(d,this._events,t,e,{context:i,listeners:this._listeners});return this};h.stopListening=function(t,e,r){var s=this._listeningTo;if(!s)return this;var n=t?[t._listenId]:i.keys(s);for(var a=0;a<n.length;a++){var o=s[n[a]];if(!o)break;o.obj.off(e,r,this)}if(i.isEmpty(s))this._listeningTo=void 0;return this};var d=function(t,e,r,s){if(!t)return;var n=0,a;var o=s.context,h=s.listeners;if(!e&&!r&&!o){var u=i.keys(h);for(;n<u.length;n++){a=h[u[n]];delete h[a.id];delete a.listeningTo[a.objId]}return}var l=e?[e]:i.keys(t);for(;n<l.length;n++){e=l[n];var c=t[e];if(!c)break;var f=[];for(var d=0;d<c.length;d++){var v=c[d];if(r&&r!==v.callback&&r!==v.callback._callback||o&&o!==v.context){f.push(v)}else{a=v.listening;if(a&&--a.count===0){delete h[a.id];delete a.listeningTo[a.objId]}}}if(f.length){t[e]=f}else{delete t[e]}}if(i.size(t))return t};h.once=function(t,e,r){var s=l(v,{},t,e,i.bind(this.off,this));return this.on(s,void 0,r)};h.listenToOnce=function(t,e,r){var s=l(v,{},e,r,i.bind(this.stopListening,this,t));return this.listenTo(t,s)};var v=function(t,e,r,s){if(r){var n=t[e]=i.once(function(){s(e,n);r.apply(this,arguments)});n._callback=r}return t};h.trigger=function(t){if(!this._events)return this;var e=Math.max(0,arguments.length-1);var i=Array(e);for(var r=0;r<e;r++)i[r]=arguments[r+1];l(g,this._events,t,void 0,i);return this};var g=function(t,e,i,r){if(t){var s=t[e];var n=t.all;if(s&&n)n=n.slice();if(s)p(s,r);if(n)p(n,[e].concat(r))}return t};var p=function(t,e){var i,r=-1,s=t.length,n=e[0],a=e[1],o=e[2];switch(e.length){case 0:while(++r<s)(i=t[r]).callback.call(i.ctx);return;case 1:while(++r<s)(i=t[r]).callback.call(i.ctx,n);return;case 2:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a);return;case 3:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a,o);return;default:while(++r<s)(i=t[r]).callback.apply(i.ctx,e);return}};h.bind=h.on;h.unbind=h.off;i.extend(e,h);var m=e.Model=function(t,e){var r=t||{};e||(e={});this.cid=i.uniqueId(this.cidPrefix);this.attributes={};if(e.collection)this.collection=e.collection;if(e.parse)r=this.parse(r,e)||{};r=i.defaults({},r,i.result(this,"defaults"));this.set(r,e);this.changed={};this.initialize.apply(this,arguments)};i.extend(m.prototype,h,{changed:null,validationError:null,idAttribute:"id",cidPrefix:"c",initialize:function(){},toJSON:function(t){return i.clone(this.attributes)},sync:function(){return e.sync.apply(this,arguments)},get:function(t){return this.attributes[t]},escape:function(t){return i.escape(this.get(t))},has:function(t){return this.get(t)!=null},matches:function(t){return!!i.iteratee(t,this)(this.attributes)},set:function(t,e,r){if(t==null)return this;var s;if(typeof t==="object"){s=t;r=e}else{(s={})[t]=e}r||(r={});if(!this._validate(s,r))return false;var n=r.unset;var a=r.silent;var o=[];var h=this._changing;this._changing=true;if(!h){this._previousAttributes=i.clone(this.attributes);this.changed={}}var u=this.attributes;var l=this.changed;var c=this._previousAttributes;if(this.idAttribute in s)this.id=s[this.idAttribute];for(var f in s){e=s[f];if(!i.isEqual(u[f],e))o.push(f);if(!i.isEqual(c[f],e)){l[f]=e}else{delete l[f]}n?delete u[f]:u[f]=e}if(!a){if(o.length)this._pending=r;for(var d=0;d<o.length;d++){this.trigger("change:"+o[d],this,u[o[d]],r)}}if(h)return this;if(!a){while(this._pending){r=this._pending;this._pending=false;this.trigger("change",this,r)}}this._pending=false;this._changing=false;return this},unset:function(t,e){return this.set(t,void 0,i.extend({},e,{unset:true}))},clear:function(t){var e={};for(var r in this.attributes)e[r]=void 0;return this.set(e,i.extend({},t,{unset:true}))},hasChanged:function(t){if(t==null)return!i.isEmpty(this.changed);return i.has(this.changed,t)},changedAttributes:function(t){if(!t)return this.hasChanged()?i.clone(this.changed):false;var e=this._changing?this._previousAttributes:this.attributes;var r={};for(var s in t){var n=t[s];if(i.isEqual(e[s],n))continue;r[s]=n}return i.size(r)?r:false},previous:function(t){if(t==null||!this._previousAttributes)return null;return this._previousAttributes[t]},previousAttributes:function(){return i.clone(this._previousAttributes)},fetch:function(t){t=i.extend({parse:true},t);var e=this;var r=t.success;t.success=function(i){var s=t.parse?e.parse(i,t):i;if(!e.set(s,t))return false;if(r)r.call(t.context,e,i,t);e.trigger("sync",e,i,t)};q(this,t);return this.sync("read",this,t)},save:function(t,e,r){var s;if(t==null||typeof t==="object"){s=t;r=e}else{(s={})[t]=e}r=i.extend({validate:true,parse:true},r);var n=r.wait;if(s&&!n){if(!this.set(s,r))return false}else{if(!this._validate(s,r))return false}var a=this;var o=r.success;var h=this.attributes;r.success=function(t){a.attributes=h;var e=r.parse?a.parse(t,r):t;if(n)e=i.extend({},s,e);if(e&&!a.set(e,r))return false;if(o)o.call(r.context,a,t,r);a.trigger("sync",a,t,r)};q(this,r);if(s&&n)this.attributes=i.extend({},h,s);var u=this.isNew()?"create":r.patch?"patch":"update";if(u==="patch"&&!r.attrs)r.attrs=s;var l=this.sync(u,this,r);this.attributes=h;return l},destroy:function(t){t=t?i.clone(t):{};var e=this;var r=t.success;var s=t.wait;var n=function(){e.stopListening();e.trigger("destroy",e,e.collection,t)};t.success=function(i){if(s)n();if(r)r.call(t.context,e,i,t);if(!e.isNew())e.trigger("sync",e,i,t)};var a=false;if(this.isNew()){i.defer(t.success)}else{q(this,t);a=this.sync("delete",this,t)}if(!s)n();return a},url:function(){var t=i.result(this,"urlRoot")||i.result(this.collection,"url")||M();if(this.isNew())return t;var e=this.get(this.idAttribute);return t.replace(/[^\/]$/,"$&/")+encodeURIComponent(e)},parse:function(t,e){return t},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return!this.has(this.idAttribute)},isValid:function(t){return this._validate({},i.defaults({validate:true},t))},_validate:function(t,e){if(!e.validate||!this.validate)return true;t=i.extend({},this.attributes,t);var r=this.validationError=this.validate(t,e)||null;if(!r)return true;this.trigger("invalid",this,r,i.extend(e,{validationError:r}));return false}});var _={keys:1,values:1,pairs:1,invert:1,pick:0,omit:0,chain:1,isEmpty:1};o(m,_,"attributes");var y=e.Collection=function(t,e){e||(e={});if(e.model)this.model=e.model;if(e.comparator!==void 0)this.comparator=e.comparator;this._reset();this.initialize.apply(this,arguments);if(t)this.reset(t,i.extend({silent:true},e))};var b={add:true,remove:true,merge:true};var x={add:true,remove:false};i.extend(y.prototype,h,{model:m,initialize:function(){},toJSON:function(t){return this.map(function(e){return e.toJSON(t)})},sync:function(){return e.sync.apply(this,arguments)},add:function(t,e){return this.set(t,i.extend({merge:false},e,x))},remove:function(t,e){e=i.extend({},e);var r=!i.isArray(t);t=r?[t]:i.clone(t);var s=this._removeModels(t,e);if(!e.silent&&s)this.trigger("update",this,e);return r?s[0]:s},set:function(t,e){e=i.defaults({},e,b);if(e.parse&&!this._isModel(t))t=this.parse(t,e);var r=!i.isArray(t);t=r?t?[t]:[]:t.slice();var s,n,a,o,h;var u=e.at;if(u!=null)u=+u;if(u<0)u+=this.length+1;var l=this.comparator&&u==null&&e.sort!==false;var c=i.isString(this.comparator)?this.comparator:null;var f=[],d=[],v={};var g=e.add,p=e.merge,m=e.remove;var _=!l&&g&&m?[]:false;var y=false;for(var x=0;x<t.length;x++){a=t[x];if(o=this.get(a)){if(m)v[o.cid]=true;if(p&&a!==o){a=this._isModel(a)?a.attributes:a;if(e.parse)a=o.parse(a,e);o.set(a,e);if(l&&!h&&o.hasChanged(c))h=true}t[x]=o}else if(g){n=t[x]=this._prepareModel(a,e);if(!n)continue;f.push(n);this._addReference(n,e)}n=o||n;if(!n)continue;s=this.modelId(n.attributes);if(_&&(n.isNew()||!v[s])){_.push(n);y=y||!this.models[x]||n.cid!==this.models[x].cid}v[s]=true}if(m){for(var x=0;x<this.length;x++){if(!v[(n=this.models[x]).cid])d.push(n)}if(d.length)this._removeModels(d,e)}if(f.length||y){if(l)h=true;this.length+=f.length;if(u!=null){for(var x=0;x<f.length;x++){this.models.splice(u+x,0,f[x])}}else{if(_)this.models.length=0;var w=_||f;for(var x=0;x<w.length;x++){this.models.push(w[x])}}}if(h)this.sort({silent:true});if(!e.silent){var E=u!=null?i.clone(e):e;for(var x=0;x<f.length;x++){if(u!=null)E.index=u+x;(n=f[x]).trigger("add",n,this,E)}if(h||y)this.trigger("sort",this,e);if(f.length||d.length)this.trigger("update",this,e)}return r?t[0]:t},reset:function(t,e){e=e?i.clone(e):{};for(var r=0;r<this.models.length;r++){this._removeReference(this.models[r],e)}e.previousModels=this.models;this._reset();t=this.add(t,i.extend({silent:true},e));if(!e.silent)this.trigger("reset",this,e);return t},push:function(t,e){return this.add(t,i.extend({at:this.length},e))},pop:function(t){var e=this.at(this.length-1);return this.remove(e,t)},unshift:function(t,e){return this.add(t,i.extend({at:0},e))},shift:function(t){var e=this.at(0);return this.remove(e,t)},slice:function(){return n.apply(this.models,arguments)},get:function(t){if(t==null)return void 0;var e=this.modelId(this._isModel(t)?t.attributes:t);return this._byId[t]||this._byId[e]||this._byId[t.cid]},at:function(t){if(t<0)t+=this.length;return this.models[t]},where:function(t,e){var r=i.matches(t);return this[e?"find":"filter"](function(t){return r(t.attributes)})},findWhere:function(t){return this.where(t,true)},sort:function(t){if(!this.comparator)throw new Error("Cannot sort a set without a comparator");t||(t={});if(i.isString(this.comparator)||this.comparator.length===1){this.models=this.sortBy(this.comparator,this)}else{this.models.sort(i.bind(this.comparator,this))}if(!t.silent)this.trigger("sort",this,t);return this},pluck:function(t){return i.invoke(this.models,"get",t)},fetch:function(t){t=i.extend({parse:true},t);var e=t.success;var r=this;t.success=function(i){var s=t.reset?"reset":"set";r[s](i,t);if(e)e.call(t.context,r,i,t);r.trigger("sync",r,i,t)};q(this,t);return this.sync("read",this,t)},create:function(t,e){e=e?i.clone(e):{};var r=e.wait;t=this._prepareModel(t,e);if(!t)return false;if(!r)this.add(t,e);var s=this;var n=e.success;e.success=function(t,e,i){if(r)s.add(t,i);if(n)n.call(i.context,t,e,i)};t.save(null,e);return t},parse:function(t,e){return t},clone:function(){return new this.constructor(this.models,{model:this.model,comparator:this.comparator})},modelId:function(t){return t[this.model.prototype.idAttribute||"id"]},_reset:function(){this.length=0;this.models=[];this._byId={}},_prepareModel:function(t,e){if(this._isModel(t)){if(!t.collection)t.collection=this;return t}e=e?i.clone(e):{};e.collection=this;var r=new this.model(t,e);if(!r.validationError)return r;this.trigger("invalid",this,r.validationError,e);return false},_removeModels:function(t,e){var i=[];for(var r=0;r<t.length;r++){var s=this.get(t[r]);if(!s)continue;var n=this.indexOf(s);this.models.splice(n,1);this.length--;if(!e.silent){e.index=n;s.trigger("remove",s,this,e)}i.push(s);this._removeReference(s,e)}return i.length?i:false},_isModel:function(t){return t instanceof m},_addReference:function(t,e){this._byId[t.cid]=t;var i=this.modelId(t.attributes);if(i!=null)this._byId[i]=t;t.on("all",this._onModelEvent,this)},_removeReference:function(t,e){delete this._byId[t.cid];var i=this.modelId(t.attributes);if(i!=null)delete this._byId[i];if(this===t.collection)delete t.collection;t.off("all",this._onModelEvent,this)},_onModelEvent:function(t,e,i,r){if((t==="add"||t==="remove")&&i!==this)return;if(t==="destroy")this.remove(e,r);if(t==="change"){var s=this.modelId(e.previousAttributes());var n=this.modelId(e.attributes);if(s!==n){if(s!=null)delete this._byId[s];if(n!=null)this._byId[n]=e}}this.trigger.apply(this,arguments)}});var w={forEach:3,each:3,map:3,collect:3,reduce:4,foldl:4,inject:4,reduceRight:4,foldr:4,find:3,detect:3,filter:3,select:3,reject:3,every:3,all:3,some:3,any:3,include:2,contains:2,invoke:0,max:3,min:3,toArray:1,size:1,first:3,head:3,take:3,initial:3,rest:3,tail:3,drop:3,last:3,without:0,difference:0,indexOf:3,shuffle:1,lastIndexOf:3,isEmpty:1,chain:1,sample:3,partition:3};o(y,w,"models");var E=["groupBy","countBy","sortBy","indexBy"];i.each(E,function(t){if(!i[t])return;y.prototype[t]=function(e,r){var s=i.isFunction(e)?e:function(t){return t.get(e)};return i[t](this.models,s,r)}});var k=e.View=function(t){this.cid=i.uniqueId("view");i.extend(this,i.pick(t,I));this._ensureElement();this.initialize.apply(this,arguments)};var S=/^(\S+)\s*(.*)$/;var I=["model","collection","el","id","attributes","className","tagName","events"];i.extend(k.prototype,h,{tagName:"div",$:function(t){return this.$el.find(t)},initialize:function(){},render:function(){return this},remove:function(){this._removeElement();this.stopListening();return this},_removeElement:function(){this.$el.remove()},setElement:function(t){this.undelegateEvents();this._setElement(t);this.delegateEvents();return this},_setElement:function(t){this.$el=t instanceof e.$?t:e.$(t);this.el=this.$el[0]},delegateEvents:function(t){t||(t=i.result(this,"events"));if(!t)return this;this.undelegateEvents();for(var e in t){var r=t[e];if(!i.isFunction(r))r=this[r];if(!r)continue;var s=e.match(S);this.delegate(s[1],s[2],i.bind(r,this))}return this},delegate:function(t,e,i){this.$el.on(t+".delegateEvents"+this.cid,e,i);return this},undelegateEvents:function(){if(this.$el)this.$el.off(".delegateEvents"+this.cid);return this},undelegate:function(t,e,i){this.$el.off(t+".delegateEvents"+this.cid,e,i);return this},_createElement:function(t){return document.createElement(t)},_ensureElement:function(){if(!this.el){var t=i.extend({},i.result(this,"attributes"));if(this.id)t.id=i.result(this,"id");if(this.className)t["class"]=i.result(this,"className");this.setElement(this._createElement(i.result(this,"tagName")));this._setAttributes(t)}else{this.setElement(i.result(this,"el"))}},_setAttributes:function(t){this.$el.attr(t)}});e.sync=function(t,r,s){var n=T[t];i.defaults(s||(s={}),{emulateHTTP:e.emulateHTTP,emulateJSON:e.emulateJSON});var a={type:n,dataType:"json"};if(!s.url){a.url=i.result(r,"url")||M()}if(s.data==null&&r&&(t==="create"||t==="update"||t==="patch")){a.contentType="application/json";a.data=JSON.stringify(s.attrs||r.toJSON(s))}if(s.emulateJSON){a.contentType="application/x-www-form-urlencoded";a.data=a.data?{model:a.data}:{}}if(s.emulateHTTP&&(n==="PUT"||n==="DELETE"||n==="PATCH")){a.type="POST";if(s.emulateJSON)a.data._method=n;var o=s.beforeSend;s.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",n);if(o)return o.apply(this,arguments)}}if(a.type!=="GET"&&!s.emulateJSON){a.processData=false}var h=s.error;s.error=function(t,e,i){s.textStatus=e;s.errorThrown=i;if(h)h.call(s.context,t,e,i)};var u=s.xhr=e.ajax(i.extend(a,s));r.trigger("request",r,u,s);return u};var T={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};e.ajax=function(){return e.$.ajax.apply(e.$,arguments)};var P=e.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var H=/\((.*?)\)/g;var $=/(\(\?)?:\w+/g;var A=/\*\w+/g;var C=/[\-{}\[\]+?.,\\\^$|#\s]/g;i.extend(P.prototype,h,{initialize:function(){},route:function(t,r,s){if(!i.isRegExp(t))t=this._routeToRegExp(t);if(i.isFunction(r)){s=r;r=""}if(!s)s=this[r];var n=this;e.history.route(t,function(i){var a=n._extractParameters(t,i);if(n.execute(s,a,r)!==false){n.trigger.apply(n,["route:"+r].concat(a));n.trigger("route",r,a);e.history.trigger("route",n,r,a)}});return this},execute:function(t,e,i){if(t)t.apply(this,e)},navigate:function(t,i){e.history.navigate(t,i);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=i.result(this,"routes");var t,e=i.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(C,"\\$&").replace(H,"(?:$1)?").replace($,function(t,e){return e?t:"([^/?]+)"}).replace(A,"([^?]*?)");return new RegExp("^"+t+"(?:\\?([\\s\\S]*))?$")},_extractParameters:function(t,e){var r=t.exec(e).slice(1);return i.map(r,function(t,e){if(e===r.length-1)return t||null;return t?decodeURIComponent(t):null})}});var N=e.History=function(){this.handlers=[];i.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var R=/^[#\/]|\s+$/g;var j=/^\/+|\/+$/g;var O=/#.*$/;N.started=false;i.extend(N.prototype,h,{interval:50,atRoot:function(){var t=this.location.pathname.replace(/[^\/]$/,"$&/");return t===this.root&&!this.getSearch()},matchRoot:function(){var t=this.decodeFragment(this.location.pathname);var e=t.slice(0,this.root.length-1)+"/";return e===this.root},decodeFragment:function(t){return decodeURI(t.replace(/%25/g,"%2525"))},getSearch:function(){var t=this.location.href.replace(/#.*/,"").match(/\?.+/);return t?t[0]:""},getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getPath:function(){var t=this.decodeFragment(this.location.pathname+this.getSearch()).slice(this.root.length-1);return t.charAt(0)==="/"?t.slice(1):t},getFragment:function(t){if(t==null){if(this._usePushState||!this._wantsHashChange){t=this.getPath()}else{t=this.getHash()}}return t.replace(R,"")},start:function(t){if(N.started)throw new Error("Backbone.history has already been started");N.started=true;this.options=i.extend({root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._hasHashChange="onhashchange"in window;this._useHashChange=this._wantsHashChange&&this._hasHashChange;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.history&&this.history.pushState);this._usePushState=this._wantsPushState&&this._hasPushState;this.fragment=this.getFragment();this.root=("/"+this.root+"/").replace(j,"/");if(this._wantsHashChange&&this._wantsPushState){if(!this._hasPushState&&!this.atRoot()){var e=this.root.slice(0,-1)||"/";this.location.replace(e+"#"+this.getPath());return true}else if(this._hasPushState&&this.atRoot()){this.navigate(this.getHash(),{replace:true})}}if(!this._hasHashChange&&this._wantsHashChange&&!this._usePushState){this.iframe=document.createElement("iframe");this.iframe.src="javascript:0";this.iframe.style.display="none";this.iframe.tabIndex=-1;var r=document.body;var s=r.insertBefore(this.iframe,r.firstChild).contentWindow;s.document.open();s.document.close();s.location.hash="#"+this.fragment}var n=window.addEventListener||function(t,e){return attachEvent("on"+t,e)};if(this._usePushState){n("popstate",this.checkUrl,false)}else if(this._useHashChange&&!this.iframe){n("hashchange",this.checkUrl,false)}else if(this._wantsHashChange){this._checkUrlInterval=setInterval(this.checkUrl,this.interval)}if(!this.options.silent)return this.loadUrl()},stop:function(){var t=window.removeEventListener||function(t,e){return detachEvent("on"+t,e)};if(this._usePushState){t("popstate",this.checkUrl,false)}else if(this._useHashChange&&!this.iframe){t("hashchange",this.checkUrl,false)}if(this.iframe){document.body.removeChild(this.iframe);this.iframe=null}if(this._checkUrlInterval)clearInterval(this._checkUrlInterval);N.started=false},route:function(t,e){this.handlers.unshift({route:t,callback:e})},checkUrl:function(t){var e=this.getFragment();if(e===this.fragment&&this.iframe){e=this.getHash(this.iframe.contentWindow)}if(e===this.fragment)return false;if(this.iframe)this.navigate(e);this.loadUrl()},loadUrl:function(t){if(!this.matchRoot())return false;t=this.fragment=this.getFragment(t);return i.any(this.handlers,function(e){if(e.route.test(t)){e.callback(t);return true}})},navigate:function(t,e){if(!N.started)return false;if(!e||e===true)e={trigger:!!e};t=this.getFragment(t||"");var i=this.root;if(t===""||t.charAt(0)==="?"){i=i.slice(0,-1)||"/"}var r=i+t;t=this.decodeFragment(t.replace(O,""));if(this.fragment===t)return;this.fragment=t;if(this._usePushState){this.history[e.replace?"replaceState":"pushState"]({},document.title,r)}else if(this._wantsHashChange){this._updateHash(this.location,t,e.replace);if(this.iframe&&t!==this.getHash(this.iframe.contentWindow)){var s=this.iframe.contentWindow;if(!e.replace){s.document.open();s.document.close()}this._updateHash(s.location,t,e.replace)}}else{return this.location.assign(r)}if(e.trigger)return this.loadUrl(t)},_updateHash:function(t,e,i){if(i){var r=t.href.replace(/(javascript:|#).*$/,"");t.replace(r+"#"+e)}else{t.hash="#"+e}}});e.history=new N;var U=function(t,e){var r=this;var s;if(t&&i.has(t,"constructor")){s=t.constructor}else{s=function(){return r.apply(this,arguments)}}i.extend(s,r,e);var n=function(){this.constructor=s};n.prototype=r.prototype;s.prototype=new n;if(t)i.extend(s.prototype,t);s.__super__=r.prototype;return s};m.extend=y.extend=P.extend=k.extend=N.extend=U;var M=function(){throw new Error('A "url" property or function must be specified')};var q=function(t,e){var i=e.error;e.error=function(r){if(i)i.call(e.context,t,r,e);t.trigger("error",t,r,e)}};return e}); +//# sourceMappingURL=backbone-min.map
\ No newline at end of file diff --git a/core/vendor/backbone/backbone-min.map b/core/vendor/backbone/backbone-min.map new file mode 100644 index 00000000000..f01489a5cb1 --- /dev/null +++ b/core/vendor/backbone/backbone-min.map @@ -0,0 +1 @@ +{"version":3,"file":"backbone-min.js","sources":["backbone.js"],"names":["factory","root","self","global","define","amd","_","$","exports","Backbone","require","e","jQuery","Zepto","ender","previousBackbone","slice","VERSION","noConflict","this","emulateHTTP","emulateJSON","addMethod","length","method","attribute","value","iteratee","context","defaultVal","args","call","arguments","unshift","apply","addUnderscoreMethods","Class","methods","each","prototype","Events","eventSplitter","eventsApi","memo","name","callback","opts","i","names","keys","test","split","on","internalOn","obj","listening","_events","onApi","ctx","listeners","_listeners","id","listenTo","_listenId","uniqueId","listeningTo","_listeningTo","thisId","objId","count","events","options","handlers","push","off","offApi","stopListening","ids","isEmpty","remaining","j","handler","_callback","size","once","onceMap","bind","listenToOnce","map","offer","trigger","Math","max","Array","triggerApi","objEvents","cb","allEvents","all","triggerEvents","concat","ev","l","a1","a2","a3","unbind","extend","Model","attributes","attrs","cid","cidPrefix","collection","parse","defaults","result","set","changed","initialize","validationError","idAttribute","toJSON","clone","sync","get","attr","escape","has","matches","key","val","_validate","unset","silent","changes","changing","_changing","_previousAttributes","current","prev","isEqual","_pending","clear","hasChanged","changedAttributes","diff","old","previous","previousAttributes","fetch","model","success","resp","serverAttrs","wrapError","save","validate","wait","isNew","patch","xhr","destroy","defer","url","base","urlError","replace","encodeURIComponent","constructor","isValid","error","modelMethods","values","pairs","invert","pick","omit","chain","Collection","models","comparator","_reset","reset","setOptions","add","remove","merge","addOptions","singular","isArray","removed","_removeModels","_isModel","existing","sort","at","sortable","sortAttr","isString","toAdd","toRemove","modelMap","order","orderChanged","_prepareModel","_addReference","modelId","splice","orderedModels","addOpts","index","_removeReference","previousModels","pop","shift","_byId","where","first","findWhere","Error","sortBy","pluck","invoke","create","callbackOpts","indexOf","_onModelEvent","event","prevId","collectionMethods","forEach","collect","reduce","foldl","inject","reduceRight","foldr","find","detect","filter","select","reject","every","some","any","include","contains","min","toArray","head","take","initial","rest","tail","drop","last","without","difference","shuffle","lastIndexOf","sample","partition","attributeMethods","iterator","isFunction","View","viewOptions","_ensureElement","delegateEventSplitter","tagName","selector","$el","render","_removeElement","setElement","element","undelegateEvents","_setElement","delegateEvents","el","match","delegate","eventName","listener","undelegate","_createElement","document","createElement","className","_setAttributes","type","methodMap","params","dataType","data","contentType","JSON","stringify","_method","beforeSend","setRequestHeader","processData","textStatus","errorThrown","ajax","update","delete","read","Router","routes","_bindRoutes","optionalParam","namedParam","splatParam","escapeRegExp","route","isRegExp","_routeToRegExp","router","history","fragment","_extractParameters","execute","navigate","optional","RegExp","exec","param","decodeURIComponent","History","bindAll","window","location","routeStripper","rootStripper","pathStripper","started","interval","atRoot","path","pathname","getSearch","matchRoot","decodeFragment","decodeURI","href","getHash","getPath","charAt","getFragment","_usePushState","_wantsHashChange","start","hashChange","_hasHashChange","_useHashChange","_wantsPushState","pushState","_hasPushState","iframe","src","style","display","tabIndex","body","iWindow","insertBefore","firstChild","contentWindow","open","close","hash","addEventListener","attachEvent","checkUrl","_checkUrlInterval","setInterval","loadUrl","stop","removeEventListener","detachEvent","removeChild","clearInterval","title","_updateHash","assign","protoProps","staticProps","parent","child","Surrogate","__super__"],"mappings":"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"}
\ No newline at end of file diff --git a/core/vendor/backbone/backbone.js b/core/vendor/backbone/backbone.js new file mode 100644 index 00000000000..58800425c70 --- /dev/null +++ b/core/vendor/backbone/backbone.js @@ -0,0 +1,1873 @@ +// Backbone.js 1.2.1 + +// (c) 2010-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// Backbone may be freely distributed under the MIT license. +// For all details and documentation: +// http://backbonejs.org + +(function(factory) { + + // Establish the root object, `window` (`self`) in the browser, or `global` on the server. + // We use `self` instead of `window` for `WebWorker` support. + var root = (typeof self == 'object' && self.self == self && self) || + (typeof global == 'object' && global.global == global && global); + + // Set up Backbone appropriately for the environment. Start with AMD. + if (typeof define === 'function' && define.amd) { + define(['underscore', 'jquery', 'exports'], function(_, $, exports) { + // Export global even in AMD case in case this script is loaded with + // others that may still expect a global Backbone. + root.Backbone = factory(root, exports, _, $); + }); + + // Next for Node.js or CommonJS. jQuery may not be needed as a module. + } else if (typeof exports !== 'undefined') { + var _ = require('underscore'), $; + try { $ = require('jquery'); } catch(e) {} + factory(root, exports, _, $); + + // Finally, as a browser global. + } else { + root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$)); + } + +}(function(root, Backbone, _, $) { + + // Initial Setup + // ------------- + + // Save the previous value of the `Backbone` variable, so that it can be + // restored later on, if `noConflict` is used. + var previousBackbone = root.Backbone; + + // Create a local reference to a common array method we'll want to use later. + var slice = [].slice; + + // Current version of the library. Keep in sync with `package.json`. + Backbone.VERSION = '1.2.1'; + + // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns + // the `$` variable. + Backbone.$ = $; + + // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable + // to its previous owner. Returns a reference to this Backbone object. + Backbone.noConflict = function() { + root.Backbone = previousBackbone; + return this; + }; + + // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option + // will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and + // set a `X-Http-Method-Override` header. + Backbone.emulateHTTP = false; + + // Turn on `emulateJSON` to support legacy servers that can't deal with direct + // `application/json` requests ... this will encode the body as + // `application/x-www-form-urlencoded` instead and will send the model in a + // form param named `model`. + Backbone.emulateJSON = false; + + // Proxy Underscore methods to a Backbone class' prototype using a + // particular attribute as the data argument + var addMethod = function(length, method, attribute) { + switch (length) { + case 1: return function() { + return _[method](this[attribute]); + }; + case 2: return function(value) { + return _[method](this[attribute], value); + }; + case 3: return function(iteratee, context) { + return _[method](this[attribute], iteratee, context); + }; + case 4: return function(iteratee, defaultVal, context) { + return _[method](this[attribute], iteratee, defaultVal, context); + }; + default: return function() { + var args = slice.call(arguments); + args.unshift(this[attribute]); + return _[method].apply(_, args); + }; + } + }; + var addUnderscoreMethods = function(Class, methods, attribute) { + _.each(methods, function(length, method) { + if (_[method]) Class.prototype[method] = addMethod(length, method, attribute); + }); + }; + + // Backbone.Events + // --------------- + + // A module that can be mixed in to *any object* in order to provide it with + // custom events. You may bind with `on` or remove with `off` callback + // functions to an event; `trigger`-ing an event fires all callbacks in + // succession. + // + // var object = {}; + // _.extend(object, Backbone.Events); + // object.on('expand', function(){ alert('expanded'); }); + // object.trigger('expand'); + // + var Events = Backbone.Events = {}; + + // Regular expression used to split event strings. + var eventSplitter = /\s+/; + + // Iterates over the standard `event, callback` (as well as the fancy multiple + // space-separated events `"change blur", callback` and jQuery-style event + // maps `{event: callback}`), reducing them by manipulating `memo`. + // Passes a normalized single event name and callback, as well as any + // optional `opts`. + var eventsApi = function(iteratee, memo, name, callback, opts) { + var i = 0, names; + if (name && typeof name === 'object') { + // Handle event maps. + if (callback !== void 0 && 'context' in opts && opts.context === void 0) opts.context = callback; + for (names = _.keys(name); i < names.length ; i++) { + memo = iteratee(memo, names[i], name[names[i]], opts); + } + } else if (name && eventSplitter.test(name)) { + // Handle space separated event names. + for (names = name.split(eventSplitter); i < names.length; i++) { + memo = iteratee(memo, names[i], callback, opts); + } + } else { + memo = iteratee(memo, name, callback, opts); + } + return memo; + }; + + // Bind an event to a `callback` function. Passing `"all"` will bind + // the callback to all events fired. + Events.on = function(name, callback, context) { + return internalOn(this, name, callback, context); + }; + + // An internal use `on` function, used to guard the `listening` argument from + // the public API. + var internalOn = function(obj, name, callback, context, listening) { + obj._events = eventsApi(onApi, obj._events || {}, name, callback, { + context: context, + ctx: obj, + listening: listening + }); + + if (listening) { + var listeners = obj._listeners || (obj._listeners = {}); + listeners[listening.id] = listening; + } + + return obj; + }; + + // Inversion-of-control versions of `on`. Tell *this* object to listen to + // an event in another object... keeping track of what it's listening to. + Events.listenTo = function(obj, name, callback) { + if (!obj) return this; + var id = obj._listenId || (obj._listenId = _.uniqueId('l')); + var listeningTo = this._listeningTo || (this._listeningTo = {}); + var listening = listeningTo[id]; + + // This object is not listening to any other events on `obj` yet. + // Setup the necessary references to track the listening callbacks. + if (!listening) { + var thisId = this._listenId || (this._listenId = _.uniqueId('l')); + listening = listeningTo[id] = {obj: obj, objId: id, id: thisId, listeningTo: listeningTo, count: 0}; + } + + // Bind callbacks on obj, and keep track of them on listening. + internalOn(obj, name, callback, this, listening); + return this; + }; + + // The reducing API that adds a callback to the `events` object. + var onApi = function(events, name, callback, options) { + if (callback) { + var handlers = events[name] || (events[name] = []); + var context = options.context, ctx = options.ctx, listening = options.listening; + if (listening) listening.count++; + + handlers.push({ callback: callback, context: context, ctx: context || ctx, listening: listening }); + } + return events; + }; + + // Remove one or many callbacks. If `context` is null, removes all + // callbacks with that function. If `callback` is null, removes all + // callbacks for the event. If `name` is null, removes all bound + // callbacks for all events. + Events.off = function(name, callback, context) { + if (!this._events) return this; + this._events = eventsApi(offApi, this._events, name, callback, { + context: context, + listeners: this._listeners + }); + return this; + }; + + // Tell this object to stop listening to either specific events ... or + // to every object it's currently listening to. + Events.stopListening = function(obj, name, callback) { + var listeningTo = this._listeningTo; + if (!listeningTo) return this; + + var ids = obj ? [obj._listenId] : _.keys(listeningTo); + + for (var i = 0; i < ids.length; i++) { + var listening = listeningTo[ids[i]]; + + // If listening doesn't exist, this object is not currently + // listening to obj. Break out early. + if (!listening) break; + + listening.obj.off(name, callback, this); + } + if (_.isEmpty(listeningTo)) this._listeningTo = void 0; + + return this; + }; + + // The reducing API that removes a callback from the `events` object. + var offApi = function(events, name, callback, options) { + // No events to consider. + if (!events) return; + + var i = 0, listening; + var context = options.context, listeners = options.listeners; + + // Delete all events listeners and "drop" events. + if (!name && !callback && !context) { + var ids = _.keys(listeners); + for (; i < ids.length; i++) { + listening = listeners[ids[i]]; + delete listeners[listening.id]; + delete listening.listeningTo[listening.objId]; + } + return; + } + + var names = name ? [name] : _.keys(events); + for (; i < names.length; i++) { + name = names[i]; + var handlers = events[name]; + + // Bail out if there are no events stored. + if (!handlers) break; + + // Replace events if there are any remaining. Otherwise, clean up. + var remaining = []; + for (var j = 0; j < handlers.length; j++) { + var handler = handlers[j]; + if ( + callback && callback !== handler.callback && + callback !== handler.callback._callback || + context && context !== handler.context + ) { + remaining.push(handler); + } else { + listening = handler.listening; + if (listening && --listening.count === 0) { + delete listeners[listening.id]; + delete listening.listeningTo[listening.objId]; + } + } + } + + // Update tail event if the list has any events. Otherwise, clean up. + if (remaining.length) { + events[name] = remaining; + } else { + delete events[name]; + } + } + if (_.size(events)) return events; + }; + + // Bind an event to only be triggered a single time. After the first time + // the callback is invoked, it will be removed. When multiple events are + // passed in using the space-separated syntax, the event will fire once for every + // event you passed in, not once for a combination of all events + Events.once = function(name, callback, context) { + // Map the event into a `{event: once}` object. + var events = eventsApi(onceMap, {}, name, callback, _.bind(this.off, this)); + return this.on(events, void 0, context); + }; + + // Inversion-of-control versions of `once`. + Events.listenToOnce = function(obj, name, callback) { + // Map the event into a `{event: once}` object. + var events = eventsApi(onceMap, {}, name, callback, _.bind(this.stopListening, this, obj)); + return this.listenTo(obj, events); + }; + + // Reduces the event callbacks into a map of `{event: onceWrapper}`. + // `offer` unbinds the `onceWrapper` after it has been called. + var onceMap = function(map, name, callback, offer) { + if (callback) { + var once = map[name] = _.once(function() { + offer(name, once); + callback.apply(this, arguments); + }); + once._callback = callback; + } + return map; + }; + + // Trigger one or many events, firing all bound callbacks. Callbacks are + // passed the same arguments as `trigger` is, apart from the event name + // (unless you're listening on `"all"`, which will cause your callback to + // receive the true name of the event as the first argument). + Events.trigger = function(name) { + if (!this._events) return this; + + var length = Math.max(0, arguments.length - 1); + var args = Array(length); + for (var i = 0; i < length; i++) args[i] = arguments[i + 1]; + + eventsApi(triggerApi, this._events, name, void 0, args); + return this; + }; + + // Handles triggering the appropriate event callbacks. + var triggerApi = function(objEvents, name, cb, args) { + if (objEvents) { + var events = objEvents[name]; + var allEvents = objEvents.all; + if (events && allEvents) allEvents = allEvents.slice(); + if (events) triggerEvents(events, args); + if (allEvents) triggerEvents(allEvents, [name].concat(args)); + } + return objEvents; + }; + + // A difficult-to-believe, but optimized internal dispatch function for + // triggering events. Tries to keep the usual cases speedy (most internal + // Backbone events have 3 arguments). + var triggerEvents = function(events, args) { + var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2]; + switch (args.length) { + case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return; + case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return; + case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return; + case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return; + default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return; + } + }; + + // Aliases for backwards compatibility. + Events.bind = Events.on; + Events.unbind = Events.off; + + // Allow the `Backbone` object to serve as a global event bus, for folks who + // want global "pubsub" in a convenient place. + _.extend(Backbone, Events); + + // Backbone.Model + // -------------- + + // Backbone **Models** are the basic data object in the framework -- + // frequently representing a row in a table in a database on your server. + // A discrete chunk of data and a bunch of useful, related methods for + // performing computations and transformations on that data. + + // Create a new model with the specified attributes. A client id (`cid`) + // is automatically generated and assigned for you. + var Model = Backbone.Model = function(attributes, options) { + var attrs = attributes || {}; + options || (options = {}); + this.cid = _.uniqueId(this.cidPrefix); + this.attributes = {}; + if (options.collection) this.collection = options.collection; + if (options.parse) attrs = this.parse(attrs, options) || {}; + attrs = _.defaults({}, attrs, _.result(this, 'defaults')); + this.set(attrs, options); + this.changed = {}; + this.initialize.apply(this, arguments); + }; + + // Attach all inheritable methods to the Model prototype. + _.extend(Model.prototype, Events, { + + // A hash of attributes whose current and previous value differ. + changed: null, + + // The value returned during the last failed validation. + validationError: null, + + // The default name for the JSON `id` attribute is `"id"`. MongoDB and + // CouchDB users may want to set this to `"_id"`. + idAttribute: 'id', + + // The prefix is used to create the client id which is used to identify models locally. + // You may want to override this if you're experiencing name clashes with model ids. + cidPrefix: 'c', + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // Return a copy of the model's `attributes` object. + toJSON: function(options) { + return _.clone(this.attributes); + }, + + // Proxy `Backbone.sync` by default -- but override this if you need + // custom syncing semantics for *this* particular model. + sync: function() { + return Backbone.sync.apply(this, arguments); + }, + + // Get the value of an attribute. + get: function(attr) { + return this.attributes[attr]; + }, + + // Get the HTML-escaped value of an attribute. + escape: function(attr) { + return _.escape(this.get(attr)); + }, + + // Returns `true` if the attribute contains a value that is not null + // or undefined. + has: function(attr) { + return this.get(attr) != null; + }, + + // Special-cased proxy to underscore's `_.matches` method. + matches: function(attrs) { + return !!_.iteratee(attrs, this)(this.attributes); + }, + + // Set a hash of model attributes on the object, firing `"change"`. This is + // the core primitive operation of a model, updating the data and notifying + // anyone who needs to know about the change in state. The heart of the beast. + set: function(key, val, options) { + if (key == null) return this; + + // Handle both `"key", value` and `{key: value}` -style arguments. + var attrs; + if (typeof key === 'object') { + attrs = key; + options = val; + } else { + (attrs = {})[key] = val; + } + + options || (options = {}); + + // Run validation. + if (!this._validate(attrs, options)) return false; + + // Extract attributes and options. + var unset = options.unset; + var silent = options.silent; + var changes = []; + var changing = this._changing; + this._changing = true; + + if (!changing) { + this._previousAttributes = _.clone(this.attributes); + this.changed = {}; + } + + var current = this.attributes; + var changed = this.changed; + var prev = this._previousAttributes; + + // Check for changes of `id`. + if (this.idAttribute in attrs) this.id = attrs[this.idAttribute]; + + // For each `set` attribute, update or delete the current value. + for (var attr in attrs) { + val = attrs[attr]; + if (!_.isEqual(current[attr], val)) changes.push(attr); + if (!_.isEqual(prev[attr], val)) { + changed[attr] = val; + } else { + delete changed[attr]; + } + unset ? delete current[attr] : current[attr] = val; + } + + // Trigger all relevant attribute changes. + if (!silent) { + if (changes.length) this._pending = options; + for (var i = 0; i < changes.length; i++) { + this.trigger('change:' + changes[i], this, current[changes[i]], options); + } + } + + // You might be wondering why there's a `while` loop here. Changes can + // be recursively nested within `"change"` events. + if (changing) return this; + if (!silent) { + while (this._pending) { + options = this._pending; + this._pending = false; + this.trigger('change', this, options); + } + } + this._pending = false; + this._changing = false; + return this; + }, + + // Remove an attribute from the model, firing `"change"`. `unset` is a noop + // if the attribute doesn't exist. + unset: function(attr, options) { + return this.set(attr, void 0, _.extend({}, options, {unset: true})); + }, + + // Clear all attributes on the model, firing `"change"`. + clear: function(options) { + var attrs = {}; + for (var key in this.attributes) attrs[key] = void 0; + return this.set(attrs, _.extend({}, options, {unset: true})); + }, + + // Determine if the model has changed since the last `"change"` event. + // If you specify an attribute name, determine if that attribute has changed. + hasChanged: function(attr) { + if (attr == null) return !_.isEmpty(this.changed); + return _.has(this.changed, attr); + }, + + // Return an object containing all the attributes that have changed, or + // false if there are no changed attributes. Useful for determining what + // parts of a view need to be updated and/or what attributes need to be + // persisted to the server. Unset attributes will be set to undefined. + // You can also pass an attributes object to diff against the model, + // determining if there *would be* a change. + changedAttributes: function(diff) { + if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; + var old = this._changing ? this._previousAttributes : this.attributes; + var changed = {}; + for (var attr in diff) { + var val = diff[attr]; + if (_.isEqual(old[attr], val)) continue; + changed[attr] = val; + } + return _.size(changed) ? changed : false; + }, + + // Get the previous value of an attribute, recorded at the time the last + // `"change"` event was fired. + previous: function(attr) { + if (attr == null || !this._previousAttributes) return null; + return this._previousAttributes[attr]; + }, + + // Get all of the attributes of the model at the time of the previous + // `"change"` event. + previousAttributes: function() { + return _.clone(this._previousAttributes); + }, + + // Fetch the model from the server, merging the response with the model's + // local attributes. Any changed attributes will trigger a "change" event. + fetch: function(options) { + options = _.extend({parse: true}, options); + var model = this; + var success = options.success; + options.success = function(resp) { + var serverAttrs = options.parse ? model.parse(resp, options) : resp; + if (!model.set(serverAttrs, options)) return false; + if (success) success.call(options.context, model, resp, options); + model.trigger('sync', model, resp, options); + }; + wrapError(this, options); + return this.sync('read', this, options); + }, + + // Set a hash of model attributes, and sync the model to the server. + // If the server returns an attributes hash that differs, the model's + // state will be `set` again. + save: function(key, val, options) { + // Handle both `"key", value` and `{key: value}` -style arguments. + var attrs; + if (key == null || typeof key === 'object') { + attrs = key; + options = val; + } else { + (attrs = {})[key] = val; + } + + options = _.extend({validate: true, parse: true}, options); + var wait = options.wait; + + // If we're not waiting and attributes exist, save acts as + // `set(attr).save(null, opts)` with validation. Otherwise, check if + // the model will be valid when the attributes, if any, are set. + if (attrs && !wait) { + if (!this.set(attrs, options)) return false; + } else { + if (!this._validate(attrs, options)) return false; + } + + // After a successful server-side save, the client is (optionally) + // updated with the server-side state. + var model = this; + var success = options.success; + var attributes = this.attributes; + options.success = function(resp) { + // Ensure attributes are restored during synchronous saves. + model.attributes = attributes; + var serverAttrs = options.parse ? model.parse(resp, options) : resp; + if (wait) serverAttrs = _.extend({}, attrs, serverAttrs); + if (serverAttrs && !model.set(serverAttrs, options)) return false; + if (success) success.call(options.context, model, resp, options); + model.trigger('sync', model, resp, options); + }; + wrapError(this, options); + + // Set temporary attributes if `{wait: true}` to properly find new ids. + if (attrs && wait) this.attributes = _.extend({}, attributes, attrs); + + var method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update'); + if (method === 'patch' && !options.attrs) options.attrs = attrs; + var xhr = this.sync(method, this, options); + + // Restore attributes. + this.attributes = attributes; + + return xhr; + }, + + // Destroy this model on the server if it was already persisted. + // Optimistically removes the model from its collection, if it has one. + // If `wait: true` is passed, waits for the server to respond before removal. + destroy: function(options) { + options = options ? _.clone(options) : {}; + var model = this; + var success = options.success; + var wait = options.wait; + + var destroy = function() { + model.stopListening(); + model.trigger('destroy', model, model.collection, options); + }; + + options.success = function(resp) { + if (wait) destroy(); + if (success) success.call(options.context, model, resp, options); + if (!model.isNew()) model.trigger('sync', model, resp, options); + }; + + var xhr = false; + if (this.isNew()) { + _.defer(options.success); + } else { + wrapError(this, options); + xhr = this.sync('delete', this, options); + } + if (!wait) destroy(); + return xhr; + }, + + // Default URL for the model's representation on the server -- if you're + // using Backbone's restful methods, override this to change the endpoint + // that will be called. + url: function() { + var base = + _.result(this, 'urlRoot') || + _.result(this.collection, 'url') || + urlError(); + if (this.isNew()) return base; + var id = this.get(this.idAttribute); + return base.replace(/[^\/]$/, '$&/') + encodeURIComponent(id); + }, + + // **parse** converts a response into the hash of attributes to be `set` on + // the model. The default implementation is just to pass the response along. + parse: function(resp, options) { + return resp; + }, + + // Create a new model with identical attributes to this one. + clone: function() { + return new this.constructor(this.attributes); + }, + + // A model is new if it has never been saved to the server, and lacks an id. + isNew: function() { + return !this.has(this.idAttribute); + }, + + // Check if the model is currently in a valid state. + isValid: function(options) { + return this._validate({}, _.defaults({validate: true}, options)); + }, + + // Run validation against the next complete set of model attributes, + // returning `true` if all is well. Otherwise, fire an `"invalid"` event. + _validate: function(attrs, options) { + if (!options.validate || !this.validate) return true; + attrs = _.extend({}, this.attributes, attrs); + var error = this.validationError = this.validate(attrs, options) || null; + if (!error) return true; + this.trigger('invalid', this, error, _.extend(options, {validationError: error})); + return false; + } + + }); + + // Underscore methods that we want to implement on the Model. + var modelMethods = { keys: 1, values: 1, pairs: 1, invert: 1, pick: 0, + omit: 0, chain: 1, isEmpty: 1 }; + + // Mix in each Underscore method as a proxy to `Model#attributes`. + addUnderscoreMethods(Model, modelMethods, 'attributes'); + + // Backbone.Collection + // ------------------- + + // If models tend to represent a single row of data, a Backbone Collection is + // more analogous to a table full of data ... or a small slice or page of that + // table, or a collection of rows that belong together for a particular reason + // -- all of the messages in this particular folder, all of the documents + // belonging to this particular author, and so on. Collections maintain + // indexes of their models, both in order, and for lookup by `id`. + + // Create a new **Collection**, perhaps to contain a specific type of `model`. + // If a `comparator` is specified, the Collection will maintain + // its models in sort order, as they're added and removed. + var Collection = Backbone.Collection = function(models, options) { + options || (options = {}); + if (options.model) this.model = options.model; + if (options.comparator !== void 0) this.comparator = options.comparator; + this._reset(); + this.initialize.apply(this, arguments); + if (models) this.reset(models, _.extend({silent: true}, options)); + }; + + // Default options for `Collection#set`. + var setOptions = {add: true, remove: true, merge: true}; + var addOptions = {add: true, remove: false}; + + // Define the Collection's inheritable methods. + _.extend(Collection.prototype, Events, { + + // The default model for a collection is just a **Backbone.Model**. + // This should be overridden in most cases. + model: Model, + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // The JSON representation of a Collection is an array of the + // models' attributes. + toJSON: function(options) { + return this.map(function(model) { return model.toJSON(options); }); + }, + + // Proxy `Backbone.sync` by default. + sync: function() { + return Backbone.sync.apply(this, arguments); + }, + + // Add a model, or list of models to the set. + add: function(models, options) { + return this.set(models, _.extend({merge: false}, options, addOptions)); + }, + + // Remove a model, or a list of models from the set. + remove: function(models, options) { + options = _.extend({}, options); + var singular = !_.isArray(models); + models = singular ? [models] : _.clone(models); + var removed = this._removeModels(models, options); + if (!options.silent && removed) this.trigger('update', this, options); + return singular ? removed[0] : removed; + }, + + // Update a collection by `set`-ing a new list of models, adding new ones, + // removing models that are no longer present, and merging models that + // already exist in the collection, as necessary. Similar to **Model#set**, + // the core operation for updating the data contained by the collection. + set: function(models, options) { + options = _.defaults({}, options, setOptions); + if (options.parse && !this._isModel(models)) models = this.parse(models, options); + var singular = !_.isArray(models); + models = singular ? (models ? [models] : []) : models.slice(); + var id, model, attrs, existing, sort; + var at = options.at; + if (at != null) at = +at; + if (at < 0) at += this.length + 1; + var sortable = this.comparator && (at == null) && options.sort !== false; + var sortAttr = _.isString(this.comparator) ? this.comparator : null; + var toAdd = [], toRemove = [], modelMap = {}; + var add = options.add, merge = options.merge, remove = options.remove; + var order = !sortable && add && remove ? [] : false; + var orderChanged = false; + + // Turn bare objects into model references, and prevent invalid models + // from being added. + for (var i = 0; i < models.length; i++) { + attrs = models[i]; + + // If a duplicate is found, prevent it from being added and + // optionally merge it into the existing model. + if (existing = this.get(attrs)) { + if (remove) modelMap[existing.cid] = true; + if (merge && attrs !== existing) { + attrs = this._isModel(attrs) ? attrs.attributes : attrs; + if (options.parse) attrs = existing.parse(attrs, options); + existing.set(attrs, options); + if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true; + } + models[i] = existing; + + // If this is a new, valid model, push it to the `toAdd` list. + } else if (add) { + model = models[i] = this._prepareModel(attrs, options); + if (!model) continue; + toAdd.push(model); + this._addReference(model, options); + } + + // Do not add multiple models with the same `id`. + model = existing || model; + if (!model) continue; + id = this.modelId(model.attributes); + if (order && (model.isNew() || !modelMap[id])) { + order.push(model); + + // Check to see if this is actually a new model at this index. + orderChanged = orderChanged || !this.models[i] || model.cid !== this.models[i].cid; + } + + modelMap[id] = true; + } + + // Remove nonexistent models if appropriate. + if (remove) { + for (var i = 0; i < this.length; i++) { + if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model); + } + if (toRemove.length) this._removeModels(toRemove, options); + } + + // See if sorting is needed, update `length` and splice in new models. + if (toAdd.length || orderChanged) { + if (sortable) sort = true; + this.length += toAdd.length; + if (at != null) { + for (var i = 0; i < toAdd.length; i++) { + this.models.splice(at + i, 0, toAdd[i]); + } + } else { + if (order) this.models.length = 0; + var orderedModels = order || toAdd; + for (var i = 0; i < orderedModels.length; i++) { + this.models.push(orderedModels[i]); + } + } + } + + // Silently sort the collection if appropriate. + if (sort) this.sort({silent: true}); + + // Unless silenced, it's time to fire all appropriate add/sort events. + if (!options.silent) { + var addOpts = at != null ? _.clone(options) : options; + for (var i = 0; i < toAdd.length; i++) { + if (at != null) addOpts.index = at + i; + (model = toAdd[i]).trigger('add', model, this, addOpts); + } + if (sort || orderChanged) this.trigger('sort', this, options); + if (toAdd.length || toRemove.length) this.trigger('update', this, options); + } + + // Return the added (or merged) model (or models). + return singular ? models[0] : models; + }, + + // When you have more items than you want to add or remove individually, + // you can reset the entire set with a new list of models, without firing + // any granular `add` or `remove` events. Fires `reset` when finished. + // Useful for bulk operations and optimizations. + reset: function(models, options) { + options = options ? _.clone(options) : {}; + for (var i = 0; i < this.models.length; i++) { + this._removeReference(this.models[i], options); + } + options.previousModels = this.models; + this._reset(); + models = this.add(models, _.extend({silent: true}, options)); + if (!options.silent) this.trigger('reset', this, options); + return models; + }, + + // Add a model to the end of the collection. + push: function(model, options) { + return this.add(model, _.extend({at: this.length}, options)); + }, + + // Remove a model from the end of the collection. + pop: function(options) { + var model = this.at(this.length - 1); + return this.remove(model, options); + }, + + // Add a model to the beginning of the collection. + unshift: function(model, options) { + return this.add(model, _.extend({at: 0}, options)); + }, + + // Remove a model from the beginning of the collection. + shift: function(options) { + var model = this.at(0); + return this.remove(model, options); + }, + + // Slice out a sub-array of models from the collection. + slice: function() { + return slice.apply(this.models, arguments); + }, + + // Get a model from the set by id. + get: function(obj) { + if (obj == null) return void 0; + var id = this.modelId(this._isModel(obj) ? obj.attributes : obj); + return this._byId[obj] || this._byId[id] || this._byId[obj.cid]; + }, + + // Get the model at the given index. + at: function(index) { + if (index < 0) index += this.length; + return this.models[index]; + }, + + // Return models with matching attributes. Useful for simple cases of + // `filter`. + where: function(attrs, first) { + var matches = _.matches(attrs); + return this[first ? 'find' : 'filter'](function(model) { + return matches(model.attributes); + }); + }, + + // Return the first model with matching attributes. Useful for simple cases + // of `find`. + findWhere: function(attrs) { + return this.where(attrs, true); + }, + + // Force the collection to re-sort itself. You don't need to call this under + // normal circumstances, as the set will maintain sort order as each item + // is added. + sort: function(options) { + if (!this.comparator) throw new Error('Cannot sort a set without a comparator'); + options || (options = {}); + + // Run sort based on type of `comparator`. + if (_.isString(this.comparator) || this.comparator.length === 1) { + this.models = this.sortBy(this.comparator, this); + } else { + this.models.sort(_.bind(this.comparator, this)); + } + + if (!options.silent) this.trigger('sort', this, options); + return this; + }, + + // Pluck an attribute from each model in the collection. + pluck: function(attr) { + return _.invoke(this.models, 'get', attr); + }, + + // Fetch the default set of models for this collection, resetting the + // collection when they arrive. If `reset: true` is passed, the response + // data will be passed through the `reset` method instead of `set`. + fetch: function(options) { + options = _.extend({parse: true}, options); + var success = options.success; + var collection = this; + options.success = function(resp) { + var method = options.reset ? 'reset' : 'set'; + collection[method](resp, options); + if (success) success.call(options.context, collection, resp, options); + collection.trigger('sync', collection, resp, options); + }; + wrapError(this, options); + return this.sync('read', this, options); + }, + + // Create a new instance of a model in this collection. Add the model to the + // collection immediately, unless `wait: true` is passed, in which case we + // wait for the server to agree. + create: function(model, options) { + options = options ? _.clone(options) : {}; + var wait = options.wait; + model = this._prepareModel(model, options); + if (!model) return false; + if (!wait) this.add(model, options); + var collection = this; + var success = options.success; + options.success = function(model, resp, callbackOpts) { + if (wait) collection.add(model, callbackOpts); + if (success) success.call(callbackOpts.context, model, resp, callbackOpts); + }; + model.save(null, options); + return model; + }, + + // **parse** converts a response into a list of models to be added to the + // collection. The default implementation is just to pass it through. + parse: function(resp, options) { + return resp; + }, + + // Create a new collection with an identical list of models as this one. + clone: function() { + return new this.constructor(this.models, { + model: this.model, + comparator: this.comparator + }); + }, + + // Define how to uniquely identify models in the collection. + modelId: function (attrs) { + return attrs[this.model.prototype.idAttribute || 'id']; + }, + + // Private method to reset all internal state. Called when the collection + // is first initialized or reset. + _reset: function() { + this.length = 0; + this.models = []; + this._byId = {}; + }, + + // Prepare a hash of attributes (or other model) to be added to this + // collection. + _prepareModel: function(attrs, options) { + if (this._isModel(attrs)) { + if (!attrs.collection) attrs.collection = this; + return attrs; + } + options = options ? _.clone(options) : {}; + options.collection = this; + var model = new this.model(attrs, options); + if (!model.validationError) return model; + this.trigger('invalid', this, model.validationError, options); + return false; + }, + + // Internal method called by both remove and set. + // Returns removed models, or false if nothing is removed. + _removeModels: function(models, options) { + var removed = []; + for (var i = 0; i < models.length; i++) { + var model = this.get(models[i]); + if (!model) continue; + + var index = this.indexOf(model); + this.models.splice(index, 1); + this.length--; + + if (!options.silent) { + options.index = index; + model.trigger('remove', model, this, options); + } + + removed.push(model); + this._removeReference(model, options); + } + return removed.length ? removed : false; + }, + + // Method for checking whether an object should be considered a model for + // the purposes of adding to the collection. + _isModel: function (model) { + return model instanceof Model; + }, + + // Internal method to create a model's ties to a collection. + _addReference: function(model, options) { + this._byId[model.cid] = model; + var id = this.modelId(model.attributes); + if (id != null) this._byId[id] = model; + model.on('all', this._onModelEvent, this); + }, + + // Internal method to sever a model's ties to a collection. + _removeReference: function(model, options) { + delete this._byId[model.cid]; + var id = this.modelId(model.attributes); + if (id != null) delete this._byId[id]; + if (this === model.collection) delete model.collection; + model.off('all', this._onModelEvent, this); + }, + + // Internal method called every time a model in the set fires an event. + // Sets need to update their indexes when models change ids. All other + // events simply proxy through. "add" and "remove" events that originate + // in other collections are ignored. + _onModelEvent: function(event, model, collection, options) { + if ((event === 'add' || event === 'remove') && collection !== this) return; + if (event === 'destroy') this.remove(model, options); + if (event === 'change') { + var prevId = this.modelId(model.previousAttributes()); + var id = this.modelId(model.attributes); + if (prevId !== id) { + if (prevId != null) delete this._byId[prevId]; + if (id != null) this._byId[id] = model; + } + } + this.trigger.apply(this, arguments); + } + + }); + + // Underscore methods that we want to implement on the Collection. + // 90% of the core usefulness of Backbone Collections is actually implemented + // right here: + var collectionMethods = { forEach: 3, each: 3, map: 3, collect: 3, reduce: 4, + foldl: 4, inject: 4, reduceRight: 4, foldr: 4, find: 3, detect: 3, filter: 3, + select: 3, reject: 3, every: 3, all: 3, some: 3, any: 3, include: 2, + contains: 2, invoke: 0, max: 3, min: 3, toArray: 1, size: 1, first: 3, + head: 3, take: 3, initial: 3, rest: 3, tail: 3, drop: 3, last: 3, + without: 0, difference: 0, indexOf: 3, shuffle: 1, lastIndexOf: 3, + isEmpty: 1, chain: 1, sample: 3, partition: 3 }; + + // Mix in each Underscore method as a proxy to `Collection#models`. + addUnderscoreMethods(Collection, collectionMethods, 'models'); + + // Underscore methods that take a property name as an argument. + var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy']; + + // Use attributes instead of properties. + _.each(attributeMethods, function(method) { + if (!_[method]) return; + Collection.prototype[method] = function(value, context) { + var iterator = _.isFunction(value) ? value : function(model) { + return model.get(value); + }; + return _[method](this.models, iterator, context); + }; + }); + + // Backbone.View + // ------------- + + // Backbone Views are almost more convention than they are actual code. A View + // is simply a JavaScript object that represents a logical chunk of UI in the + // DOM. This might be a single item, an entire list, a sidebar or panel, or + // even the surrounding frame which wraps your whole app. Defining a chunk of + // UI as a **View** allows you to define your DOM events declaratively, without + // having to worry about render order ... and makes it easy for the view to + // react to specific changes in the state of your models. + + // Creating a Backbone.View creates its initial element outside of the DOM, + // if an existing element is not provided... + var View = Backbone.View = function(options) { + this.cid = _.uniqueId('view'); + _.extend(this, _.pick(options, viewOptions)); + this._ensureElement(); + this.initialize.apply(this, arguments); + }; + + // Cached regex to split keys for `delegate`. + var delegateEventSplitter = /^(\S+)\s*(.*)$/; + + // List of view options to be merged as properties. + var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events']; + + // Set up all inheritable **Backbone.View** properties and methods. + _.extend(View.prototype, Events, { + + // The default `tagName` of a View's element is `"div"`. + tagName: 'div', + + // jQuery delegate for element lookup, scoped to DOM elements within the + // current view. This should be preferred to global lookups where possible. + $: function(selector) { + return this.$el.find(selector); + }, + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // **render** is the core function that your view should override, in order + // to populate its element (`this.el`), with the appropriate HTML. The + // convention is for **render** to always return `this`. + render: function() { + return this; + }, + + // Remove this view by taking the element out of the DOM, and removing any + // applicable Backbone.Events listeners. + remove: function() { + this._removeElement(); + this.stopListening(); + return this; + }, + + // Remove this view's element from the document and all event listeners + // attached to it. Exposed for subclasses using an alternative DOM + // manipulation API. + _removeElement: function() { + this.$el.remove(); + }, + + // Change the view's element (`this.el` property) and re-delegate the + // view's events on the new element. + setElement: function(element) { + this.undelegateEvents(); + this._setElement(element); + this.delegateEvents(); + return this; + }, + + // Creates the `this.el` and `this.$el` references for this view using the + // given `el`. `el` can be a CSS selector or an HTML string, a jQuery + // context or an element. Subclasses can override this to utilize an + // alternative DOM manipulation API and are only required to set the + // `this.el` property. + _setElement: function(el) { + this.$el = el instanceof Backbone.$ ? el : Backbone.$(el); + this.el = this.$el[0]; + }, + + // Set callbacks, where `this.events` is a hash of + // + // *{"event selector": "callback"}* + // + // { + // 'mousedown .title': 'edit', + // 'click .button': 'save', + // 'click .open': function(e) { ... } + // } + // + // pairs. Callbacks will be bound to the view, with `this` set properly. + // Uses event delegation for efficiency. + // Omitting the selector binds the event to `this.el`. + delegateEvents: function(events) { + events || (events = _.result(this, 'events')); + if (!events) return this; + this.undelegateEvents(); + for (var key in events) { + var method = events[key]; + if (!_.isFunction(method)) method = this[method]; + if (!method) continue; + var match = key.match(delegateEventSplitter); + this.delegate(match[1], match[2], _.bind(method, this)); + } + return this; + }, + + // Add a single event listener to the view's element (or a child element + // using `selector`). This only works for delegate-able events: not `focus`, + // `blur`, and not `change`, `submit`, and `reset` in Internet Explorer. + delegate: function(eventName, selector, listener) { + this.$el.on(eventName + '.delegateEvents' + this.cid, selector, listener); + return this; + }, + + // Clears all callbacks previously bound to the view by `delegateEvents`. + // You usually don't need to use this, but may wish to if you have multiple + // Backbone views attached to the same DOM element. + undelegateEvents: function() { + if (this.$el) this.$el.off('.delegateEvents' + this.cid); + return this; + }, + + // A finer-grained `undelegateEvents` for removing a single delegated event. + // `selector` and `listener` are both optional. + undelegate: function(eventName, selector, listener) { + this.$el.off(eventName + '.delegateEvents' + this.cid, selector, listener); + return this; + }, + + // Produces a DOM element to be assigned to your view. Exposed for + // subclasses using an alternative DOM manipulation API. + _createElement: function(tagName) { + return document.createElement(tagName); + }, + + // Ensure that the View has a DOM element to render into. + // If `this.el` is a string, pass it through `$()`, take the first + // matching element, and re-assign it to `el`. Otherwise, create + // an element from the `id`, `className` and `tagName` properties. + _ensureElement: function() { + if (!this.el) { + var attrs = _.extend({}, _.result(this, 'attributes')); + if (this.id) attrs.id = _.result(this, 'id'); + if (this.className) attrs['class'] = _.result(this, 'className'); + this.setElement(this._createElement(_.result(this, 'tagName'))); + this._setAttributes(attrs); + } else { + this.setElement(_.result(this, 'el')); + } + }, + + // Set attributes from a hash on this view's element. Exposed for + // subclasses using an alternative DOM manipulation API. + _setAttributes: function(attributes) { + this.$el.attr(attributes); + } + + }); + + // Backbone.sync + // ------------- + + // Override this function to change the manner in which Backbone persists + // models to the server. You will be passed the type of request, and the + // model in question. By default, makes a RESTful Ajax request + // to the model's `url()`. Some possible customizations could be: + // + // * Use `setTimeout` to batch rapid-fire updates into a single request. + // * Send up the models as XML instead of JSON. + // * Persist models via WebSockets instead of Ajax. + // + // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests + // as `POST`, with a `_method` parameter containing the true HTTP method, + // as well as all requests with the body as `application/x-www-form-urlencoded` + // instead of `application/json` with the model in a param named `model`. + // Useful when interfacing with server-side languages like **PHP** that make + // it difficult to read the body of `PUT` requests. + Backbone.sync = function(method, model, options) { + var type = methodMap[method]; + + // Default options, unless specified. + _.defaults(options || (options = {}), { + emulateHTTP: Backbone.emulateHTTP, + emulateJSON: Backbone.emulateJSON + }); + + // Default JSON-request options. + var params = {type: type, dataType: 'json'}; + + // Ensure that we have a URL. + if (!options.url) { + params.url = _.result(model, 'url') || urlError(); + } + + // Ensure that we have the appropriate request data. + if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) { + params.contentType = 'application/json'; + params.data = JSON.stringify(options.attrs || model.toJSON(options)); + } + + // For older servers, emulate JSON by encoding the request into an HTML-form. + if (options.emulateJSON) { + params.contentType = 'application/x-www-form-urlencoded'; + params.data = params.data ? {model: params.data} : {}; + } + + // For older servers, emulate HTTP by mimicking the HTTP method with `_method` + // And an `X-HTTP-Method-Override` header. + if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) { + params.type = 'POST'; + if (options.emulateJSON) params.data._method = type; + var beforeSend = options.beforeSend; + options.beforeSend = function(xhr) { + xhr.setRequestHeader('X-HTTP-Method-Override', type); + if (beforeSend) return beforeSend.apply(this, arguments); + }; + } + + // Don't process data on a non-GET request. + if (params.type !== 'GET' && !options.emulateJSON) { + params.processData = false; + } + + // Pass along `textStatus` and `errorThrown` from jQuery. + var error = options.error; + options.error = function(xhr, textStatus, errorThrown) { + options.textStatus = textStatus; + options.errorThrown = errorThrown; + if (error) error.call(options.context, xhr, textStatus, errorThrown); + }; + + // Make the request, allowing the user to override any Ajax options. + var xhr = options.xhr = Backbone.ajax(_.extend(params, options)); + model.trigger('request', model, xhr, options); + return xhr; + }; + + // Map from CRUD to HTTP for our default `Backbone.sync` implementation. + var methodMap = { + 'create': 'POST', + 'update': 'PUT', + 'patch': 'PATCH', + 'delete': 'DELETE', + 'read': 'GET' + }; + + // Set the default implementation of `Backbone.ajax` to proxy through to `$`. + // Override this if you'd like to use a different library. + Backbone.ajax = function() { + return Backbone.$.ajax.apply(Backbone.$, arguments); + }; + + // Backbone.Router + // --------------- + + // Routers map faux-URLs to actions, and fire events when routes are + // matched. Creating a new one sets its `routes` hash, if not set statically. + var Router = Backbone.Router = function(options) { + options || (options = {}); + if (options.routes) this.routes = options.routes; + this._bindRoutes(); + this.initialize.apply(this, arguments); + }; + + // Cached regular expressions for matching named param parts and splatted + // parts of route strings. + var optionalParam = /\((.*?)\)/g; + var namedParam = /(\(\?)?:\w+/g; + var splatParam = /\*\w+/g; + var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; + + // Set up all inheritable **Backbone.Router** properties and methods. + _.extend(Router.prototype, Events, { + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // Manually bind a single named route to a callback. For example: + // + // this.route('search/:query/p:num', 'search', function(query, num) { + // ... + // }); + // + route: function(route, name, callback) { + if (!_.isRegExp(route)) route = this._routeToRegExp(route); + if (_.isFunction(name)) { + callback = name; + name = ''; + } + if (!callback) callback = this[name]; + var router = this; + Backbone.history.route(route, function(fragment) { + var args = router._extractParameters(route, fragment); + if (router.execute(callback, args, name) !== false) { + router.trigger.apply(router, ['route:' + name].concat(args)); + router.trigger('route', name, args); + Backbone.history.trigger('route', router, name, args); + } + }); + return this; + }, + + // Execute a route handler with the provided parameters. This is an + // excellent place to do pre-route setup or post-route cleanup. + execute: function(callback, args, name) { + if (callback) callback.apply(this, args); + }, + + // Simple proxy to `Backbone.history` to save a fragment into the history. + navigate: function(fragment, options) { + Backbone.history.navigate(fragment, options); + return this; + }, + + // Bind all defined routes to `Backbone.history`. We have to reverse the + // order of the routes here to support behavior where the most general + // routes can be defined at the bottom of the route map. + _bindRoutes: function() { + if (!this.routes) return; + this.routes = _.result(this, 'routes'); + var route, routes = _.keys(this.routes); + while ((route = routes.pop()) != null) { + this.route(route, this.routes[route]); + } + }, + + // Convert a route string into a regular expression, suitable for matching + // against the current location hash. + _routeToRegExp: function(route) { + route = route.replace(escapeRegExp, '\\$&') + .replace(optionalParam, '(?:$1)?') + .replace(namedParam, function(match, optional) { + return optional ? match : '([^/?]+)'; + }) + .replace(splatParam, '([^?]*?)'); + return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$'); + }, + + // Given a route, and a URL fragment that it matches, return the array of + // extracted decoded parameters. Empty or unmatched parameters will be + // treated as `null` to normalize cross-browser behavior. + _extractParameters: function(route, fragment) { + var params = route.exec(fragment).slice(1); + return _.map(params, function(param, i) { + // Don't decode the search params. + if (i === params.length - 1) return param || null; + return param ? decodeURIComponent(param) : null; + }); + } + + }); + + // Backbone.History + // ---------------- + + // Handles cross-browser history management, based on either + // [pushState](http://diveintohtml5.info/history.html) and real URLs, or + // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange) + // and URL fragments. If the browser supports neither (old IE, natch), + // falls back to polling. + var History = Backbone.History = function() { + this.handlers = []; + _.bindAll(this, 'checkUrl'); + + // Ensure that `History` can be used outside of the browser. + if (typeof window !== 'undefined') { + this.location = window.location; + this.history = window.history; + } + }; + + // Cached regex for stripping a leading hash/slash and trailing space. + var routeStripper = /^[#\/]|\s+$/g; + + // Cached regex for stripping leading and trailing slashes. + var rootStripper = /^\/+|\/+$/g; + + // Cached regex for stripping urls of hash. + var pathStripper = /#.*$/; + + // Has the history handling already been started? + History.started = false; + + // Set up all inheritable **Backbone.History** properties and methods. + _.extend(History.prototype, Events, { + + // The default interval to poll for hash changes, if necessary, is + // twenty times a second. + interval: 50, + + // Are we at the app root? + atRoot: function() { + var path = this.location.pathname.replace(/[^\/]$/, '$&/'); + return path === this.root && !this.getSearch(); + }, + + // Does the pathname match the root? + matchRoot: function() { + var path = this.decodeFragment(this.location.pathname); + var root = path.slice(0, this.root.length - 1) + '/'; + return root === this.root; + }, + + // Unicode characters in `location.pathname` are percent encoded so they're + // decoded for comparison. `%25` should not be decoded since it may be part + // of an encoded parameter. + decodeFragment: function(fragment) { + return decodeURI(fragment.replace(/%25/g, '%2525')); + }, + + // In IE6, the hash fragment and search params are incorrect if the + // fragment contains `?`. + getSearch: function() { + var match = this.location.href.replace(/#.*/, '').match(/\?.+/); + return match ? match[0] : ''; + }, + + // Gets the true hash value. Cannot use location.hash directly due to bug + // in Firefox where location.hash will always be decoded. + getHash: function(window) { + var match = (window || this).location.href.match(/#(.*)$/); + return match ? match[1] : ''; + }, + + // Get the pathname and search params, without the root. + getPath: function() { + var path = this.decodeFragment( + this.location.pathname + this.getSearch() + ).slice(this.root.length - 1); + return path.charAt(0) === '/' ? path.slice(1) : path; + }, + + // Get the cross-browser normalized URL fragment from the path or hash. + getFragment: function(fragment) { + if (fragment == null) { + if (this._usePushState || !this._wantsHashChange) { + fragment = this.getPath(); + } else { + fragment = this.getHash(); + } + } + return fragment.replace(routeStripper, ''); + }, + + // Start the hash change handling, returning `true` if the current URL matches + // an existing route, and `false` otherwise. + start: function(options) { + if (History.started) throw new Error('Backbone.history has already been started'); + History.started = true; + + // Figure out the initial configuration. Do we need an iframe? + // Is pushState desired ... is it available? + this.options = _.extend({root: '/'}, this.options, options); + this.root = this.options.root; + this._wantsHashChange = this.options.hashChange !== false; + this._hasHashChange = 'onhashchange' in window; + this._useHashChange = this._wantsHashChange && this._hasHashChange; + this._wantsPushState = !!this.options.pushState; + this._hasPushState = !!(this.history && this.history.pushState); + this._usePushState = this._wantsPushState && this._hasPushState; + this.fragment = this.getFragment(); + + // Normalize root to always include a leading and trailing slash. + this.root = ('/' + this.root + '/').replace(rootStripper, '/'); + + // Transition from hashChange to pushState or vice versa if both are + // requested. + if (this._wantsHashChange && this._wantsPushState) { + + // If we've started off with a route from a `pushState`-enabled + // browser, but we're currently in a browser that doesn't support it... + if (!this._hasPushState && !this.atRoot()) { + var root = this.root.slice(0, -1) || '/'; + this.location.replace(root + '#' + this.getPath()); + // Return immediately as browser will do redirect to new url + return true; + + // Or if we've started out with a hash-based route, but we're currently + // in a browser where it could be `pushState`-based instead... + } else if (this._hasPushState && this.atRoot()) { + this.navigate(this.getHash(), {replace: true}); + } + + } + + // Proxy an iframe to handle location events if the browser doesn't + // support the `hashchange` event, HTML5 history, or the user wants + // `hashChange` but not `pushState`. + if (!this._hasHashChange && this._wantsHashChange && !this._usePushState) { + this.iframe = document.createElement('iframe'); + this.iframe.src = 'javascript:0'; + this.iframe.style.display = 'none'; + this.iframe.tabIndex = -1; + var body = document.body; + // Using `appendChild` will throw on IE < 9 if the document is not ready. + var iWindow = body.insertBefore(this.iframe, body.firstChild).contentWindow; + iWindow.document.open(); + iWindow.document.close(); + iWindow.location.hash = '#' + this.fragment; + } + + // Add a cross-platform `addEventListener` shim for older browsers. + var addEventListener = window.addEventListener || function (eventName, listener) { + return attachEvent('on' + eventName, listener); + }; + + // Depending on whether we're using pushState or hashes, and whether + // 'onhashchange' is supported, determine how we check the URL state. + if (this._usePushState) { + addEventListener('popstate', this.checkUrl, false); + } else if (this._useHashChange && !this.iframe) { + addEventListener('hashchange', this.checkUrl, false); + } else if (this._wantsHashChange) { + this._checkUrlInterval = setInterval(this.checkUrl, this.interval); + } + + if (!this.options.silent) return this.loadUrl(); + }, + + // Disable Backbone.history, perhaps temporarily. Not useful in a real app, + // but possibly useful for unit testing Routers. + stop: function() { + // Add a cross-platform `removeEventListener` shim for older browsers. + var removeEventListener = window.removeEventListener || function (eventName, listener) { + return detachEvent('on' + eventName, listener); + }; + + // Remove window listeners. + if (this._usePushState) { + removeEventListener('popstate', this.checkUrl, false); + } else if (this._useHashChange && !this.iframe) { + removeEventListener('hashchange', this.checkUrl, false); + } + + // Clean up the iframe if necessary. + if (this.iframe) { + document.body.removeChild(this.iframe); + this.iframe = null; + } + + // Some environments will throw when clearing an undefined interval. + if (this._checkUrlInterval) clearInterval(this._checkUrlInterval); + History.started = false; + }, + + // Add a route to be tested when the fragment changes. Routes added later + // may override previous routes. + route: function(route, callback) { + this.handlers.unshift({route: route, callback: callback}); + }, + + // Checks the current URL to see if it has changed, and if it has, + // calls `loadUrl`, normalizing across the hidden iframe. + checkUrl: function(e) { + var current = this.getFragment(); + + // If the user pressed the back button, the iframe's hash will have + // changed and we should use that for comparison. + if (current === this.fragment && this.iframe) { + current = this.getHash(this.iframe.contentWindow); + } + + if (current === this.fragment) return false; + if (this.iframe) this.navigate(current); + this.loadUrl(); + }, + + // Attempt to load the current URL fragment. If a route succeeds with a + // match, returns `true`. If no defined routes matches the fragment, + // returns `false`. + loadUrl: function(fragment) { + // If the root doesn't match, no routes can match either. + if (!this.matchRoot()) return false; + fragment = this.fragment = this.getFragment(fragment); + return _.any(this.handlers, function(handler) { + if (handler.route.test(fragment)) { + handler.callback(fragment); + return true; + } + }); + }, + + // Save a fragment into the hash history, or replace the URL state if the + // 'replace' option is passed. You are responsible for properly URL-encoding + // the fragment in advance. + // + // The options object can contain `trigger: true` if you wish to have the + // route callback be fired (not usually desirable), or `replace: true`, if + // you wish to modify the current URL without adding an entry to the history. + navigate: function(fragment, options) { + if (!History.started) return false; + if (!options || options === true) options = {trigger: !!options}; + + // Normalize the fragment. + fragment = this.getFragment(fragment || ''); + + // Don't include a trailing slash on the root. + var root = this.root; + if (fragment === '' || fragment.charAt(0) === '?') { + root = root.slice(0, -1) || '/'; + } + var url = root + fragment; + + // Strip the hash and decode for matching. + fragment = this.decodeFragment(fragment.replace(pathStripper, '')); + + if (this.fragment === fragment) return; + this.fragment = fragment; + + // If pushState is available, we use it to set the fragment as a real URL. + if (this._usePushState) { + this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url); + + // If hash changes haven't been explicitly disabled, update the hash + // fragment to store history. + } else if (this._wantsHashChange) { + this._updateHash(this.location, fragment, options.replace); + if (this.iframe && (fragment !== this.getHash(this.iframe.contentWindow))) { + var iWindow = this.iframe.contentWindow; + + // Opening and closing the iframe tricks IE7 and earlier to push a + // history entry on hash-tag change. When replace is true, we don't + // want this. + if (!options.replace) { + iWindow.document.open(); + iWindow.document.close(); + } + + this._updateHash(iWindow.location, fragment, options.replace); + } + + // If you've told us that you explicitly don't want fallback hashchange- + // based history, then `navigate` becomes a page refresh. + } else { + return this.location.assign(url); + } + if (options.trigger) return this.loadUrl(fragment); + }, + + // Update the hash location, either replacing the current entry, or adding + // a new one to the browser history. + _updateHash: function(location, fragment, replace) { + if (replace) { + var href = location.href.replace(/(javascript:|#).*$/, ''); + location.replace(href + '#' + fragment); + } else { + // Some browsers require that `hash` contains a leading #. + location.hash = '#' + fragment; + } + } + + }); + + // Create the default Backbone.history. + Backbone.history = new History; + + // Helpers + // ------- + + // Helper function to correctly set up the prototype chain for subclasses. + // Similar to `goog.inherits`, but uses a hash of prototype properties and + // class properties to be extended. + var extend = function(protoProps, staticProps) { + var parent = this; + var child; + + // The constructor function for the new subclass is either defined by you + // (the "constructor" property in your `extend` definition), or defaulted + // by us to simply call the parent constructor. + if (protoProps && _.has(protoProps, 'constructor')) { + child = protoProps.constructor; + } else { + child = function(){ return parent.apply(this, arguments); }; + } + + // Add static properties to the constructor function, if supplied. + _.extend(child, parent, staticProps); + + // Set the prototype chain to inherit from `parent`, without calling + // `parent` constructor function. + var Surrogate = function(){ this.constructor = child; }; + Surrogate.prototype = parent.prototype; + child.prototype = new Surrogate; + + // Add prototype properties (instance properties) to the subclass, + // if supplied. + if (protoProps) _.extend(child.prototype, protoProps); + + // Set a convenience property in case the parent's prototype is needed + // later. + child.__super__ = parent.prototype; + + return child; + }; + + // Set up inheritance for the model, collection, router, view and history. + Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend; + + // Throw an error when a URL is needed, and none is supplied. + var urlError = function() { + throw new Error('A "url" property or function must be specified'); + }; + + // Wrap an optional error callback with a fallback error event. + var wrapError = function(model, options) { + var error = options.error; + options.error = function(resp) { + if (error) error.call(options.context, model, resp, options); + model.trigger('error', model, resp, options); + }; + }; + + return Backbone; + +})); |