Skip to content

Instantly share code, notes, and snippets.

@amclean
Created December 11, 2009 22:45
Show Gist options
  • Save amclean/254576 to your computer and use it in GitHub Desktop.
Save amclean/254576 to your computer and use it in GitHub Desktop.
// Handles JavaScript history management and callbacks. To use, register a
// regexp that matches the history hash with its corresponding callback:
//
// dc.history.register(/^#search/, controller.runSearch);
//
// And then you can save arbitrary history fragments.
//
// dc.history.save('search/freedom/p3');
//
DV.history = {
// The interval at which the window location is polled.
URL_CHECK_INTERVAL : 500,
// We need to use an iFrame to save history if we're in an old version of IE.
USE_IFRAME : jQuery.browser.msie && jQuery.browser.version < 8,
// The ordered list of history handlers matchers and callbacks.
handlers : [],
// executed as a last resort for route matches
defaultCallback: null,
// The current recorded window.location.hash.
hash : window.location.hash,
// Initialize history with an empty set of handlers.
// Bind to the HTML5 'onhashchange' callback, if it exists. Otherwise,
// start polling the window location.
initialize : function() {
_.bindAll(this, 'checkURL');
if (this.USE_IFRAME) this.iframe = jQuery('<iframe src="javascript:0"/>').hide().appendTo('body')[0].contentWindow;
if ('onhashchange' in window) {
window.onhashchange = this.checkURL;
} else {
setInterval(this.checkURL, this.URL_CHECK_INTERVAL);
}
},
// Register a history handler. Pass a regular expression that can be used to
// match your URLs, and the callback to be invoked with the remainder of the
// hash, when matched.
register : function(matcher, callback, defaultRoute) {
this.handlers.push({matcher : matcher, callback : callback});
},
// Save a moment into browser history. Make sure you've registered a handler
// for it. You're responsible for pre-escaping the URL fragment.
save : function(hash) {
window.location.hash = this.hash = (hash ? '#' + hash : '');
if (this.USE_IFRAME && (this.hash != this.iframe.location.hash)) {
this.iframe.document.open().close();
this.iframe.location.hash = this.hash;
}
},
// Check the current URL hash against the recorded one, firing callbacks.
checkURL : function() {
var current = (this.USE_IFRAME ? this.iframe : window).location.hash;
if (current == this.hash || current == decodeURIComponent(this.hash)) return false;
if (this.USE_IFRAME) window.location.hash = current;
this.loadURL();
},
// Load the history callback associated with the current page fragment. On
// pages that support history, this method should be called at page load,
// after all the history callbacks have been registered.
loadURL : function() {
var hash = this.hash = window.location.hash;
// go through matches in reverse order so that oldest rules are executed last
for(var i = this.handlers.length-1; i >= 0; i--){
var match = hash.match(this.handlers[i].matcher);
if (match) {
this.handlers[i].callback(match.slice(1,match.length));
return;
}
}
if(this.defaultCallback != null) this.defaultCallback();
}
};
jQuery(document).ready(function(){ DV.history.initialize(); });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment