// -- Sammy -- /sammy.js // http://code.quirkey.com/sammy // Version: 0.4.1 // Built: Mon Jan 11 22:02:15 -0500 2010 (function(f){var c="([^/]+)",e=/:([\w\d]+)/g,b=/\?([^#]*)$/,a=decodeURIComponent,d=[];Sammy={};Sammy.VERSION="0.4.1";Sammy.addLogger=function(g){d.push(g)};Sammy.log=function(){var g=f.makeArray(arguments);g.unshift("["+Date()+"]");f.each(d,function(j,h){h.apply(Sammy,g)})};if(typeof window.console!="undefined"){if(f.isFunction(console.log.apply)){Sammy.addLogger(function(){window.console.log.apply(console,arguments)})}else{Sammy.addLogger(function(){window.console.log(arguments)})}}else{if(typeof console!="undefined"){Sammy.addLogger(function(){console.log.apply(console,arguments)})}}Sammy.Object=function(g){this.extend(g)};f.extend(Sammy.Object.prototype,{extend:function(g){f.extend(this,g)},clone:function(g){if(typeof g=="undefined"){g=this}return f.extend({},g)},toHash:function(){var g={};this.each(function(i,h){if(!f.isFunction(h)){g[i]=h}});return g},toHTML:function(){var g="";this.each(function(i,h){if(!f.isFunction(h)){g+=""+i+" "+h+"
"}});return g},uuid:function(){if(typeof this._uuid=="undefined"||!this._uuid){this._uuid=(new Date()).getTime()+"-"+parseInt(Math.random()*1000)}return this._uuid},each:function(){var i,h,j,g;i=this;if(typeof arguments[0]!="function"){h=arguments[0];j=arguments[1]}else{h=this;j=arguments[0]}g=function(){return j.apply(i,arguments)};f.each(h,g)},keys:function(g){var h=[];for(var i in this){if(!f.isFunction(this[i])||!g){h.push(i)}}return h},join:function(){var h=f.makeArray(arguments);var g=h.shift();return h.join(g)},log:function(){Sammy.log.apply(Sammy,arguments)},toString:function(g){var h=[];this.each(function(j,i){if(!f.isFunction(i)||g){h.push('"'+j+'": '+i.toString())}});return"Sammy.Object: {"+h.join(",")+"}"}});Sammy.HashLocationProxy=function(h,g){this.app=h;if("onhashchange" in window){Sammy.log("native hash change exists, using");this.is_native=true}else{Sammy.log("no native hash change, falling back to polling");this.is_native=false;this._startPolling(g)}};Sammy.HashLocationProxy.prototype={bind:function(){var g=this.app;f(window).bind("hashchange."+this.app.eventNamespace(),function(){g.trigger("location-changed")})},unbind:function(){f(window).die("hashchange."+this.app.eventNamespace())},getLocation:function(){var g=window.location.toString().match(/^[^#]*(#.+)$/);return g?g[1]:""},setLocation:function(g){return window.location=g},_startPolling:function(i){var h=this;if(!Sammy.HashLocationProxy._interval){if(!i){i=10}var g=function(){current_location=h.getLocation();if(!Sammy.HashLocationProxy._last_location||current_location!=Sammy.HashLocationProxy._last_location){setTimeout(function(){f(window).trigger("hashchange")},1)}Sammy.HashLocationProxy._last_location=current_location};g();Sammy.HashLocationProxy._interval=setInterval(g,i);f(window).bind("unload",function(){clearInterval(Sammy.HashLocationProxy._interval)})}}};Sammy.DataLocationProxy=function(h,g){this.app=h;this.data_name=g||"sammy-location"};Sammy.DataLocationProxy.prototype={bind:function(){var g=this;this.app.$element().bind("setData",function(i,h){if(h==g.data_name){g.app.trigger("location-changed")}})},unbind:function(){this.app.$element().die("setData")},getLocation:function(){return this.app.$element().data(this.data_name)},setLocation:function(g){return this.app.$element().data(this.data_name,g)}};Sammy.Application=function(g){var h=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(j,k){this._defineRouteShortcut(k)});if(f.isFunction(g)){g.apply(this,[this])}if(!this.location_proxy){this.location_proxy=new Sammy.HashLocationProxy(h,this.run_interval_every)}if(this.debug){this.bindToAllEvents(function(j,i){h.log(h.toString(),j.cleaned_type,i||{})})}};Sammy.Application.prototype=f.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,location_proxy:null,toString:function(){return"Sammy.Application:"+this.element_selector},$element:function(){return f(this.element_selector)},use:function(){var g=f.makeArray(arguments);var h=g.shift();try{g.unshift(this);h.apply(this,g)}catch(i){if(typeof h=="undefined"){throw ("Error: called use() but plugin is not defined")}else{if(!f.isFunction(h)){throw ("Error: called use() but '"+h.toString()+"' is not a function")}else{throw (i)}}}},route:function(j,h,l){var i=this,k=[],g;if(h.constructor==String){e.lastIndex=0;while((path_match=e.exec(h))!=null){k.push(path_match[1])}h=new RegExp(h.replace(e,c)+"$")}g={verb:j,path:h,callback:l,param_names:k};if(typeof this.routes[j]=="undefined"||this.routes[j].length==0){this.routes[j]=[g]}else{this.routes[j].push(g)}return g},eventNamespace:function(){return[this.data_store_name,this.namespace].join("-")},bind:function(g,i,k){var j=this;if(typeof k=="undefined"){k=i}var h=function(){var n,l,m;n=arguments[0];m=arguments[1];if(m&&m.context){l=m.context;delete m.context}else{l=new j.context_prototype(j,"bind",n.type,m)}n.cleaned_type=n.type.replace(j.eventNamespace(),"");k.apply(l,[n,m])};if(!this.listeners[g]){this.listeners[g]=[]}this.listeners[g].push(h);if(this.isRunning()){return this._listen(g,h)}},trigger:function(g,h){return this.$element().trigger([g,this.eventNamespace()].join("."),[h])},refresh:function(){this.last_location=null},before:function(g){return this.befores.push(g)},after:function(g){return this.bind("event-context-after",g)},isRunning:function(){return this._running},helpers:function(g){f.extend(this.context_prototype.prototype,g)},helper:function(g,h){this.context_prototype.prototype[g]=h},run:function(g){if(this.isRunning()){return false}var h=this;this.each(this.listeners.toHash(),function(i,j){this.each(j,function(l,k){this._listen(i,k)})});this.trigger("run",{start_url:g});this._running=true;this.$element().data(this.data_store_name,this);this.last_location=null;if(this.getLocation()==""&&typeof g!="undefined"){this.setLocation(g)}this._checkLocation();this.location_proxy.bind();this.bind("location-changed",function(){h._checkLocation()});this.bind("changed",function(){h.$element().find("form:not(."+h.eventNamespace()+")").bind("submit",function(){return h._checkFormSubmission(this)}).addClass(h.eventNamespace())});f("body").bind("onunload",function(){h.unload()});this.trigger("changed")},unload:function(){if(!this.isRunning()){return false}var g=this;this.trigger("unload");this.location_proxy.unbind();this.$element().find("form").unbind("submit").removeClass(g.eventNamespace());this.$element().removeData(this.data_store_name);this.each(this.listeners.toHash(),function(h,i){this.each(i,function(k,j){this._unlisten(h,j)})});this._running=false},bindToAllEvents:function(g){this.each(this.APP_EVENTS,function(h,j){this.bind(j,g)});this.each(this.listeners.keys(true),function(j,h){if(this.APP_EVENTS.indexOf(h)==-1){this.bind(h,g)}})},routablePath:function(g){return g.replace(b,"")},lookupRoute:function(i,h){var g=false;this.trigger("lookup-route",{verb:i,path:h});if(typeof this.routes[i]!="undefined"){this.each(this.routes[i],function(k,j){if(this.routablePath(h).match(j.path)){g=j;return false}})}return g},runRoute:function(n,k,m){this.log("runRoute",[n,k].join(" "));this.trigger("run-route",{verb:n,path:k,params:m});if(typeof m=="undefined"){m={}}f.extend(m,this._parseQueryString(k));var h=this.lookupRoute(n,k);if(h){this.trigger("route-found",{route:h});if((path_params=h.path.exec(this.routablePath(k)))!=null){path_params.shift();this.each(path_params,function(o,p){if(h.param_names[o]){m[h.param_names[o]]=a(p)}else{if(!m.splat){m.splat=[]}m.splat.push(a(p))}})}var i=new this.context_prototype(this,n,k,m);this.last_route=h;var g=true;var l=this.befores.slice(0);while(l.length>0){if(l.shift().apply(i)===false){return false}}i.trigger("event-context-before",{context:i});var j=h.callback.apply(i,[i]);i.trigger("event-context-after",{context:i});return j}else{this.notFound(n,k)}},getLocation:function(){return this.location_proxy.getLocation()},setLocation:function(g){return this.location_proxy.setLocation(g)},swap:function(g){return this.$element().html(g)},notFound:function(h,g){this.trigger("error-404",{verb:h,path:g});throw ("404 Not Found "+h+" "+g)},_defineRouteShortcut:function(h){var g=this;this[h]=function(i,j){g.route.apply(g,[h,i,j])}},_checkLocation:function(){try{var g,h;g=this.getLocation();if(g!=this.last_location){h=this.runRoute("get",g)}this.last_location=g}catch(i){this.last_location=g;if(i.toString().match(/^404/)&&this.silence_404){return h}else{throw (i)}}return h},_checkFormSubmission:function(i){var g,k,m,l,h;this.trigger("check-form-submission",{form:i});g=f(i);k=g.attr("action");m=f.trim(g.attr("method").toString().toLowerCase());if(!m||m==""){m="get"}l=f.extend({},this._parseFormParams(g),{"$form":g});try{h=this.runRoute(m,k,l)}catch(j){if(j.toString().match(/^404/)&&this.silence_404){return true}else{throw (j)}}return(typeof h=="undefined")?false:h},_parseFormParams:function(g){var h={};f.each(g.serializeArray(),function(j,k){if(h[k.name]){if(f.isArray(h[k.name])){h[k.name].push(k.value)}else{h[k.name]=[h[k.name],k.value]}}else{h[k.name]=k.value}});return h},_parseQueryString:function(l){var j={},k,h,m,g;k=l.match(b);if(k){h=k[1].split("&");for(g=0;g1){h.unshift("/");i=this.join.apply(this,h)}else{i=h[0]}this.trigger("redirect",{to:i});this.app.last_location=this.path;this.app.setLocation(i);if(g==i){this.app.trigger("location-changed")}},trigger:function(g,h){if(typeof h=="undefined"){h={}}if(!h.context){h.context=this}return this.app.trigger(g,h)},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(" ")}});f.sammy=function(g){return new Sammy.Application(g)}})(jQuery);