﻿/*
* jQuery history plugin
*
* Copyright (c) 2006 Taku Sano (Mikage Sawatari)
* Licensed under the MIT License:
*   http://www.opensource.org/licenses/mit-license.php
*
* Modified by Lincoln Cooper to add Safari support and only call the callback once during initialization
* for msie when no initial hash supplied.
* API rewrite by Lauris Buk�is-Haberkorns
*/

(function($j) {

    function History() {
        this._curHash = '';
        this._callback = function(hash) { };
    };

    $j.extend(History.prototype, {

        init: function(callback) {
            this._callback = callback;
            this._curHash = location.hash;

            if ($j.browser.msie) {
                // To stop the callback firing twice during initilization if no hash present
                if (this._curHash == '') {
                    this._curHash = '#';
                }

                // add hidden iframe for IE
                $j("body").prepend('<iframe id="jQuery_history" style="display: none;"></iframe>');
                var iframe = $j("#jQuery_history")[0].contentWindow.document;
                iframe.open();
                iframe.close();
                iframe.location.hash = this._curHash;
            }
            else if ($j.browser.safari) {
                // etablish back/forward stacks
                this._historyBackStack = [];
                this._historyBackStack.length = history.length;
                this._historyForwardStack = [];
                this._isFirst = true;
                this._dontCheck = false;
            }
            this._callback(this._curHash.replace(/^#/, ''));
            setInterval(this._check, 100);
        },

        add: function(hash) {
            // This makes the looping function do something
            this._historyBackStack.push(hash);

            this._historyForwardStack.length = 0; // clear forwardStack (true click occured)
            this._isFirst = true;
        },

        _check: function() {
            if ($j.browser.msie) {
                // On IE, check for location.hash of iframe
                var ihistory = $j("#jQuery_history")[0];
                var iframe = ihistory.contentDocument || ihistory.contentWindow.document;
                var current_hash = iframe.location.hash;
                if (current_hash != $j.history._curHash) {

                    location.hash = current_hash;
                    $j.history._curHash = current_hash;
                    $j.history._callback(current_hash.replace(/^#/, ''));

                }
            } else if ($j.browser.safari) {
                if (!$j.history._dontCheck) {
                    var historyDelta = history.length - $j.history._historyBackStack.length;

                    if (historyDelta) { // back or forward button has been pushed
                        $j.history._isFirst = false;
                        if (historyDelta < 0) { // back button has been pushed
                            // move items to forward stack
                            for (var i = 0; i < Math.abs(historyDelta); i++) $j.history._historyForwardStack.unshift($j.history._historyBackStack.pop());
                        } else { // forward button has been pushed
                            // move items to back stack
                            for (var i = 0; i < historyDelta; i++) $j.history._historyBackStack.push($j.history._historyForwardStack.shift());
                        }
                        var cachedHash = $j.history._historyBackStack[$j.history._historyBackStack.length - 1];
                        if (cachedHash != undefined) {
                            $j.history._curHash = location.hash;
                            $j.history._callback(cachedHash);
                        }
                    } else if ($j.history._historyBackStack[$j.history._historyBackStack.length - 1] == undefined && !$j.history._isFirst) {
                        // back button has been pushed to beginning and URL already pointed to hash (e.g. a bookmark)
                        // document.URL doesn't change in Safari
                        if (document.URL.indexOf('#') >= 0) {
                            $j.history._callback(document.URL.split('#')[1]);
                        } else {
                            $j.history._callback('');
                        }
                        $j.history._isFirst = true;
                    }
                }
            } else {
                // otherwise, check for location.hash
                var current_hash = location.hash;
                if (current_hash != $j.history._curHash) {
                    $j.history._curHash = current_hash;
                    $j.history._callback(current_hash.replace(/^#/, ''));
                }
            }
        },

        load: function(hash) {
            var newhash;

            if ($j.browser.safari) {
                newhash = hash;
            } else {
                newhash = '#' + hash;
                location.hash = newhash;
            }
            this._curHash = newhash;

            if ($j.browser.msie) {
                var ihistory = $j("#jQuery_history")[0]; // TODO: need contentDocument?
                var iframe = ihistory.contentWindow.document;
                iframe.open();
                iframe.close();
                iframe.location.hash = newhash;
                this._callback(hash);
            }
            else if ($j.browser.safari) {
                this._dontCheck = true;
                // Manually keep track of the history values for Safari
                this.add(hash);

                // Wait a while before allowing checking so that Safari has time to update the "history" object
                // correctly (otherwise the check loop would detect a false change in hash).
                var fn = function() { $j.history._dontCheck = false; };
                window.setTimeout(fn, 200);
                this._callback(hash);
                // N.B. "location.hash=" must be the last line of code for Safari as execution stops afterwards.
                //      By explicitly using the "location.hash" command (instead of using a variable set to "location.hash") the
                //      URL in the browser and the "history" object are both updated correctly.
                location.hash = newhash;
            }
            else {
                this._callback(hash);
            }
        }
    });

    $j(document).ready(function() {
        $j.history = new History(); // singleton instance
    });

})(jQuery);

