Created
February 20, 2013 00:59
-
-
Save shanna/4991764 to your computer and use it in GitHub Desktop.
A javascript router.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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