﻿/*
* 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($) {

	function History() {
		this._curHash = '';
		this._callback = function(hash) { };
	};

	$.extend(History.prototype, {

		init: function(callback) {
			this._callback = callback;
			this._curHash = location.hash;

			if ($.browser.msie) {
				// To stop the callback firing twice during initilization if no hash present
				if (this._curHash == '') {
					this._curHash = '#';
				}

				// add hidden iframe for IE
				$("body").prepend('<iframe id="jQuery_history" style="display: none;" src="javascript:void(0);"></iframe>');
				var iframe = $("#jQuery_history")[0].contentWindow.document;
				iframe.open();
				iframe.close();
				iframe.location.hash = this._curHash;
			}
			else if ($.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 ($.browser.msie) {
				// On IE, check for location.hash of iframe
				var ihistory = $("#jQuery_history")[0];
				var iframe = ihistory.contentDocument || ihistory.contentWindow.document;
				var current_hash = iframe.location.hash;
				if (current_hash != $.history._curHash) {

					location.hash = current_hash;
					$.history._curHash = current_hash;
					$.history._callback(current_hash.replace(/^#/, ''));

				}
			} else if ($.browser.safari) {
				if (!$.history._dontCheck) {
					var historyDelta = history.length - $.history._historyBackStack.length;

					if (historyDelta) { // back or forward button has been pushed
						$.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++) $.history._historyForwardStack.unshift($.history._historyBackStack.pop());
						} else { // forward button has been pushed
							// move items to back stack
							for (var i = 0; i < historyDelta; i++) $.history._historyBackStack.push($.history._historyForwardStack.shift());
						}
						var cachedHash = $.history._historyBackStack[$.history._historyBackStack.length - 1];
						if (cachedHash != undefined) {
							$.history._curHash = location.hash;
							$.history._callback(cachedHash);
						}
					} else if ($.history._historyBackStack[$.history._historyBackStack.length - 1] == undefined && !$.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 (location.hash.indexOf('#') >= 0) {
							$.history._callback(location.hash.split('#')[1]);
						} else {
							$.history._callback('');
						}
						$.history._isFirst = true;
					}
				}
			} else {
				// otherwise, check for location.hash
				var current_hash = location.hash;
				if (current_hash != $.history._curHash) {
					$.history._curHash = current_hash;
					$.history._callback(current_hash.replace(/^#/, ''));
				}
			}
		},

		isKonqueror: function() {
			return /KHTML|Konqueror/.test(navigator.userAgent);
		},

		load: function(hash) {
			var newhash;

			if ($.browser.safari) {
				newhash = hash;
			} else {
				newhash = (this.isKonqueror() ? '' : '#') + hash;
				location.hash = newhash;
			}

			this._curHash = newhash;

			if ($.browser.msie) {
				var ihistory = $("#jQuery_history")[0]; // TODO: need contentDocument?
				var iframe = ihistory.contentWindow.document;
				iframe.open();
				iframe.close();
				iframe.location.hash = newhash;
				this._callback(hash);
			}
			else if ($.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() { $.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);
			}
		}
	});

	$(document).ready(function() {
		$.history = new History(); // singleton instance
	});

})(jQuery);