Skip to content

Instantly share code, notes, and snippets.

@daniellizik
Created April 20, 2016 20:53
Show Gist options
  • Save daniellizik/3a1bbdeb915a46097aa5e9116c58172e to your computer and use it in GitHub Desktop.
Save daniellizik/3a1bbdeb915a46097aa5e9116c58172e to your computer and use it in GitHub Desktop.
hash router
(function(name, global, factory) {
//amd
if (typeof global.define === 'function' && global.define.amd)
global.define([], function() { return factory; });
//common js
else if (typeof global.module === 'object' && global.module.exports) {
global.module.exports = factory;
//browser
else if (global.window)
global[name] = factory;
})('hashRouter', this, (function(utils) {
var util = utils(),
$ = util.$,
ui = util.ui;
/**
* @factory simpleHashRouter
*
* config params
* @param attr {string} - name of html5 data attribute to look for, similar to ui-router's <ui-view> directive
* @param otherwise {string} = base route if app is started with no hash route specified
*
* @returns this {object} - context of factory
* @property routes {object} - object literal containing all hash routes as they are registered with the .hash method
* @property config {object} - config object passed to factory
* @property hash {function} - main method used to instantiate new routes
* @property here {string} - the current hash
*/
return function(config) {
var self = {
routes: {},
config: config,
hash: hash,
here: ''
};
watch(self);
otherwise(self);
return self;
}
/**
* @method simpleHashRouter.hash
*
* config params
* @param policy {function} - synchronous function must return true for route to render
* @param resolve {function} - promise to run before route is rendered
* @param after {function} - function to run after route has been rendered
* @param name {string} - name of the route, must be specified in html with configurable attribute
*/
function hash(config) {
var self = this;
var instance = routeFactory.call(self, config);
if (!this.routes.hasOwnProperty(instance.hash))
self.routes[instance.hash] = instance;
return self;
}
function routeFactory(config) {
return {
hash: '#' + config.name,
name: config.name,
after: config.after || function() {},
policy: config.policy || function() { return true; },
resolve: config.resolve || function() { return Promise.resolve(); }
}
}
function watch(self) {
var urls = {}, route;
window.addEventListener('hashchange', function(e) {
loc = location.hash;
//update main factory instance
self.here = loc;
if (self.routes.hasOwnProperty(loc)) {
route = self.routes[loc];
view.call(self, route)
route.after.call(self, route)
}
});
}
function otherwise(self) {
if (!self.here || self.here === '')
location.hash = self.config.otherwise;
}
function view(route) {
var self = this,
attr = self.config.attr,
uiview = ui(attr, self.here.slice(1));
for (p in self.routes) {
if (p !== self.here)
ui(attr, p.slice(1)).style.display = 'none';
//resolve, after
else {
if (route.policy() === true) {
route.resolve().then(function() {
route.after();
uiview.style.display = 'block';
});
}
}
}
}
})(
function utils() {
//crappy jquery
function $(s) {
var list = document.querySelectorAll(s);
if (list.length === 1)
return document.querySelector(s);
else
return Array.prototype.slice.call(list);
}
//finds the uiview easily
function ui(attr, val) {
var selector ='[' + attr + '="' + val + '"]';
return $(selector);
}
return {
$: $,
ui: ui
};
}
));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment