rack-oauth2-server 1.2.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +14 -0
- data/Gemfile +3 -0
- data/README.rdoc +26 -7
- data/Rakefile +1 -1
- data/VERSION +1 -0
- data/lib/rack/oauth2/admin/css/screen.css +233 -0
- data/lib/rack/oauth2/admin/images/loading.gif +0 -0
- data/lib/rack/oauth2/admin/js/application.js +154 -0
- data/lib/rack/oauth2/admin/js/jquery.js +166 -0
- data/lib/rack/oauth2/admin/js/jquery.tmpl.js +414 -0
- data/lib/rack/oauth2/admin/js/sammy.js +5 -0
- data/lib/rack/oauth2/admin/js/sammy.json.js +5 -0
- data/lib/rack/oauth2/admin/js/sammy.storage.js +5 -0
- data/lib/rack/oauth2/admin/js/sammy.title.js +5 -0
- data/lib/rack/oauth2/admin/js/sammy.tmpl.js +5 -0
- data/lib/rack/oauth2/admin/js/underscore.js +722 -0
- data/lib/rack/oauth2/admin/views/client.tmpl +48 -0
- data/lib/rack/oauth2/admin/views/clients.tmpl +36 -0
- data/lib/rack/oauth2/admin/views/edit.tmpl +57 -0
- data/lib/rack/oauth2/admin/views/index.html +26 -0
- data/lib/rack/oauth2/models/access_grant.rb +6 -4
- data/lib/rack/oauth2/models/access_token.rb +36 -4
- data/lib/rack/oauth2/models/auth_request.rb +4 -3
- data/lib/rack/oauth2/models/client.rb +15 -2
- data/lib/rack/oauth2/server.rb +71 -58
- data/lib/rack/oauth2/server/admin.rb +216 -0
- data/lib/rack/oauth2/server/helper.rb +4 -4
- data/lib/rack/oauth2/sinatra.rb +2 -2
- data/rack-oauth2-server.gemspec +2 -3
- data/test/admin/api_test.rb +196 -0
- data/test/admin_test_.rb +49 -0
- data/test/{access_grant_test.rb → oauth/access_grant_test.rb} +1 -1
- data/test/{access_token_test.rb → oauth/access_token_test.rb} +83 -12
- data/test/{authorization_test.rb → oauth/authorization_test.rb} +1 -1
- data/test/rails/config/environment.rb +2 -0
- data/test/rails/log/test.log +72938 -0
- data/test/setup.rb +17 -1
- data/test/sinatra/my_app.rb +1 -1
- metadata +27 -9
- data/lib/rack/oauth2/server/version.rb +0 -9
@@ -0,0 +1,5 @@
|
|
1
|
+
// -- Sammy -- /sammy.js
|
2
|
+
// http://code.quirkey.com/sammy
|
3
|
+
// Version: 0.6.2
|
4
|
+
// Built: Mon Oct 11 12:41:51 -0700 2010
|
5
|
+
(function(g,i){var n,f="([^/]+)",j=/:([\w\d]+)/g,k=/\?([^#]*)$/,b=function(o){return Array.prototype.slice.call(o)},c=function(o){return Object.prototype.toString.call(o)==="[object Function]"},l=function(o){return Object.prototype.toString.call(o)==="[object Array]"},h=decodeURIComponent,e=function(o){return o.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")},m=function(o){return function(p,q){return this.route.apply(this,[o,p,q])}},a={},d=[];n=function(){var p=b(arguments),q,o;n.apps=n.apps||{};if(p.length===0||p[0]&&c(p[0])){return n.apply(n,["body"].concat(p))}else{if(typeof(o=p.shift())=="string"){q=n.apps[o]||new n.Application();q.element_selector=o;if(p.length>0){g.each(p,function(r,s){q.use(s)})}if(q.element_selector!=o){delete n.apps[o]}n.apps[q.element_selector]=q;return q}}};n.VERSION="0.6.2";n.addLogger=function(o){d.push(o)};n.log=function(){var o=b(arguments);o.unshift("["+Date()+"]");g.each(d,function(q,p){p.apply(n,o)})};if(typeof i.console!="undefined"){if(c(console.log.apply)){n.addLogger(function(){i.console.log.apply(console,arguments)})}else{n.addLogger(function(){i.console.log(arguments)})}}else{if(typeof console!="undefined"){n.addLogger(function(){console.log.apply(console,arguments)})}}g.extend(n,{makeArray:b,isFunction:c,isArray:l});n.Object=function(o){return g.extend(this,o||{})};g.extend(n.Object.prototype,{escapeHTML:e,h:e,toHash:function(){var o={};g.each(this,function(q,p){if(!c(p)){o[q]=p}});return o},toHTML:function(){var o="";g.each(this,function(q,p){if(!c(p)){o+="<strong>"+q+"</strong> "+p+"<br />"}});return o},keys:function(o){var p=[];for(var q in this){if(!c(this[q])||!o){p.push(q)}}return p},has:function(o){return this[o]&&g.trim(this[o].toString())!=""},join:function(){var p=b(arguments);var o=p.shift();return p.join(o)},log:function(){n.log.apply(n,arguments)},toString:function(o){var p=[];g.each(this,function(r,q){if(!c(q)||o){p.push('"'+r+'": '+q.toString())}});return"Sammy.Object: {"+p.join(",")+"}"}});n.HashLocationProxy=function(p,o){this.app=p;this.is_native=false;this._startPolling(o)};n.HashLocationProxy.prototype={bind:function(){var o=this,p=this.app;g(i).bind("hashchange."+this.app.eventNamespace(),function(r,q){if(o.is_native===false&&!q){n.log("native hash change exists, using");o.is_native=true;i.clearInterval(n.HashLocationProxy._interval)}p.trigger("location-changed")});if(!n.HashLocationProxy._bindings){n.HashLocationProxy._bindings=0}n.HashLocationProxy._bindings++},unbind:function(){g(i).unbind("hashchange."+this.app.eventNamespace());n.HashLocationProxy._bindings--;if(n.HashLocationProxy._bindings<=0){i.clearInterval(n.HashLocationProxy._interval)}},getLocation:function(){var o=i.location.toString().match(/^[^#]*(#.+)$/);return o?o[1]:""},setLocation:function(o){return(i.location=o)},_startPolling:function(q){var p=this;if(!n.HashLocationProxy._interval){if(!q){q=10}var o=function(){var r=p.getLocation();if(!n.HashLocationProxy._last_location||r!=n.HashLocationProxy._last_location){i.setTimeout(function(){g(i).trigger("hashchange",[true])},13)}n.HashLocationProxy._last_location=r};o();n.HashLocationProxy._interval=i.setInterval(o,q)}}};n.Application=function(o){var p=this;this.routes={};this.listeners=new n.Object({});this.arounds=[];this.befores=[];this.namespace=(new Date()).getTime()+"-"+parseInt(Math.random()*1000,10);this.context_prototype=function(){n.EventContext.apply(this,arguments)};this.context_prototype.prototype=new n.EventContext();if(c(o)){o.apply(this,[this])}if(!this._location_proxy){this.setLocationProxy(new n.HashLocationProxy(this,this.run_interval_every))}if(this.debug){this.bindToAllEvents(function(r,q){p.log(p.toString(),r.cleaned_type,q||{})})}};n.Application.prototype=g.extend({},n.Object.prototype,{ROUTE_VERBS:["get","post","put","delete"],APP_EVENTS:["run","unload","lookup-route","run-route","route-found","event-context-before","event-context-after","changed","error","check-form-submission","redirect","location-changed"],_last_route:null,_location_proxy:null,_running:false,element_selector:"body",debug:false,raise_errors:false,run_interval_every:50,template_engine:null,toString:function(){return"Sammy.Application:"+this.element_selector},$element:function(){return g(this.element_selector)},use:function(){var o=b(arguments),q=o.shift(),p=q||"";try{o.unshift(this);if(typeof q=="string"){p="Sammy."+q;q=n[q]}q.apply(this,o)}catch(r){if(typeof q==="undefined"){this.error("Plugin Error: called use() but plugin ("+p.toString()+") is not defined",r)}else{if(!c(q)){this.error("Plugin Error: called use() but '"+p.toString()+"' is not a function",r)}else{this.error("Plugin Error",r)}}}return this},setLocationProxy:function(o){var p=this._location_proxy;this._location_proxy=o;if(this.isRunning()){if(p){p.unbind()}this._location_proxy.bind()}},route:function(s,p,u){var r=this,t=[],o,q;if(!u&&c(p)){p=s;u=p;s="any"}s=s.toLowerCase();if(p.constructor==String){j.lastIndex=0;while((q=j.exec(p))!==null){t.push(q[1])}p=new RegExp("^"+p.replace(j,f)+"$")}if(typeof u=="string"){u=r[u]}o=function(v){var w={verb:v,path:p,callback:u,param_names:t};r.routes[v]=r.routes[v]||[];r.routes[v].push(w)};if(s==="any"){g.each(this.ROUTE_VERBS,function(x,w){o(w)})}else{o(s)}return this},get:m("get"),post:m("post"),put:m("put"),del:m("delete"),any:m("any"),mapRoutes:function(p){var o=this;g.each(p,function(q,r){o.route.apply(o,r)});return this},eventNamespace:function(){return["sammy-app",this.namespace].join("-")},bind:function(o,q,s){var r=this;if(typeof s=="undefined"){s=q}var p=function(){var v,t,u;v=arguments[0];u=arguments[1];if(u&&u.context){t=u.context;delete u.context}else{t=new r.context_prototype(r,"bind",v.type,u,v.target)}v.cleaned_type=v.type.replace(r.eventNamespace(),"");s.apply(t,[v,u])};if(!this.listeners[o]){this.listeners[o]=[]}this.listeners[o].push(p);if(this.isRunning()){this._listen(o,p)}return this},trigger:function(o,p){this.$element().trigger([o,this.eventNamespace()].join("."),[p]);return this},refresh:function(){this.last_location=null;this.trigger("location-changed");return this},before:function(o,p){if(c(o)){p=o;o={}}this.befores.push([o,p]);return this},after:function(o){return this.bind("event-context-after",o)},around:function(o){this.arounds.push(o);return this},isRunning:function(){return this._running},helpers:function(o){g.extend(this.context_prototype.prototype,o);return this},helper:function(o,p){this.context_prototype.prototype[o]=p;return this},run:function(o){if(this.isRunning()){return false}var p=this;g.each(this.listeners.toHash(),function(q,r){g.each(r,function(t,s){p._listen(q,s)})});this.trigger("run",{start_url:o});this._running=true;this.last_location=null;if(this.getLocation()==""&&typeof o!="undefined"){this.setLocation(o)}this._checkLocation();this._location_proxy.bind();this.bind("location-changed",function(){p._checkLocation()});this.bind("submit",function(r){var q=p._checkFormSubmission(g(r.target).closest("form"));return(q===false)?r.preventDefault():false});g(i).bind("beforeunload",function(){p.unload()});return this.trigger("changed")},unload:function(){if(!this.isRunning()){return false}var o=this;this.trigger("unload");this._location_proxy.unbind();this.$element().unbind("submit").removeClass(o.eventNamespace());g.each(this.listeners.toHash(),function(p,q){g.each(q,function(s,r){o._unlisten(p,r)})});this._running=false;return this},bindToAllEvents:function(p){var o=this;g.each(this.APP_EVENTS,function(q,r){o.bind(r,p)});g.each(this.listeners.keys(true),function(r,q){if(o.APP_EVENTS.indexOf(q)==-1){o.bind(q,p)}});return this},routablePath:function(o){return o.replace(k,"")},lookupRoute:function(r,p){var q=this,o=false;this.trigger("lookup-route",{verb:r,path:p});if(typeof this.routes[r]!="undefined"){g.each(this.routes[r],function(t,s){if(q.routablePath(p).match(s.path)){o=s;return false}})}return o},runRoute:function(q,D,s,v){var r=this,B=this.lookupRoute(q,D),p,y,t,x,C,z,w,A,o;this.log("runRoute",[q,D].join(" "));this.trigger("run-route",{verb:q,path:D,params:s});if(typeof s=="undefined"){s={}}g.extend(s,this._parseQueryString(D));if(B){this.trigger("route-found",{route:B});if((A=B.path.exec(this.routablePath(D)))!==null){A.shift();g.each(A,function(E,F){if(B.param_names[E]){s[B.param_names[E]]=h(F)}else{if(!s.splat){s.splat=[]}s.splat.push(h(F))}})}p=new this.context_prototype(this,q,D,s,v);t=this.arounds.slice(0);C=this.befores.slice(0);w=[p].concat(s.splat);y=function(){var E;while(C.length>0){z=C.shift();if(r.contextMatchesOptions(p,z[0])){E=z[1].apply(p,[p]);if(E===false){return false}}}r.last_route=B;p.trigger("event-context-before",{context:p});E=B.callback.apply(p,w);p.trigger("event-context-after",{context:p});return E};g.each(t.reverse(),function(E,F){var G=y;y=function(){return F.apply(p,[G])}});try{o=y()}catch(u){this.error(["500 Error",q,D].join(" "),u)}return o}else{return this.notFound(q,D)}},contextMatchesOptions:function(r,t,p){var q=t;if(typeof q==="undefined"||q=={}){return true}if(typeof p==="undefined"){p=true}if(typeof q==="string"||c(q.test)){q={path:q}}if(q.only){return this.contextMatchesOptions(r,q.only,true)}else{if(q.except){return this.contextMatchesOptions(r,q.except,false)}}var o=true,s=true;if(q.path){if(c(q.path.test)){o=q.path.test(r.path)}else{o=(q.path.toString()===r.path)}}if(q.verb){s=q.verb===r.verb}return p?(s&&o):!(s&&o)},getLocation:function(){return this._location_proxy.getLocation()},setLocation:function(o){return this._location_proxy.setLocation(o)},swap:function(o){return this.$element().html(o)},templateCache:function(o,p){if(typeof p!="undefined"){return a[o]=p}else{return a[o]}},clearTemplateCache:function(){return a={}},notFound:function(q,p){var o=this.error(["404 Not Found",q,p].join(" "));return(q==="get")?o:true},error:function(p,o){if(!o){o=new Error()}o.message=[p,o.message].join(" ");this.trigger("error",{message:o.message,error:o});if(this.raise_errors){throw (o)}else{this.log(o.message,o)}},_checkLocation:function(){var o,p;o=this.getLocation();if(!this.last_location||this.last_location[0]!="get"||this.last_location[1]!=o){this.last_location=["get",o];p=this.runRoute("get",o)}return p},_getFormVerb:function(q){var p=g(q),r,o;o=p.find('input[name="_method"]');if(o.length>0){r=o.val()}if(!r){r=p[0].getAttribute("method")}return g.trim(r.toString().toLowerCase())},_checkFormSubmission:function(q){var o,r,t,s,p;this.trigger("check-form-submission",{form:q});o=g(q);r=o.attr("action");t=this._getFormVerb(o);if(!t||t==""){t="get"}this.log("_checkFormSubmission",o,r,t);if(t==="get"){this.setLocation(r+"?"+o.serialize());p=false}else{s=g.extend({},this._parseFormParams(o));p=this.runRoute(t,r,s,q.get(0))}return(typeof p=="undefined")?false:p},_parseFormParams:function(o){var r={},q=o.serializeArray(),p;for(p=0;p<q.length;p++){r=this._parseParamPair(r,q[p].name,q[p].value)}return r},_parseQueryString:function(r){var t={},q,p,s,o;q=r.match(k);if(q){p=q[1].split("&");for(o=0;o<p.length;o++){s=p[o].split("=");t=this._parseParamPair(t,h(s[0]),h(s[1]))}}return t},_parseParamPair:function(q,o,p){if(q[o]){if(l(q[o])){q[o].push(p)}else{q[o]=[q[o],p]}}else{q[o]=p}return q},_listen:function(o,p){return this.$element().bind([o,this.eventNamespace()].join("."),p)},_unlisten:function(o,p){return this.$element().unbind([o,this.eventNamespace()].join("."),p)}});n.RenderContext=function(o){this.event_context=o;this.callbacks=[];this.previous_content=null;this.content=null;this.next_engine=false;this.waiting=false};g.extend(n.RenderContext.prototype,{then:function(q){if(!c(q)){if(typeof q==="string"&&q in this.event_context){var p=this.event_context[q];q=function(r){return p.apply(this.event_context,[r])}}else{return this}}var o=this;if(this.waiting){this.callbacks.push(q)}else{this.wait();i.setTimeout(function(){var r=q.apply(o,[o.content,o.previous_content]);if(r!==false){o.next(r)}},13)}return this},wait:function(){this.waiting=true},next:function(o){this.waiting=false;if(typeof o!=="undefined"){this.previous_content=this.content;this.content=o}if(this.callbacks.length>0){this.then(this.callbacks.shift())}},load:function(o,p,r){var q=this;return this.then(function(){var s,t,v,u;if(c(p)){r=p;p={}}else{p=g.extend({},p)}if(r){this.then(r)}if(typeof o==="string"){v=(o.match(/\.json$/)||p.json);s=((v&&p.cache===true)||p.cache!==false);q.next_engine=q.event_context.engineFor(o);delete p.cache;delete p.json;if(p.engine){q.next_engine=p.engine;delete p.engine}if(s&&(t=this.event_context.app.templateCache(o))){return t}this.wait();g.ajax(g.extend({url:o,data:{},dataType:v?"json":null,type:"get",success:function(w){if(s){q.event_context.app.templateCache(o,w)}q.next(w)}},p));return false}else{if(o.nodeType){return o.innerHTML}if(o.selector){q.next_engine=o.attr("data-engine");if(p.clone===false){return o.remove()[0].innerHTML.toString()}else{return o[0].innerHTML.toString()}}}})},render:function(o,p,q){if(c(o)&&!p){return this.then(o)}else{if(!p&&this.content){p=this.content}return this.load(o).interpolate(p,o).then(q)}},partial:function(o,p){return this.render(o,p).swap()},send:function(){var q=this,p=b(arguments),o=p.shift();if(l(p[0])){p=p[0]}return this.then(function(r){p.push(function(s){q.next(s)});q.wait();o.apply(o,p);return false})},collect:function(s,r,o){var q=this;var p=function(){if(c(s)){r=s;s=this.content}var t=[],u=false;g.each(s,function(v,x){var w=r.apply(q,[v,x]);if(w.jquery&&w.length==1){w=w[0];u=true}t.push(w);return w});return u?t:t.join("")};return o?p():this.then(p)},renderEach:function(o,p,q,r){if(l(p)){r=q;q=p;p=null}return this.load(o).then(function(t){var s=this;if(!q){q=l(this.previous_content)?this.previous_content:[]}if(r){g.each(q,function(u,w){var x={},v=this.next_engine||o;p?(x[p]=w):(x=w);r(w,s.event_context.interpolate(t,x,v))})}else{return this.collect(q,function(u,w){var x={},v=this.next_engine||o;p?(x[p]=w):(x=w);return this.event_context.interpolate(t,x,v)},true)}})},interpolate:function(r,q,o){var p=this;return this.then(function(t,s){if(!r&&s){r=s}if(this.next_engine){q=this.next_engine;this.next_engine=false}var u=p.event_context.interpolate(t,r,q);return o?s+u:u})},swap:function(){return this.then(function(o){this.event_context.swap(o)}).trigger("changed",{})},appendTo:function(o){return this.then(function(p){g(o).append(p)}).trigger("changed",{})},prependTo:function(o){return this.then(function(p){g(o).prepend(p)}).trigger("changed",{})},replace:function(o){return this.then(function(p){g(o).html(p)}).trigger("changed",{})},trigger:function(o,p){return this.then(function(q){if(typeof p=="undefined"){p={content:q}}this.event_context.trigger(o,p)})}});n.EventContext=function(s,r,p,q,o){this.app=s;this.verb=r;this.path=p;this.params=new n.Object(q);this.target=o};n.EventContext.prototype=g.extend({},n.Object.prototype,{$element:function(){return this.app.$element()},engineFor:function(q){var p=this,o;if(c(q)){return q}q=q.toString();if((o=q.match(/\.([^\.]+)$/))){q=o[1]}if(q&&c(p[q])){return p[q]}if(p.app.template_engine){return this.engineFor(p.app.template_engine)}return function(r,s){return r}},interpolate:function(p,q,o){return this.engineFor(o).apply(this,[p,q])},render:function(o,p,q){return new n.RenderContext(this).render(o,p,q)},renderEach:function(o,p,q,r){return new n.RenderContext(this).renderEach(o,p,q,r)},load:function(o,p,q){return new n.RenderContext(this).load(o,p,q)},partial:function(o,p){return new n.RenderContext(this).partial(o,p)},send:function(){var o=new n.RenderContext(this);return o.send.apply(o,arguments)},redirect:function(){var q,p=b(arguments),o=this.app.getLocation();if(p.length>1){p.unshift("/");q=this.join.apply(this,p)}else{q=p[0]}this.trigger("redirect",{to:q});this.app.last_location=[this.verb,this.path];this.app.setLocation(q);if(o==q){this.app.trigger("location-changed")}},trigger:function(o,p){if(typeof p=="undefined"){p={}}if(!p.context){p.context=this}return this.app.trigger(o,p)},eventNamespace:function(){return this.app.eventNamespace()},swap:function(o){return this.app.swap(o)},notFound:function(){return this.app.notFound(this.verb,this.path)},json:function(o){return g.parseJSON(o)},toString:function(){return"Sammy.EventContext: "+[this.verb,this.path,this.params].join(" ")}});g.sammy=i.Sammy=n})(jQuery,window);
|
@@ -0,0 +1,5 @@
|
|
1
|
+
// -- Sammy -- /plugins/sammy.json.js
|
2
|
+
// http://code.quirkey.com/sammy
|
3
|
+
// Version: 0.6.2
|
4
|
+
// Built: Mon Oct 11 12:41:43 -0700 2010
|
5
|
+
(function($){if(!window.JSON){window.JSON={}}(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z"};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}());Sammy=Sammy||{};Sammy.JSON=function(app){app.helpers({json:function(object){if(typeof object=="string"){return JSON.parse(object)}else{return JSON.stringify(object)}}})}})(jQuery);
|
@@ -0,0 +1,5 @@
|
|
1
|
+
// -- Sammy -- /plugins/sammy.storage.js
|
2
|
+
// http://code.quirkey.com/sammy
|
3
|
+
// Version: 0.6.2
|
4
|
+
// Built: Mon Oct 11 12:41:48 -0700 2010
|
5
|
+
(function(a){Sammy=Sammy||{};Sammy.Store=function(c){var b=this;this.options=c||{};this.name=this.options.name||"store";this.element=this.options.element||"body";this.$element=a(this.element);if(a.isArray(this.options.type)){a.each(this.options.type,function(d,e){if(Sammy.Store.isAvailable(e)){b.type=e;return false}})}else{this.type=this.options.type||"memory"}this.meta_key=this.options.meta_key||"__keys__";this.storage=new Sammy.Store[Sammy.Store.stores[this.type]](this.name,this.element,this.options)};Sammy.Store.stores={memory:"Memory",data:"Data",local:"LocalStorage",session:"SessionStorage",cookie:"Cookie"};a.extend(Sammy.Store.prototype,{isAvailable:function(){if(a.isFunction(this.storage.isAvailable)){return this.storage.isAvailable()}else{true}},exists:function(b){return this.storage.exists(b)},set:function(c,d){var b=(typeof d=="string")?d:JSON.stringify(d);c=c.toString();this.storage.set(c,b);if(c!=this.meta_key){this._addKey(c);this.$element.trigger("set-"+this.name,{key:c,value:d});this.$element.trigger("set-"+this.name+"-"+c,{key:c,value:d})}return d},get:function(b){var c=this.storage.get(b);if(typeof c=="undefined"||c==null||c==""){return c}try{return JSON.parse(c)}catch(d){return c}},clear:function(b){this._removeKey(b);return this.storage.clear(b)},clearAll:function(){var b=this;this.each(function(c,d){b.clear(c)})},keys:function(){return this.get(this.meta_key)||[]},each:function(e){var b=0,d=this.keys(),c;for(b;b<d.length;b++){c=e(d[b],this.get(d[b]));if(c===false){return false}}},filter:function(c){var b=[];this.each(function(d,e){if(c(d,e)){b.push([d,e])}return true});return b},first:function(c){var b=false;this.each(function(d,e){if(c(d,e)){b=[d,e];return false}});return b},fetch:function(b,c){if(!this.exists(b)){return this.set(b,c.apply(this))}else{return this.get(b)}},load:function(b,d,e){var c=this;a.get(d,function(f){c.set(b,f);if(e){e.apply(this,[f])}})},_addKey:function(b){var c=this.keys();if(a.inArray(b,c)==-1){c.push(b)}this.set(this.meta_key,c)},_removeKey:function(c){var d=this.keys();var b=a.inArray(c,d);if(b!=-1){d.splice(b,1)}this.set(this.meta_key,d)}});Sammy.Store.isAvailable=function(b){try{return Sammy.Store[Sammy.Store.stores[b]].prototype.isAvailable()}catch(c){return false}};Sammy.Store.Memory=function(b,c){this.name=b;this.element=c;this.namespace=[this.element,this.name].join(".");Sammy.Store.Memory.store=Sammy.Store.Memory.store||{};Sammy.Store.Memory.store[this.namespace]=Sammy.Store.Memory.store[this.namespace]||{};this.store=Sammy.Store.Memory.store[this.namespace]};a.extend(Sammy.Store.Memory.prototype,{isAvailable:function(){return true},exists:function(b){return(typeof this.store[b]!="undefined")},set:function(b,c){return this.store[b]=c},get:function(b){return this.store[b]},clear:function(b){delete this.store[b]}});Sammy.Store.Data=function(b,c){this.name=b;this.element=c;this.$element=a(c)};a.extend(Sammy.Store.Data.prototype,{isAvailable:function(){return true},exists:function(b){return !!this.$element.data(this._key(b))},set:function(b,c){return this.$element.data(this._key(b),c)},get:function(b){return this.$element.data(this._key(b))},clear:function(b){this.$element.removeData(this._key(b))},_key:function(b){return["store",this.name,b].join(".")}});Sammy.Store.LocalStorage=function(b,c){this.name=b;this.element=c};a.extend(Sammy.Store.LocalStorage.prototype,{isAvailable:function(){return("localStorage" in window)&&(window.location.protocol!="file:")},exists:function(b){return(this.get(b)!=null)},set:function(b,c){return window.localStorage.setItem(this._key(b),c)},get:function(b){return window.localStorage.getItem(this._key(b))},clear:function(b){window.localStorage.removeItem(this._key(b))},_key:function(b){return["store",this.element,this.name,b].join(".")}});Sammy.Store.SessionStorage=function(b,c){this.name=b;this.element=c};a.extend(Sammy.Store.SessionStorage.prototype,{isAvailable:function(){return("sessionStorage" in window)&&(window.location.protocol!="file:")&&(a.isFunction(window.sessionStorage.setItem))},exists:function(b){return(this.get(b)!=null)},set:function(b,c){return window.sessionStorage.setItem(this._key(b),c)},get:function(b){var c=window.sessionStorage.getItem(this._key(b));if(c&&typeof c.value!="undefined"){c=c.value}return c},clear:function(b){window.sessionStorage.removeItem(this._key(b))},_key:function(b){return["store",this.element,this.name,b].join(".")}});Sammy.Store.Cookie=function(c,d,b){this.name=c;this.element=d;this.options=b||{};this.path=this.options.path||"/";this.expires_in=this.options.expires_in||(14*24*60*60)};a.extend(Sammy.Store.Cookie.prototype,{isAvailable:function(){return("cookie" in document)&&(window.location.protocol!="file:")},exists:function(b){return(this.get(b)!=null)},set:function(b,c){return this._setCookie(b,c)},get:function(b){return this._getCookie(b)},clear:function(b){this._setCookie(b,"",-1)},_key:function(b){return["store",this.element,this.name,b].join(".")},_getCookie:function(c){var d=this._key(c).replace(/(\.|\*|\(|\)|\[|\])/g,"\\$1");var b=document.cookie.match("(^|;\\s)"+d+"=([^;]*)(;|$)");return(b?b[2]:null)},_setCookie:function(e,f,c){if(!c){c=(this.expires_in*1000)}var d=new Date();d.setTime(d.getTime()+c);var b=[this._key(e),"=",f,"; expires=",d.toGMTString(),"; path=",this.path].join("");document.cookie=b}});Sammy.Storage=function(b){this.use(Sammy.JSON);this.stores=this.stores||{};this.store=function(d,c){if(typeof this.stores[d]=="undefined"){var e="clear"+d.substr(0,1).toUpperCase()+d.substr(1);this.stores[d]=new Sammy.Store(a.extend({name:d,element:this.element_selector},c||{}));this[d]=function(f,g){if(typeof g=="undefined"){return this.stores[d].get(f)}else{if(a.isFunction(g)){return this.stores[d].fetch(f,g)}else{return this.stores[d].set(f,g)}}};this[e]=function(){return this.stores[d].clearAll()};this.helper(d,function(){return this.app[d].apply(this.app,arguments)});this.helper(e,function(){return this.app[e]()})}return this.stores[d]};this.helpers({store:function(){return this.app.store.apply(this.app,arguments)}})};Sammy.Session=function(c,b){this.use(Sammy.Storage);this.store("session",a.extend({type:["local","cookie","memory"]},b))};Sammy.Cache=function(c,b){this.use(Sammy.Storage);this.cache_partials=true;this.store("cache",a.extend({type:["local","session","memory"]},b))}})(jQuery);
|
@@ -0,0 +1,5 @@
|
|
1
|
+
// -- Sammy -- /plugins/sammy.title.js
|
2
|
+
// http://code.quirkey.com/sammy
|
3
|
+
// Version: 0.6.2
|
4
|
+
// Built: Mon Oct 11 12:41:49 -0700 2010
|
5
|
+
(function(a){Sammy=Sammy||{};Sammy.Title=function(){this.setTitle=function(b){if(!a.isFunction(b)){this.title_function=function(c){return[b,c].join(" ")}}else{this.title_function=b}};this.helper("title",function(){var b=a.makeArray(arguments).join(" ");if(this.app.title_function){b=this.app.title_function(b)}document.title=b})}})(jQuery);
|
@@ -0,0 +1,5 @@
|
|
1
|
+
// -- Sammy -- /plugins/sammy.tmpl.js
|
2
|
+
// http://code.quirkey.com/sammy
|
3
|
+
// Version: 0.6.2
|
4
|
+
// Built: Mon Oct 11 12:41:50 -0700 2010
|
5
|
+
(function(i,f){var t=i.fn.domManip,h="_tmplitem",u=/^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,p={},e={},y,x={key:0,data:{}},w=0,q=0,g=[];function k(B,A,D,E){var C={data:E||(A?A.data:{}),_wrap:A?A._wrap:null,tmpl:null,parent:A||null,nodes:[],calls:c,nest:b,wrap:n,html:r,update:z};if(B){i.extend(C,B,{nodes:[],parent:A})}if(D){C.tmpl=D;C._ctnt=C._ctnt||C.tmpl(i,C);C.key=++w;(g.length?e:p)[w]=C}return C}i.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(A,B){i.fn[A]=function(C){var F=[],I=i(C),E,G,D,J,H=this.length===1&&this[0].parentNode;y=p||{};if(H&&H.nodeType===11&&H.childNodes.length===1&&I.length===1){I[B](this[0]);F=this}else{for(G=0,D=I.length;G<D;G++){q=G;E=(G>0?this.clone(true):this).get();i.fn[B].apply(i(I[G]),E);F=F.concat(E)}q=0;F=this.pushStack(F,A,I.selector)}J=y;y=null;i.tmpl.complete(J);return F}});i.fn.extend({tmpl:function(C,B,A){return i.tmpl(this[0],C,B,A)},tmplItem:function(){return i.tmplItem(this[0])},template:function(A){return i.template(A,this[0])},domManip:function(C,G,H,B){if(C[0]&&C[0].nodeType){var F=i.makeArray(arguments),E=C.length,D=0,A;while(D<E&&!(A=i.data(C[D++],"tmplItem"))){}if(E>1){F[0]=[i.makeArray(C)]}if(A&&q){F[2]=function(I){i.tmpl.afterManip(this,I,H)}}t.apply(this,F)}else{t.apply(this,arguments)}q=0;if(!y){i.tmpl.complete(p)}return this}});i.extend({tmpl:function(C,F,E,B){var D,A=!B;if(A){B=x;C=i.template[C]||i.template(null,C);e={}}else{if(!C){C=B.tmpl;p[B.key]=B;B.nodes=[];if(B.wrapped){s(B,B.wrapped)}return i(m(B,null,B.tmpl(i,B)))}}if(!C){return[]}if(typeof F==="function"){F=F.call(B||{})}if(E&&E.wrapped){s(E,E.wrapped)}D=i.isArray(F)?i.map(F,function(G){return G?k(E,B,C,G):null}):[k(E,B,C,F)];return A?i(m(B,null,D)):D},tmplItem:function(B){var A;if(B instanceof i){B=B[0]}while(B&&B.nodeType===1&&!(A=i.data(B,"tmplItem"))&&(B=B.parentNode)){}return A||x},template:function(B,A){if(A){if(typeof A==="string"){A=l(A)}else{if(A instanceof i){A=A[0]||{}}}if(A.nodeType){A=i.data(A,"tmpl")||i.data(A,"tmpl",l(A.innerHTML))}return typeof B==="string"?(i.template[B]=A):A}return B?(typeof B!=="string"?i.template(null,B):(i.template[B]||i.template(null,u.test(B)?B:i(B)))):null},encode:function(A){return(""+A).split("<").join("<").split(">").join(">").split('"').join(""").split("'").join("'")}});i.extend(i.tmpl,{tag:{tmpl:{_default:{$2:"null"},open:"if($notnull_1){_=_.concat($item.nest($1,$2));}"},wrap:{_default:{$2:"null"},open:"$item.calls(_,$1,$2);_=[];",close:"call=$item.calls();_=call._.concat($item.wrap(call,_));"},each:{_default:{$2:"$index, $value"},open:"if($notnull_1){$.each($1a,function($2){with(this){",close:"}});}"},"if":{open:"if(($notnull_1) && $1a){",close:"}"},"else":{_default:{$1:"true"},open:"}else if(($notnull_1) && $1a){"},html:{open:"if($notnull_1){_.push($1a);}"},"=":{_default:{$1:"$data"},open:"if($notnull_1){_.push($.encode($1a));}"},"!":{open:""}},complete:function(A){p={}},afterManip:function v(C,A,D){var B=A.nodeType===11?i.makeArray(A.childNodes):A.nodeType===1?[A]:[];D.call(C,A);o(B);q++}});function m(A,E,C){var D,B=C?i.map(C,function(F){return(typeof F==="string")?(A.key?F.replace(/(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g,"$1 "+h+'="'+A.key+'" $2'):F):m(F,A,F._ctnt)}):A;if(E){return B}B=B.join("");B.replace(/^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/,function(G,H,F,I){D=i(F).get();o(D);if(H){D=a(H).concat(D)}if(I){D=D.concat(a(I))}});return D?D:a(B)}function a(B){var A=document.createElement("div");A.innerHTML=B;return i.makeArray(A.childNodes)}function l(A){return new Function("jQuery","$item","var $=jQuery,call,_=[],$data=$item.data;with($data){_.push('"+i.trim(A).replace(/([\\'])/g,"\\$1").replace(/[\r\t\n]/g," ").replace(/\$\{([^\}]*)\}/g,"{{= $1}}").replace(/\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g,function(I,C,G,D,E,J,F){var L=i.tmpl.tag[G],B,H,K;if(!L){throw"Template command not found: "+G}B=L._default||[];if(J&&!/\w$/.test(E)){E+=J;J=""}if(E){E=j(E);F=F?(","+j(F)+")"):(J?")":"");H=J?(E.indexOf(".")>-1?E+J:("("+E+").call($item"+F)):E;K=J?H:"(typeof("+E+")==='function'?("+E+").call($item):("+E+"))"}else{K=H=B.$1||"null"}D=j(D);return"');"+L[C?"close":"open"].split("$notnull_1").join(E?"typeof("+E+")!=='undefined' && ("+E+")!=null":"true").split("$1a").join(K).split("$1").join(H).split("$2").join(D?D.replace(/\s*([^\(]+)\s*(\((.*?)\))?/g,function(N,M,O,P){P=P?(","+P+")"):(O?")":"");return P?("("+M+").call($item"+P):N}):(B.$2||""))+"_.push('"})+"');}return _;")}function s(B,A){B._wrap=m(B,true,i.isArray(A)?A:[u.test(A)?A:i(A).html()]).join("")}function j(A){return A?A.replace(/\\'/g,"'").replace(/\\\\/g,"\\"):null}function d(A){var B=document.createElement("div");B.appendChild(A.cloneNode(true));return B.innerHTML}function o(G){var I="_"+q,B,A,E={},F,D,C;for(F=0,D=G.length;F<D;F++){if((B=G[F]).nodeType!==1){continue}A=B.getElementsByTagName("*");for(C=A.length-1;C>=0;C--){H(A[C])}H(B)}function H(O){var L,N=O,M,J,K;if((K=O.getAttribute(h))){while(N.parentNode&&(N=N.parentNode).nodeType===1&&!(L=N.getAttribute(h))){}if(L!==K){N=N.parentNode?(N.nodeType===11?0:(N.getAttribute(h)||0)):0;if(!(J=p[K])){J=e[K];J=k(J,p[N]||e[N],null,true);J.key=++w;p[w]=J}if(q){P(K)}}O.removeAttribute(h)}else{if(q&&(J=i.data(O,"tmplItem"))){P(J.key);p[J.key]=J;N=i.data(O.parentNode,"tmplItem");N=N?N.key:0}}if(J){M=J;while(M&&M.key!=N){M.nodes.push(O);M=M.parent}delete J._ctnt;delete J._wrap;i.data(O,"tmplItem",J)}function P(Q){Q=Q+I;J=E[Q]=(E[Q]||k(J,p[J.parent.key+I]||J.parent,null,true))}}}function c(C,A,D,B){if(!C){return g.pop()}g.push({_:C,tmpl:A,item:this,data:D,options:B})}function b(A,C,B){return i.tmpl(i.template(A),C,B,this)}function n(C,A){var B=C.options||{};B.wrapped=A;return i.tmpl(i.template(C.tmpl),C.data,B,C.item)}function r(B,C){var A=this._wrap;return i.map(i(i.isArray(A)?A.join(""):A).filter(B||"*"),function(D){return C?D.innerText||D.textContent:D.outerHTML||d(D)})}function z(){var A=this.nodes;i.tmpl(null,null,null,this).insertBefore(A[0]);i(A).remove()}Sammy=Sammy||{};Sammy.Tmpl=function(C,A){var B=function(E,F,D){if(typeof D=="undefined"){D=E}if(!i.template[D]){i.template(D,E)}return i.tmpl(D,i.extend({},this,F))};if(!A){A="tmpl"}C.helper(A,B)}})(jQuery);
|
@@ -0,0 +1,722 @@
|
|
1
|
+
// (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
|
2
|
+
// Underscore is freely distributable under the terms of the MIT license.
|
3
|
+
// Portions of Underscore are inspired by or borrowed from Prototype.js,
|
4
|
+
// Oliver Steele's Functional, and John Resig's Micro-Templating.
|
5
|
+
// For all details and documentation:
|
6
|
+
// http://documentcloud.github.com/underscore
|
7
|
+
|
8
|
+
(function() {
|
9
|
+
|
10
|
+
// Baseline setup
|
11
|
+
// --------------
|
12
|
+
|
13
|
+
// Establish the root object, `window` in the browser, or `global` on the server.
|
14
|
+
var root = this;
|
15
|
+
|
16
|
+
// Save the previous value of the `_` variable.
|
17
|
+
var previousUnderscore = root._;
|
18
|
+
|
19
|
+
// Establish the object that gets thrown to break out of a loop iteration.
|
20
|
+
var breaker = typeof StopIteration !== 'undefined' ? StopIteration : '__break__';
|
21
|
+
|
22
|
+
// Quick regexp-escaping function, because JS doesn't have a `RegExp.escape()`.
|
23
|
+
var escapeRegExp = function(s) { return s.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1'); };
|
24
|
+
|
25
|
+
// Save bytes in the minified (but not gzipped) version:
|
26
|
+
var ArrayProto = Array.prototype, ObjProto = Object.prototype;
|
27
|
+
|
28
|
+
// Create quick reference variables for speed access to core prototypes.
|
29
|
+
var slice = ArrayProto.slice,
|
30
|
+
unshift = ArrayProto.unshift,
|
31
|
+
toString = ObjProto.toString,
|
32
|
+
hasOwnProperty = ObjProto.hasOwnProperty,
|
33
|
+
propertyIsEnumerable = ObjProto.propertyIsEnumerable;
|
34
|
+
|
35
|
+
// All **ECMAScript 5** native function implementations that we hope to use
|
36
|
+
// are declared here.
|
37
|
+
var
|
38
|
+
nativeForEach = ArrayProto.forEach,
|
39
|
+
nativeMap = ArrayProto.map,
|
40
|
+
nativeReduce = ArrayProto.reduce,
|
41
|
+
nativeReduceRight = ArrayProto.reduceRight,
|
42
|
+
nativeFilter = ArrayProto.filter,
|
43
|
+
nativeEvery = ArrayProto.every,
|
44
|
+
nativeSome = ArrayProto.some,
|
45
|
+
nativeIndexOf = ArrayProto.indexOf,
|
46
|
+
nativeLastIndexOf = ArrayProto.lastIndexOf,
|
47
|
+
nativeIsArray = Array.isArray,
|
48
|
+
nativeKeys = Object.keys;
|
49
|
+
|
50
|
+
// Create a safe reference to the Underscore object for use below.
|
51
|
+
var _ = function(obj) { return new wrapper(obj); };
|
52
|
+
|
53
|
+
// Export the Underscore object for **CommonJS**.
|
54
|
+
if (typeof exports !== 'undefined') exports._ = _;
|
55
|
+
|
56
|
+
// Export Underscore to the global scope.
|
57
|
+
root._ = _;
|
58
|
+
|
59
|
+
// Current version.
|
60
|
+
_.VERSION = '1.1.1';
|
61
|
+
|
62
|
+
// Collection Functions
|
63
|
+
// --------------------
|
64
|
+
|
65
|
+
// The cornerstone, an `each` implementation.
|
66
|
+
// Handles objects implementing `forEach`, arrays, and raw objects.
|
67
|
+
// Delegates to **ECMAScript 5**'s native `forEach` if available.
|
68
|
+
var each = _.forEach = function(obj, iterator, context) {
|
69
|
+
try {
|
70
|
+
if (nativeForEach && obj.forEach === nativeForEach) {
|
71
|
+
obj.forEach(iterator, context);
|
72
|
+
} else if (_.isNumber(obj.length)) {
|
73
|
+
for (var i = 0, l = obj.length; i < l; i++) iterator.call(context, obj[i], i, obj);
|
74
|
+
} else {
|
75
|
+
for (var key in obj) {
|
76
|
+
if (hasOwnProperty.call(obj, key)) iterator.call(context, obj[key], key, obj);
|
77
|
+
}
|
78
|
+
}
|
79
|
+
} catch(e) {
|
80
|
+
if (e != breaker) throw e;
|
81
|
+
}
|
82
|
+
return obj;
|
83
|
+
};
|
84
|
+
|
85
|
+
// Return the results of applying the iterator to each element.
|
86
|
+
// Delegates to **ECMAScript 5**'s native `map` if available.
|
87
|
+
_.map = function(obj, iterator, context) {
|
88
|
+
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
|
89
|
+
var results = [];
|
90
|
+
each(obj, function(value, index, list) {
|
91
|
+
results[results.length] = iterator.call(context, value, index, list);
|
92
|
+
});
|
93
|
+
return results;
|
94
|
+
};
|
95
|
+
|
96
|
+
// **Reduce** builds up a single result from a list of values, aka `inject`,
|
97
|
+
// or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
|
98
|
+
_.reduce = function(obj, iterator, memo, context) {
|
99
|
+
if (nativeReduce && obj.reduce === nativeReduce) {
|
100
|
+
if (context) iterator = _.bind(iterator, context);
|
101
|
+
return obj.reduce(iterator, memo);
|
102
|
+
}
|
103
|
+
each(obj, function(value, index, list) {
|
104
|
+
memo = iterator.call(context, memo, value, index, list);
|
105
|
+
});
|
106
|
+
return memo;
|
107
|
+
};
|
108
|
+
|
109
|
+
// The right-associative version of reduce, also known as `foldr`. Uses
|
110
|
+
// Delegates to **ECMAScript 5**'s native reduceRight if available.
|
111
|
+
_.reduceRight = function(obj, iterator, memo, context) {
|
112
|
+
if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
|
113
|
+
if (context) iterator = _.bind(iterator, context);
|
114
|
+
return obj.reduceRight(iterator, memo);
|
115
|
+
}
|
116
|
+
var reversed = _.clone(_.toArray(obj)).reverse();
|
117
|
+
return _.reduce(reversed, iterator, memo, context);
|
118
|
+
};
|
119
|
+
|
120
|
+
// Return the first value which passes a truth test.
|
121
|
+
_.detect = function(obj, iterator, context) {
|
122
|
+
var result;
|
123
|
+
each(obj, function(value, index, list) {
|
124
|
+
if (iterator.call(context, value, index, list)) {
|
125
|
+
result = value;
|
126
|
+
_.breakLoop();
|
127
|
+
}
|
128
|
+
});
|
129
|
+
return result;
|
130
|
+
};
|
131
|
+
|
132
|
+
// Return all the elements that pass a truth test.
|
133
|
+
// Delegates to **ECMAScript 5**'s native `filter` if available.
|
134
|
+
_.filter = function(obj, iterator, context) {
|
135
|
+
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
|
136
|
+
var results = [];
|
137
|
+
each(obj, function(value, index, list) {
|
138
|
+
if (iterator.call(context, value, index, list)) results[results.length] = value;
|
139
|
+
});
|
140
|
+
return results;
|
141
|
+
};
|
142
|
+
|
143
|
+
// Return all the elements for which a truth test fails.
|
144
|
+
_.reject = function(obj, iterator, context) {
|
145
|
+
var results = [];
|
146
|
+
each(obj, function(value, index, list) {
|
147
|
+
if (!iterator.call(context, value, index, list)) results[results.length] = value;
|
148
|
+
});
|
149
|
+
return results;
|
150
|
+
};
|
151
|
+
|
152
|
+
// Determine whether all of the elements match a truth test.
|
153
|
+
// Delegates to **ECMAScript 5**'s native `every` if available.
|
154
|
+
_.every = function(obj, iterator, context) {
|
155
|
+
iterator = iterator || _.identity;
|
156
|
+
if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
|
157
|
+
var result = true;
|
158
|
+
each(obj, function(value, index, list) {
|
159
|
+
if (!(result = result && iterator.call(context, value, index, list))) _.breakLoop();
|
160
|
+
});
|
161
|
+
return result;
|
162
|
+
};
|
163
|
+
|
164
|
+
// Determine if at least one element in the object matches a truth test.
|
165
|
+
// Delegates to **ECMAScript 5**'s native `some` if available.
|
166
|
+
_.some = function(obj, iterator, context) {
|
167
|
+
iterator = iterator || _.identity;
|
168
|
+
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
|
169
|
+
var result = false;
|
170
|
+
each(obj, function(value, index, list) {
|
171
|
+
if (result = iterator.call(context, value, index, list)) _.breakLoop();
|
172
|
+
});
|
173
|
+
return result;
|
174
|
+
};
|
175
|
+
|
176
|
+
// Determine if a given value is included in the array or object using `===`.
|
177
|
+
_.include = function(obj, target) {
|
178
|
+
if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
|
179
|
+
var found = false;
|
180
|
+
each(obj, function(value) {
|
181
|
+
if (found = value === target) _.breakLoop();
|
182
|
+
});
|
183
|
+
return found;
|
184
|
+
};
|
185
|
+
|
186
|
+
// Invoke a method (with arguments) on every item in a collection.
|
187
|
+
_.invoke = function(obj, method) {
|
188
|
+
var args = slice.call(arguments, 2);
|
189
|
+
return _.map(obj, function(value) {
|
190
|
+
return (method ? value[method] : value).apply(value, args);
|
191
|
+
});
|
192
|
+
};
|
193
|
+
|
194
|
+
// Convenience version of a common use case of `map`: fetching a property.
|
195
|
+
_.pluck = function(obj, key) {
|
196
|
+
return _.map(obj, function(value){ return value[key]; });
|
197
|
+
};
|
198
|
+
|
199
|
+
// Return the maximum element or (element-based computation).
|
200
|
+
_.max = function(obj, iterator, context) {
|
201
|
+
if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
|
202
|
+
var result = {computed : -Infinity};
|
203
|
+
each(obj, function(value, index, list) {
|
204
|
+
var computed = iterator ? iterator.call(context, value, index, list) : value;
|
205
|
+
computed >= result.computed && (result = {value : value, computed : computed});
|
206
|
+
});
|
207
|
+
return result.value;
|
208
|
+
};
|
209
|
+
|
210
|
+
// Return the minimum element (or element-based computation).
|
211
|
+
_.min = function(obj, iterator, context) {
|
212
|
+
if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
|
213
|
+
var result = {computed : Infinity};
|
214
|
+
each(obj, function(value, index, list) {
|
215
|
+
var computed = iterator ? iterator.call(context, value, index, list) : value;
|
216
|
+
computed < result.computed && (result = {value : value, computed : computed});
|
217
|
+
});
|
218
|
+
return result.value;
|
219
|
+
};
|
220
|
+
|
221
|
+
// Sort the object's values by a criterion produced by an iterator.
|
222
|
+
_.sortBy = function(obj, iterator, context) {
|
223
|
+
return _.pluck(_.map(obj, function(value, index, list) {
|
224
|
+
return {
|
225
|
+
value : value,
|
226
|
+
criteria : iterator.call(context, value, index, list)
|
227
|
+
};
|
228
|
+
}).sort(function(left, right) {
|
229
|
+
var a = left.criteria, b = right.criteria;
|
230
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
231
|
+
}), 'value');
|
232
|
+
};
|
233
|
+
|
234
|
+
// Use a comparator function to figure out at what index an object should
|
235
|
+
// be inserted so as to maintain order. Uses binary search.
|
236
|
+
_.sortedIndex = function(array, obj, iterator) {
|
237
|
+
iterator = iterator || _.identity;
|
238
|
+
var low = 0, high = array.length;
|
239
|
+
while (low < high) {
|
240
|
+
var mid = (low + high) >> 1;
|
241
|
+
iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
|
242
|
+
}
|
243
|
+
return low;
|
244
|
+
};
|
245
|
+
|
246
|
+
// Safely convert anything iterable into a real, live array.
|
247
|
+
_.toArray = function(iterable) {
|
248
|
+
if (!iterable) return [];
|
249
|
+
if (iterable.toArray) return iterable.toArray();
|
250
|
+
if (_.isArray(iterable)) return iterable;
|
251
|
+
if (_.isArguments(iterable)) return slice.call(iterable);
|
252
|
+
return _.values(iterable);
|
253
|
+
};
|
254
|
+
|
255
|
+
// Return the number of elements in an object.
|
256
|
+
_.size = function(obj) {
|
257
|
+
return _.toArray(obj).length;
|
258
|
+
};
|
259
|
+
|
260
|
+
// Array Functions
|
261
|
+
// ---------------
|
262
|
+
|
263
|
+
// Get the first element of an array. Passing **n** will return the first N
|
264
|
+
// values in the array. Aliased as `head`. The **guard** check allows it to work
|
265
|
+
// with `_.map`.
|
266
|
+
_.first = function(array, n, guard) {
|
267
|
+
return n && !guard ? slice.call(array, 0, n) : array[0];
|
268
|
+
};
|
269
|
+
|
270
|
+
// Returns everything but the first entry of the array. Aliased as `tail`.
|
271
|
+
// Especially useful on the arguments object. Passing an **index** will return
|
272
|
+
// the rest of the values in the array from that index onward. The **guard**
|
273
|
+
// check allows it to work with `_.map`.
|
274
|
+
_.rest = function(array, index, guard) {
|
275
|
+
return slice.call(array, _.isUndefined(index) || guard ? 1 : index);
|
276
|
+
};
|
277
|
+
|
278
|
+
// Get the last element of an array.
|
279
|
+
_.last = function(array) {
|
280
|
+
return array[array.length - 1];
|
281
|
+
};
|
282
|
+
|
283
|
+
// Trim out all falsy values from an array.
|
284
|
+
_.compact = function(array) {
|
285
|
+
return _.filter(array, function(value){ return !!value; });
|
286
|
+
};
|
287
|
+
|
288
|
+
// Return a completely flattened version of an array.
|
289
|
+
_.flatten = function(array) {
|
290
|
+
return _.reduce(array, function(memo, value) {
|
291
|
+
if (_.isArray(value)) return memo.concat(_.flatten(value));
|
292
|
+
memo[memo.length] = value;
|
293
|
+
return memo;
|
294
|
+
}, []);
|
295
|
+
};
|
296
|
+
|
297
|
+
// Return a version of the array that does not contain the specified value(s).
|
298
|
+
_.without = function(array) {
|
299
|
+
var values = slice.call(arguments, 1);
|
300
|
+
return _.filter(array, function(value){ return !_.include(values, value); });
|
301
|
+
};
|
302
|
+
|
303
|
+
// Produce a duplicate-free version of the array. If the array has already
|
304
|
+
// been sorted, you have the option of using a faster algorithm.
|
305
|
+
_.uniq = function(array, isSorted) {
|
306
|
+
return _.reduce(array, function(memo, el, i) {
|
307
|
+
if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el;
|
308
|
+
return memo;
|
309
|
+
}, []);
|
310
|
+
};
|
311
|
+
|
312
|
+
// Produce an array that contains every item shared between all the
|
313
|
+
// passed-in arrays.
|
314
|
+
_.intersect = function(array) {
|
315
|
+
var rest = slice.call(arguments, 1);
|
316
|
+
return _.filter(_.uniq(array), function(item) {
|
317
|
+
return _.every(rest, function(other) {
|
318
|
+
return _.indexOf(other, item) >= 0;
|
319
|
+
});
|
320
|
+
});
|
321
|
+
};
|
322
|
+
|
323
|
+
// Zip together multiple lists into a single array -- elements that share
|
324
|
+
// an index go together.
|
325
|
+
_.zip = function() {
|
326
|
+
var args = slice.call(arguments);
|
327
|
+
var length = _.max(_.pluck(args, 'length'));
|
328
|
+
var results = new Array(length);
|
329
|
+
for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
|
330
|
+
return results;
|
331
|
+
};
|
332
|
+
|
333
|
+
// If the browser doesn't supply us with indexOf (I'm looking at you, MSIE),
|
334
|
+
// we need this function. Return the position of the first occurence of an
|
335
|
+
// item in an array, or -1 if the item is not included in the array.
|
336
|
+
// Delegates to **ECMAScript 5**'s native `indexOf` if available.
|
337
|
+
_.indexOf = function(array, item) {
|
338
|
+
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
|
339
|
+
for (var i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
|
340
|
+
return -1;
|
341
|
+
};
|
342
|
+
|
343
|
+
|
344
|
+
// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
|
345
|
+
_.lastIndexOf = function(array, item) {
|
346
|
+
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
|
347
|
+
var i = array.length;
|
348
|
+
while (i--) if (array[i] === item) return i;
|
349
|
+
return -1;
|
350
|
+
};
|
351
|
+
|
352
|
+
// Generate an integer Array containing an arithmetic progression. A port of
|
353
|
+
// the native Python `range()` function. See
|
354
|
+
// [the Python documentation](http://docs.python.org/library/functions.html#range).
|
355
|
+
_.range = function(start, stop, step) {
|
356
|
+
var a = slice.call(arguments);
|
357
|
+
var solo = a.length <= 1;
|
358
|
+
var start = solo ? 0 : a[0], stop = solo ? a[0] : a[1], step = a[2] || 1;
|
359
|
+
var len = Math.ceil((stop - start) / step);
|
360
|
+
if (len <= 0) return [];
|
361
|
+
var range = new Array(len);
|
362
|
+
for (var i = start, idx = 0; true; i += step) {
|
363
|
+
if ((step > 0 ? i - stop : stop - i) >= 0) return range;
|
364
|
+
range[idx++] = i;
|
365
|
+
}
|
366
|
+
};
|
367
|
+
|
368
|
+
// Function Functions
|
369
|
+
// ------------------
|
370
|
+
|
371
|
+
// Create a function bound to a given object (assigning `this`, and arguments,
|
372
|
+
// optionally). Binding with arguments is also known as `curry`.
|
373
|
+
_.bind = function(func, obj) {
|
374
|
+
var args = slice.call(arguments, 2);
|
375
|
+
return function() {
|
376
|
+
return func.apply(obj || {}, args.concat(slice.call(arguments)));
|
377
|
+
};
|
378
|
+
};
|
379
|
+
|
380
|
+
// Bind all of an object's methods to that object. Useful for ensuring that
|
381
|
+
// all callbacks defined on an object belong to it.
|
382
|
+
_.bindAll = function(obj) {
|
383
|
+
var funcs = slice.call(arguments, 1);
|
384
|
+
if (funcs.length == 0) funcs = _.functions(obj);
|
385
|
+
each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
|
386
|
+
return obj;
|
387
|
+
};
|
388
|
+
|
389
|
+
// Memoize an expensive function by storing its results.
|
390
|
+
_.memoize = function(func, hasher) {
|
391
|
+
var memo = {};
|
392
|
+
hasher = hasher || _.identity;
|
393
|
+
return function() {
|
394
|
+
var key = hasher.apply(this, arguments);
|
395
|
+
return key in memo ? memo[key] : (memo[key] = func.apply(this, arguments));
|
396
|
+
};
|
397
|
+
};
|
398
|
+
|
399
|
+
// Delays a function for the given number of milliseconds, and then calls
|
400
|
+
// it with the arguments supplied.
|
401
|
+
_.delay = function(func, wait) {
|
402
|
+
var args = slice.call(arguments, 2);
|
403
|
+
return setTimeout(function(){ return func.apply(func, args); }, wait);
|
404
|
+
};
|
405
|
+
|
406
|
+
// Defers a function, scheduling it to run after the current call stack has
|
407
|
+
// cleared.
|
408
|
+
_.defer = function(func) {
|
409
|
+
return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
|
410
|
+
};
|
411
|
+
|
412
|
+
// Returns the first function passed as an argument to the second,
|
413
|
+
// allowing you to adjust arguments, run code before and after, and
|
414
|
+
// conditionally execute the original function.
|
415
|
+
_.wrap = function(func, wrapper) {
|
416
|
+
return function() {
|
417
|
+
var args = [func].concat(slice.call(arguments));
|
418
|
+
return wrapper.apply(wrapper, args);
|
419
|
+
};
|
420
|
+
};
|
421
|
+
|
422
|
+
// Returns a function that is the composition of a list of functions, each
|
423
|
+
// consuming the return value of the function that follows.
|
424
|
+
_.compose = function() {
|
425
|
+
var funcs = slice.call(arguments);
|
426
|
+
return function() {
|
427
|
+
var args = slice.call(arguments);
|
428
|
+
for (var i=funcs.length-1; i >= 0; i--) {
|
429
|
+
args = [funcs[i].apply(this, args)];
|
430
|
+
}
|
431
|
+
return args[0];
|
432
|
+
};
|
433
|
+
};
|
434
|
+
|
435
|
+
// Object Functions
|
436
|
+
// ----------------
|
437
|
+
|
438
|
+
// Retrieve the names of an object's properties.
|
439
|
+
// Delegates to **ECMAScript 5**'s native `Object.keys`
|
440
|
+
_.keys = nativeKeys || function(obj) {
|
441
|
+
if (_.isArray(obj)) return _.range(0, obj.length);
|
442
|
+
var keys = [];
|
443
|
+
for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key;
|
444
|
+
return keys;
|
445
|
+
};
|
446
|
+
|
447
|
+
// Retrieve the values of an object's properties.
|
448
|
+
_.values = function(obj) {
|
449
|
+
return _.map(obj, _.identity);
|
450
|
+
};
|
451
|
+
|
452
|
+
// Return a sorted list of the function names available on the object.
|
453
|
+
_.functions = function(obj) {
|
454
|
+
return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();
|
455
|
+
};
|
456
|
+
|
457
|
+
// Extend a given object with all the properties in passed-in object(s).
|
458
|
+
_.extend = function(obj) {
|
459
|
+
each(slice.call(arguments, 1), function(source) {
|
460
|
+
for (var prop in source) obj[prop] = source[prop];
|
461
|
+
});
|
462
|
+
return obj;
|
463
|
+
};
|
464
|
+
|
465
|
+
// Create a (shallow-cloned) duplicate of an object.
|
466
|
+
_.clone = function(obj) {
|
467
|
+
if (_.isArray(obj)) return obj.slice(0);
|
468
|
+
return _.extend({}, obj);
|
469
|
+
};
|
470
|
+
|
471
|
+
// Invokes interceptor with the obj, and then returns obj.
|
472
|
+
// The primary purpose of this method is to "tap into" a method chain, in
|
473
|
+
// order to perform operations on intermediate results within the chain.
|
474
|
+
_.tap = function(obj, interceptor) {
|
475
|
+
interceptor(obj);
|
476
|
+
return obj;
|
477
|
+
};
|
478
|
+
|
479
|
+
// Perform a deep comparison to check if two objects are equal.
|
480
|
+
_.isEqual = function(a, b) {
|
481
|
+
// Check object identity.
|
482
|
+
if (a === b) return true;
|
483
|
+
// Different types?
|
484
|
+
var atype = typeof(a), btype = typeof(b);
|
485
|
+
if (atype != btype) return false;
|
486
|
+
// Basic equality test (watch out for coercions).
|
487
|
+
if (a == b) return true;
|
488
|
+
// One is falsy and the other truthy.
|
489
|
+
if ((!a && b) || (a && !b)) return false;
|
490
|
+
// One of them implements an isEqual()?
|
491
|
+
if (a.isEqual) return a.isEqual(b);
|
492
|
+
// Check dates' integer values.
|
493
|
+
if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
|
494
|
+
// Both are NaN?
|
495
|
+
if (_.isNaN(a) && _.isNaN(b)) return false;
|
496
|
+
// Compare regular expressions.
|
497
|
+
if (_.isRegExp(a) && _.isRegExp(b))
|
498
|
+
return a.source === b.source &&
|
499
|
+
a.global === b.global &&
|
500
|
+
a.ignoreCase === b.ignoreCase &&
|
501
|
+
a.multiline === b.multiline;
|
502
|
+
// If a is not an object by this point, we can't handle it.
|
503
|
+
if (atype !== 'object') return false;
|
504
|
+
// Check for different array lengths before comparing contents.
|
505
|
+
if (a.length && (a.length !== b.length)) return false;
|
506
|
+
// Nothing else worked, deep compare the contents.
|
507
|
+
var aKeys = _.keys(a), bKeys = _.keys(b);
|
508
|
+
// Different object sizes?
|
509
|
+
if (aKeys.length != bKeys.length) return false;
|
510
|
+
// Recursive comparison of contents.
|
511
|
+
for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
|
512
|
+
return true;
|
513
|
+
};
|
514
|
+
|
515
|
+
// Is a given array or object empty?
|
516
|
+
_.isEmpty = function(obj) {
|
517
|
+
if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
|
518
|
+
for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
|
519
|
+
return true;
|
520
|
+
};
|
521
|
+
|
522
|
+
// Is a given value a DOM element?
|
523
|
+
_.isElement = function(obj) {
|
524
|
+
return !!(obj && obj.nodeType == 1);
|
525
|
+
};
|
526
|
+
|
527
|
+
// Is a given value an array?
|
528
|
+
// Delegates to ECMA5's native Array.isArray
|
529
|
+
_.isArray = nativeIsArray || function(obj) {
|
530
|
+
return !!(obj && obj.concat && obj.unshift && !obj.callee);
|
531
|
+
};
|
532
|
+
|
533
|
+
// Is a given variable an arguments object?
|
534
|
+
_.isArguments = function(obj) {
|
535
|
+
return !!(obj && obj.callee);
|
536
|
+
};
|
537
|
+
|
538
|
+
// Is a given value a function?
|
539
|
+
_.isFunction = function(obj) {
|
540
|
+
return !!(obj && obj.constructor && obj.call && obj.apply);
|
541
|
+
};
|
542
|
+
|
543
|
+
// Is a given value a string?
|
544
|
+
_.isString = function(obj) {
|
545
|
+
return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
|
546
|
+
};
|
547
|
+
|
548
|
+
// Is a given value a number?
|
549
|
+
_.isNumber = function(obj) {
|
550
|
+
return (obj === +obj) || (toString.call(obj) === '[object Number]');
|
551
|
+
};
|
552
|
+
|
553
|
+
// Is a given value a boolean?
|
554
|
+
_.isBoolean = function(obj) {
|
555
|
+
return obj === true || obj === false;
|
556
|
+
};
|
557
|
+
|
558
|
+
// Is a given value a date?
|
559
|
+
_.isDate = function(obj) {
|
560
|
+
return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
|
561
|
+
};
|
562
|
+
|
563
|
+
// Is the given value a regular expression?
|
564
|
+
_.isRegExp = function(obj) {
|
565
|
+
return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
|
566
|
+
};
|
567
|
+
|
568
|
+
// Is the given value NaN -- this one is interesting. NaN != NaN, and
|
569
|
+
// isNaN(undefined) == true, so we make sure it's a number first.
|
570
|
+
_.isNaN = function(obj) {
|
571
|
+
return _.isNumber(obj) && isNaN(obj);
|
572
|
+
};
|
573
|
+
|
574
|
+
// Is a given value equal to null?
|
575
|
+
_.isNull = function(obj) {
|
576
|
+
return obj === null;
|
577
|
+
};
|
578
|
+
|
579
|
+
// Is a given variable undefined?
|
580
|
+
_.isUndefined = function(obj) {
|
581
|
+
return typeof obj == 'undefined';
|
582
|
+
};
|
583
|
+
|
584
|
+
// Utility Functions
|
585
|
+
// -----------------
|
586
|
+
|
587
|
+
// Run Underscore.js in *noConflict* mode, returning the `_` variable to its
|
588
|
+
// previous owner. Returns a reference to the Underscore object.
|
589
|
+
_.noConflict = function() {
|
590
|
+
root._ = previousUnderscore;
|
591
|
+
return this;
|
592
|
+
};
|
593
|
+
|
594
|
+
// Keep the identity function around for default iterators.
|
595
|
+
_.identity = function(value) {
|
596
|
+
return value;
|
597
|
+
};
|
598
|
+
|
599
|
+
// Run a function **n** times.
|
600
|
+
_.times = function (n, iterator, context) {
|
601
|
+
for (var i = 0; i < n; i++) iterator.call(context, i);
|
602
|
+
};
|
603
|
+
|
604
|
+
// Break out of the middle of an iteration.
|
605
|
+
_.breakLoop = function() {
|
606
|
+
throw breaker;
|
607
|
+
};
|
608
|
+
|
609
|
+
// Add your own custom functions to the Underscore object, ensuring that
|
610
|
+
// they're correctly added to the OOP wrapper as well.
|
611
|
+
_.mixin = function(obj) {
|
612
|
+
each(_.functions(obj), function(name){
|
613
|
+
addToWrapper(name, _[name] = obj[name]);
|
614
|
+
});
|
615
|
+
};
|
616
|
+
|
617
|
+
// Generate a unique integer id (unique within the entire client session).
|
618
|
+
// Useful for temporary DOM ids.
|
619
|
+
var idCounter = 0;
|
620
|
+
_.uniqueId = function(prefix) {
|
621
|
+
var id = idCounter++;
|
622
|
+
return prefix ? prefix + id : id;
|
623
|
+
};
|
624
|
+
|
625
|
+
// By default, Underscore uses ERB-style template delimiters, change the
|
626
|
+
// following template settings to use alternative delimiters.
|
627
|
+
_.templateSettings = {
|
628
|
+
evaluate : /<\%([\s\S]+?)%>/g,
|
629
|
+
interpolate : /<\%\=([\s\S]+?)%>/g
|
630
|
+
};
|
631
|
+
|
632
|
+
// JavaScript micro-templating, similar to John Resig's implementation.
|
633
|
+
// Underscore templating handles arbitrary delimiters, preserves whitespace,
|
634
|
+
// and correctly escapes quotes within interpolated code.
|
635
|
+
_.template = function(str, data) {
|
636
|
+
var c = _.templateSettings;
|
637
|
+
var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
|
638
|
+
'with(obj||{}){__p.push(\'' +
|
639
|
+
str.replace(/'/g, "\\'")
|
640
|
+
.replace(c.interpolate, function(match, code) {
|
641
|
+
return "'," + code.replace(/\\'/g, "'") + ",'";
|
642
|
+
})
|
643
|
+
.replace(c.evaluate || null, function(match, code) {
|
644
|
+
return "');" + code.replace(/\\'/g, "'")
|
645
|
+
.replace(/[\r\n\t]/g, ' ') + "__p.push('";
|
646
|
+
})
|
647
|
+
.replace(/\r/g, '\\r')
|
648
|
+
.replace(/\n/g, '\\n')
|
649
|
+
.replace(/\t/g, '\\t')
|
650
|
+
+ "');}return __p.join('');";
|
651
|
+
var func = new Function('obj', tmpl);
|
652
|
+
return data ? func(data) : func;
|
653
|
+
};
|
654
|
+
|
655
|
+
// Aliases:
|
656
|
+
// --------
|
657
|
+
|
658
|
+
_.each = _.forEach;
|
659
|
+
_.foldl = _.inject = _.reduce;
|
660
|
+
_.foldr = _.reduceRight;
|
661
|
+
_.select = _.filter;
|
662
|
+
_.all = _.every;
|
663
|
+
_.any = _.some;
|
664
|
+
_.contains = _.include;
|
665
|
+
_.head = _.first;
|
666
|
+
_.tail = _.rest;
|
667
|
+
_.methods = _.functions;
|
668
|
+
|
669
|
+
// The OOP Wrapper
|
670
|
+
// ---------------
|
671
|
+
|
672
|
+
// If Underscore is called as a function, it returns a wrapped object that
|
673
|
+
// can be used OO-style. This wrapper holds altered versions of all the
|
674
|
+
// underscore functions. Wrapped objects may be chained.
|
675
|
+
var wrapper = function(obj) { this._wrapped = obj; };
|
676
|
+
|
677
|
+
// Helper function to continue chaining intermediate results.
|
678
|
+
var result = function(obj, chain) {
|
679
|
+
return chain ? _(obj).chain() : obj;
|
680
|
+
};
|
681
|
+
|
682
|
+
// A method to easily add functions to the OOP wrapper.
|
683
|
+
var addToWrapper = function(name, func) {
|
684
|
+
wrapper.prototype[name] = function() {
|
685
|
+
var args = slice.call(arguments);
|
686
|
+
unshift.call(args, this._wrapped);
|
687
|
+
return result(func.apply(_, args), this._chain);
|
688
|
+
};
|
689
|
+
};
|
690
|
+
|
691
|
+
// Add all of the Underscore functions to the wrapper object.
|
692
|
+
_.mixin(_);
|
693
|
+
|
694
|
+
// Add all mutator Array functions to the wrapper.
|
695
|
+
each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
696
|
+
var method = ArrayProto[name];
|
697
|
+
wrapper.prototype[name] = function() {
|
698
|
+
method.apply(this._wrapped, arguments);
|
699
|
+
return result(this._wrapped, this._chain);
|
700
|
+
};
|
701
|
+
});
|
702
|
+
|
703
|
+
// Add all accessor Array functions to the wrapper.
|
704
|
+
each(['concat', 'join', 'slice'], function(name) {
|
705
|
+
var method = ArrayProto[name];
|
706
|
+
wrapper.prototype[name] = function() {
|
707
|
+
return result(method.apply(this._wrapped, arguments), this._chain);
|
708
|
+
};
|
709
|
+
});
|
710
|
+
|
711
|
+
// Start chaining a wrapped Underscore object.
|
712
|
+
wrapper.prototype.chain = function() {
|
713
|
+
this._chain = true;
|
714
|
+
return this;
|
715
|
+
};
|
716
|
+
|
717
|
+
// Extracts the result from a wrapped and chained object.
|
718
|
+
wrapper.prototype.value = function() {
|
719
|
+
return this._wrapped;
|
720
|
+
};
|
721
|
+
|
722
|
+
})();
|