history.pushState -> location.hash -> query strings (no rewrites needed)

http://benalman.com/

by bizamajig

HTML

<script src="http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js"></script>
<h1>history.pushState -> location.hash -> query string</h1>

<p>I know that using full paths is "all the rage" with pushState-enabled apps and demos, but by using query strings instead of full paths for both the default non-JavaScript links and enhanced pushState versions, the app can remain "single page" and not need any kind of server-side rewrites.</p>

<p>I've tested this in Chrome and FF4 (which support pushState) and FF2 (which doesn't), with JavaScript both enabled and disabled.</p>

<p>I need to spend more time with it, but this feels like a "best of both worlds" approach: it uses the latest technologies in a cool way, degrades well, and is very easy to implement.</p>

<h2>Sample application links:</h2>

<a href="?aaa" class="internal">aaa</a>
<a href="?bbb" class="internal">bbb</a>
<a href="?ccc" class="internal">ccc</a>

<h2>Log:</h2>
<div id="log"></div>

CSS

h1, h2 {
    font-weight: 700;
}

h1, h2, p {
    margin: 0.6em 0;
}

JavaScript

// unsure of the proper test for this
var supports_pushState = 'pushState' in history;

$('a.internal').on('click', function() {
alert( '1 - ' + this.search );    
alert( '2 - ' + this.search.replace( /^\?/, '' ) );    
    var state = this.search.replace( /^\?/, '' );
    if ( supports_pushState ) {
        if ( state !== last_state ) {
            history.pushState( {}, this.title || '', '?' + state );
            handle( state, 'click' );
        }
    } else {
        location.hash = '#' + state;
    }
    
    return false;
});

var last_state;
function handle( state, type ) {
    if ( state !== last_state ) {
        last_state = state;
        
        // application code here
        $('#log').append( 'state: ' + state + ' (' + type + ')<br>');
    }
};

$(window)
    .bind( 'popstate', function(e){
        handle( location.search.replace( /^\?/, '' ), e.type );
    })
    .bind( 'hashchange', function(e){
        handle( location.hash.replace( /^#/, '' ), e.type );
    })
    .trigger( supports_pushState ? 'popstate' : 'hashchange' );