Files
similarWords/app/js/routie.js
2013-04-06 00:30:43 +02:00

203 lines
4.7 KiB
JavaScript

/*!
* routie - a tiny hash router
* v0.3.0
* https://github.com/jgallen23/routie
* copyright JGA 2012
* MIT License
*/
(function(w) {
var routes = [];
var map = {};
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);
//check against current hash
var hash = getHash();
checkRoute(hash, this);
};
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);
};
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);
} else {
w.attachEvent('onhashchange', hashChanged);
}
};
var removeListener = function() {
if (w.removeEventListener) {
w.removeEventListener('hashchange', hashChanged);
} else {
w.detachEvent('onhashchange', hashChanged);
}
};
addListener();
w.routie = routie;
})(window);