Skip to content

Instantly share code, notes, and snippets.

@nbubna
Created July 11, 2012 14:35
Show Gist options
  • Save nbubna/3090765 to your computer and use it in GitHub Desktop.
Save nbubna/3090765 to your computer and use it in GitHub Desktop.
state.js - browser history and bookmarks for ajax apps
/**
* Copyright (c) 2012, ESHA Research
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* @version 0.4
* @requires jQuery
* @name state
* @author Nathan Bubna
*/
;(function($, window, $doc, location, history) {
var state = window.state = function(id, arg, e) {
return !id ? $.extend({}, _state) :
arg === undefined ? state.of(id, e) :
$.isFunction(arg) ? state.bind(id, arg) :
state.set(id, arg, e);
},
_state = {};
state.of = function(id, e) {
var is = state.get(id),
was = _state[id];
if (!is && !(id in _state)) {
is = state.get(id, true);// check hash for new ids
}
if ((is || was) && is !== was) {
_state[id] = is;
$doc.trigger(id+'.state', is, was, e);
}
return is;
};
state.ofAll = function(e) {
for (var id in _state) state.of(id, e);
};
state.bind = function(id, fn) {
$doc.on(id+'.state', fn);
return state.of(id);// track this id
};
state.get = function(id, hash) {
var re = new RegExp('&?'+id+'=([^&#;$]+)'),
val = state.getAll(hash).match(re) || '';
return val && decodeURIComponent(val[1].replace(/\+/g, '%20'));
};
state.set = function(id, val) {
val = val === undefined || val === null ? '' : ''+val;
if (val !== _state[id]) {
_state[id] = val;
var pair = val ? id+'='+val : '',
re = new RegExp('&?'+id+'=[^&#;$]*&?'),
rest = state.getAll().replace(re, '');
if (pair && rest) pair += '&';
state.setAll(pair+rest);
}
};
state.getAll = function(hash) {
var part = state.hash || hash ? location.hash : location.search;
return part && part.length > 1 ? part.substring(1) : '';
};
state.setAll = function(s) {
history.pushState(null,'', '?'+s+location.hash); // keep hash to play nice
};
$doc
.on('state.state', function(e, id, val){ state(id, val, e); })
.on('back.state', function(){ history.back(); })
.on('forward.state', function(){ history.forward(); });
if ('history' in window && 'pushState' in history) {
$(window).on('popstate.state', state.ofAll);
} else {
state.hash = true;
state.setAll = function(s){ location.hash = s; }
$(window).on('hashchange.state', state.ofAll);
}
})(jQuery, window, $(document), window.location, window.history);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment