/* 
 * Ajax Navigation 0.7.5 (FORKED)
 *  by Weston Ruter, Shepherd Interactive <http://www.shepherd-interactive.com/>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Incorporates portions of DOM-load solutions from jQuery and Prototype.
 * 
 * $Id: ajax-navigation.js 241 2008-05-05 19:16:55Z weston $
 * Copyright 2008, Shepherd Interactive. All rights reserved.
 *
 *
 * Example Usage:
 * <script type="text/javascript" src="ajax-navigation.js"></script>
 * <script type="text/javascript">
 * AjaxNavigation.addUpdateSelector("//html:title");
 * AjaxNavigation.addUpdateSelector("//html:h2[@id='page-title']");
 * AjaxNavigation.addUpdateSelector("//html:ul[@id='navigation']//li", ['class']);
 * AjaxNavigation.addUpdateSelector("//html:div[@id='content']");
 *
 * AjaxNavigation.baseURI = "/ajaxified/sub/directory/"; //defaults to "/"
 *
 * //Note: example using jQuery
 * AjaxNavigation.onenable = function(){
 *    $('#status').html('Ajax Navigation ON!');
 * }
 * AjaxNavigation.ondisable = function(){
 *    $('#status').html('Ajax Navigation OFF!');
 * }
 * $(document).ready(function(){
 *   if(!AjaxNavigation.isReady())
 *   	return;
 *   
 *   //don't use $.click(fn) or else this will be assigned again once page changes via Ajax
 *   $('#toggleAjax').click(function(){ 
 *     if(AjaxNavigation.isEnabled())
 * 	     AjaxNavigation.disable();
 *     else
 *       AjaxNavigation.enable();
 *   });
 * });
 *
 * //The following functions will be called whether Ajax Navigation is enabled or disabled
 * //  whenever the DOM is loaded, and when the page is loaded or is unloaded.
 * //  Important to use these DOM0-Event handlers because it is not possible for MSIE to window.fireEvent('load', fn)
 * $(document).ready(function(){
 *   if(window.AjaxNavigation && AjaxNavigation.isReady())
 *     $('#load-state').html('dom-loaded!');
 * });
 * window.onload = function(){
 *   if(window.AjaxNavigation && AjaxNavigation.isReady())
 *     $('#load-state').html('loaded!');
 * }
 * window.onunload = function(){
 *   if(window.AjaxNavigation && AjaxNavigation.isReady())
 *     $('#load-state').html('unloaded!');
 * }
 * </script>
 * 
 */

