History & Back Button Support using jQuery

History & Back Button Support using jQuery Featuring Ben Alman's (@cowboy) jQuery BBQ Plugin

by Reusablecode

HTML

<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.0/themes/humanity/jquery-ui.css">
<script src="http://github.com/cowboy/jquery-bbq/raw/v1.2.1/jquery.ba-bbq.js"></script>
<script src="http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js"></script>
<div class="demo">
    <ul id="sortable">
        <li id="1" class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Item 1</li>
        <li id="2" class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Item 2</li>
        <li id="3" class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Item 3</li>
        <li id="4" class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Item 4</li>
        <li id="5" class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Item 5</li>
        <li id="6" class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Item 6</li>
        <li id="7" class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Item 7</li>
    </ul>
</div>

<div id="details" title="Tweet" style="display: none;">
    <p>Dialog <span id="dialogNumber">0</span></p>
</div>
<script type="text/javascript">
    firebug.env.height = 200;
    
    $('<a />', { 
        id : 'show',
        text : window.location.pathname.indexOf('show/light') > 0 ? 
            'View Full Screen' : 'Edit using jsFiddle', 
        href : window.location.pathname.indexOf('show/light') > 0 ?
            window.location.pathname.replace(/light\/$/gi, "") :
            window.location.pathname.replace(/show\/$/gi, ""),
        target : '_blank'
    }).appendTo('body');    
</script>

CSS

#sortable { list-style-type: none; margin: 0; padding: 0; width: 60%; }
#sortable li { margin: 0 3px 3px 3px; padding: 0.4em; padding-left: 1.5em; font-size: 1.4em; height: 18px; }
#sortable li span { position: absolute; margin-left: -1.3em; }
#show {position: fixed; top: 0px; right: 0px; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(238, 238, 238); color: rgb(33, 33, 33); border-bottom-left-radius: 10px 10px; border-bottom-width: 1px; border-left-width: 1px; border-bottom-style: solid; border-left-style: solid; border-bottom-color: rgb(153, 153, 153); border-left-color: rgb(153, 153, 153); border-right-width: 0px; border-right-style: initial; border-right-color: initial; border-top-width: 0px; border-top-style: initial; border-top-color: initial; text-decoration: none; font: normal normal normal 14px/normal Helvetica, Arial; display: block; background-position: initial initial; background-repeat: initial initial; }

JavaScript

$("#sortable").sortable({
    update: function(event, ui) {
        //Generate unique id & store list item ids in cache
        var indexes = $(this).sortable("toArray");
        var sequenceId = new Date().valueOf().toString();
        $(this).data('sequence').cache[sequenceId] = indexes;
        $.bbq.pushState({ sequenceId: sequenceId });
    }
}).disableSelection();

$("#sortable li").live('click', function(e) {
    $.bbq.pushState({ dialogId : $(this).attr('id')});
    return false;
});

//Set initial sequence state of page on 1st page load
var initialSequence = $("#sortable").sortable("toArray");
$("#sortable").data('sequence', {
    cache: {
        '': initialSequence
    }
});

$('#details').dialog({
    autoOpen: false,
    width: 800,
    modal: true,
    buttons: {
        "Cancel": function() {
            $(this).dialog("close");
            $.bbq.removeState("dialogId");
        },
        "Save": function() {
            $(this).dialog("close");
            $.bbq.removeState("dialogId");
        }
    }
});

$(window).bind("hashchange", function(e) {
    //sequenceId: Key in cache that refers to list item sequence indexes
    var sequenceId = e.getState("sequenceId") || '',
        //dialogId: Id of the list item that should be used in open dialog
        dialogId = e.getState("dialogId") || '',
        //indexes: Sequence array of the list item ids
        indexes = $("#sortable").data('sequence').cache[sequenceId];
    
    console.log('sequenceId: ' + sequenceId);
    console.log('indexes: ' + indexes);
    console.log('dialogId: ' + dialogId);
    
    //Open dialog using id of list item or close if not present
    if(dialogId) {
        $("#dialogNumber").text(dialogId);
        $('#details').dialog('open');
    } else {
        $('#details').dialog('close');
    }
    
    //Sort the list items based on the indexes stored in cache
    $("#sortable li").reorder(indexes);
});

//Reorder items based on the ids within the indexes...