Skip to content

Instantly share code, notes, and snippets.

@documentcloud
Forked from amclean/gist:254576
Created December 11, 2009 22:46

Revisions

  1. documentcloud renamed this gist Dec 11, 2009. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. @amclean amclean created this gist Dec 11, 2009.
    82 changes: 82 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,82 @@
    // 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 : [],
    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(); });