(function(){
if(typeof AjaxNavigation != 'undefined')
	return;

var queuedPages = [];
var landed = false;
var initialized = false;
var enabled = true;
var resolvedBaseURI = '';
var previousPathName = "";
var previousPageTarget = "";
var hashChangePollTimer;
var resolvedBaseURI = "";
var reBaseURI = null;
var jQueryReadyList = [];
var ieFrame;
var isOldMSIE = /MSIE [1-7]\D/.test(navigator.userAgent);
var msie_previousHash;
var msie_locationChangePollTimer;
var divsForSWFObject = [];
var isInHistory = true;
var isDOMLoading = true;
var xhr = (function(){
	try {
		return new XMLHttpRequest();
	}
	catch(e){
		if(window.ActiveXObject){
			try {
				return new ActiveXObject('Msxml2.XMLHTTP');
			}
			catch(e){
				try {
					return new ActiveXObject('Microsoft.XMLHTTP');
				}
				catch(e){}
			}
		}
	}
	return null;
})();
var selectorUpdates = [
	//{xpath:'//html:head/html:title', deep:true, attributes:[]},
	//{xpath:'//html:body', deep:true, attributes:['class']}
];

window.AjaxNavigation = {
	baseURI : '/',
	namespacePrefixLookup:{
		html:'http://www.w3.org/1999/xhtml',
		svg:'http://www.w3.org/2000/svg',
		m:'http://www.w3.org/1998/Math/MathML'
	},
	addUpdateSelector: function(xpath/*:String*/, attributes/*:Array = []*/){
		if(!attributes || attributes.length === 0)
			attributes = null;
		else if(typeof attributes == 'string')
			attributes = [attributes];
		
		selectorUpdates.push({
			xpath:xpath,
			attributes:attributes
		});
	},
	
	enabled:true,
	
	init:function init(e){
		if(initialized)
			return;
		initialized = true;
		
		if(!xhr || !enabled || getSavedState() === false){ //this should be in AjaxNavigation.isDisabled()
			AjaxNavigation.disable();
		}
		else {
			AjaxNavigation.enable();
		}
	},
	
	navigate: function(uri){
		//Navigate away from this page if not requesting a page from the base URI
		if(!reBaseURI.test(uri)){
			self.location = uri;
			return;
		}
		self.location = '#' + uri.replace(reBaseURI, '');
		
		//Don't do Ajax if the URL is not part of the base URI
		//if(!reBaseURI.test(el.href))
		//	return;
		
		//Clean up the requested URI
		//uri = uri.replace(/^https?:\/\/[^\/]+/i, '');
		//if(uri.substr(0,1) != '/')
		//	uri = resolvedBaseURI + uri;
	},
	
	hasXHR:function(){
		return !!xhr;
	},
	isReady: function(){
		if(getSavedState() === false)
			return true;
		if(!enabled)
			return true;
		if(!landed)
			return false;
		return true;
	},
	isEnabled: function(){
		return enabled;
	},
	
	onenable:null,
	blankPage:"blank.html", //for MSIE
	enable: function(){
		//if(enabled)
		//	return;
		enabled = true;
		//document.cookie = "AjaxNavigation=1; path=/";
		setSavedState(true);
		if(!ieFrame && isOldMSIE){
			//Prepare and add the iframe to the document
			ieFrame = document.createElement('iframe');
			var hash = self.location.hash.replace(/^#/,'');
			ieFrame.src = AjaxNavigation.blankPage + '?' + hash;
			msie_previousHash = hash;
			ieFrame.style.display = 'none';
			document.body.appendChild(ieFrame);
			
			//Function for checking to see if the iframe's location has changed, i.e. if the back button has been pressed
			var iframeCheckLocation = function(){
				var ieHash = decodeURIComponent(ieFrame.contentWindow.location.search.substr(1));
				if(msie_previousHash != ieHash){
					var topHash = self.location.hash.substr(1);
					if(ieHash != topHash)
						self.location = '#' + ieHash;
					msie_previousHash = ieHash;
				}
			};
			
			//Keep checking the iframe's location to see if it has changed
			msie_locationChangePollTimer = window.setInterval(function(){
				if(!ieFrame)
					window.clearInterval(msie_locationChangePollTimer);
				else
					iframeCheckLocation();
			}, 100);
			ieFrame.onload = iframeCheckLocation;
			ieFrame.onunload = iframeCheckLocation;
			ieFrame.checkLocation = iframeCheckLocation;
		}
		
		setLandedAndResolveURI();
		
		//Poll for location change, or add a hashchanged event handler if supported
		hashChangePollTimer = window.setInterval(function(){
			hashChangeHandler();
		}, 100);
		try {
			if(document.addEventListener)
				document.addEventListener('hashchange', hashChangeHandler, false);
			//else if(document.attachEvent)
			//	document.attachEvent('onhashchange', hashChangeHandler);
			else if(!window.onhashchange)
				window.onhashchange = hashChangeHandler;
		}
		catch(e){}
		
		//Ajaxify all links with event delegation
		//We also need to do Event Delegation for all Form Submit events!
		var body = document.getElementsByTagName('body')[0];
		if(body.addEventListener){
			body.addEventListener('click', linkclick, false);
			//body.addEventListener('submit', formsubmit, false); //TODO
		}
		else if(body.attachEvent){
			body.attachEvent('onclick', linkclick);
			//body.attachEvent('onsubmit', formsubmit); //TODO
		}
		else {
			AjaxNavigation.disable();
			return;
		}
		
		hashChangeHandler();
		
		if(AjaxNavigation.onenable)
			tryFunction(AjaxNavigation.onenable);
	},
	hrefDisallowRegExp: /wp-/,
	ondisable:null,
	disable: function(){
		enabled = false;
		setSavedState(false);
		
		if(ieFrame){
			window.clearInterval(msie_locationChangePollTimer);
			ieFrame.parentNode.removeChild(ieFrame);
			ieFrame = null;
		}
		
		//Stop polling for a change in location.hash, or remove the hashchanged event if supported
		window.clearInterval(hashChangePollTimer);
		try {
			if(document.removeEventListener)
				document.removeEventListener('hashchange', hashChangeHandler);
			else if(document.detachEvent)
				document.detachEvent('onhashchange', hashChangeHandler);
			else
				window.onhashchange = null;
		}
		catch(e){}
		
		//Remove event delegation
		var body = document.getElementsByTagName('body')[0];
		if(body.removeEventListener)
			body.removeEventListener('click', linkclick, false);
		else if(body.detachEvent)
			body.detachEvent('onclick', linkclick);
		
		if(AjaxNavigation.ondisable)
			tryFunction(AjaxNavigation.ondisable);
		
		//Redirect to the non-hash URI if a hash is provided and if it is not simply a page anchor target
		var hash = self.location.hash.substr(1);
		if(hash && !document.getElementById(hash))
			replaceURL(AjaxNavigation.baseURI + hash);
		else
			landed = true;
		
	},
	
	scrollToTop:function(){
		window.scrollTo(0,0);
	},
	
	onloading: function(){
		var body = document.getElementsByTagName('body')[0];
		body.style.cursor = "wait";
	},
	onloaded: function(){
		var body = document.getElementsByTagName('body')[0];
		body.style.cursor = "";
	},
	onhashchange:null
};

//Functions for storing and retreiving whether AjaxNavigation has been enabled
function setSavedState(value){
	if(window.sessionStorage)
		sessionStorage.AjaxNavigation = value ? 1 : 0;
	else
		document.cookie = 'AjaxNavigation=' + (value?1:0) + "; path=/";
}
function getSavedState(value){
	if(window.sessionStorage){
		if(!sessionStorage.AjaxNavigation)
			return undefined;
		return !!parseInt(sessionStorage.AjaxNavigation);
	}
	else {
		var m = document.cookie.match(/AjaxNavigation=(\d)/);
		if(!m)
			return undefined;
		return !!parseInt(m[1]);
	}
}


//INSERT xpathsnapshot.js here
if(typeof XPathSnapshot == 'undefined')
	throw Error('XPathSnapshot not available; include xpathsnapshot.js');

function replaceURL(URL){
	if(isOldMSIE)
		window.setTimeout(function(){
			self.location.replace(URL);
		}, 500);
	else
		self.location.replace(URL);
}


function tryFunction(fn){
	try {
		return fn();
	}
	catch(err){ //throw exception within setTimeout so that the current execution will not be aborted
		setTimeout(function(){
			throw err;
		}, 0); //using 0 milliseconds done at <http://novemberborn.net/javascript/threading-quick-tip>
		return undefined;
	}
}


//function nativeHashChangeHandler(e){
//	alert(window.event)
//	window.clearInterval(hashChangePollTimer);
//	hashChangeHandler(e);
//};
function hashChangeHandler(e){
	//If the hashchange event is supported, stop polling
	if((e && e.type == 'hashchange') || (window.event && event.type == 'hashchange')){
		window.clearInterval(hashChangePollTimer);
	}
	
	//Check to see if the hash has changed and if the actual page has changed and not just the anchor
	var hash/*:String*/ = self.location.hash.substr(1);
	if(hash && document.getElementById(hash))
		return;
	if(/WebKit/.test(navigator.userAgent)) //WebKit seems to uri-encode the second hash
		hash = hash.replace(/%23/, '#');
	var pathName/*:String*/ = hash.replace(/#.*/, '');
	var pageTarget/*:String*/ = hash.replace(/^.*?(#|$)/, '');
	var hasPageTarget/*:String*/ = hash.indexOf('#') != -1;
	//If hash pathName is the same as previous, then we do not do an Ajax request, but just scroll to the page target
	if(pathName == previousPathName){
		if(!isDOMLoading){
			if(hasPageTarget && pageTarget != previousPageTarget && (!pageTarget || document.getElementById(pageTarget))){
				
				//Scroll to top because just hash was provided but empty
				if(!pageTarget)
					window.scrollTo(0,0);
				//Scroll to the element whose ID is the same as the sub-hash
				else {
					var targetEl = document.getElementById(pageTarget);
					if(targetEl.scrollIntoView)
						targetEl.scrollIntoView();
					else {
						var el/*:DOMNode*/ = targetEl;
						var x/*:Number*/ = 0;
						var y/*:Number*/ = 0;
						while(el != null){
							x += el.offsetLeft;
							y += el.offsetTop;
							el = el.offsetParent;
						}
						window.scrollTo(x,y);
					}
				}
			}
			previousPageTarget = pageTarget;
		}
		return;
	}
	
	queuedPages.push(pathName);
	if(ieFrame){
		//Is this even needed?
		var msie_hash = decodeURIComponent(ieFrame.contentWindow.location.search.substr(1));
		if(msie_hash != hash){
			//alert('msie_hash == ' + msie_hash)
			ieFrame.contentWindow.location.search = encodeURIComponent(hash);
		}
	}
	
	//previousPageTarget = pageTarget;
	previousPathName = pathName; //store previous hash
	
	//Load the requested URI via XHR
	if(typeof xhr.abort != 'undefined')
		xhr.abort();
	var url = resolvedBaseURI + hash;
	if(AjaxNavigation.onhashchange)
		tryFunction(AjaxNavigation.onhashchange);
	
	//Only do this if <= IE 7
	if(isOldMSIE){
		var rand = parseInt(Math.random() * 1000000);
		if(url.indexOf('?') == -1){
			if(url.indexOf('#') != -1)
				url = url.replace(/#/, "?an-rand=" + rand + "#");
			else
				url += "?an-rand=" + rand;
		}
		else {
			url = url.replace(/\?/, "?an-rand=" + rand + "&");
		}
	}
		
	if(/MSIE \d/.test(navigator.userAgent))
		url += url.indexOf('?') == -1 ? "?xml=1" : '&xml=1';
	xhr.open('GET', url); //+hash //for MSIE, maybe resolvedBaseURI + pathName + '?RAND#' + pageTarget
	xhr.setRequestHeader('Accept', 'text/xml'); //application/xhtml+xml
	if(xhr.overrideMimeType)
		xhr.overrideMimeType('text/xml');
	//xhr.setRequestHeader('User-Agent', navigator.userAgent + ' Ajax/XMLHttpRequest');
	xhr.onreadystatechange = function(){
		try {
			if(xhr.readyState == 4){
				landed = true;
	
				var docA = document;
				var docB = xhr.responseXML;
				
				//MSIE is dying trying to get an XHTML document over XHR
				if(docB && !docB.documentElement && window.ActiveXObject){
					docB = new ActiveXObject("Microsoft.XMLDOM");
					docB.async = false;
					docB.loadXML(xhr.responseText);
				}
				
				//Unable to get document
				if(!docB)
					throw Error("<p>Error: The document you tried to load is invalid XML.</p>");
				//Internet Explorer parser error
				else if(!docB.documentElement)
					throw Error("Unable to get documentElement from XHR request... either the response does not have a MIME type of text/xml or there is an XML parser error: " + xhr.responseText);
				//Firefox parse error message
				else if(docB.documentElement.nodeName == 'parsererror')
					throw Error("Error: The document you tried to load is invalid XML.");
				//Clone docB onto document based off of selectorUpdates
				
				var documentTitle;
				
				var titleEl;
				if(document.getElementsByTagNameNS)
					titleEL = document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'title')[0];
				if(!titleEl)
					titleEl = document.getElementsByTagName('title')[0];
				
				for(var i = 0; i < selectorUpdates.length; i++){
					var selector = selectorUpdates[i];
					
					//Get the nodes from both documents that need to be updated
					var nodesA = (new XPathSnapshot(selector.xpath, docA, docA, function(prefix){return AjaxNavigation.namespacePrefixLookup[prefix]})).toArray(); //, null, 0, null
					if(!nodesA.length)
						throw Error("XPath expression '" +  selector.xpath + "' returned no elements.");
					var nodesB = (new XPathSnapshot(selector.xpath, docB, docB, function(prefix){return AjaxNavigation.namespacePrefixLookup[prefix]})).toArray(); //, null, 0, null
					if(!nodesB.length)
						throw Error("XPath expression '" +  selector.xpath + "' returned no elements.");
					
					//Special case in IE if the node is the document title
					if(nodesA.length && nodesB.length && nodesA[0] == titleEl && nodesB[0].nodeName.replace(/^.*:/,'').toLowerCase() == 'title'){
						document.title = nodesB[0].firstChild.nodeValue;
						documentTitle = nodesB[0].firstChild.nodeValue; //save and do later for old MSIE
					}
					else if(nodesA[0].nodeType == 1){
						for(var j = 0; j < nodesB.length; j++){
							var nodeA = nodesA[j];
							var nodeB = nodesB[j];
							
							//Only synchronize the indicated attributes
							if(selector.attributes){
								for(var k = 0; k < selector.attributes.length; k++){
									var attrName = selector.attributes[k];
									var attrValue = nodeB.getAttribute(attrName);
									if(!attrValue)
										nodeA.removeAttribute(attrName);
									else if(attrName == 'class')
										nodeA.className = attrValue;
									else if(attrName == 'style')
										nodeA.style.cssText = attrValue;
									else
										nodeA.setAttribute(attrName, attrValue);
								}
							}
							//Replace the entire elements and their children
							else {
								try {
									nodeB = document.importNode(nodeB, true);
								}
								catch(e){
									nodeB = nodeB.cloneNode(true);
									if(document.adoptNode)
										document.adoptNode(nodeB);
								}
		
								try {
									nodeA.parentNode.replaceChild(nodeB, nodeA);
								}
								//Manually clone the nodes into HTML
								catch(e){
									nodeA.parentNode.replaceChild(convertXMLElementToHTML(nodeB), nodeA);
									if(window.swfobject){
										while(divsForSWFObject.length){
											var obj = divsForSWFObject.pop();
											swfobject.embedSWF(
												obj.dataset.params.movie,
												obj.id,
												obj.dataset.attributes.width,
												obj.dataset.attributes.height,
												'8.0.0',
												null,
												null,
												obj.dataset.params,
												obj.dataset.attributes
											);
										}
									}
								}
							}
						}
					}
				}
				
				//Fix for Safari Bug 17897: Not Rendering Images Imported from XHTML Document <http://bugs.webkit.org/show_bug.cgi?id=17897>
				if(/WebKit/.test(navigator.userAgent)){
					var imgs = docA.getElementsByTagName('img');
					for(var i = 0; i < imgs.length; i++)
						imgs[i].src = imgs[i].src;
				}
				
				//For redirects to work for IE and Safari, something "Orig-URI" response header must be returned
				//  by the server to the client. Note that Orig-URI was intended for clients to send to the server, not the other way around
				//  see: http://www.tools.ietf.org/html/draft-ietf-http-v10-spec-01#section-8.21
				//There is also the URI header: http://www.tools.ietf.org/html/draft-ietf-http-v10-spec-01#section-8.28
				
				var destURI;
				//Standard HTML5 HTMLDocument interface; kinda supported by Safari, but does not reflect redirected URL
				if(docB.URL)
					destURI = docB.URI;
				//None support this yet
				else if(docB.location)
					destURI = docB.location.href;
				//Firefox supports this
				else if(docB.baseURI)
					destURI = docB.baseURI;
				//IE should supposedly support this, but doesn't: http://msdn.microsoft.com/en-us/library/ms767669(VS.85).aspx
				else if(docB.url)
					destURI = docB.url;
				
				if(destURI){
					var loadedHash = destURI.replace(reBaseURI, '').replace(/&an-rand=\d*/, '').replace(/\?an-rand=\d*$/, '');
					if(loadedHash != self.location.hash.substr(1)){
						//Save these so that we don't trigger another hashchanged event
						previousPathName = loadedHash.replace(/#.*/, '');
						previousPageTarget = loadedHash.replace(/^.*?(#|$)/, '');
						
						//alert('self.location.replace(' + loadedHash + ')');
						self.location.replace('#' + loadedHash);
						//return;
					}
				}
				
				if(isOldMSIE){
					window.setTimeout(function(){
						document.title = documentTitle;
					}, 500);
				}
				
				queuedPages = [];
				
				tryFunction(fireDOMLoad);
				if(!isInHistory)
					tryFunction(AjaxNavigation.scrollToTop);
				//else
				//	restoreScrollPosition(uri??);
				isInHistory = true;
				
				//NOTE: We need to wait until all external resources are loaded to fire the 'load' event
				tryFunction(fireLoad);
				
				if(AjaxNavigation.onloaded)
					tryFunction(AjaxNavigation.onloaded);
				
			}//End if(xhr.readyState == 4)
		}
		catch(e){
			//Don't throw the error if we have more pages pending to load; it may just be that they aborted too soon
			if(queuedPages.length > 1){
				if(AjaxNavigation.debugging && window.console && console.warn)
					console.warn(e);
				return;
			}
			if(AjaxNavigation.debugging)
				throw e;
			AjaxNavigation.disable();
			return;
		}
	};
	
	//Fire unload handlers
	if(landed)
		tryFunction(fireUnload);
	
	xhr.send(null);
	
	if(AjaxNavigation.onloading)
		tryFunction(AjaxNavigation.onloading);
}
	

function setLandedAndResolveURI(){
	//Reset the baseURI
	if(!AjaxNavigation.baseURI)
		resolvedBaseURI = '/';
	else {
		if(/\.\//.test(AjaxNavigation.baseURI)){
			//AjaxNavigation.disable();
			throw Error("Relative URIs are not allowed for AjaxNavigation.baseURI.");
		}
		//Remove the protocol and domain, and make sure that there is a trailing slash
		resolvedBaseURI = AjaxNavigation.baseURI.replace(/^https?:\/\/[^\/]*/i, '').replace(/(#|\?).+$/,'');
		if(!/\/$/.test(resolvedBaseURI)){
			resolvedBaseURI += '/';
		}
	}
	
	reBaseURI = new RegExp('^(https?:\/\/' + self.location.host.replace(/\./g, '\\.') + "(:" + self.location.port + ")?)?" + resolvedBaseURI.replace(/\./g, '\\.'), 'i');
	var remainingURI = self.location.href.replace(reBaseURI, '');
	if(remainingURI && enabled){
		//Remove tangling ? from URL
		if(remainingURI == '?'){ 
			replaceURL(resolvedBaseURI);
			//console.info('1location.replace(' + resolvedBaseURI)
			return false;
		}
		//Redirect to the baseURI with remainingURI provided as hash
		else if(/^[^#]/.test(remainingURI)){
			replaceURL(resolvedBaseURI + '#' + remainingURI);
			return false;
		}
		//We are coming to the page for the first time and it has a hash which requires us to do an Ajax request
		else if(!landed && /^#.+/.test(remainingURI) && !document.getElementById(remainingURI)){ //THIS SHOULD BE LANDED=TRUE!
			//console.info('We are coming to the page for the first time and it has a hash which requires us to do an Ajax request')
			landed = false;
			return false;
		}
	}
	landed = true;
	return true;
}
	
//Event delegation function to Ajaxify links on the page
function isLinkElement(el){ //MSIE honors 
	var name = el.nodeName.toLowerCase().replace(/.+?:/,'');
	return !!(el.href || (el.getAttributeNodeNS && el.getAttributeNodeNS('http://www.w3.org/1999/xlink', 'href'))) && (name == 'a' || name == 'area');
}
function linkclick(e){
	if(!e)
		e = window.event;
	var el = e.target ? e.target : e.srcElement;
	if(!el)
		return;
	if(!isLinkElement(el)){ //in case an element was clicked inside of a hyperlink element
		while(el = el.parentNode){
			if(isLinkElement(el))
				break;
		}
	}
	if(!el)
		return;

	//We need to put the URI into the hash, but we also need to secretly pass the URI
	//  so that it can go and find out what the final URIs after redirects
	var href;
	if(el.namespaceURI == 'http://www.w3.org/2000/svg' && el.getAttributeNodeNS){
		var hrefNode = el.getAttributeNodeNS('http://www.w3.org/1999/xlink', 'href');
		href = hrefNode.nodeValue;
		if(!/^http:/.test(href)){
			if(href.substr(0, 1) == '/')
				href = el.baseURI.replace(/(#|\?).*/,'') + href.substr(1);
			else //TODO: THIS NEEDS TO BE RESOLVED
				href = el.baseURI.replace(/(#|\?).*/,'') + href;
		}
	}
	else {
		href = el.href;
	}
	
	//Don't do Ajax if the URL is not part of the base URI
	if(!href || !reBaseURI.test(href) || (AjaxNavigation.hrefDisallowRegExp && AjaxNavigation.hrefDisallowRegExp.test(href))){
		return;
	}
	
	var newHash = href.replace(reBaseURI, '');
	
	isInHistory = false; //by being false, this will allow us to scroll to the top
	
	//In order to prevent IE from double clicking, we must not prevent the default action of this click
	//  and change the iframe location at the same time
	if(ieFrame){
		el.originalHref = el.href;
		el.href = '#' + newHash;
		msie_previousHash = newHash;
		window.setTimeout(function(){
			el.href = el.originalHref;
			el.originalHref = null;
		}, 10);
		ieFrame.contentWindow.location.search = encodeURIComponent(newHash);
		return;
	}
	
	if(e.preventDefault)
		e.preventDefault();
	else
		e.returnValue = false;
	
	//Put the URI into the hash
	self.location = '#' + newHash;
	hashChangeHandler();
}

var isSubmittingForm
function formsubmit(e){
	if(!e)
		e = window.event;
	
	//Problem with this is that there
	//We need to get the form contents here, setting a flag to disable onHashChanged from doing anything
	//And then once the form results come back, we would then need to change the URL to match
	// the resultant URL... but this can't be retrieved!
	
	if(e.preventDefault)
		e.preventDefault();
	else
		e.returnValue = false;
	return false;
}

//document.createElement replacement that is aware of MSIE issues
var createElement = (function(){
	try {
		var test = document.createElement('<div id="foo">');
	}
	catch(e){}
	
	if(test && test.nodeName.toLowerCase() == 'div' && test.id == 'foo'){
		return function(nodeName, attrs){
			var tag = '<' + nodeName;
			for(var name in attrs){
				tag += " " + name + '="' + attrs[name].replace(/"/g, '&quot;') + '"';
			}
			tag += '>';
			return document.createElement(tag);
		}
	}
	else {
		return function(nodeName, attrs){
			var el = document.createElement(nodeName);
			for(var name in attrs){
				el.setAttribute(name, attrs[name]);
			}
			return el;
		}
	}
})();

var preserveWhitespaceDepth = 0; //Required for MSIE <= 7

//Function which copies XML nodes into HTML ones if XML DOM can't be directly imported
function convertXMLElementToHTML(source){
	var sourceAttrs = {};
	for(var i = 0; i < source.attributes.length; i++)
		sourceAttrs[source.attributes[i].nodeName] = source.attributes[i].nodeValue;
	
	//This is needed for msie
	if(source.nodeName.toLowerCase() == 'object'){
		
		var obj = createElement('div', {
			'id':source.getAttribute('id'),
			'class':source.getAttribute('class')
		});
		
		if(!obj.dataset) //HTML5
			obj.dataset = {};
		
		obj.dataset.params = {};
		obj.dataset.attributes = sourceAttrs;
		
		var params = source.getElementsByTagName('param');
		for(var i = 0; i < params.length; i++)
			obj.dataset.params[params[i].getAttribute('name')] = params[i].getAttribute('value');
		
		var img = source.getElementsByTagName('img')[0];
		if(img)
			obj.appendChild(convertXMLElementToHTML(img));
		divsForSWFObject.push(obj);
		
		return obj;
	}
	
	var dest = createElement(source.nodeName, sourceAttrs);
	for(var i = 0; i < source.childNodes.length; i++){
		var sourceNode = source.childNodes[i];
		switch(sourceNode.nodeType){
			case 1: /*Node.ELEMENT_NODE*/
				var nodeName = sourceNode.nodeName.toLowerCase();
				if(nodeName == 'pre')
					preserveWhitespaceDepth++;
				var child = convertXMLElementToHTML(sourceNode);
				if(nodeName == 'pre')
					preserveWhitespaceDepth--;
				if(child)
					dest.appendChild(child);
				break;
			case 3: /*Node.TEXT_NODE*/
			case 4: /*Node.CDATA_SECTION_NODE*/
				dest.appendChild(document.createTextNode(!preserveWhitespaceDepth ? sourceNode.nodeValue.replace(/\s\s+/g, ' ') : sourceNode.nodeValue));
				break;
			//case 7: /*Node.PROCESSING_INSTRUCTION_NODE*/
			//	dest.appendChild(document.createProcessingInstruction(sourceNode.nodeValue));
			//	break;
			case 8: /*Node.COMMENT_NODE*/
				dest.appendChild(document.createComment(sourceNode.nodeValue));
				break;
		}
	}
	return dest;
}
	
function fireDOMLoad(){
	isDOMLoading = false;
	
	//Fire jQuery's 'ready' event handlers
	if(window.jQuery && jQuery.ready){
		jQuery.isReady = false;
		//Restore the readyList functions because jQuery deletes them after DOMContentLoaded
		jQuery.readyList = jQueryReadyList;
		//for(var i = 0; i < jQuery.readyList.length; i++)
		//	jQuery.readyList[i]();
		//jQuery(document).ready();
		jQuery.ready();
	}
	
	//Use Prototype to fire dom:loaded events
	//Issue: Prototype does not dispatch DOMContentLoaded events
	if(window.Prototype && document.fire){
		document.loaded = false;
		document.fire('dom:loaded');
		document.loaded = true;
	}
	
	//This works at least in Firefox 2, Opera 9.23, and Safari 3.1.1
	if(document.createEvent && document.dispatchEvent){
		var evt = document.createEvent('HTMLEvents');
		evt.initEvent('DOMContentLoaded', false, false);
		document.dispatchEvent(evt);
	}
	//This is a long shot
	else {
		var scripts = document.getElementsByTagName('script');
		for(var i = 0; i < scripts.length; i++){
			if(scripts[i].onreadystatechange){
				scripts[i].onreadystatechange(evt);
				break;
			}
		}
	}
}
//Save the list of onReady functions to be called again at a late time
if(window.jQuery && jQuery.ready){
	jQuery(document).ready(function(){
		//Save the readyList functions because jQuery deletes them after DOMContentLoaded
		jQueryReadyList = jQuery.readyList;
	});
}

function fireLoad(){
	try {
		var evt;
		if(document.createEvent)
			evt = document.createEvent('HTMLEvents');
		else if(document.createEventObject)
			evt = document.createEventObject();
		
		//This works for Firefox 2 and Opera 9.23, but the object doesn't exist in Safari
		if(window.dispatchEvent){
			evt.initEvent('load', false, false);
			window.dispatchEvent(evt);
		}
		//Safari: The hope was that firing a bubbling load event on BODY would go up to the window
		//        object as it works for onunload, but unfortunately it isn't working
		else if(document.documentElement.dispatchEvent){
			evt.initEvent('load', true, false);
			document.documentElement.dispatchEvent(evt);
		}
		//IE: Unfortunately, no such object
		else if(window.fireEvent){
			window.fireEvent('onload', evt);
		}
	}
	catch(e){}
	if(window.onload)
		window.onload(evt);
}

function fireUnload(){
	isDOMLoading = true;
	try {
		var evt;
		if(document.createEvent)
			evt = document.createEvent('HTMLEvents');
		else if(document.createEventObject)
			evt = document.createEventObject();
		
		//This works for Firefox 2 and Opera 9.23, but the object doesn't exist in Safari
		if(window.dispatchEvent){
			evt.initEvent('unload', false, false);
			window.dispatchEvent(evt);
		}
		//Safari: Since window.dispatchEvent doesn't exist, we fire it on the body element
		//        and have it bubble up to the window object
		else if(document.documentElement.dispatchEvent){
			evt.initEvent('unload', true, false);
			document.documentElement.dispatchEvent(evt);
		}
		//IE: Unfortunately, no such object
		else if(window.fireEvent){
			window.fireEvent('onunload', evt);
		}
	}
	catch(e){}
	
	if(window.onunload)
		window.onunload(evt);
}




/*-------------------------------------------------------------------------------------------
 * Initialization once DOM loads
 *------------------------------------------------------------------------------------------*/
//function init(e){
//	if(initialized)
//		return;
//	initialized = true;
//	
//	if(!AjaxNavigation.hasXHR() || !enabled || getSavedState() === false){ //this should be in AjaxNavigation.isDisabled()
//		AjaxNavigation.disable();
//	}
//	else {
//		AjaxNavigation.enable();
//	}
//}




/*The following was abandoned in favor of manually calling AjaxNavigation.init() on DOM-load*/

///* From Prototype.js:
//   Support for the DOMContentLoaded event is based on work by Dan Webb,
//   Matthias Miller, Dean Edwards and John Resig. */
//
//var timer;
//if(document.addEventListener){
//	document.addEventListener("DOMContentLoaded", init, false);
//	
//	if(/WebKit/.test(navigator.userAgent)){
//		timer = window.setInterval(function(){
//			if (/loaded|complete/.test(document.readyState))
//				init();
//		}, 0);
//		document.addEventListener('load', init, false);
//	}
//}
//else {
//	document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
//	document.getElementById("__onDOMContentLoaded").onreadystatechange = function(){
//		if(this.readyState == "complete"){
//			this.onreadystatechange = null;
//			init();
//		}
//	};
//}
})();