Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Backbone.js 0.3.3

  • Loading branch information...
commit 3505bde58ec82f15e920298813d37476242793bb 1 parent c7a7aa5
@jashkenas jashkenas authored
View
46 backbone-min.js
@@ -1,27 +1,27 @@
-// Backbone.js 0.3.2
+// Backbone.js 0.3.3
// (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
// Backbone may be freely distributed under the MIT license.
// For all details and documentation:
// http://documentcloud.github.com/backbone
-(function(){var e;e=typeof exports!=="undefined"?exports:this.Backbone={};e.VERSION="0.3.2";var f=this._;if(!f&&typeof require!=="undefined")f=require("underscore")._;var h=this.jQuery;e.emulateHTTP=false;e.emulateJSON=false;e.Events={bind:function(a,b){this._callbacks||(this._callbacks={});(this._callbacks[a]||(this._callbacks[a]=[])).push(b);return this},unbind:function(a,b){var c;if(a){if(c=this._callbacks)if(b){c=c[a];if(!c)return this;for(var d=0,g=c.length;d<g;d++)if(b===c[d]){c.splice(d,1);
-break}}else c[a]=[]}else this._callbacks={};return this},trigger:function(a){var b,c,d,g;if(!(c=this._callbacks))return this;if(b=c[a]){d=0;for(g=b.length;d<g;d++)b[d].apply(this,Array.prototype.slice.call(arguments,1))}if(b=c.all){d=0;for(g=b.length;d<g;d++)b[d].apply(this,arguments)}return this}};e.Model=function(a,b){a||(a={});if(this.defaults)a=f.extend({},this.defaults,a);this.attributes={};this.cid=f.uniqueId("c");this.set(a,{silent:true});this._previousAttributes=f.clone(this.attributes);if(b&&
-b.collection)this.collection=b.collection;this.initialize(a,b)};f.extend(e.Model.prototype,e.Events,{_previousAttributes:null,_changed:false,initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},set:function(a,b){b||(b={});if(!a)return this;if(a.attributes)a=a.attributes;var c=this.attributes;if(!b.silent&&this.validate&&!this._performValidation(a,b))return false;if("id"in a)this.id=a.id;for(var d in a){var g=a[d];if(!f.isEqual(c[d],
-g)){c[d]=g;if(!b.silent){this._changed=true;this.trigger("change:"+d,this,g)}}}!b.silent&&this._changed&&this.change();return this},unset:function(a,b){b||(b={});var c={};c[a]=void 0;if(!b.silent&&this.validate&&!this._performValidation(c,b))return false;delete this.attributes[a];if(!b.silent){this._changed=true;this.trigger("change:"+a,this);this.change()}return this},clear:function(a){a||(a={});var b=this.attributes,c={};for(attr in b)c[attr]=void 0;if(!a.silent&&this.validate&&!this._performValidation(c,
-a))return false;this.attributes={};if(!a.silent){this._changed=true;for(attr in b)this.trigger("change:"+attr,this);this.change()}return this},fetch:function(a){a||(a={});var b=this,c=a.error&&f.bind(a.error,null,b);(this.sync||e.sync)("read",this,function(d){if(!b.set(b.parse(d),a))return false;a.success&&a.success(b,d)},c);return this},save:function(a,b){b||(b={});if(a&&!this.set(a,b))return false;var c=this,d=b.error&&f.bind(b.error,null,c),g=this.isNew()?"create":"update";(this.sync||e.sync)(g,
-this,function(i){if(!c.set(c.parse(i),b))return false;b.success&&b.success(c,i)},d);return this},destroy:function(a){a||(a={});var b=this,c=a.error&&f.bind(a.error,null,b);(this.sync||e.sync)("delete",this,function(d){b.collection&&b.collection.remove(b);a.success&&a.success(b,d)},c);return this},url:function(){var a=j(this.collection);if(this.isNew())return a;return a+(a.charAt(a.length-1)=="/"?"":"/")+this.id},parse:function(a){return a},clone:function(){return new this.constructor(this)},isNew:function(){return!this.id},
-change:function(){this.trigger("change",this);this._previousAttributes=f.clone(this.attributes);this._changed=false},hasChanged:function(a){if(a)return this._previousAttributes[a]!=this.attributes[a];return this._changed},changedAttributes:function(a){a||(a=this.attributes);var b=this._previousAttributes,c=false,d;for(d in a)if(!f.isEqual(b[d],a[d])){c=c||{};c[d]=a[d]}return c},previous:function(a){if(!a||!this._previousAttributes)return null;return this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},
-_performValidation:function(a,b){var c=this.validate(a);if(c){b.error?b.error(this,c):this.trigger("error",this,c);return false}return true}});e.Collection=function(a,b){b||(b={});if(b.comparator){this.comparator=b.comparator;delete b.comparator}this._boundOnModelEvent=f.bind(this._onModelEvent,this);this._reset();a&&this.refresh(a,{silent:true});this.initialize(a,b)};f.extend(e.Collection.prototype,e.Events,{model:e.Model,initialize:function(){},toJSON:function(){return this.map(function(a){return a.toJSON()})},
-add:function(a,b){if(f.isArray(a))for(var c=0,d=a.length;c<d;c++)this._add(a[c],b);else this._add(a,b);return this},remove:function(a,b){if(f.isArray(a))for(var c=0,d=a.length;c<d;c++)this._remove(a[c],b);else this._remove(a,b);return this},get:function(a){if(a==null)return null;return this._byId[a.id!=null?a.id:a]},getByCid:function(a){return a&&this._byCid[a.cid||a]},at:function(a){return this.models[a]},sort:function(a){a||(a={});if(!this.comparator)throw Error("Cannot sort a set without a comparator");
-this.models=this.sortBy(this.comparator);a.silent||this.trigger("refresh",this);return this},pluck:function(a){return f.map(this.models,function(b){return b.get(a)})},refresh:function(a,b){a||(a=[]);b||(b={});this._reset();this.add(a,{silent:true});b.silent||this.trigger("refresh",this);return this},fetch:function(a){a||(a={});var b=this,c=a.error&&f.bind(a.error,null,b);(this.sync||e.sync)("read",this,function(d){b.refresh(b.parse(d));a.success&&a.success(b,d)},c);return this},create:function(a,
-b){var c=this;b||(b={});if(a instanceof e.Model)a.collection=c;else a=new this.model(a,{collection:c});return a.save(null,{success:function(d,g){c.add(d);b.success&&b.success(d,g)},error:b.error})},parse:function(a){return a},chain:function(){return f(this.models).chain()},_reset:function(){this.length=0;this.models=[];this._byId={};this._byCid={}},_add:function(a,b){b||(b={});a instanceof e.Model||(a=new this.model(a,{collection:this}));var c=this.getByCid(a);if(c)throw Error(["Can't add the same model to a set twice",
-c.id]);this._byId[a.id]=a;this._byCid[a.cid]=a;a.collection=this;this.models.splice(this.comparator?this.sortedIndex(a,this.comparator):this.length,0,a);a.bind("all",this._boundOnModelEvent);this.length++;b.silent||a.trigger("add",a,this);return a},_remove:function(a,b){b||(b={});a=this.getByCid(a)||this.get(a);if(!a)return null;delete this._byId[a.id];delete this._byCid[a.cid];delete a.collection;this.models.splice(this.indexOf(a),1);this.length--;b.silent||a.trigger("remove",a,this);a.unbind("all",
-this._boundOnModelEvent);return a},_onModelEvent:function(a,b){if(a==="change:id"){delete this._byId[b.previous("id")];this._byId[b.id]=b}this.trigger.apply(this,arguments)}});f.each(["forEach","each","map","reduce","reduceRight","find","detect","filter","select","reject","every","all","some","any","include","invoke","max","min","sortBy","sortedIndex","toArray","size","first","rest","last","without","indexOf","lastIndexOf","isEmpty"],function(a){e.Collection.prototype[a]=function(){return f[a].apply(f,
-[this.models].concat(f.toArray(arguments)))}});e.Controller=function(a){a||(a={});if(a.routes)this.routes=a.routes;this._bindRoutes();this.initialize(a)};var o=/:([\w\d]+)/g,p=/\*([\w\d]+)/g;f.extend(e.Controller.prototype,e.Events,{initialize:function(){},route:function(a,b,c){e.history||(e.history=new e.History);f.isRegExp(a)||(a=this._routeToRegExp(a));e.history.route(a,f.bind(function(d){d=this._extractParameters(a,d);c.apply(this,d);this.trigger.apply(this,["route:"+b].concat(d))},this))},saveLocation:function(a){e.history.saveLocation(a)},
-_bindRoutes:function(){if(this.routes)for(var a in this.routes){var b=this.routes[a];this.route(a,b,this[b])}},_routeToRegExp:function(a){a=a.replace(o,"([^/]*)").replace(p,"(.*?)");return RegExp("^"+a+"$")},_extractParameters:function(a,b){return a.exec(b).slice(1)}});e.History=function(){this.handlers=[];this.fragment=this.getFragment();f.bindAll(this,"checkUrl")};var k=/^#*/;f.extend(e.History.prototype,{interval:50,getFragment:function(a){return(a||window.location).hash.replace(k,"")},start:function(){var a=
-document.documentMode;if(a=h.browser.msie&&(!a||a<=7))this.iframe=h('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow;"onhashchange"in window&&!a?h(window).bind("hashchange",this.checkUrl):setInterval(this.checkUrl,this.interval);return this.loadUrl()},route:function(a,b){this.handlers.push({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();if(a==this.fragment&&this.iframe)a=this.getFragment(this.iframe.location);if(a==this.fragment||a==decodeURIComponent(this.fragment))return false;
-if(this.iframe)window.location.hash=this.iframe.location.hash=a;this.loadUrl()},loadUrl:function(){var a=this.fragment=this.getFragment();return f.any(this.handlers,function(b){if(b.route.test(a)){b.callback(a);return true}})},saveLocation:function(a){a=(a||"").replace(k,"");if(this.fragment!=a){window.location.hash=this.fragment=a;if(this.iframe&&a!=this.getFragment(this.iframe.location)){this.iframe.document.open().close();this.iframe.location.hash=a}}}});e.View=function(a){this._configure(a||{});
-this._ensureElement();this.delegateEvents();this.initialize(a)};var l=function(a){return h(a,this.el)},q=/^(\w+)\s*(.*)$/;f.extend(e.View.prototype,e.Events,{tagName:"div",$:l,jQuery:l,initialize:function(){},render:function(){return this},remove:function(){h(this.el).remove();return this},make:function(a,b,c){a=document.createElement(a);b&&h(a).attr(b);c&&h(a).html(c);return a},delegateEvents:function(a){if(a||(a=this.events)){h(this.el).unbind();for(var b in a){var c=a[b],d=b.match(q),g=d[1];d=
-d[2];c=f.bind(this[c],this);d===""?h(this.el).bind(g,c):h(this.el).delegate(d,g,c)}}},_configure:function(a){if(this.options)a=f.extend({},this.options,a);if(a.model)this.model=a.model;if(a.collection)this.collection=a.collection;if(a.el)this.el=a.el;if(a.id)this.id=a.id;if(a.className)this.className=a.className;if(a.tagName)this.tagName=a.tagName;this.options=a},_ensureElement:function(){if(!this.el){var a={};if(this.id)a.id=this.id;if(this.className)a.className=this.className;this.el=this.make(this.tagName,
-a)}}});var m=function(a,b){var c=r(this,a,b);c.extend=m;return c};e.Model.extend=e.Collection.extend=e.Controller.extend=e.View.extend=m;var s={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};e.sync=function(a,b,c,d){var g=s[a];a=a==="create"||a==="update"?JSON.stringify(b.toJSON()):null;b={url:j(b),type:g,contentType:"application/json",data:a,dataType:"json",processData:false,success:c,error:d};if(e.emulateJSON){b.contentType="application/x-www-form-urlencoded";b.processData=true;b.data=
-a?{model:a}:{}}if(e.emulateHTTP)if(g==="PUT"||g==="DELETE"){if(e.emulateJSON)b.data._method=g;b.type="POST";b.beforeSend=function(i){i.setRequestHeader("X-HTTP-Method-Override",g)}}h.ajax(b)};var n=function(){},r=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){return a.apply(this,arguments)};n.prototype=a.prototype;d.prototype=new n;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},j=function(a){if(!(a&&a.url))throw Error("A 'url' property or function must be specified");
-return f.isFunction(a.url)?a.url():a.url}})();
+(function(){var e;e=typeof exports!=="undefined"?exports:this.Backbone={};e.VERSION="0.3.3";var f=this._;if(!f&&typeof require!=="undefined")f=require("underscore")._;var h=this.jQuery||this.Zepto;e.emulateHTTP=false;e.emulateJSON=false;e.Events={bind:function(a,b){this._callbacks||(this._callbacks={});(this._callbacks[a]||(this._callbacks[a]=[])).push(b);return this},unbind:function(a,b){var c;if(a){if(c=this._callbacks)if(b){c=c[a];if(!c)return this;for(var d=0,g=c.length;d<g;d++)if(b===c[d]){c.splice(d,
+1);break}}else c[a]=[]}else this._callbacks={};return this},trigger:function(a){var b,c,d,g;if(!(c=this._callbacks))return this;if(b=c[a]){d=0;for(g=b.length;d<g;d++)b[d].apply(this,Array.prototype.slice.call(arguments,1))}if(b=c.all){d=0;for(g=b.length;d<g;d++)b[d].apply(this,arguments)}return this}};e.Model=function(a,b){a||(a={});if(this.defaults)a=f.extend({},this.defaults,a);this.attributes={};this._escapedAttributes={};this.cid=f.uniqueId("c");this.set(a,{silent:true});this._previousAttributes=
+f.clone(this.attributes);if(b&&b.collection)this.collection=b.collection;this.initialize(a,b)};f.extend(e.Model.prototype,e.Events,{_previousAttributes:null,_changed:false,initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},escape:function(a){var b;if(b=this._escapedAttributes[a])return b;b=this.attributes[a];return this._escapedAttributes[a]=(b==null?"":b).replace(/&(?!\w+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,
+"&quot;")},set:function(a,b){b||(b={});if(!a)return this;if(a.attributes)a=a.attributes;var c=this.attributes,d=this._escapedAttributes;if(!b.silent&&this.validate&&!this._performValidation(a,b))return false;if("id"in a)this.id=a.id;for(var g in a){var i=a[g];if(!f.isEqual(c[g],i)){c[g]=i;delete d[g];if(!b.silent){this._changed=true;this.trigger("change:"+g,this,i,b)}}}!b.silent&&this._changed&&this.change(b);return this},unset:function(a,b){b||(b={});var c={};c[a]=void 0;if(!b.silent&&this.validate&&
+!this._performValidation(c,b))return false;delete this.attributes[a];delete this._escapedAttributes[a];if(!b.silent){this._changed=true;this.trigger("change:"+a,this,void 0,b);this.change(b)}return this},clear:function(a){a||(a={});var b=this.attributes,c={};for(attr in b)c[attr]=void 0;if(!a.silent&&this.validate&&!this._performValidation(c,a))return false;this.attributes={};this._escapedAttributes={};if(!a.silent){this._changed=true;for(attr in b)this.trigger("change:"+attr,this,void 0,a);this.change(a)}return this},
+fetch:function(a){a||(a={});var b=this,c=j(a.error,b,a);(this.sync||e.sync)("read",this,function(d){if(!b.set(b.parse(d),a))return false;a.success&&a.success(b,d)},c);return this},save:function(a,b){b||(b={});if(a&&!this.set(a,b))return false;var c=this,d=j(b.error,c,b),g=this.isNew()?"create":"update";(this.sync||e.sync)(g,this,function(i){if(!c.set(c.parse(i),b))return false;b.success&&b.success(c,i)},d);return this},destroy:function(a){a||(a={});var b=this,c=j(a.error,b,a);(this.sync||e.sync)("delete",
+this,function(d){b.collection&&b.collection.remove(b);a.success&&a.success(b,d)},c);return this},url:function(){var a=k(this.collection);if(this.isNew())return a;return a+(a.charAt(a.length-1)=="/"?"":"/")+this.id},parse:function(a){return a},clone:function(){return new this.constructor(this)},isNew:function(){return!this.id},change:function(a){this.trigger("change",this,a);this._previousAttributes=f.clone(this.attributes);this._changed=false},hasChanged:function(a){if(a)return this._previousAttributes[a]!=
+this.attributes[a];return this._changed},changedAttributes:function(a){a||(a=this.attributes);var b=this._previousAttributes,c=false,d;for(d in a)if(!f.isEqual(b[d],a[d])){c=c||{};c[d]=a[d]}return c},previous:function(a){if(!a||!this._previousAttributes)return null;return this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},_performValidation:function(a,b){var c=this.validate(a);if(c){b.error?b.error(this,c):this.trigger("error",this,c,b);return false}return true}});
+e.Collection=function(a,b){b||(b={});if(b.comparator){this.comparator=b.comparator;delete b.comparator}this._boundOnModelEvent=f.bind(this._onModelEvent,this);this._reset();a&&this.refresh(a,{silent:true});this.initialize(a,b)};f.extend(e.Collection.prototype,e.Events,{model:e.Model,initialize:function(){},toJSON:function(){return this.map(function(a){return a.toJSON()})},add:function(a,b){if(f.isArray(a))for(var c=0,d=a.length;c<d;c++)this._add(a[c],b);else this._add(a,b);return this},remove:function(a,
+b){if(f.isArray(a))for(var c=0,d=a.length;c<d;c++)this._remove(a[c],b);else this._remove(a,b);return this},get:function(a){if(a==null)return null;return this._byId[a.id!=null?a.id:a]},getByCid:function(a){return a&&this._byCid[a.cid||a]},at:function(a){return this.models[a]},sort:function(a){a||(a={});if(!this.comparator)throw Error("Cannot sort a set without a comparator");this.models=this.sortBy(this.comparator);a.silent||this.trigger("refresh",this,a);return this},pluck:function(a){return f.map(this.models,
+function(b){return b.get(a)})},refresh:function(a,b){a||(a=[]);b||(b={});this._reset();this.add(a,{silent:true});b.silent||this.trigger("refresh",this,b);return this},fetch:function(a){a||(a={});var b=this,c=j(a.error,b,a);(this.sync||e.sync)("read",this,function(d){b.refresh(b.parse(d));a.success&&a.success(b,d)},c);return this},create:function(a,b){var c=this;b||(b={});if(a instanceof e.Model)a.collection=c;else a=new this.model(a,{collection:c});return a.save(null,{success:function(d,g){c.add(d);
+b.success&&b.success(d,g)},error:b.error})},parse:function(a){return a},chain:function(){return f(this.models).chain()},_reset:function(){this.length=0;this.models=[];this._byId={};this._byCid={}},_add:function(a,b){b||(b={});a instanceof e.Model||(a=new this.model(a,{collection:this}));var c=this.getByCid(a);if(c)throw Error(["Can't add the same model to a set twice",c.id]);this._byId[a.id]=a;this._byCid[a.cid]=a;a.collection=this;this.models.splice(this.comparator?this.sortedIndex(a,this.comparator):
+this.length,0,a);a.bind("all",this._boundOnModelEvent);this.length++;b.silent||a.trigger("add",a,this,b);return a},_remove:function(a,b){b||(b={});a=this.getByCid(a)||this.get(a);if(!a)return null;delete this._byId[a.id];delete this._byCid[a.cid];delete a.collection;this.models.splice(this.indexOf(a),1);this.length--;b.silent||a.trigger("remove",a,this,b);a.unbind("all",this._boundOnModelEvent);return a},_onModelEvent:function(a,b){if(a==="change:id"){delete this._byId[b.previous("id")];this._byId[b.id]=
+b}this.trigger.apply(this,arguments)}});f.each(["forEach","each","map","reduce","reduceRight","find","detect","filter","select","reject","every","all","some","any","include","invoke","max","min","sortBy","sortedIndex","toArray","size","first","rest","last","without","indexOf","lastIndexOf","isEmpty"],function(a){e.Collection.prototype[a]=function(){return f[a].apply(f,[this.models].concat(f.toArray(arguments)))}});e.Controller=function(a){a||(a={});if(a.routes)this.routes=a.routes;this._bindRoutes();
+this.initialize(a)};var o=/:([\w\d]+)/g,p=/\*([\w\d]+)/g;f.extend(e.Controller.prototype,e.Events,{initialize:function(){},route:function(a,b,c){e.history||(e.history=new e.History);f.isRegExp(a)||(a=this._routeToRegExp(a));e.history.route(a,f.bind(function(d){d=this._extractParameters(a,d);c.apply(this,d);this.trigger.apply(this,["route:"+b].concat(d))},this))},saveLocation:function(a){e.history.saveLocation(a)},_bindRoutes:function(){if(this.routes)for(var a in this.routes){var b=this.routes[a];
+this.route(a,b,this[b])}},_routeToRegExp:function(a){a=a.replace(o,"([^/]*)").replace(p,"(.*?)");return RegExp("^"+a+"$")},_extractParameters:function(a,b){return a.exec(b).slice(1)}});e.History=function(){this.handlers=[];this.fragment=this.getFragment();f.bindAll(this,"checkUrl")};var l=/^#*/;f.extend(e.History.prototype,{interval:50,getFragment:function(a){return(a||window.location).hash.replace(l,"")},start:function(){var a=document.documentMode;if(a=h.browser.msie&&(!a||a<=7))this.iframe=h('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow;
+"onhashchange"in window&&!a?h(window).bind("hashchange",this.checkUrl):setInterval(this.checkUrl,this.interval);return this.loadUrl()},route:function(a,b){this.handlers.push({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();if(a==this.fragment&&this.iframe)a=this.getFragment(this.iframe.location);if(a==this.fragment||a==decodeURIComponent(this.fragment))return false;if(this.iframe)window.location.hash=this.iframe.location.hash=a;this.loadUrl()},loadUrl:function(){var a=this.fragment=
+this.getFragment();return f.any(this.handlers,function(b){if(b.route.test(a)){b.callback(a);return true}})},saveLocation:function(a){a=(a||"").replace(l,"");if(this.fragment!=a){window.location.hash=this.fragment=a;if(this.iframe&&a!=this.getFragment(this.iframe.location)){this.iframe.document.open().close();this.iframe.location.hash=a}}}});e.View=function(a){this._configure(a||{});this._ensureElement();this.delegateEvents();this.initialize(a)};var q=/^(\w+)\s*(.*)$/;f.extend(e.View.prototype,e.Events,
+{tagName:"div",$:function(a){return h(a,this.el)},initialize:function(){},render:function(){return this},remove:function(){h(this.el).remove();return this},make:function(a,b,c){a=document.createElement(a);b&&h(a).attr(b);c&&h(a).html(c);return a},delegateEvents:function(a){if(a||(a=this.events)){h(this.el).unbind();for(var b in a){var c=a[b],d=b.match(q),g=d[1];d=d[2];c=f.bind(this[c],this);d===""?h(this.el).bind(g,c):h(this.el).delegate(d,g,c)}}},_configure:function(a){if(this.options)a=f.extend({},
+this.options,a);if(a.model)this.model=a.model;if(a.collection)this.collection=a.collection;if(a.el)this.el=a.el;if(a.id)this.id=a.id;if(a.className)this.className=a.className;if(a.tagName)this.tagName=a.tagName;this.options=a},_ensureElement:function(){if(!this.el){var a={};if(this.id)a.id=this.id;if(this.className)a["class"]=this.className;this.el=this.make(this.tagName,a)}}});var m=function(a,b){var c=r(this,a,b);c.extend=m;return c};e.Model.extend=e.Collection.extend=e.Controller.extend=e.View.extend=
+m;var s={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};e.sync=function(a,b,c,d){var g=s[a];a=a==="create"||a==="update"?JSON.stringify(b.toJSON()):null;b={url:k(b),type:g,contentType:"application/json",data:a,dataType:"json",processData:false,success:c,error:d};if(e.emulateJSON){b.contentType="application/x-www-form-urlencoded";b.processData=true;b.data=a?{model:a}:{}}if(e.emulateHTTP)if(g==="PUT"||g==="DELETE"){if(e.emulateJSON)b.data._method=g;b.type="POST";b.beforeSend=function(i){i.setRequestHeader("X-HTTP-Method-Override",
+g)}}h.ajax(b)};var n=function(){},r=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){return a.apply(this,arguments)};n.prototype=a.prototype;d.prototype=new n;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},k=function(a){if(!(a&&a.url))throw Error("A 'url' property or function must be specified");return f.isFunction(a.url)?a.url():a.url},j=function(a,b,c){return function(d){a?a(b,d):b.trigger("error",b,d,c)}}})();
View
26 backbone.js
@@ -1,4 +1,4 @@
-// Backbone.js 0.3.2
+// Backbone.js 0.3.3
// (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
// Backbone may be freely distributed under the MIT license.
// For all details and documentation:
@@ -19,13 +19,13 @@
}
// Current version of the library. Keep in sync with `package.json`.
- Backbone.VERSION = '0.3.2';
+ Backbone.VERSION = '0.3.3';
// Require Underscore, if we're on the server, and it's not already present.
var _ = this._;
if (!_ && (typeof require !== 'undefined')) _ = require("underscore")._;
- // For Backbone's purposes, jQuery owns the `$` variable.
+ // For Backbone's purposes, either jQuery or Zepto owns the `$` variable.
var $ = this.jQuery || this.Zepto;
// Turn on `emulateHTTP` to use support legacy HTTP servers. Setting this option will
@@ -762,10 +762,10 @@
this.initialize(options);
};
- // jQuery lookup, scoped to DOM elements within the current view.
- // This should be prefered to global jQuery lookups, if you're dealing with
+ // Element lookup, scoped to DOM elements within the current view.
+ // This should be prefered to global lookups, if you're dealing with
// a specific view.
- var jQueryDelegate = function(selector) {
+ var selectorDelegate = function(selector) {
return $(selector, this.el);
};
@@ -778,9 +778,8 @@
// The default `tagName` of a View's element is `"div"`.
tagName : 'div',
- // Attach the jQuery function as the `$` and `jQuery` properties.
- $ : jQueryDelegate,
- jQuery : jQueryDelegate,
+ // Attach the `selectorDelegate` function as the `$` property.
+ $ : selectorDelegate,
// Initialize is an empty function by default. Override it with your own
// initialization logic.
@@ -822,7 +821,7 @@
// }
//
// pairs. Callbacks will be bound to the view, with `this` set properly.
- // Uses jQuery event delegation for efficiency.
+ // Uses event delegation for efficiency.
// Omitting the selector binds the event to `this.el`.
// This only works for delegate-able events: not `focus`, `blur`, and
// not `change`, `submit`, and `reset` in Internet Explorer.
@@ -891,7 +890,7 @@
// 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, uses jQuery to make a RESTful Ajax request
+ // model in question. By default, uses 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.
@@ -1006,10 +1005,7 @@
// Helper function to escape a string for HTML rendering.
var escapeHTML = function(string) {
- return string.replace(/&(?!\w+;)/g, '&amp;')
- .replace(/</g, '&lt;')
- .replace(/>/g, '&gt;')
- .replace(/"/g, '&quot;');
+ return string.replace(/&(?!\w+;)/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
};
})();
View
234 docs/backbone.html
126 additions, 108 deletions not shown
View
2  examples/todos/index.html
@@ -6,7 +6,7 @@
<link href="todos.css" media="all" rel="stylesheet" type="text/css"/>
<script src="../../test/vendor/json2.js"></script>
<script src="../../test/vendor/jquery-1.4.2.js"></script>
- <script src="../../test/vendor/underscore-1.1.0.js"></script>
+ <script src="../../test/vendor/underscore-1.1.3.js"></script>
<script src="../../backbone.js"></script>
<script src="../backbone-localstorage.js"></script>
<script src="todos.js"></script>
View
218 index.html
@@ -142,15 +142,15 @@
<body>
<div id="sidebar" class="interface">
-
+
<a class="toc_title" href="#">
- Backbone.js <span class="version">(0.3.2)</span>
+ Backbone.js <span class="version">(0.3.3)</span>
</a>
-
+
<a class="toc_title" href="#Introduction">
Introduction
</a>
-
+
<a class="toc_title" href="#Events">
Events
</a>
@@ -159,7 +159,7 @@
<li>– <a href="#Events-unbind">unbind</a></li>
<li>– <a href="#Events-trigger">trigger</a></li>
</ul>
-
+
<a class="toc_title" href="#Model">
Model
</a>
@@ -167,6 +167,7 @@
<li>– <a href="#Model-extend">extend</a></li>
<li>– <a href="#Model-constructor">constructor / initialize</a></li>
<li>– <a href="#Model-get">get</a></li>
+ <li>– <a href="#Model-escape">escape</a></li>
<li>– <a href="#Model-set">set</a></li>
<li>– <a href="#Model-unset">unset</a></li>
<li>– <a href="#Model-clear">clear</a></li>
@@ -189,7 +190,7 @@
<li>– <a href="#Model-previous">previous</a></li>
<li>– <a href="#Model-previousAttributes">previousAttributes</a></li>
</ul>
-
+
<a class="toc_title" href="#Collection">
Collection
</a>
@@ -215,7 +216,7 @@
<li>– <a href="#Collection-refresh">refresh</a></li>
<li>– <a href="#Collection-create">create</a></li>
</ul>
-
+
<a class="toc_title" href="#Controller">
Controller
</a>
@@ -226,7 +227,7 @@
<li>– <a href="#Controller-route">route</a></li>
<li>– <a href="#Controller-saveLocation">saveLocation</a></li>
</ul>
-
+
<a class="toc_title" href="#History">
History
</a>
@@ -234,7 +235,7 @@
<li>– <a href="#History-start">start</a></li>
<li>– <a href="#History-saveLocation">saveLocation</a></li>
</ul>
-
+
<a class="toc_title" href="#Sync">
Sync
</a>
@@ -243,7 +244,7 @@
<li>– <a href="#Sync-emulateHTTP">Backbone.emulateHTTP</a></li>
<li>– <a href="#Sync-emulateJSON">Backbone.emulateJSON</a></li>
</ul>
-
+
<a class="toc_title" href="#View">
View
</a>
@@ -251,21 +252,21 @@
<li>– <a href="#View-extend">extend</a></li>
<li>– <a href="#View-constructor">constructor / initialize</a></li>
<li>– <a href="#View-el">el</a></li>
- <li>– <a href="#View-jQuery">$ (jQuery)</a></li>
+ <li>– <a href="#View-dollar">$ (jQuery or Zepto)</a></li>
<li>– <a href="#View-render">render</a></li>
<li>– <a href="#View-remove">remove</a></li>
<li>– <a href="#View-make">make</a></li>
<li>– <a href="#View-delegateEvents">delegateEvents</a></li>
</ul>
-
+
<a class="toc_title" href="#examples">
Examples
</a>
-
+
<a class="toc_title" href="#changelog">
Change Log
</a>
-
+
</div>
<div class="container">
@@ -285,7 +286,7 @@
<p>
The project is <a href="http://github.com/documentcloud/backbone/">hosted on GitHub</a>,
and the <a href="docs/backbone.html">annotated source code</a> is available,
- as well as an online <a href="test/test.html">test suite</a>, and
+ as well as an online <a href="test/test.html">test suite</a>, and
<a href="examples/todos/index.html">example application</a>.
</p>
@@ -310,12 +311,12 @@ <h2 id="downloads">
<table>
<tr>
- <td><a href="backbone.js">Development Version (0.3.2)</a></td>
- <td><i>33kb, Uncompressed with Comments</i></td>
+ <td><a href="backbone.js">Development Version (0.3.3)</a></td>
+ <td><i>35kb, Uncompressed with Comments</i></td>
</tr>
<tr>
- <td><a href="backbone-min.js">Production Version (0.3.2)</a></td>
- <td><i>3.7kb, Packed and Gzipped</i></td>
+ <td><a href="backbone-min.js">Production Version (0.3.3)</a></td>
+ <td><i>3.9kb, Packed and Gzipped</i></td>
</tr>
</table>
@@ -324,9 +325,9 @@ <h2 id="downloads">
<a href="http://documentcloud.github.com/underscore/">Underscore.js</a>.
For RESTful persistence, and DOM manipulation with
<a href="#View">Backbone.View</a>,
- it's highly recommended to include <a href="http://jquery.com">jQuery</a>,
- and <a href="http://www.json.org/json2.js">json2.js</a>
- (both of which you may already have on the page).
+ it's highly recommended to include
+ <a href="http://www.json.org/json2.js">json2.js</a>, and either
+ <a href="http://jquery.com">jQuery</a> or <a href="http://zeptojs.com/">Zepto</a>.
</p>
<h2 id="Introduction">Introduction</h2>
@@ -369,8 +370,9 @@ <h2 id="Introduction">Introduction</h2>
Both frameworks measure in the hundreds of kilobytes when packed and
gzipped, and megabytes of JavaScript, CSS, and images when loaded in the browser
&mdash; there's a lot of room underneath for libraries of a more moderate scope.
- Backbone is a <i>2 kilobyte</i> include that provides
- just the core concepts of models, events, collections, views, and persistence.
+ Backbone is a <i>4 kilobyte</i> include that provides
+ just the core concepts of models, events, collections, views, controllers,
+ and persistence.
</p>
<p>
@@ -548,6 +550,23 @@ <h2 id="Model">Backbone.Model</h2>
Get the current value of an attribute from the model. For example:
<tt>note.get("title")</tt>
</p>
+
+ <p id="Model-escape">
+ <b class="header">escape</b><code>model.escape(attribute)</code>
+ <br />
+ Similar to <a href="#Model-get">get</a>, but returns the HTML-escaped version
+ of a model's attribute. If you're interpolating data from the model into
+ HTML, using <b>escape</b> to retrieve attributes will prevent
+ <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">XSS</a> attacks.
+ </p>
+
+<pre class="runnable">
+var hacker = new Backbone.Model({
+ name: "&lt;script&gt;alert('xss')&lt;/script&gt;"
+});
+
+alert(hacker.escape('name'));
+</pre>
<p id="Model-set">
<b class="header">set</b><code>model.set(attributes, [options])</code>
@@ -578,7 +597,7 @@ <h2 id="Model">Backbone.Model</h2>
Remove an attribute by deleting it from the internal attributes hash.
Fires a <tt>"change"</tt> event unless <tt>silent</tt> is passed as an option.
</p>
-
+
<p id="Model-clear">
<b class="header">clear</b><code>model.clear([options])</code>
<br />
@@ -614,15 +633,15 @@ <h2 id="Model">Backbone.Model</h2>
them directly. If you'd like to retrieve and munge a copy of the model's
attributes, use <a href="#Model-toJSON">toJSON</a> instead.
</p>
-
+
<p id="Model-defaults">
<b class="header">defaults</b><code>model.defaults</code>
<br />
The <b>defaults</b> hash can be used to specify the default attributes
- for your model. When creating an instance of the model, any unspecified
+ for your model. When creating an instance of the model, any unspecified
attributes will be set to their default value.
</p>
-
+
<pre class="runnable">
var Meal = Backbone.Model.extend({
defaults: {
@@ -807,13 +826,13 @@ <h2 id="Model">Backbone.Model</h2>
Override this if you need to work with a preexisting API, or better namespace
your responses.
</p>
-
+
<p>
If you're working with a Rails backend, you'll notice that Rails' default
<tt>to_json</tt> implementation includes a model's attributes under a
namespace. To disable this behavior for seamless Backbone integration, set:
</p>
-
+
<pre>
ActiveRecord::Base.include_root_in_json = false
</pre>
@@ -1288,24 +1307,24 @@ <h2 id="Controller">Backbone.Controller</h2>
<b>Backbone.Controller</b> provides methods for routing client-side URL
fragments, and connecting them to actions and events.
</p>
-
+
<p class="warning">
- Backbone controllers do not yet make use of HTML5 <b>pushState</b> and
- <b>replaceState</b>. Currently, <b>pushState</b> and <b>replaceState</b>
- need special handling on the server-side, cause you to mint duplicate URLs,
- and have an incomplete API. We may start supporting them in the future
+ Backbone controllers do not yet make use of HTML5 <b>pushState</b> and
+ <b>replaceState</b>. Currently, <b>pushState</b> and <b>replaceState</b>
+ need special handling on the server-side, cause you to mint duplicate URLs,
+ and have an incomplete API. We may start supporting them in the future
when these issues have been resolved.
</p>
-
+
<p>
- During page load, after your application has finished creating all of its controllers,
+ During page load, after your application has finished creating all of its controllers,
be sure to call <tt>Backbone.history.start()</tt> to route the initial URL.
</p>
-
+
<p id="Controller-extend">
<b class="header">extend</b><code>Backbone.Controller.extend(properties, [classProperties])</code>
<br />
- Get started by creating a custom controller class. You'll
+ Get started by creating a custom controller class. You'll
want to define actions that are triggered when certain URL fragments are
matched, and provide a <a href="#Controller-routes">routes</a> hash
that pairs routes to actions.
@@ -1319,11 +1338,11 @@ <h2 id="Controller">Backbone.Controller</h2>
"search/:query": "search", // #search/kiwis
"search/:query/p:page": "search" // #search/kiwis/p7
},
-
+
help: function() {
...
},
-
+
search: function(query, page) {
...
}
@@ -1340,23 +1359,23 @@ <h2 id="Controller">Backbone.Controller</h2>
component between slashes; and splat parts <tt>*splat</tt>, which can match
any number of URL components.
</p>
-
+
<p>
- For example, a route of <tt>"search/:query/p:page"</tt> will match
- a fragment of <tt>#search/obama/p2</tt>, passing <tt>"obama"</tt>
- and <tt>"2"</tt> to the action. A route of <tt>"file/*path"</tt> will
- match <tt>#file/nested/folder/file.txt</tt>,
+ For example, a route of <tt>"search/:query/p:page"</tt> will match
+ a fragment of <tt>#search/obama/p2</tt>, passing <tt>"obama"</tt>
+ and <tt>"2"</tt> to the action. A route of <tt>"file/*path"</tt> will
+ match <tt>#file/nested/folder/file.txt</tt>,
passing <tt>"nested/folder/file.txt"</tt> to the action.
</p>
-
+
<p>
When the visitor presses the back button, or enters a URL, and a particular
- route is matched, the name of the action will be fired as an
+ route is matched, the name of the action will be fired as an
<a href="#Events">event</a>, so that other objects can listen to the controller,
and be notified. In the following example, visiting <tt>#help/uploading</tt>
will fire a <tt>route:help</tt> event from the controller.
</p>
-
+
<pre>
routes: {
"help/:page": "help",
@@ -1375,31 +1394,31 @@ <h2 id="Controller">Backbone.Controller</h2>
<p id="Controller-constructor">
<b class="header">constructor / initialize</b><code>new Controller([options])</code>
<br />
- When creating a new controller, you may pass its
- <a href="#Controller-routes">routes</a> hash directly as an option, if you
- choose. All <tt>options</tt> will also be passed to your <tt>initialize</tt>
+ When creating a new controller, you may pass its
+ <a href="#Controller-routes">routes</a> hash directly as an option, if you
+ choose. All <tt>options</tt> will also be passed to your <tt>initialize</tt>
function, if defined.
</p>
-
+
<p id="Controller-route">
<b class="header">route</b><code>controller.route(route, name, callback)</code>
<br />
Manually create a route for the controller, The <tt>route</tt> argument may
be a <a href="#Controller-routes">routing string</a> or regular expression.
- Each matching capture from the route or regular expression will be passed as
+ Each matching capture from the route or regular expression will be passed as
an argument to the callback. The <tt>name</tt> argument will be triggered as
a <tt>"route:name"</tt> event whenever the route is matched.
</p>
-
+
<pre>
initialize: function(options) {
-
+
// Matches #page/10, passing "10"
this.route("page/:number", "page", function(number){ ... });
-
+
// Matches /117-a/b/c/open, passing "117-a/b/c"
this.route(/^(.*?)\/open$/, "open", function(id){ ... });
-
+
}
</pre>
@@ -1411,32 +1430,32 @@ <h2 id="Controller">Backbone.Controller</h2>
without triggering a <tt>hashchange</tt> event. (If you would prefer to
trigger the event and routing, you can just set the hash directly.)
</p>
-
+
<pre>
openPage: function(pageNumber) {
- this.document.pages.at(pageNumber).open();
+ this.document.pages.at(pageNumber).open();
this.saveLocation("page/" + pageNumber);
}
</pre>
-
+
<h2 id="History">Backbone.history</h2>
<p>
<b>History</b> serves as a global router (per frame) to handle <tt>hashchange</tt>
- events, match the appropriate route, and trigger callbacks. You shouldn't
+ events, match the appropriate route, and trigger callbacks. You shouldn't
ever have to create one of these yourself &mdash; you should use the reference
to <tt>Backbone.history</tt> that will be created for you automatically if you make use
of <a href="#Controller">Controllers</a> with <a href="#Controller-routes">routes</a>.
</p>
-
+
<p id="History-start">
<b class="header">start</b><code>Backbone.history.start()</code>
<br />
- When all of your <a href="#Controller">Controllers</a> have been created,
+ When all of your <a href="#Controller">Controllers</a> have been created,
and all of the routes are set up properly, call <tt>Backbone.history.start()</tt>
to begin monitoring <tt>hashchange</tt> events, and dispatching routes.
</p>
-
+
<pre>
$(function(){
new WorkspaceController();
@@ -1450,7 +1469,7 @@ <h2 id="Sync">Backbone.sync</h2>
<p>
<b>Backbone.sync</b> is the function the Backbone calls every time it
attempts to read or save a model to the server. By default, it uses
- <tt>jQuery.ajax</tt> to make a RESTful JSON request. You can override
+ <tt>(jQuery/Zepto).ajax</tt> to make a RESTful JSON request. You can override
it in order to use a different persistence strategy, such as WebSockets,
XML transport, or Local Storage.
</p>
@@ -1467,10 +1486,10 @@ <h2 id="Sync">Backbone.sync</h2>
</ul>
<p>
- With the default implementation, when <b>Backbone.sync</b> sends up a request to save
+ With the default implementation, when <b>Backbone.sync</b> sends up a request to save
a model, its attributes will be passed, serialized as JSON, and sent in the HTTP body
- with content-type <tt>application/json</tt>. When returning a JSON response,
- send down the attributes of the model that have been changed by the server, and need
+ with content-type <tt>application/json</tt>. When returning a JSON response,
+ send down the attributes of the model that have been changed by the server, and need
to be updated on the client. When responding to a <tt>"read"</tt> request from a collection
(<a href="#Collection#fetch">Collection#fetch</a>), send down an array
of model attribute objects.
@@ -1528,8 +1547,8 @@ <h2 id="Sync">Backbone.sync</h2>
<br />
If you're working with a legacy web server that can't handle requests
encoded as <tt>application/json</tt>, setting <tt>Backbone.emulateJSON = true;</tt>
- will cause the JSON to be serialized under a <tt>model</tt> parameter, and
- the request to be made with a <tt>application/x-www-form-urlencoded</tt>
+ will cause the JSON to be serialized under a <tt>model</tt> parameter, and
+ the request to be made with a <tt>application/x-www-form-urlencoded</tt>
mime type, as if from an HTML form.
</p>
@@ -1620,11 +1639,11 @@ <h2 id="View">Backbone.View</h2>
and <tt>id</tt> properties, if specified. If not, <b>el</b> is an empty <tt>div</tt>.
</p>
- <p id="View-jQuery">
- <b class="header">$ (jQuery)</b><code>view.$(selector)</code>
+ <p id="View-dollar">
+ <b class="header">$ (jQuery or Zepto)</b><code>view.$(selector)</code>
<br />
- If jQuery is included on the page, each view has a <b>$</b> or <b>jQuery</b>
- function that runs queries scoped within the view's element. If you use this
+ If jQuery or Zepto is included on the page, each view has a
+ <b>$</b> function that runs queries scoped within the view's element. If you use this
scoped jQuery function, you don't have to use model ids as part of your query
to pull out specific elements in a list, and can rely much more on HTML class
attributes. It's equivalent to running: <tt>$(selector, this.el)</tt>
@@ -1682,7 +1701,7 @@ <h2 id="View">Backbone.View</h2>
to package up JavaScript templates stored in <tt>/app/views</tt> as part
of our main <tt>core.js</tt> asset package.
</p>
-
+
<p id="View-remove">
<b class="header">remove</b><code>view.remove()</code>
<br />
@@ -1788,26 +1807,26 @@ <h2 id="examples">Examples</h2>
<img src="docs/images/todos.png" alt="Todos" style="margin: 10px auto;" />
</a>
</div>
-
+
<p>
- The <a href="http://www.documentcloud.org/">DocumentCloud</a> workspace
- is built on Backbone.js, with <i>Documents</i>, <i>Projects</i>,
+ The <a href="http://www.documentcloud.org/">DocumentCloud</a> workspace
+ is built on Backbone.js, with <i>Documents</i>, <i>Projects</i>,
<i>Notes</i>, and <i>Accounts</i> all as Backbone models and collections.
</p>
-
+
<div style="text-align: center;">
<img src="docs/images/dc-workspace.png" alt="DocumentCloud Workspace" style="margin: 10px auto;" />
</div>
-
+
<p>
- <a href="http://bennolan.com/">Ben Nolan</a> created
+ <a href="http://bennolan.com/">Ben Nolan</a> created
<a href="http://bennolan.com/2010/11/24/backbone-jquery-demo.html">an example "Backbone Mobile" application</a>, combining Backbone.js
with <a href="http://jquerymobile.com/">jQuery Mobile</a>. You can
- <a href="http://bennolan.com/science/backbone-mobile/">try the app</a>
- in your browser, or view the
+ <a href="http://bennolan.com/science/backbone-mobile/">try the app</a>
+ in your browser, or view the
<a href="https://github.com/bnolan/backbone-mobile">source code</a> on Github.
</p>
-
+
<div style="text-align: center;">
<a href="http://bennolan.com/science/backbone-mobile/">
<img src="docs/images/backbone-mobile.png" alt="Backbone Mobile" style="margin: 10px auto;" />
@@ -1815,29 +1834,40 @@ <h2 id="examples">Examples</h2>
</div>
<h2 id="changelog">Change Log</h2>
-
+
+ <p>
+ <b class="header">0.3.3</b> &mdash; <small><i>Dec 1, 2010</i></small><br />
+ Backbone.js now supports <a href="http://zeptojs.com">Zepto</a>, alongside
+ jQuery, as a framework for DOM manipulation and Ajax support.
+ Implemented <a href="#Model-escape">Model#escape</a>, to efficiently handle
+ attributes intended for HTML interpolation. When trying to persist a model,
+ failed requests will now trigger an <tt>"error"</tt> event. The
+ ubiquitous <tt>options</tt> argument is now passed as the final argument
+ to all <tt>"change"</tt> events.
+ </p>
+
<p>
<b class="header">0.3.2</b> &mdash; <small><i>Nov 23, 2010</i></small><br />
Bugfix for IE7 + iframe-based "hashchange" events. <tt>sync</tt> may now be
overridden on a per-model, or per-collection basis. Fixed recursion error
- when calling <tt>save</tt> with no changed attributes, within a
+ when calling <tt>save</tt> with no changed attributes, within a
<tt>"change"</tt> event.
</p>
-
+
<p>
<b class="header">0.3.1</b> &mdash; <small><i>Nov 15, 2010</i></small><br />
All <tt>"add"</tt> and <tt>"remove"</tt> events are now sent through the
model, so that views can listen for them without having to know about the
collection. Added a <tt>remove</tt> method to <a href="#View">Backbone.View</a>.
<tt>toJSON</tt> is no longer called at all for <tt>'read'</tt> and <tt>'delete'</tt> requests.
- Backbone routes are now able to load empty URL fragments.
+ Backbone routes are now able to load empty URL fragments.
</p>
-
+
<p>
<b class="header">0.3.0</b> &mdash; <small><i>Nov 9, 2010</i></small><br />
- Backbone now has <a href="#Controller">Controllers</a> and
- <a href="#History">History</a>, for doing client-side routing based on
- URL fragments.
+ Backbone now has <a href="#Controller">Controllers</a> and
+ <a href="#History">History</a>, for doing client-side routing based on
+ URL fragments.
Added <tt>emulateHTTP</tt> to provide support for legacy servers that don't
do <tt>PUT</tt> and <tt>DELETE</tt>.
Added <tt>emulateJSON</tt> for servers that can't accept <tt>application/json</tt>
@@ -1893,7 +1923,7 @@ <h2 id="changelog">Change Log</h2>
</div>
- <script src="test/vendor/underscore-1.1.0.js"></script>
+ <script src="test/vendor/underscore-1.1.3.js"></script>
<script src="test/vendor/jquery-1.4.2.js"></script>
<script src="test/vendor/json2.js"></script>
<script src="backbone.js"></script>
View
2  package.json
@@ -10,5 +10,5 @@
},
"lib" : ".",
"main" : "backbone.js",
- "version" : "0.3.2"
+ "version" : "0.3.3"
}
Please sign in to comment.
Something went wrong with that request. Please try again.