backbonejs-rails 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,33 +1,37 @@
1
- // Backbone.js 0.5.3
2
- // (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
1
+ // Backbone.js 0.9.1
2
+
3
+ // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
3
4
  // Backbone may be freely distributed under the MIT license.
4
5
  // For all details and documentation:
5
- // http://documentcloud.github.com/backbone
6
- (function(){var h=this,p=h.Backbone,e;e=typeof exports!=="undefined"?exports:h.Backbone={};e.VERSION="0.5.3";var f=h._;if(!f&&typeof require!=="undefined")f=require("underscore")._;var g=h.jQuery||h.Zepto;e.noConflict=function(){h.Backbone=p;return this};e.emulateHTTP=!1;e.emulateJSON=!1;e.Events={bind:function(a,b,c){var d=this._callbacks||(this._callbacks={});(d[a]||(d[a]=[])).push([b,c]);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=
7
- 0,e=c.length;d<e;d++)if(c[d]&&b===c[d][0]){c[d]=null;break}}else c[a]=[]}else this._callbacks={};return this},trigger:function(a){var b,c,d,e,f=2;if(!(c=this._callbacks))return this;for(;f--;)if(b=f?a:"all",b=c[b])for(var g=0,h=b.length;g<h;g++)(d=b[g])?(e=f?Array.prototype.slice.call(arguments,1):arguments,d[0].apply(d[1]||this,e)):(b.splice(g,1),g--,h--);return this}};e.Model=function(a,b){var c;a||(a={});if(c=this.defaults)f.isFunction(c)&&(c=c.call(this)),a=f.extend({},c,a);this.attributes={};
8
- this._escapedAttributes={};this.cid=f.uniqueId("c");this.set(a,{silent:!0});this._changed=!1;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:!1,idAttribute:"id",initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},escape:function(a){var b;if(b=this._escapedAttributes[a])return b;b=this.attributes[a];
9
- return this._escapedAttributes[a]=(b==null?"":""+b).replace(/&(?!\w+;|#\d+;|#x[\da-f]+;)/gi,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")},has:function(a){return this.attributes[a]!=null},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!1;if(this.idAttribute in a)this.id=a[this.idAttribute];
10
- var e=this._changing;this._changing=!0;for(var g in a){var h=a[g];if(!f.isEqual(c[g],h))c[g]=h,delete d[g],this._changed=!0,b.silent||this.trigger("change:"+g,this,h,b)}!e&&!b.silent&&this._changed&&this.change(b);this._changing=!1;return this},unset:function(a,b){if(!(a in this.attributes))return this;b||(b={});var c={};c[a]=void 0;if(!b.silent&&this.validate&&!this._performValidation(c,b))return!1;delete this.attributes[a];delete this._escapedAttributes[a];a==this.idAttribute&&delete this.id;this._changed=
11
- !0;b.silent||(this.trigger("change:"+a,this,void 0,b),this.change(b));return this},clear:function(a){a||(a={});var b,c=this.attributes,d={};for(b in c)d[b]=void 0;if(!a.silent&&this.validate&&!this._performValidation(d,a))return!1;this.attributes={};this._escapedAttributes={};this._changed=!0;if(!a.silent){for(b in c)this.trigger("change:"+b,this,void 0,a);this.change(a)}return this},fetch:function(a){a||(a={});var b=this,c=a.success;a.success=function(d,e,f){if(!b.set(b.parse(d,f),a))return!1;c&&
12
- c(b,d)};a.error=i(a.error,b,a);return(this.sync||e.sync).call(this,"read",this,a)},save:function(a,b){b||(b={});if(a&&!this.set(a,b))return!1;var c=this,d=b.success;b.success=function(a,e,f){if(!c.set(c.parse(a,f),b))return!1;d&&d(c,a,f)};b.error=i(b.error,c,b);var f=this.isNew()?"create":"update";return(this.sync||e.sync).call(this,f,this,b)},destroy:function(a){a||(a={});if(this.isNew())return this.trigger("destroy",this,this.collection,a);var b=this,c=a.success;a.success=function(d){b.trigger("destroy",
13
- b,b.collection,a);c&&c(b,d)};a.error=i(a.error,b,a);return(this.sync||e.sync).call(this,"delete",this,a)},url:function(){var a=k(this.collection)||this.urlRoot||l();if(this.isNew())return a;return a+(a.charAt(a.length-1)=="/"?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this)},isNew:function(){return this.id==null},change:function(a){this.trigger("change",this,a);this._previousAttributes=f.clone(this.attributes);this._changed=!1},hasChanged:function(a){if(a)return this._previousAttributes[a]!=
14
- this.attributes[a];return this._changed},changedAttributes:function(a){a||(a=this.attributes);var b=this._previousAttributes,c=!1,d;for(d in a)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)return b.error?b.error(this,c,b):this.trigger("error",this,c,b),!1;return!0}});
15
- e.Collection=function(a,b){b||(b={});if(b.comparator)this.comparator=b.comparator;f.bindAll(this,"_onModelEvent","_removeReference");this._reset();a&&this.reset(a,{silent:!0});this.initialize.apply(this,arguments)};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=
16
- 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("reset",this,a);return this},pluck:function(a){return f.map(this.models,function(b){return b.get(a)})},
17
- reset:function(a,b){a||(a=[]);b||(b={});this.each(this._removeReference);this._reset();this.add(a,{silent:!0});b.silent||this.trigger("reset",this,b);return this},fetch:function(a){a||(a={});var b=this,c=a.success;a.success=function(d,f,e){b[a.add?"add":"reset"](b.parse(d,e),a);c&&c(b,d)};a.error=i(a.error,b,a);return(this.sync||e.sync).call(this,"read",this,a)},create:function(a,b){var c=this;b||(b={});a=this._prepareModel(a,b);if(!a)return!1;var d=b.success;b.success=function(a,e,f){c.add(a,b);
18
- d&&d(a,e,f)};a.save(null,b);return a},parse:function(a){return a},chain:function(){return f(this.models).chain()},_reset:function(){this.length=0;this.models=[];this._byId={};this._byCid={}},_prepareModel:function(a,b){if(a instanceof e.Model){if(!a.collection)a.collection=this}else{var c=a;a=new this.model(c,{collection:this});a.validate&&!a._performValidation(c,b)&&(a=!1)}return a},_add:function(a,b){b||(b={});a=this._prepareModel(a,b);if(!a)return!1;var c=this.getByCid(a);if(c)throw Error(["Can't add the same model to a set twice",
19
- c.id]);this._byId[a.id]=a;this._byCid[a.cid]=a;this.models.splice(b.at!=null?b.at:this.comparator?this.sortedIndex(a,this.comparator):this.length,0,a);a.bind("all",this._onModelEvent);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];this.models.splice(this.indexOf(a),1);this.length--;b.silent||a.trigger("remove",a,this,b);this._removeReference(a);return a},
20
- _removeReference:function(a){this==a.collection&&delete a.collection;a.unbind("all",this._onModelEvent)},_onModelEvent:function(a,b,c,d){(a=="add"||a=="remove")&&c!=this||(a=="destroy"&&this._remove(b,d),b&&a==="change:"+b.idAttribute&&(delete this._byId[b.previous(b.idAttribute)],this._byId[b.id]=b),this.trigger.apply(this,arguments))}});f.each(["forEach","each","map","reduce","reduceRight","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","max",
21
- "min","sortBy","sortedIndex","toArray","size","first","rest","last","without","indexOf","lastIndexOf","isEmpty","groupBy"],function(a){e.Collection.prototype[a]=function(){return f[a].apply(f,[this.models].concat(f.toArray(arguments)))}});e.Router=function(a){a||(a={});if(a.routes)this.routes=a.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var q=/:([\w\d]+)/g,r=/\*([\w\d]+)/g,s=/[-[\]{}()+?.,\\^$|#\s]/g;f.extend(e.Router.prototype,e.Events,{initialize:function(){},route:function(a,
22
- 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))},navigate:function(a,b){e.history.navigate(a,b)},_bindRoutes:function(){if(this.routes){var a=[],b;for(b in this.routes)a.unshift([b,this.routes[b]]);b=0;for(var c=a.length;b<c;b++)this.route(a[b][0],a[b][1],this[a[b][1]])}},_routeToRegExp:function(a){a=a.replace(s,"\\$&").replace(q,
23
- "([^/]*)").replace(r,"(.*?)");return RegExp("^"+a+"$")},_extractParameters:function(a,b){return a.exec(b).slice(1)}});e.History=function(){this.handlers=[];f.bindAll(this,"checkUrl")};var j=/^#*/,t=/msie [\w.]+/,m=!1;f.extend(e.History.prototype,{interval:50,getFragment:function(a,b){if(a==null)if(this._hasPushState||b){a=window.location.pathname;var c=window.location.search;c&&(a+=c);a.indexOf(this.options.root)==0&&(a=a.substr(this.options.root.length))}else a=window.location.hash;return decodeURIComponent(a.replace(j,
24
- ""))},start:function(a){if(m)throw Error("Backbone.history has already been started");this.options=f.extend({},{root:"/"},this.options,a);this._wantsPushState=!!this.options.pushState;this._hasPushState=!(!this.options.pushState||!window.history||!window.history.pushState);a=this.getFragment();var b=document.documentMode;if(b=t.exec(navigator.userAgent.toLowerCase())&&(!b||b<=7))this.iframe=g('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow,this.navigate(a);
25
- this._hasPushState?g(window).bind("popstate",this.checkUrl):"onhashchange"in window&&!b?g(window).bind("hashchange",this.checkUrl):setInterval(this.checkUrl,this.interval);this.fragment=a;m=!0;a=window.location;b=a.pathname==this.options.root;if(this._wantsPushState&&!this._hasPushState&&!b)return this.fragment=this.getFragment(null,!0),window.location.replace(this.options.root+"#"+this.fragment),!0;else if(this._wantsPushState&&this._hasPushState&&b&&a.hash)this.fragment=a.hash.replace(j,""),window.history.replaceState({},
26
- document.title,a.protocol+"//"+a.host+this.options.root+this.fragment);if(!this.options.silent)return this.loadUrl()},route:function(a,b){this.handlers.unshift({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();a==this.fragment&&this.iframe&&(a=this.getFragment(this.iframe.location.hash));if(a==this.fragment||a==decodeURIComponent(this.fragment))return!1;this.iframe&&this.navigate(a);this.loadUrl()||this.loadUrl(window.location.hash)},loadUrl:function(a){var b=this.fragment=this.getFragment(a);
27
- return f.any(this.handlers,function(a){if(a.route.test(b))return a.callback(b),!0})},navigate:function(a,b){var c=(a||"").replace(j,"");if(!(this.fragment==c||this.fragment==decodeURIComponent(c))){if(this._hasPushState){var d=window.location;c.indexOf(this.options.root)!=0&&(c=this.options.root+c);this.fragment=c;window.history.pushState({},document.title,d.protocol+"//"+d.host+c)}else if(window.location.hash=this.fragment=c,this.iframe&&c!=this.getFragment(this.iframe.location.hash))this.iframe.document.open().close(),
28
- this.iframe.location.hash=c;b&&this.loadUrl(a)}}});e.View=function(a){this.cid=f.uniqueId("view");this._configure(a||{});this._ensureElement();this.delegateEvents();this.initialize.apply(this,arguments)};var u=/^(\S+)\s*(.*)$/,n=["model","collection","el","id","attributes","className","tagName"];f.extend(e.View.prototype,e.Events,{tagName:"div",$:function(a){return g(a,this.el)},initialize:function(){},render:function(){return this},remove:function(){g(this.el).remove();return this},make:function(a,
29
- b,c){a=document.createElement(a);b&&g(a).attr(b);c&&g(a).html(c);return a},delegateEvents:function(a){if(a||(a=this.events))for(var b in f.isFunction(a)&&(a=a.call(this)),g(this.el).unbind(".delegateEvents"+this.cid),a){var c=this[a[b]];if(!c)throw Error('Event "'+a[b]+'" does not exist');var d=b.match(u),e=d[1];d=d[2];c=f.bind(c,this);e+=".delegateEvents"+this.cid;d===""?g(this.el).bind(e,c):g(this.el).delegate(d,e,c)}},_configure:function(a){this.options&&(a=f.extend({},this.options,a));for(var b=
30
- 0,c=n.length;b<c;b++){var d=n[b];a[d]&&(this[d]=a[d])}this.options=a},_ensureElement:function(){if(this.el){if(f.isString(this.el))this.el=g(this.el).get(0)}else{var a=this.attributes||{};if(this.id)a.id=this.id;if(this.className)a["class"]=this.className;this.el=this.make(this.tagName,a)}}});e.Model.extend=e.Collection.extend=e.Router.extend=e.View.extend=function(a,b){var c=v(this,a,b);c.extend=this.extend;return c};var w={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};e.sync=function(a,
31
- b,c){var d=w[a];c=f.extend({type:d,dataType:"json"},c);if(!c.url)c.url=k(b)||l();if(!c.data&&b&&(a=="create"||a=="update"))c.contentType="application/json",c.data=JSON.stringify(b.toJSON());if(e.emulateJSON)c.contentType="application/x-www-form-urlencoded",c.data=c.data?{model:c.data}:{};if(e.emulateHTTP&&(d==="PUT"||d==="DELETE")){if(e.emulateJSON)c.data._method=d;c.type="POST";c.beforeSend=function(a){a.setRequestHeader("X-HTTP-Method-Override",d)}}if(c.type!=="GET"&&!e.emulateJSON)c.processData=
32
- !1;return g.ajax(c)};var o=function(){},v=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){return a.apply(this,arguments)};f.extend(d,a);o.prototype=a.prototype;d.prototype=new o;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)return null;return f.isFunction(a.url)?a.url():a.url},l=function(){throw Error('A "url" property or function must be specified');},i=function(a,b,c){return function(d){a?
33
- a(b,d,c):b.trigger("error",b,d,c)}}}).call(this);
6
+ // http://backbonejs.org
7
+ (function(){var i=this,r=i.Backbone,s=Array.prototype.slice,t=Array.prototype.splice,g;g="undefined"!==typeof exports?exports:i.Backbone={};g.VERSION="0.9.1";var f=i._;!f&&"undefined"!==typeof require&&(f=require("underscore"));var h=i.jQuery||i.Zepto||i.ender;g.setDomLibrary=function(a){h=a};g.noConflict=function(){i.Backbone=r;return this};g.emulateHTTP=!1;g.emulateJSON=!1;g.Events={on:function(a,b,c){for(var d,a=a.split(/\s+/),e=this._callbacks||(this._callbacks={});d=a.shift();){d=e[d]||(e[d]=
8
+ {});var f=d.tail||(d.tail=d.next={});f.callback=b;f.context=c;d.tail=f.next={}}return this},off:function(a,b,c){var d,e,f;if(a){if(e=this._callbacks)for(a=a.split(/\s+/);d=a.shift();)if(f=e[d],delete e[d],b&&f)for(;(f=f.next)&&f.next;)if(!(f.callback===b&&(!c||f.context===c)))this.on(d,f.callback,f.context)}else delete this._callbacks;return this},trigger:function(a){var b,c,d,e;if(!(d=this._callbacks))return this;e=d.all;for((a=a.split(/\s+/)).push(null);b=a.shift();)e&&a.push({next:e.next,tail:e.tail,
9
+ event:b}),(c=d[b])&&a.push({next:c.next,tail:c.tail});for(e=s.call(arguments,1);c=a.pop();){b=c.tail;for(d=c.event?[c.event].concat(e):e;(c=c.next)!==b;)c.callback.apply(c.context||this,d)}return this}};g.Events.bind=g.Events.on;g.Events.unbind=g.Events.off;g.Model=function(a,b){var c;a||(a={});b&&b.parse&&(a=this.parse(a));if(c=j(this,"defaults"))a=f.extend({},c,a);b&&b.collection&&(this.collection=b.collection);this.attributes={};this._escapedAttributes={};this.cid=f.uniqueId("c");if(!this.set(a,
10
+ {silent:!0}))throw Error("Can't create an invalid model");delete this._changed;this._previousAttributes=f.clone(this.attributes);this.initialize.apply(this,arguments)};f.extend(g.Model.prototype,g.Events,{idAttribute:"id",initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},escape:function(a){var b;if(b=this._escapedAttributes[a])return b;b=this.attributes[a];return this._escapedAttributes[a]=f.escape(null==b?"":""+b)},has:function(a){return null!=
11
+ this.attributes[a]},set:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c||(c={});if(!d)return this;d instanceof g.Model&&(d=d.attributes);if(c.unset)for(e in d)d[e]=void 0;if(!this._validate(d,c))return!1;this.idAttribute in d&&(this.id=d[this.idAttribute]);var b=this.attributes,k=this._escapedAttributes,n=this._previousAttributes||{},h=this._setting;this._changed||(this._changed={});this._setting=!0;for(e in d)if(a=d[e],f.isEqual(b[e],a)||delete k[e],c.unset?delete b[e]:b[e]=
12
+ a,this._changing&&!f.isEqual(this._changed[e],a)&&(this.trigger("change:"+e,this,a,c),this._moreChanges=!0),delete this._changed[e],!f.isEqual(n[e],a)||f.has(b,e)!=f.has(n,e))this._changed[e]=a;h||(!c.silent&&this.hasChanged()&&this.change(c),this._setting=!1);return this},unset:function(a,b){(b||(b={})).unset=!0;return this.set(a,null,b)},clear:function(a){(a||(a={})).unset=!0;return this.set(f.clone(this.attributes),a)},fetch:function(a){var a=a?f.clone(a):{},b=this,c=a.success;a.success=function(d,
13
+ e,f){if(!b.set(b.parse(d,f),a))return!1;c&&c(b,d)};a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},save:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c=c?f.clone(c):{};c.wait&&(e=f.clone(this.attributes));a=f.extend({},c,{silent:!0});if(d&&!this.set(d,c.wait?a:c))return!1;var k=this,h=c.success;c.success=function(a,b,e){b=k.parse(a,e);c.wait&&(b=f.extend(d||{},b));if(!k.set(b,c))return!1;h?h(k,a):k.trigger("sync",k,a,c)};c.error=g.wrapError(c.error,
14
+ k,c);b=this.isNew()?"create":"update";b=(this.sync||g.sync).call(this,b,this,c);c.wait&&this.set(e,a);return b},destroy:function(a){var a=a?f.clone(a):{},b=this,c=a.success,d=function(){b.trigger("destroy",b,b.collection,a)};if(this.isNew())return d();a.success=function(e){a.wait&&d();c?c(b,e):b.trigger("sync",b,e,a)};a.error=g.wrapError(a.error,b,a);var e=(this.sync||g.sync).call(this,"delete",this,a);a.wait||d();return e},url:function(){var a=j(this.collection,"url")||j(this,"urlRoot")||o();return this.isNew()?
15
+ a:a+("/"==a.charAt(a.length-1)?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return null==this.id},change:function(a){if(this._changing||!this.hasChanged())return this;this._moreChanges=this._changing=!0;for(var b in this._changed)this.trigger("change:"+b,this,this._changed[b],a);for(;this._moreChanges;)this._moreChanges=!1,this.trigger("change",this,a);this._previousAttributes=f.clone(this.attributes);
16
+ delete this._changed;this._changing=!1;return this},hasChanged:function(a){return!arguments.length?!f.isEmpty(this._changed):this._changed&&f.has(this._changed,a)},changedAttributes:function(a){if(!a)return this.hasChanged()?f.clone(this._changed):!1;var b,c=!1,d=this._previousAttributes,e;for(e in a)if(!f.isEqual(d[e],b=a[e]))(c||(c={}))[e]=b;return c},previous:function(a){return!arguments.length||!this._previousAttributes?null:this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},
17
+ isValid:function(){return!this.validate(this.attributes)},_validate:function(a,b){if(b.silent||!this.validate)return!0;var a=f.extend({},this.attributes,a),c=this.validate(a,b);if(!c)return!0;b&&b.error?b.error(this,c,b):this.trigger("error",this,c,b);return!1}});g.Collection=function(a,b){b||(b={});b.comparator&&(this.comparator=b.comparator);this._reset();this.initialize.apply(this,arguments);a&&this.reset(a,{silent:!0,parse:b.parse})};f.extend(g.Collection.prototype,g.Events,{model:g.Model,initialize:function(){},
18
+ toJSON:function(){return this.map(function(a){return a.toJSON()})},add:function(a,b){var c,d,e,g,h,i={},j={};b||(b={});a=f.isArray(a)?a.slice():[a];for(c=0,d=a.length;c<d;c++){if(!(e=a[c]=this._prepareModel(a[c],b)))throw Error("Can't add an invalid model to a collection");if(i[g=e.cid]||this._byCid[g]||null!=(h=e.id)&&(j[h]||this._byId[h]))throw Error("Can't add the same model to a collection twice");i[g]=j[h]=e}for(c=0;c<d;c++)(e=a[c]).on("all",this._onModelEvent,this),this._byCid[e.cid]=e,null!=
19
+ e.id&&(this._byId[e.id]=e);this.length+=d;t.apply(this.models,[null!=b.at?b.at:this.models.length,0].concat(a));this.comparator&&this.sort({silent:!0});if(b.silent)return this;for(c=0,d=this.models.length;c<d;c++)if(i[(e=this.models[c]).cid])b.index=c,e.trigger("add",e,this,b);return this},remove:function(a,b){var c,d,e,g;b||(b={});a=f.isArray(a)?a.slice():[a];for(c=0,d=a.length;c<d;c++)if(g=this.getByCid(a[c])||this.get(a[c]))delete this._byId[g.id],delete this._byCid[g.cid],e=this.indexOf(g),this.models.splice(e,
20
+ 1),this.length--,b.silent||(b.index=e,g.trigger("remove",g,this,b)),this._removeReference(g);return this},get:function(a){return null==a?null:this._byId[null!=a.id?a.id:a]},getByCid:function(a){return a&&this._byCid[a.cid||a]},at:function(a){return this.models[a]},sort:function(a){a||(a={});if(!this.comparator)throw Error("Cannot sort a set without a comparator");var b=f.bind(this.comparator,this);1==this.comparator.length?this.models=this.sortBy(b):this.models.sort(b);a.silent||this.trigger("reset",
21
+ this,a);return this},pluck:function(a){return f.map(this.models,function(b){return b.get(a)})},reset:function(a,b){a||(a=[]);b||(b={});for(var c=0,d=this.models.length;c<d;c++)this._removeReference(this.models[c]);this._reset();this.add(a,{silent:!0,parse:b.parse});b.silent||this.trigger("reset",this,b);return this},fetch:function(a){a=a?f.clone(a):{};void 0===a.parse&&(a.parse=!0);var b=this,c=a.success;a.success=function(d,e,f){b[a.add?"add":"reset"](b.parse(d,f),a);c&&c(b,d)};a.error=g.wrapError(a.error,
22
+ b,a);return(this.sync||g.sync).call(this,"read",this,a)},create:function(a,b){var c=this,b=b?f.clone(b):{},a=this._prepareModel(a,b);if(!a)return!1;b.wait||c.add(a,b);var d=b.success;b.success=function(e,f){b.wait&&c.add(e,b);d?d(e,f):e.trigger("sync",a,f,b)};a.save(null,b);return a},parse:function(a){return a},chain:function(){return f(this.models).chain()},_reset:function(){this.length=0;this.models=[];this._byId={};this._byCid={}},_prepareModel:function(a,b){a instanceof g.Model?a.collection||
23
+ (a.collection=this):(b.collection=this,a=new this.model(a,b),a._validate(a.attributes,b)||(a=!1));return a},_removeReference:function(a){this==a.collection&&delete a.collection;a.off("all",this._onModelEvent,this)},_onModelEvent:function(a,b,c,d){("add"==a||"remove"==a)&&c!=this||("destroy"==a&&this.remove(b,d),b&&a==="change:"+b.idAttribute&&(delete this._byId[b.previous(b.idAttribute)],this._byId[b.id]=b),this.trigger.apply(this,arguments))}});f.each("forEach,each,map,reduce,reduceRight,find,detect,filter,select,reject,every,all,some,any,include,contains,invoke,max,min,sortBy,sortedIndex,toArray,size,first,initial,rest,last,without,indexOf,shuffle,lastIndexOf,isEmpty,groupBy".split(","),
24
+ function(a){g.Collection.prototype[a]=function(){return f[a].apply(f,[this.models].concat(f.toArray(arguments)))}});g.Router=function(a){a||(a={});a.routes&&(this.routes=a.routes);this._bindRoutes();this.initialize.apply(this,arguments)};var u=/:\w+/g,v=/\*\w+/g,w=/[-[\]{}()+?.,\\^$|#\s]/g;f.extend(g.Router.prototype,g.Events,{initialize:function(){},route:function(a,b,c){g.history||(g.history=new g.History);f.isRegExp(a)||(a=this._routeToRegExp(a));c||(c=this[b]);g.history.route(a,f.bind(function(d){d=
25
+ this._extractParameters(a,d);c&&c.apply(this,d);this.trigger.apply(this,["route:"+b].concat(d));g.history.trigger("route",this,b,d)},this));return this},navigate:function(a,b){g.history.navigate(a,b)},_bindRoutes:function(){if(this.routes){var a=[],b;for(b in this.routes)a.unshift([b,this.routes[b]]);b=0;for(var c=a.length;b<c;b++)this.route(a[b][0],a[b][1],this[a[b][1]])}},_routeToRegExp:function(a){a=a.replace(w,"\\$&").replace(u,"([^/]+)").replace(v,"(.*?)");return RegExp("^"+a+"$")},_extractParameters:function(a,
26
+ b){return a.exec(b).slice(1)}});g.History=function(){this.handlers=[];f.bindAll(this,"checkUrl")};var m=/^[#\/]/,x=/msie [\w.]+/,l=!1;f.extend(g.History.prototype,g.Events,{interval:50,getFragment:function(a,b){if(null==a)if(this._hasPushState||b){var a=window.location.pathname,c=window.location.search;c&&(a+=c)}else a=window.location.hash;a=decodeURIComponent(a);a.indexOf(this.options.root)||(a=a.substr(this.options.root.length));return a.replace(m,"")},start:function(a){if(l)throw Error("Backbone.history has already been started");
27
+ this.options=f.extend({},{root:"/"},this.options,a);this._wantsHashChange=!1!==this.options.hashChange;this._wantsPushState=!!this.options.pushState;this._hasPushState=!(!this.options.pushState||!window.history||!window.history.pushState);var a=this.getFragment(),b=document.documentMode;if(b=x.exec(navigator.userAgent.toLowerCase())&&(!b||7>=b))this.iframe=h('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow,this.navigate(a);this._hasPushState?h(window).bind("popstate",
28
+ this.checkUrl):this._wantsHashChange&&"onhashchange"in window&&!b?h(window).bind("hashchange",this.checkUrl):this._wantsHashChange&&(this._checkUrlInterval=setInterval(this.checkUrl,this.interval));this.fragment=a;l=!0;a=window.location;b=a.pathname==this.options.root;if(this._wantsHashChange&&this._wantsPushState&&!this._hasPushState&&!b)return this.fragment=this.getFragment(null,!0),window.location.replace(this.options.root+"#"+this.fragment),!0;this._wantsPushState&&this._hasPushState&&b&&a.hash&&
29
+ (this.fragment=a.hash.replace(m,""),window.history.replaceState({},document.title,a.protocol+"//"+a.host+this.options.root+this.fragment));if(!this.options.silent)return this.loadUrl()},stop:function(){h(window).unbind("popstate",this.checkUrl).unbind("hashchange",this.checkUrl);clearInterval(this._checkUrlInterval);l=!1},route:function(a,b){this.handlers.unshift({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();a==this.fragment&&this.iframe&&(a=this.getFragment(this.iframe.location.hash));
30
+ if(a==this.fragment||a==decodeURIComponent(this.fragment))return!1;this.iframe&&this.navigate(a);this.loadUrl()||this.loadUrl(window.location.hash)},loadUrl:function(a){var b=this.fragment=this.getFragment(a);return f.any(this.handlers,function(a){if(a.route.test(b))return a.callback(b),!0})},navigate:function(a,b){if(!l)return!1;if(!b||!0===b)b={trigger:b};var c=(a||"").replace(m,"");this.fragment==c||this.fragment==decodeURIComponent(c)||(this._hasPushState?(0!=c.indexOf(this.options.root)&&(c=
31
+ this.options.root+c),this.fragment=c,window.history[b.replace?"replaceState":"pushState"]({},document.title,c)):this._wantsHashChange?(this.fragment=c,this._updateHash(window.location,c,b.replace),this.iframe&&c!=this.getFragment(this.iframe.location.hash)&&(b.replace||this.iframe.document.open().close(),this._updateHash(this.iframe.location,c,b.replace))):window.location.assign(this.options.root+a),b.trigger&&this.loadUrl(a))},_updateHash:function(a,b,c){c?a.replace(a.toString().replace(/(javascript:|#).*$/,
32
+ "")+"#"+b):a.hash=b}});g.View=function(a){this.cid=f.uniqueId("view");this._configure(a||{});this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()};var y=/^(\S+)\s*(.*)$/,p="model,collection,el,id,attributes,className,tagName".split(",");f.extend(g.View.prototype,g.Events,{tagName:"div",$:function(a){return this.$el.find(a)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();return this},make:function(a,b,c){a=document.createElement(a);
33
+ b&&h(a).attr(b);c&&h(a).html(c);return a},setElement:function(a,b){this.$el=h(a);this.el=this.$el[0];!1!==b&&this.delegateEvents();return this},delegateEvents:function(a){if(a||(a=j(this,"events"))){this.undelegateEvents();for(var b in a){var c=a[b];f.isFunction(c)||(c=this[a[b]]);if(!c)throw Error('Event "'+a[b]+'" does not exist');var d=b.match(y),e=d[1],d=d[2],c=f.bind(c,this),e=e+(".delegateEvents"+this.cid);""===d?this.$el.bind(e,c):this.$el.delegate(d,e,c)}}},undelegateEvents:function(){this.$el.unbind(".delegateEvents"+
34
+ this.cid)},_configure:function(a){this.options&&(a=f.extend({},this.options,a));for(var b=0,c=p.length;b<c;b++){var d=p[b];a[d]&&(this[d]=a[d])}this.options=a},_ensureElement:function(){if(this.el)this.setElement(this.el,!1);else{var a=j(this,"attributes")||{};this.id&&(a.id=this.id);this.className&&(a["class"]=this.className);this.setElement(this.make(this.tagName,a),!1)}}});g.Model.extend=g.Collection.extend=g.Router.extend=g.View.extend=function(a,b){var c=z(this,a,b);c.extend=this.extend;return c};
35
+ var A={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};g.sync=function(a,b,c){var d=A[a],e={type:d,dataType:"json"};c.url||(e.url=j(b,"url")||o());if(!c.data&&b&&("create"==a||"update"==a))e.contentType="application/json",e.data=JSON.stringify(b.toJSON());g.emulateJSON&&(e.contentType="application/x-www-form-urlencoded",e.data=e.data?{model:e.data}:{});if(g.emulateHTTP&&("PUT"===d||"DELETE"===d))g.emulateJSON&&(e.data._method=d),e.type="POST",e.beforeSend=function(a){a.setRequestHeader("X-HTTP-Method-Override",
36
+ d)};"GET"!==e.type&&!g.emulateJSON&&(e.processData=!1);return h.ajax(f.extend(e,c))};g.wrapError=function(a,b,c){return function(d,e){e=d===b?e:d;a?a(b,e,c):b.trigger("error",b,e,c)}};var q=function(){},z=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){a.apply(this,arguments)};f.extend(d,a);q.prototype=a.prototype;d.prototype=new q;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},j=function(a,b){return!a||!a[b]?
37
+ null:f.isFunction(a[b])?a[b]():a[b]},o=function(){throw Error('A "url" property or function must be specified');}}).call(this);
@@ -1,18 +1,61 @@
1
1
  /*!
2
- ICanHaz.js version 0.9 -- by @HenrikJoreteg
2
+ ICanHaz.js version 0.10 -- by @HenrikJoreteg
3
3
  More info at: http://icanhazjs.com
4
4
  */
