/**** * Grapnel * * @author Greg Sabia Tucker * @link https://github.com/baseprime/grapnel * @version 0.7.6 * * Released under MIT License. See LICENSE.txt or http://opensource.org/licenses/MIT */ !function(root){var IS_MODULE="object"===typeof exports;function Grapnel(options){var _this=this;this.options=options||{};this.options.env=this.options.env||(IS_MODULE?"server":"client");this.options.mode=this.options.mode||(!!(this.options.env!=="server"&&this.options.pushState&&root.history&&root.history.pushState)?"pushState":"hashchange");if("function"===typeof root.addEventListener){root.addEventListener("hashchange",function(){_this.trigger("hashchange")});root.addEventListener("popstate",function(e){if(_this.state&&_this.state.previousState===null)return false;_this.trigger("navigate")})}}Grapnel.prototype.events={};Grapnel.prototype.state=null;Grapnel.regexRoute=function(path,keys,sensitive,strict){if(path instanceof RegExp)return path;if(path instanceof Array)path="("+path.join("|")+")";path=path.concat(strict?"":"/?").replace(/\/\(/g,"(?:/").replace(/\+/g,"__plus__").replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g,function(_,slash,format,key,capture,optional){keys.push({name:key,optional:!!optional});slash=slash||"";return""+(optional?"":slash)+"(?:"+(optional?slash:"")+(format||"")+(capture||format&&"([^/.]+?)"||"([^/]+?)")+")"+(optional||"")}).replace(/([\/.])/g,"\\$1").replace(/__plus__/g,"(.+)").replace(/\*/g,"(.*)");return new RegExp("^"+path+"$",sensitive?"":"i")};Grapnel._forEach=function(a,callback){if(typeof Array.prototype.forEach==="function")return Array.prototype.forEach.call(a,callback);return function(c,next){for(var i=0,n=this.length;i2?Array.prototype.slice.call(arguments,1,-1):[],handler=Array.prototype.slice.call(arguments,-1)[0],prefix=context.slice(-1)!=="/"&&value!=="/"&&value!==""?context+"/":context,path=value.substr(0,1)!=="/"?value:value.substr(1),pattern=prefix+path;return _this.add.apply(_this,[pattern].concat(middleware).concat(submiddleware).concat([handler]))}};Grapnel.prototype.navigate=function(path){return this.path(path).trigger("navigate")};Grapnel.prototype.path=function(pathname){var _this=this,frag;if("string"===typeof pathname){if(_this.options.mode==="pushState"){frag=_this.options.root?_this.options.root+pathname:pathname;root.history.pushState({},null,frag)}else if(root.location){root.location.hash=(_this.options.hashBang?"!":"")+pathname}else{root._pathname=pathname||""}return this}else if("undefined"===typeof pathname){if(_this.options.mode==="pushState"){frag=root.location.pathname.replace(_this.options.root,"")}else if(_this.options.mode!=="pushState"&&root.location){frag=root.location.hash?root.location.hash.split(_this.options.hashBang?"#!":"#")[1]:""}else{frag=root._pathname||""}return frag}else if(pathname===false){if(_this.options.mode==="pushState"){root.history.pushState({},null,_this.options.root||"/")}else if(root.location){root.location.hash=_this.options.hashBang?"!":""}return _this}};Grapnel.listen=function(){var opts,routes;if(arguments[0]&&arguments[1]){opts=arguments[0];routes=arguments[1]}else{routes=arguments[0]}return function(){for(var key in routes){this.add.call(this,key,routes[key])}return this}.call(new Grapnel(opts||{}))};function CallStack(router,extendObj){this.stack=CallStack.global.slice(0);this.router=router;this.runCallback=true;this.callbackRan=false;this.propagateEvent=true;this.value=router.path();for(var key in extendObj){this[key]=extendObj[key]}return this}function Request(route){this.route=route;this.keys=[];this.regex=Grapnel.regexRoute(route,this.keys)}CallStack.global=[];CallStack.prototype.preventDefault=function(){this.runCallback=false};CallStack.prototype.stopPropagation=function(){this.propagateEvent=false};CallStack.prototype.parent=function(){var hasParentEvents=!!(this.previousState&&this.previousState.value&&this.previousState.value==this.value);return hasParentEvents?this.previousState:false};CallStack.prototype.callback=function(){this.callbackRan=true;this.timeStamp=Date.now();this.next()};CallStack.prototype.enqueue=function(handler,atIndex){var handlers=!Array.isArray(handler)?[handler]:atIndex