Skip to content

Instantly share code, notes, and snippets.

@heisters
Created January 26, 2016 22:21
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 heisters/eb89a0f85295c33babc9 to your computer and use it in GitHub Desktop.
Save heisters/eb89a0f85295c33babc9 to your computer and use it in GitHub Desktop.
Simple window hash URL navigation
(function( exports ) {
var onDOMReady = function( fn ) {
if ( document.readyState !== 'loading' ) {
fn();
} else {
document.addEventListener( "DOMContentLoaded", fn );
}
};
exports.onDOMReady = onDOMReady;
})(this);
/**
* MicroEvent - to make any js object an event emitter (server or browser)
*
* - pure javascript - server compatible, browser compatible
* - dont rely on the browser doms
* - super simple - you get it immediatly, no mistery, no magic involved
*
* - create a MicroEventDebug with goodies to debug
* - make it safer to use
*/
(function( exports ) {
var MicroEvent = function(){};
MicroEvent.prototype = {
on: function(event, fct){
this._events = this._events || {};
this._events[event] = this._events[event] || [];
this._events[event].push(fct);
},
off: function(event, fct){
this._events = this._events || {};
if( event in this._events === false ) return;
this._events[event].splice(this._events[event].indexOf(fct), 1);
},
emit: function(event /* , args... */){
this._events = this._events || {};
if( event in this._events === false ) return;
for(var i = 0; i < this._events[event].length; i++){
this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1));
}
}
};
exports.MicroEvent = MicroEvent;
})(this);
(function( exports ) {
var HashManager = function(options) {
if (options == null) options = {};
this.defaults = options.defaults || {};
};
HashManager.prototype = new MicroEvent();
Object.defineProperties( HashManager.prototype, {
bind: { value: function() {
onDOMReady( this.onHashChange.bind( this ) );
window.addEventListener( "hashchange", this.onHashChange.bind( this ) );
} }
, onHashChange: { value: function( event ) {
if ( event ) event.preventDefault();
this.current = this.getAll();
this.emit('change', this);
this.old = this.current;
return false;
} }
, changed: { value: function(param) {
if (this.old == null) return true;
return JSON.stringify(this.get(param)) !== JSON.stringify(this.get(param, this.old));
} }
, getAll: { value: function() {
var compact = function(a) { return a.reduce(function(a2, e) { if (e !== "") a2.push(e); return a2; }, []); }
, decode = function(s) { return decodeURIComponent(s.replace(/\+/g, " ")); }
, hashParams = {}
, part = void 0
, query = window.location.hash.substring(1)
, regex = /([^;=]+)=?([^;]*)/g
, split = function(s) { return s.split(/,/g); }
;
while ( part = regex.exec(query) ) {
hashParams[decode(part[1])] = compact(split(decode(part[2])));
}
return hashParams;
} }
, get: { value: function(param, params) {
if (params == null) params = this.current;
if (params === void 0) return void 0;
return params[param] || this.defaults[param] || [];
} }
, set: { value: function(param, value) {
var current;
if ( !Array.isArray(value) ) value = [value];
current = this.getAll();
current[param] = value;
this.setAll(current);
} }
, setAll: { value: function(params) {
var keys = Object.keys(params).sort()
, keysAndValues = [];
for ( var i = 0, l = keys.length; i < l; ++i ) {
var key = keys[i];
keysAndValues.push("" + key + "=" + (params[key].join(",").replace(/\s/g, '+')));
}
history.pushState( null, null, "#" + (keysAndValues.join(";")) );
} }
, remove: { value: function(param) {
var current = this.getAll();
delete current[param];
this.setAll(current);
} }
, setDefault: { value: function(param, value) {
this.defaults[param] = value;
} }
, bindLinks: { value: function(delegateEl) {
delegateEl.addEventListener( "click", function( event ) {
if ( event.target.matches( "a[href^='#']" ) ) {
event.preventDefault();
var params = event.target.getAttribute("href").substr(1).split('=');
this.set( params[0], params[1] );
}
}.bind( this ) );
} }
} );
exports.HashManager = HashManager;
})(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment