var Path = { 'version': "0.8.4", 'map': function (path) { if (Path.routes.defined.hasOwnProperty(path)) { return Path.routes.defined[path]; } else { return new Path.core.route(path); } }, 'root': function (path) { Path.routes.root = path; }, 'rescue': function (fn) { Path.routes.rescue = fn; }, 'history': { 'initial':{}, // Empty container for "Initial Popstate" checking variables. 'pushState': function(state, title, path){ if(Path.history.supported){ if(Path.dispatch(path)){ history.pushState(state, title, path); } } else { if(Path.history.fallback){ window.location.hash = "#" + path; } } }, 'popState': function(event){ var initialPop = !Path.history.initial.popped && location.href == Path.history.initial.URL; Path.history.initial.popped = true; if(initialPop) return; Path.dispatch(document.location.pathname); }, 'listen': function(fallback){ Path.history.supported = !!(window.history && window.history.pushState); Path.history.fallback = fallback; if(Path.history.supported){ Path.history.initial.popped = ('state' in window.history), Path.history.initial.URL = location.href; window.onpopstate = Path.history.popState; } else { if(Path.history.fallback){ for(route in Path.routes.defined){ if(route.charAt(0) != "#"){ Path.routes.defined["#"+route] = Path.routes.defined[route]; Path.routes.defined["#"+route].path = "#"+route; } } Path.listen(); } } } }, 'match': function (path, parameterize) { var params = {}, route = null, possible_routes, slice, i, j, compare; for (route in Path.routes.defined) { if (route !== null && route !== undefined) { route = Path.routes.defined[route]; possible_routes = route.partition(); for (j = 0; j < possible_routes.length; j++) { slice = possible_routes[j]; compare = path; if (slice.search(/:/) > 0) { for (i = 0; i < slice.split("/").length; i++) { if ((i < compare.split("/").length) && (slice.split("/")[i].charAt(0) === ":")) { params[slice.split('/')[i].replace(/:/, '')] = compare.split("/")[i]; compare = compare.replace(compare.split("/")[i], slice.split("/")[i]); } } } if (slice === compare) { if (parameterize) { route.params = params; } return route; } } } } return null; }, 'dispatch': function (passed_route) { var previous_route, matched_route; if (Path.routes.current !== passed_route) { Path.routes.previous = Path.routes.current; Path.routes.current = passed_route; matched_route = Path.match(passed_route, true); if (Path.routes.previous) { previous_route = Path.match(Path.routes.previous); if (previous_route !== null && previous_route.do_exit !== null) { previous_route.do_exit(); } } if (matched_route !== null) { matched_route.run(); return true; } else { if (Path.routes.rescue !== null) { Path.routes.rescue(); } } } }, 'listen': function () { var fn = function(){ Path.dispatch(location.hash); } if (location.hash === "") { if (Path.routes.root !== null) { location.hash = Path.routes.root; } } // The 'document.documentMode' checks below ensure that PathJS fires the right events // even in IE "Quirks Mode". if ("onhashchange" in window && (!document.documentMode || document.documentMode >= 8)) { window.onhashchange = fn; } else { setInterval(fn, 50); } if(location.hash !== "") { Path.dispatch(location.hash); } }, 'core': { 'route': function (path) { this.path = path; this.action = null; this.do_enter = []; this.do_exit = null; this.params = {}; Path.routes.defined[path] = this; } }, 'routes': { 'current': null, 'root': null, 'rescue': null, 'previous': null, 'defined': {} } }; Path.core.route.prototype = { 'to': function (fn) { this.action = fn; return this; }, 'enter': function (fns) { if (fns instanceof Array) { this.do_enter = this.do_enter.concat(fns); } else { this.do_enter.push(fns); } return this; }, 'exit': function (fn) { this.do_exit = fn; return this; }, 'partition': function () { var parts = [], options = [], re = /\(([^}]+?)\)/g, text, i; while (text = re.exec(this.path)) { parts.push(text[1]); } options.push(this.path.split("(")[0]); for (i = 0; i < parts.length; i++) { options.push(options[options.length - 1] + parts[i]); } return options; }, 'run': function () { var halt_execution = false, i, result, previous; if (Path.routes.defined[this.path].hasOwnProperty("do_enter")) { if (Path.routes.defined[this.path].do_enter.length > 0) { for (i = 0; i < Path.routes.defined[this.path].do_enter.length; i++) { result = Path.routes.defined[this.path].do_enter[i].apply(this, null); if (result === false) { halt_execution = true; break; } } } } if (!halt_execution) { Path.routes.defined[this.path].action(); } } };