5
- (function ($) {
6
- /*!
7
- mustache.js -- Logic-less templates in JavaScript
8
-
9
- by @janl (MIT Licensed, https://github.com/janl/mustache.js/blob/master/LICENSE).
5
+ (function () {
6
+ /*
7
+ mustache.js Logic-less templates in JavaScript
10
8
 
11
9
  See http://mustache.github.com/ for more info.
12
10
  */
13
11
 
14
- var Mustache = function() {
15
- var Renderer = function() {};
12
+ var Mustache = function () {
13
+ var _toString = Object.prototype.toString;
14
+
15
+ Array.isArray = Array.isArray || function (obj) {
16
+ return _toString.call(obj) == "[object Array]";
17
+ }
18
+
19
+ var _trim = String.prototype.trim, trim;
20
+
21
+ if (_trim) {
22
+ trim = function (text) {
23
+ return text == null ? "" : _trim.call(text);
24
+ }
25
+ } else {
26
+ var trimLeft, trimRight;
27
+
28
+ // IE doesn't match non-breaking spaces with \s.
29
+ if ((/\S/).test("\xA0")) {
30
+ trimLeft = /^[\s\xA0]+/;
31
+ trimRight = /[\s\xA0]+$/;
32
+ } else {
33
+ trimLeft = /^\s+/;
34
+ trimRight = /\s+$/;
35
+ }
36
+
37
+ trim = function (text) {
38
+ return text == null ? "" :
39
+ text.toString().replace(trimLeft, "").replace(trimRight, "");
40
+ }
41
+ }
42
+
43
+ var escapeMap = {
44
+ "&": "&amp;",
45
+ "<": "&lt;",
46
+ ">": "&gt;",
47
+ '"': '&quot;',
48
+ "'": '&#39;'
49
+ };
50
+
51
+ function escapeHTML(string) {
52
+ return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) {
53
+ return escapeMap[s] || s;
54
+ });
55
+ }
56
+
57
+ var regexCache = {};
58
+ var Renderer = function () {};
16
59
 
17
60
  Renderer.prototype = {
18
61
  otag: "{{",
@@ -24,16 +67,16 @@ var Mustache = function() {
24
67
  },
25
68
  context: {},
26
69
 
27
- render: function(template, context, partials, in_recursion) {
70
+ render: function (template, context, partials, in_recursion) {
28
71
  // reset buffer & set context
29
- if(!in_recursion) {
72
+ if (!in_recursion) {
30
73
  this.context = context;
31
74
  this.buffer = []; // TODO: make this non-lazy
32
75
  }
33
76
 
34
77
  // fail fast
35
- if(!this.includes("", template)) {
36
- if(in_recursion) {
78
+ if (!this.includes("", template)) {
79
+ if (in_recursion) {
37
80
  return template;
38
81
  } else {
39
82
  this.send(template);
@@ -41,44 +84,64 @@ var Mustache = function() {
41
84
  }
42
85
  }
43
86
 
87
+ // get the pragmas together
44
88
  template = this.render_pragmas(template);
89
+
90
+ // render the template
45
91
  var html = this.render_section(template, context, partials);
46
- if(in_recursion) {
47
- return this.render_tags(html, context, partials, in_recursion);
92
+
93
+ // render_section did not find any sections, we still need to render the tags
94
+ if (html === false) {
95
+ html = this.render_tags(template, context, partials, in_recursion);
48
96
  }
49
97
 
50
- this.render_tags(html, context, partials, in_recursion);
98
+ if (in_recursion) {
99
+ return html;
100
+ } else {
101
+ this.sendLines(html);
102
+ }
51
103
  },
52
104
 
53
105
  /*
54
106
  Sends parsed lines
55
107
  */
56
- send: function(line) {
57
- if(line != "") {
108
+ send: function (line) {
109
+ if (line !== "") {
58
110
  this.buffer.push(line);
59
111
  }
60
112
  },
61
113
 
114
+ sendLines: function (text) {
115
+ if (text) {
116
+ var lines = text.split("\n");
117
+ for (var i = 0; i < lines.length; i++) {
118
+ this.send(lines[i]);
119
+ }
120
+ }
121
+ },
122
+
62
123
  /*
63
124
  Looks for %PRAGMAS
64
125
  */
65
- render_pragmas: function(template) {
126
+ render_pragmas: function (template) {
66
127
  // no pragmas
67
- if(!this.includes("%", template)) {
128
+ if (!this.includes("%", template)) {
68
129
  return template;
69
130
  }
70
131
 
71
132
  var that = this;
72
- var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" +
73
- this.ctag);
74
- return template.replace(regex, function(match, pragma, options) {
75
- if(!that.pragmas_implemented[pragma]) {
76
- throw({message:
133
+ var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) {
134
+ return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g");
135
+ });
136
+
137
+ return template.replace(regex, function (match, pragma, options) {
138
+ if (!that.pragmas_implemented[pragma]) {
139
+ throw({message:
77
140
  "This implementation of mustache doesn't understand the '" +
78
141
  pragma + "' pragma"});
79
142
  }
80
143
  that.pragmas[pragma] = {};
81
- if(options) {
144
+ if (options) {
82
145
  var opts = options.split("=");
83
146
  that.pragmas[pragma][opts[0]] = opts[1];
84
147
  }
@@ -90,12 +153,12 @@ var Mustache = function() {
90
153
  /*
91
154
  Tries to find a partial in the curent scope and render it
92
155
  */
93
- render_partial: function(name, context, partials) {
94
- name = this.trim(name);
95
- if(!partials || partials[name] === undefined) {
156
+ render_partial: function (name, context, partials) {
157
+ name = trim(name);
158
+ if (!partials || partials[name] === undefined) {
96
159
  throw({message: "unknown_partial '" + name + "'"});
97
160
  }
98
- if(typeof(context[name]) != "object") {
161
+ if (!context || typeof context[name] != "object") {
99
162
  return this.render(partials[name], context, partials, true);
100
163
  }
101
164
  return this.render(partials[name], context[name], partials, true);
@@ -104,64 +167,94 @@ var Mustache = function() {
104
167
  /*
105
168
  Renders inverted (^) and normal (#) sections
106
169
  */
107
- render_section: function(template, context, partials) {
108
- if(!this.includes("#", template) && !this.includes("^", template)) {
109
- return template;
170
+ render_section: function (template, context, partials) {
171
+ if (!this.includes("#", template) && !this.includes("^", template)) {
172
+ // did not render anything, there were no sections
173
+ return false;
110
174
  }
111
175
 
112
176
  var that = this;
113
- // CSW - Added "+?" so it finds the tighest bound, not the widest
114
- var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag +
115
- "\n*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag +
116
- "\\s*", "mg");
177
+
178
+ var regex = this.getCachedRegex("render_section", function (otag, ctag) {
179
+ // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder
180
+ return new RegExp(
181
+ "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1)
182
+
183
+ otag + // {{
184
+ "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3)
185
+ ctag + // }}
186
+
187
+ "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped
188
+
189
+ otag + // {{
190
+ "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag).
191
+ ctag + // }}
192
+
193
+ "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped.
194
+
195
+ "g");
196
+ });
197
+
117
198
 
118
199
  // for each {{#foo}}{{/foo}} section do...
119
- return template.replace(regex, function(match, type, name, content) {
120
- var value = that.find(name, context);
121
- if(type == "^") { // inverted section
122
- if(!value || that.is_array(value) && value.length === 0) {
200
+ return template.replace(regex, function (match, before, type, name, content, after) {
201
+ // before contains only tags, no sections
202
+ var renderedBefore = before ? that.render_tags(before, context, partials, true) : "",
203
+
204
+ // after may contain both sections and tags, so use full rendering function
205
+ renderedAfter = after ? that.render(after, context, partials, true) : "",
206
+
207
+ // will be computed below
208
+ renderedContent,
209
+
210
+ value = that.find(name, context);
211
+
212
+ if (type === "^") { // inverted section
213
+ if (!value || Array.isArray(value) && value.length === 0) {
123
214
  // false or empty list, render it
124
- return that.render(content, context, partials, true);
215
+ renderedContent = that.render(content, context, partials, true);
125
216
  } else {
126
- return "";
217
+ renderedContent = "";
127
218
  }
128
- } else if(type == "#") { // normal section
129
- if(that.is_array(value)) { // Enumerable, Let's loop!
130
- return that.map(value, function(row) {
131
- return that.render(content, that.create_context(row),
132
- partials, true);
219
+ } else if (type === "#") { // normal section
220
+ if (Array.isArray(value)) { // Enumerable, Let's loop!
221
+ renderedContent = that.map(value, function (row) {
222
+ return that.render(content, that.create_context(row), partials, true);
133
223
  }).join("");
134
- } else if(that.is_object(value)) { // Object, Use it as subcontext!
135
- return that.render(content, that.create_context(value),
224
+ } else if (that.is_object(value)) { // Object, Use it as subcontext!
225
+ renderedContent = that.render(content, that.create_context(value),
136
226
  partials, true);
137
- } else if(typeof value === "function") {
227
+ } else if (typeof value == "function") {
138
228
  // higher order section
139
- return value.call(context, content, function(text) {
229
+ renderedContent = value.call(context, content, function (text) {
140
230
  return that.render(text, context, partials, true);
141
231
  });
142
- } else if(value) { // boolean section
143
- return that.render(content, context, partials, true);
232
+ } else if (value) { // boolean section
233
+ renderedContent = that.render(content, context, partials, true);
144
234
  } else {
145
- return "";
235
+ renderedContent = "";
146
236
  }
147
237
  }
238
+
239
+ return renderedBefore + renderedContent + renderedAfter;
148
240
  });
149
241
  },
150
242
 
151
243
  /*
152
244
  Replace {{foo}} and friends with values from our view
153
245
  */
154
- render_tags: function(template, context, partials, in_recursion) {
246
+ render_tags: function (template, context, partials, in_recursion) {
155
247
  // tit for tat
156
248
  var that = this;
157
249
 
158
- var new_regex = function() {
159
- return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
160
- that.ctag + "+", "g");
250
+ var new_regex = function () {
251
+ return that.getCachedRegex("render_tags", function (otag, ctag) {
252
+ return new RegExp(otag + "(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?" + ctag + "+", "g");
253
+ });
161
254
  };
162
255
 
163
256
  var regex = new_regex();
164
- var tag_replace_callback = function(match, operator, name) {
257
+ var tag_replace_callback = function (match, operator, name) {
165
258
  switch(operator) {
166
259
  case "!": // ignore comments
167
260
  return "";
@@ -172,33 +265,34 @@ var Mustache = function() {
172
265
  case ">": // render partial
173
266
  return that.render_partial(name, context, partials);
174
267
  case "{": // the triple mustache is unescaped
268
+ case "&": // & operator is an alternative unescape method
175
269
  return that.find(name, context);
176
270
  default: // escape the value
177
- return that.escape(that.find(name, context));
271
+ return escapeHTML(that.find(name, context));
178
272
  }
179
273
  };
180
274
  var lines = template.split("\n");
181
275
  for(var i = 0; i < lines.length; i++) {
182
276
  lines[i] = lines[i].replace(regex, tag_replace_callback, this);
183
- if(!in_recursion) {
277
+ if (!in_recursion) {
184
278
  this.send(lines[i]);
185
279
  }
186
280
  }
187
281
 
188
- if(in_recursion) {
282
+ if (in_recursion) {
189
283
  return lines.join("\n");
190
284
  }
191
285
  },
192
286
 
193
- set_delimiters: function(delimiters) {
287
+ set_delimiters: function (delimiters) {
194
288
  var dels = delimiters.split(" ");
195
289
  this.otag = this.escape_regex(dels[0]);
196
290
  this.ctag = this.escape_regex(dels[1]);
197
291
  },
198
292
 
199
- escape_regex: function(text) {
293
+ escape_regex: function (text) {
200
294
  // thank you Simon Willison
201
- if(!arguments.callee.sRE) {
295
+ if (!arguments.callee.sRE) {
202
296
  var specials = [
203
297
  '/', '.', '*', '+', '?', '|',
204
298
  '(', ')', '[', ']', '{', '}', '\\'
@@ -214,8 +308,8 @@ var Mustache = function() {
214
308
  find `name` in current `context`. That is find me a value
215
309
  from the view object
216
310
  */
217
- find: function(name, context) {
218
- name = this.trim(name);
311
+ find: function (name, context) {
312
+ name = trim(name);
219
313
 
220
314
  // Checks whether a value is thruthy or false or 0
221
315
  function is_kinda_truthy(bool) {
@@ -223,53 +317,61 @@ var Mustache = function() {
223
317
  }
224
318
 
225
319
  var value;
226
- if(is_kinda_truthy(context[name])) {
227
- value = context[name];
228
- } else if(is_kinda_truthy(this.context[name])) {
229
- value = this.context[name];
320
+
321
+ // check for dot notation eg. foo.bar
322
+ if (name.match(/([a-z_]+)\./ig)) {
323
+ var childValue = this.walk_context(name, context);
324
+ if (is_kinda_truthy(childValue)) {
325
+ value = childValue;
326
+ }
327
+ } else {
328
+ if (is_kinda_truthy(context[name])) {
329
+ value = context[name];
330
+ } else if (is_kinda_truthy(this.context[name])) {
331
+ value = this.context[name];
332
+ }
230
333
  }
231
334
 
232
- if(typeof value === "function") {
335
+ if (typeof value == "function") {
233
336
  return value.apply(context);
234
337
  }
235
- if(value !== undefined) {
338
+ if (value !== undefined) {
236
339
  return value;
237
340
  }
238
341
  // silently ignore unkown variables
239
342
  return "";
240
343
  },
241
344
 
345
+ walk_context: function (name, context) {
346
+ var path = name.split('.');
347
+ // if the var doesn't exist in current context, check the top level context
348
+ var value_context = (context[path[0]] != undefined) ? context : this.context;
349
+ var value = value_context[path.shift()];
350
+ while (value != undefined && path.length > 0) {
351
+ value_context = value;
352
+ value = value[path.shift()];
353
+ }
354
+ // if the value is a function, call it, binding the correct context
355
+ if (typeof value == "function") {
356
+ return value.apply(value_context);
357
+ }
358
+ return value;
359
+ },
360
+
242
361
  // Utility methods
243
362
 
244
363
  /* includes tag */
245
- includes: function(needle, haystack) {
364
+ includes: function (needle, haystack) {
246
365
  return haystack.indexOf(this.otag + needle) != -1;
247
366
  },
248
367
 
249
- /*
250
- Does away with nasty characters
251
- */
252
- escape: function(s) {
253
- s = String(s === null ? "" : s);
254
- return s.replace(/&(?!\w+;)|["<>\\]/g, function(s) {
255
- switch(s) {
256
- case "&": return "&amp;";
257
- case "\\": return "\\\\";
258
- case '"': return '\"';
259
- case "<": return "&lt;";
260
- case ">": return "&gt;";
261
- default: return s;
262
- }
263
- });
264
- },
265
-
266
368
  // by @langalex, support for arrays of strings
267
- create_context: function(_context) {
268
- if(this.is_object(_context)) {
369
+ create_context: function (_context) {
370
+ if (this.is_object(_context)) {
269
371
  return _context;
270
372
  } else {
271
373
  var iterator = ".";
272
- if(this.pragmas["IMPLICIT-ITERATOR"]) {
374
+ if (this.pragmas["IMPLICIT-ITERATOR"]) {
273
375
  iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
274
376
  }
275
377
  var ctx = {};
@@ -278,25 +380,14 @@ var Mustache = function() {
278
380
  }
279
381
  },
280
382
 
281
- is_object: function(a) {
383
+ is_object: function (a) {
282
384
  return a && typeof a == "object";
283
385
  },
284
386
 
285
- is_array: function(a) {
286
- return Object.prototype.toString.call(a) === '[object Array]';
287
- },
288
-
289
- /*
290
- Gets rid of leading and trailing whitespace
291
- */
292
- trim: function(s) {
293
- return s.replace(/^\s*|\s*$/g, "");
294
- },
295
-
296
387
  /*
297
388
  Why, why, why? Because IE. Cry, cry cry.
298
389
  */
299
- map: function(array, fn) {
390
+ map: function (array, fn) {
300
391
  if (typeof array.map == "function") {
301
392
  return array.map(fn);
302
393
  } else {
@@ -307,95 +398,145 @@ var Mustache = function() {
307
398
  }
308
399
  return r;
309
400
  }
401
+ },
402
+
403
+ getCachedRegex: function (name, generator) {
404
+ var byOtag = regexCache[this.otag];
405
+ if (!byOtag) {
406
+ byOtag = regexCache[this.otag] = {};
407
+ }
408
+
409
+ var byCtag = byOtag[this.ctag];
410
+ if (!byCtag) {
411
+ byCtag = byOtag[this.ctag] = {};
412
+ }
413
+
414
+ var regex = byCtag[name];
415
+ if (!regex) {
416
+ regex = byCtag[name] = generator(this.otag, this.ctag);
417
+ }
418
+
419
+ return regex;
310
420
  }
311
421
  };
312
422
 
313
423
  return({
314
424
  name: "mustache.js",
315
- version: "0.3.0",
425
+ version: "0.4.0",
316
426
 
317
427
  /*
318
428
  Turns a template and view into HTML
319
429
  */
320
- to_html: function(template, view, partials, send_fun) {
430
+ to_html: function (template, view, partials, send_fun) {
321
431
  var renderer = new Renderer();
322
- if(send_fun) {
432
+ if (send_fun) {
323
433
  renderer.send = send_fun;
324
434
  }
325
- renderer.render(template, view, partials);
326
- if(!send_fun) {
435
+ renderer.render(template, view || {}, partials);
436
+ if (!send_fun) {
327
437
  return renderer.buffer.join("\n");
328
438
  }
329
439
  }
330
440
  });
331
- }();/*!
441
+ }();
442
+ /*!
332
443
  ICanHaz.js -- by @HenrikJoreteg
333
444
  */
334
- /*global jQuery */
335
- function ICanHaz() {
336
- var self = this;
337
- self.VERSION = "0.9";
338
- self.templates = {};
339
- self.partials = {};
340
-
341
- // public function for adding templates
342
- // We're enforcing uniqueness to avoid accidental template overwrites.
343
- // If you want a different template, it should have a different name.
344
- self.addTemplate = function (name, templateString) {
345
- if (self[name]) throw "Invalid name: " + name + ".";
346
- if (self.templates[name]) throw "Template \" + name + \" exists";
445
+ /*global */
446
+ (function () {
447
+ function trim(stuff) {
448
+ if (''.trim) return stuff.trim();
449
+ else return stuff.replace(/^\s+/, '').replace(/\s+$/, '');
450
+ }
451
+ var ich = {
452
+ VERSION: "0.10",
453
+ templates: {},
347
454
 
348
- self.templates[name] = templateString;
349
- self[name] = function (data, raw) {
350
- data = data || {};
351
- var result = Mustache.to_html(self.templates[name], data, self.partials);
352
- return raw ? result : $(result);
353
- };
354
- };
355
-
356
- // public function for adding partials
357
- self.addPartial = function (name, templateString) {
358
- if (self.partials[name]) {
359
- throw "Partial \" + name + \" exists";
360
- } else {
361
- self.partials[name] = templateString;
455
+ // grab jquery or zepto if it's there
456
+ $: (typeof window !== 'undefined') ? window.jQuery || window.Zepto || null : null,
457
+
458
+ // public function for adding templates
459
+ // can take a name and template string arguments
460
+ // or can take an object with name/template pairs
461
+ // We're enforcing uniqueness to avoid accidental template overwrites.
462
+ // If you want a different template, it should have a different name.
463
+ addTemplate: function (name, templateString) {
464
+ if (typeof name === 'object') {
465
+ for (var template in name) {
466
+ this.addTemplate(template, name[template]);
467
+ }
468
+ return;
469
+ }
470
+ if (ich[name]) {
471
+ console.error("Invalid name: " + name + ".");
472
+ } else if (ich.templates[name]) {
473
+ console.error("Template \"" + name + " \" exists");
474
+ } else {
475
+ ich.templates[name] = templateString;
476
+ ich[name] = function (data, raw) {
477
+ data = data || {};
478
+ var result = Mustache.to_html(ich.templates[name], data, ich.templates);
479
+ return (ich.$ && !raw) ? ich.$(result) : result;
480
+ };
481
+ }
482
+ },
483
+
484
+ // clears all retrieval functions and empties cache
485
+ clearAll: function () {
486
+ for (var key in ich.templates) {
487
+ delete ich[key];
488
+ }
489
+ ich.templates = {};
490
+ },
491
+
492
+ // clears/grabs
493
+ refresh: function () {
494
+ ich.clearAll();
495
+ ich.grabTemplates();
496
+ },
497
+
498
+ // grabs templates from the DOM and caches them.
499
+ // Loop through and add templates.
500
+ // Whitespace at beginning and end of all templates inside <script> tags will
501
+ // be trimmed. If you want whitespace around a partial, add it in the parent,
502
+ // not the partial. Or do it explicitly using <br/> or &nbsp;
503
+ grabTemplates: function () {
504
+ var i,
505
+ scripts = document.getElementsByTagName('script'),
506
+ script,
507
+ trash = [];
508
+ for (i = 0, l = scripts.length; i < l; i++) {
509
+ script = scripts[i];
510
+ if (script && script.innerHTML && script.id && (script.type === "text/html" || script.type === "text/x-icanhaz")) {
511
+ ich.addTemplate(script.id, trim(script.innerHTML));
512
+ trash.unshift(script);
513
+ }
514
+ }
515
+ for (i = 0, l = trash.length; i < l; i++) {
516
+ trash[i].parentNode.removeChild(trash[i]);
517
+ }
362
518
  }
363
519
  };
364
520
 
365
- // grabs templates from the DOM and caches them.
366
- // Loop through and add templates.
367
- // Whitespace at beginning and end of all templates inside <script> tags will
368
- // be trimmed. If you want whitespace around a partial, add it in the parent,
369
- // not the partial. Or do it explicitly using <br/> or &nbsp;
370
- self.grabTemplates = function () {
371
- $('script[type="text/html"]').each(function (a, b) {
372
- var script = $((typeof a === 'number') ? b : a), // Zepto doesn't bind this
373
- text = (''.trim) ? script.html().trim() : $.trim(script.html());
374
-
375
- self[script.hasClass('partial') ? 'addPartial' : 'addTemplate'](script.attr('id'), text);
376
- script.remove();
377
- });
378
- };
521
+ // Use CommonJS if applicable
522
+ if (typeof require !== 'undefined') {
523
+ module.exports = ich;
524
+ } else {
525
+ // else attach it to the window
526
+ window.ich = ich;
527
+ }
379
528
 
380
- // clears all retrieval functions and empties caches
381
- self.clearAll = function () {
382
- for (var key in self.templates) {
383
- delete self[key];
529
+ if (typeof document !== 'undefined') {
530
+ if (ich.$) {
531
+ ich.$(function () {
532
+ ich.grabTemplates();
533
+ });
534
+ } else {
535
+ document.addEventListener('DOMContentLoaded', function () {
536
+ ich.grabTemplates();
537
+ }, true);
384
538
  }
385
- self.templates = {};
386
- self.partials = {};
387
- };
388
-
389
- self.refresh = function () {
390
- self.clearAll();
391
- self.grabTemplates();
392
- };
393
- }
394
-
395
- window.ich = new ICanHaz();
396
-
397
- // init itself on document ready
398
- $(function () {
399
- ich.grabTemplates();
400
- });
401
- })(window.jQuery || window.Zepto);
539
+ }
540
+
541
+ })();
542
+ })();