Skip to content

Instantly share code, notes, and snippets.

@shanna
Created February 20, 2013 00:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shanna/4991764 to your computer and use it in GitHub Desktop.
Save shanna/4991764 to your computer and use it in GitHub Desktop.
A javascript router.
/*
Router.
Unlike larger projects (crossroads-min.js ~6.8kb, davis-min.js ~10kb, ...)
this router <1kb is intended to do one thing well; route. No events,
listeners, loggers, history or any other bullshit just a way to execute
callbacks by path.
@example
// document.location.pathname #=> /posts/media/2
var router = new Router;
router.on('/posts/{type}/{id}', function (params) {
console.warn(params); #=> {type: 'media', id: '2'}
});
@todo Optional regexp in capture group.
{name:a-z0-9+} see http://gorilla-web.appspot.com/pkg/pat
@note Requires underscore.js >= 1.4.0 (Sep 27, 2012)
*/
window.Router = (function () {
var Route = function (path, callback) {
var names = [];
re = path.replace(/((\{\w+\})|[-[\]()*+?.,\\^$|#])/g, function (matches, c, capture) {
if (c == '*') {
names.push('splat');
return '(.*?)';
}
else if (c.match(/[-[\]()+?.,\\^$|#]/)) {
return '\\' + c;
}
else if (match = /^\{(\w+)}$/.exec(capture)) {
names.push(match[1]);
return '([^/?#]+)';
}
else {
// TODO: Something has gone badly wrong.
}
});
this._regexp = new RegExp('^' + re + '$');
this._names = names;
this._callback = callback;
};
function build_params (names, captures) {
var name, value, counts = _.countBy(names, function (name) { return name });
return _.reduce(_.zip(names, captures), function (params, param) {
name = param[0], value = param[1];
if (counts[name] > 1) {
if (!params[name]) params[name] = [];
params[name].push(value);
}
else {
params[name] = value;
}
return params;
}, {});
}
Route.prototype = {
test: function (path) {
if (captures = this._regexp.exec(path)) {
this._callback(build_params(this._names, captures.slice(1)));
}
}
};
var Router = function () {
this.routes = [];
};
Router.prototype = {
on: function (path, callback) {
this.routes.push(new Route(path, callback));
},
route: function () {
_.each(this.routes, function (route) { route.test(document.location.pathname) });
},
start: function () {
var router = this;
// Avoid popstate on load chrome bug.
// http://code.google.com/p/chromium/issues/detail?id=63040#c11
router.route();
window.addEventListener('load', function () {
setTimeout(function () {
window.addEventListener('popstate', _.bind(router.route, router));
}, 0);
});
}
};
return Router;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment