| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- /*!
- * routie - a tiny hash router
- * v0.3.2
- * http://projects.jga.me/routie
- * copyright Greg Allen 2013
- * MIT License
- */
- (function(w) {
- var routes = [];
- var map = {};
- var reference = "router";
- var oldReference = w[reference];
- var Route = function(path, name) {
- this.name = name;
- this.path = path;
- this.keys = [];
- this.fns = [];
- this.params = {};
- this.regex = pathToRegexp(this.path, this.keys, false, false);
- };
- Route.prototype.addHandler = function(fn) {
- this.fns.push(fn);
- };
- Route.prototype.removeHandler = function(fn) {
- for (var i = 0, c = this.fns.length; i < c; i++) {
- var f = this.fns[i];
- if (fn == f) {
- this.fns.splice(i, 1);
- return;
- }
- }
- };
- Route.prototype.run = function(params) {
- for (var i = 0, c = this.fns.length; i < c; i++) {
- this.fns[i].apply(this, params);
- }
- };
- Route.prototype.match = function(path, params){
- var m = this.regex.exec(path);
- if (!m) return false;
- for (var i = 1, len = m.length; i < len; ++i) {
- var key = this.keys[i - 1];
- var val = ('string' == typeof m[i]) ? decodeURIComponent(m[i]) : m[i];
- if (key) {
- this.params[key.name] = val;
- }
- params.push(val);
- }
- return true;
- };
- Route.prototype.toURL = function(params) {
- var path = this.path;
- for (var param in params) {
- path = path.replace('/:'+param, '/'+params[param]);
- }
- path = path.replace(/\/:.*\?/g, '/').replace(/\?/g, '');
- if (path.indexOf(':') != -1) {
- throw new Error('missing parameters for url: '+path);
- }
- return path;
- };
- var pathToRegexp = 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');
- };
- var addHandler = function(path, fn) {
- var s = path.split(' ');
- var name = (s.length == 2) ? s[0] : null;
- path = (s.length == 2) ? s[1] : s[0];
- if (!map[path]) {
- map[path] = new Route(path, name);
- routes.push(map[path]);
- }
- map[path].addHandler(fn);
- };
- var routie = function(path, fn) {
- if (typeof fn == 'function') {
- addHandler(path, fn);
- } else if (typeof path == 'object') {
- for (var p in path) {
- addHandler(p, path[p]);
- }
- } else if (typeof fn === 'undefined') {
- routie.navigate(path);
- }
- };
- routie.lookup = function(name, obj) {
- for (var i = 0, c = routes.length; i < c; i++) {
- var route = routes[i];
- if (route.name == name) {
- return route.toURL(obj);
- }
- }
- };
- routie.remove = function(path, fn) {
- var route = map[path];
- if (!route)
- return;
- route.removeHandler(fn);
- };
- routie.removeAll = function() {
- map = {};
- routes = [];
- };
- routie.navigate = function(path, options) {
- options = options || {};
- var silent = options.silent || false;
- if (silent) {
- removeListener();
- }
- setTimeout(function() {
- window.location.hash = path;
- if (silent) {
- setTimeout(function() {
- addListener();
- }, 1);
- }
- }, 1);
- };
- routie.noConflict = function() {
- w[reference] = oldReference;
- return routie;
- };
- var getHash = function() {
- return window.location.hash.substring(1);
- };
- var checkRoute = function(hash, route) {
- var params = [];
- if (route.match(hash, params)) {
- route.run(params);
- return true;
- }
- return false;
- };
- var hashChanged = routie.reload = function() {
- var hash = getHash();
- for (var i = 0, c = routes.length; i < c; i++) {
- var route = routes[i];
- if (checkRoute(hash, route)) {
- return;
- }
- }
- };
- var addListener = function() {
- if (w.addEventListener) {
- w.addEventListener('hashchange', hashChanged, false);
- } else {
- w.attachEvent('onhashchange', hashChanged);
- }
- };
- var removeListener = function() {
- if (w.removeEventListener) {
- w.removeEventListener('hashchange', hashChanged);
- } else {
- w.detachEvent('onhashchange', hashChanged);
- }
- };
- addListener();
- w[reference] = routie;
-
- })(window);
|