// -- Sammy -- /sammy.js
// http://code.quirkey.com/sammy
// Version: 0.3.1
// Built: Sat Dec 12 00:34:46 -0500 2009
(function(e){var b="([^/]+)";var d=/:([\w\d]+)/g;var a=/\?([^#]*)$/;var c=[];Sammy={};Sammy.VERSION="0.3.1";Sammy.addLogger=function(f){c.push(f)};Sammy.log=function(){var f=e.makeArray(arguments);f.unshift("["+Date()+"]");e.each(c,function(h,g){g.apply(Sammy,f)})};if(typeof window.console!="undefined"){Sammy.addLogger(function(){window.console.log.apply(window.console,arguments)})}else{if(typeof console!="undefined"){Sammy.addLogger.push(function(){console.log.apply(console,arguments)})}}Sammy.Object=function(f){this.extend(f)};e.extend(Sammy.Object.prototype,{extend:function(f){e.extend(this,f)},clone:function(f){if(typeof f=="undefined"){f=this}return e.extend({},f)},toHash:function(){var f={};this.each(function(h,g){if(!e.isFunction(g)){f[h]=g}});return f},toHTML:function(){var f="";this.each(function(h,g){if(!e.isFunction(g)){f+="<strong>"+h+"</strong> "+g+"<br />"}});return f},uuid:function(){if(typeof this._uuid=="undefined"||!this._uuid){this._uuid=(new Date()).getTime()+"-"+parseInt(Math.random()*1000)}return this._uuid},each:function(){var h,g,i,f;h=this;if(typeof arguments[0]!="function"){g=arguments[0];i=arguments[1]}else{g=this;i=arguments[0]}f=function(){return i.apply(h,arguments)};e.each(g,f)},keys:function(f){var g=[];for(var h in this){if(!e.isFunction(this[h])||!f){g.push(h)}}return g},join:function(){var g=e.makeArray(arguments);var f=g.shift();return g.join(f)},log:function(){Sammy.log.apply(Sammy,arguments)},toString:function(f){var g=[];this.each(function(i,h){if(!e.isFunction(h)||f){g.push('"'+i+'": '+h.toString())}});return"Sammy.Object: {"+g.join(",")+"}"}});Sammy.Application=function(f){var g=this;this.routes={};this.listeners=new Sammy.Object({});this.befores=[];this.namespace=this.uuid();this.context_prototype=function(){Sammy.EventContext.apply(this,arguments)};this.context_prototype.prototype=new Sammy.EventContext();this.each(this.ROUTE_VERBS,function(h,j){this._defineRouteShortcut(j)});if(e.isFunction(f)){f.apply(this,[this])}if(this.debug){this.bindToAllEvents(function(i,h){g.log(g.toString(),i.cleaned_type,h||{})})}};Sammy.Application.prototype=e.extend({},Sammy.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-404","check-form-submission","redirect"],_last_route:null,_running:false,data_store_name:"sammy-app",element_selector:"body",debug:false,silence_404:true,run_interval_every:50,toString:function(){return"Sammy.Application:"+this.element_selector},$element:function(){return e(this.element_selector)},use:function(){var f=e.makeArray(arguments);var g=f.shift();f.unshift(this);g.apply(this,f)},route:function(i,g,k){var h=this,j=[],f;if(g.constructor==String){d.lastIndex=0;while((path_match=d.exec(g))!=null){j.push(path_match[1])}g=new RegExp(g.replace(d,b)+"$")}f={verb:i,path:g,callback:k,param_names:j};if(typeof this.routes[i]=="undefined"||this.routes[i].length==0){this.routes[i]=[f]}else{this.routes[i].push(f)}return f},eventNamespace:function(){return[this.data_store_name,this.namespace].join("-")},bind:function(f,h,j){var i=this;if(typeof j=="undefined"){j=h}var g=function(){var m,k,l;m=arguments[0];l=arguments[1];if(l&&l.context){k=l.context;delete l.context}else{k=new i.context_prototype(i,"bind",m.type,l)}m.cleaned_type=m.type.replace(i.eventNamespace(),"");j.apply(k,[m,l])};if(!this.listeners[f]){this.listeners[f]=[]}this.listeners[f].push(g);if(this.isRunning()){return this._listen(f,g)}},trigger:function(f,g){return this.$element().triggerHandler([f,this.eventNamespace()].join("."),[g])},refresh:function(){this.last_location=null},before:function(f){return this.befores.push(f)},after:function(f){return this.bind("event-context-after",f)},isRunning:function(){return this._running},helpers:function(f){e.extend(this.context_prototype.prototype,f)},run:function(f){if(this.isRunning()){return false}var g=this;this.each(this.listeners.toHash(),function(h,i){this.each(i,function(k,j){this._listen(h,j)})});this.trigger("run",{start_url:f});this._running=true;this.$element().data(this.data_store_name,this);this.last_location=null;if(this.getLocation()==""&&typeof f!="undefined"){this.setLocation(f)}this._checkLocation();this._interval=setInterval(function(){g._checkLocation.apply(g)},this.run_interval_every);this.bind("changed",function(){g.$element().find("form:not(."+g.eventNamespace()+")").bind("submit",function(){return g._checkFormSubmission(this)}).addClass(g.eventNamespace())});e("body").bind("onunload",function(){g.unload()});this.trigger("changed")},unload:function(){if(!this.isRunning()){return false}var f=this;this.trigger("unload");clearInterval(this._interval);this.$element().find("form").unbind("submit").removeClass(f.eventNamespace());this.$element().removeData(this.data_store_name);this.each(this.listeners.toHash(),function(g,h){this.each(h,function(k,j){this._unlisten(g,j)})});this._running=false},bindToAllEvents:function(f){this.each(this.APP_EVENTS,function(g,h){this.bind(h,f)});this.each(this.listeners.keys(true),function(h,g){if(this.APP_EVENTS.indexOf(g)==-1){this.bind(g,f)}})},routablePath:function(f){return f.replace(a,"")},lookupRoute:function(h,g){var f=false;this.trigger("lookup-route",{verb:h,path:g});if(typeof this.routes[h]!="undefined"){this.each(this.routes[h],function(k,j){if(this.routablePath(g).match(j.path)){f=j;return false}})}return f},runRoute:function(m,j,l){this.log("runRoute",[m,j].join(" "));this.trigger("run-route",{verb:m,path:j,params:l});if(typeof l=="undefined"){l={}}e.extend(l,this._parseQueryString(j));var g=this.lookupRoute(m,j);if(g){this.trigger("route-found",{route:g});if((path_params=g.path.exec(this.routablePath(j)))!=null){path_params.shift();this.each(path_params,function(n,o){if(g.param_names[n]){l[g.param_names[n]]=o}else{if(!l.splat){l.splat=[]}l.splat.push(o)}})}var h=new this.context_prototype(this,m,j,l);this.last_route=g;var f=true;var k=this.befores.slice(0);while(k.length>0){if(k.shift().apply(h)===false){return false}}h.trigger("event-context-before",{context:h});var i=g.callback.apply(h,[h]);h.trigger("event-context-after",{context:h});return i}else{this.notFound(m,j)}},getLocation:function(){var f=window.location.toString().match(/^[^#]*(#.+)$/);if(f){return f[1]}else{return""}},setLocation:function(f){window.location=f},swap:function(f){return this.$element().html(f)},notFound:function(g,f){this.trigger("error-404",{verb:g,path:f});throw ("404 Not Found "+g+" "+f)},_defineRouteShortcut:function(g){var f=this;this[g]=function(h,i){f.route.apply(f,[g,h,i])}},_checkLocation:function(){try{var f,g;f=this.getLocation();if(f!=this.last_location){g=this.runRoute("get",f)}this.last_location=f}catch(h){this.last_location=f;if(h.toString().match(/^404/)&&this.silence_404){return g}else{throw (h)}}return g},_checkFormSubmission:function(h){var f,j,l,k,g;this.trigger("check-form-submission",{form:h});f=e(h);j=f.attr("action");l=f.attr("method").toString().toLowerCase();k=e.extend({},this._parseFormParams(f),{"$form":f});try{g=this.runRoute(l,j,k)}catch(i){if(i.toString().match(/^404/)&&this.silence_404){return true}else{throw (i)}}return(typeof g=="undefined")?false:g},_parseFormParams:function(f){var g={};e.each(f.serializeArray(),function(h,j){if(g[j.name]){if(e.isArray(g[j.name])){g[j.name].push(j.value)}else{g[j.name]=[g[j.name],j.value]}}else{g[j.name]=j.value}});return g},_parseQueryString:function(k){var h={},j,g,l,f;j=k.match(a);if(j){g=j[1].split("&");for(f=0;f<g.length;f+=1){l=g[f].split("=");h[l[0]]=l[1]}}return h},_listen:function(f,g){return this.$element().bind([f,this.eventNamespace()].join("."),g)},_unlisten:function(f,g){return this.$element().unbind([f,this.eventNamespace()].join("."),g)}});Sammy.EventContext=function(i,h,f,g){this.app=i;this.verb=h;this.path=f;this.params=new Sammy.Object(g)};Sammy.EventContext.prototype=e.extend({},Sammy.Object.prototype,{$element:function(){return this.app.$element()},partial:function(l,k,m){var h,f,j,g="partial:"+l,i=this;if((j=l.match(/\.([^\.]+)$/))){j=j[1]}if(typeof m=="undefined"){if(e.isFunction(k)){m=k;k={}}else{m=function(n){i.app.swap(n)}}}k=e.extend({},k,this);f=function(n){if(j&&e.isFunction(i[j])){n=i[j].apply(i,[n,k])}m.apply(i,[n]);i.trigger("changed")};if(this.app.cache_partials&&this.cache(g)){f.apply(i,[this.cache(g)])}else{e.get(l,function(n){if(i.app.cache_partials){i.cache(g,n)}f.apply(i,[n])})}},redirect:function(){var g,f=e.makeArray(arguments);if(f.length>1){f.unshift("/");g=this.join.apply(this,f)}else{g=f[0]}this.trigger("redirect",{to:g});this.app.last_location=this.path;return this.app.setLocation(g)},trigger:function(f,g){if(typeof g=="undefined"){g={}}if(!g.context){g.context=this}return this.app.trigger(f,g)},eventNamespace:function(){return this.app.eventNamespace()},notFound:function(){return this.app.notFound(this.verb,this.path)},toString:function(){return"Sammy.EventContext: "+[this.verb,this.path,this.params].join(" ")}});e.sammy=function(f){return new Sammy.Application(f)}})(jQuery);