﻿
// namespaces
if(typeof(Clockwork) == 'undefined') var Clockwork = new Object();
if(typeof(Clockwork.Util) == 'undefined') Clockwork.Util = new Object();
if(typeof(Clockwork.Util.Ajax) == 'undefined') Clockwork.Util.Ajax = new Object();

/// <summary>
/// Performs an AJAX request to refresh (parts of) the page content.
/// </summary>
/// <param name="strForm">The name of the form who's fields are to be placed in the new querystring.</param>
/// <param name="fncOnLoad">The function to be called after the content has been refreshed using AJAX.</param>
/// <param name="objEvent">The event that caused this method to be called (optional, but without this parameter the value of a clicked submit button will not be submitted).</param>
/// <param name="strPage">The virtual path to the page that returns the the content as xml (optional, the default value is the current page).</param>
/// <remarks>Usually this method will be called from the html, like this: Clockwork.Util.Ajax.ajaxRefreshContent('myForm', event).</remarks>
Clockwork.Util.Ajax.ajaxRefreshContent = function(strForm, fncOnLoad, objEvent, strPage) {
	if (Clockwork.Util.Ajax.isAjaxEnabled) {
		if (typeof(strPage) == 'undefined' || strPage == null) {
			// no page specified: use current page
			strPage = Clockwork.Util.Ajax.getCurrentPageHref();
		}
		// refresh page content with ajax
		var strQuerystring = Clockwork.Util.Ajax.formToQuerystring(strForm, objEvent);
		var strUrl = strPage + strQuerystring;
		Clockwork.Util.Ajax.ajaxLoad(strUrl, function(blnOk, objXmlHttp) {
			// get response xml
			var objResponseXml;
			if (window.XMLHttpRequest && window.DOMParser) {
				// Mozilla / Opera: parse xml from string
				var parser = new DOMParser();
				objResponseXml = parser.parseFromString(objXmlHttp.responseText, "text/xml");
			} else {
				// IE: get xml from xmlhttp object
				objResponseXml = objXmlHttp.responseXML;
			}	
			
			if (blnOk && objResponseXml && objResponseXml.documentElement) {
				var arrHtmlLinks = document.getElementsByTagName('link');
				var arrHtmlScripts = document.getElementsByTagName('script');
				
				// replace contents of specified nodes
				var arrNodes = objResponseXml.documentElement.childNodes;
				for (var i = 0; i < arrNodes.length; i++) {
					var strFor = arrNodes[i].getAttribute('for');
					if (strFor) {
						var objElement = document.getElementById(strFor);
						if (objElement) {
							var strText = Clockwork.Util.Ajax.getNodeText(arrNodes[i]);
							objElement.innerHTML = strText;
						}
					} else if (arrNodes[i].nodeName == 'head') {
						var xmlHead = arrNodes[i];
						// set new title if specified
						var strTitle = xmlHead.getAttribute('title');
						if (strTitle) document.title = strTitle;
						
						for (var j = 0; j < xmlHead.childNodes.length; j++) {
							var xmlHeadPart = xmlHead.childNodes[j];
							if (xmlHeadPart.nodeName == 'link') {
								// check if allready present
								var strLinkHref = xmlHeadPart.getAttribute('href');
								var blnLinkPresent = false;
								for (var k = 0; k < arrHtmlLinks.length; k++) {
									if (arrHtmlLinks[k].getAttribute('href') == strLinkHref) {
										blnLinkPresent = true;
										break;
									}
								}
								// add if not present
								if (!blnLinkPresent) {
									var objLink = document.createElement('link');
									objLink.type = 'text/css';
									objLink.rel = 'stylesheet';
									objLink.href = strLinkHref;
									document.body.appendChild(objLink);
								}
							} else if (xmlHeadPart.nodeName == 'script') {
								// check if allready present
								var strScriptSrc = xmlHeadPart.getAttribute('src');
								var blnScriptPresent = false;
								for (var k = 0; k < arrHtmlScripts.length; k++) {
									if (arrHtmlScripts[k].getAttribute('src') == strScriptSrc) {
										blnScriptPresent = true;
										break;
									}
								}
								// add if not present
								if (!blnScriptPresent) {
									var objScript = document.createElement('script');
									objScript.src = strScriptSrc;
									objScript.type = xmlHeadPart.getAttribute('type');
									document.body.appendChild(objScript);
								}
							}
						}
					}
				}
				
				// callback function if necessary
				if (typeof(fncOnLoad) == 'function') {
					fncOnLoad();
				}
			} else {
				// AJAX request failed, go to current page with new querystring
				Clockwork.Util.Ajax.noAjaxRefresh(strForm, objEvent);
			}
		});
	} else {
		// AJAX request not allowed, go to current page with new querystring
		Clockwork.Util.Ajax.noAjaxRefresh(strForm, objEvent);
	}
}

/// <summary>
/// Reloads the page in a normal way, without ajax.
/// </summary>
/// <param name="strForm">The name of the form who's fields are to be placed in the new querystring.</param>
/// <param name="objEvent">The event that caused this method to be called (optional, but without this parameter the value of a clicked submit button will not be submitted).</param>
Clockwork.Util.Ajax.noAjaxRefresh = function(strForm, objEvent) {
	var strUrl = Clockwork.Util.Ajax.getCurrentPageHref();
	var strQuerystring = Clockwork.Util.Ajax.formToQuerystring(strForm, objEvent);
	document.location.href = strUrl + strQuerystring;
}

/// <summary>
/// Gets the text contents of an xml node.
/// </summary>
/// <param name="objNode">The node for which to get the text.</param>
/// <returns>The text contents of the specified xml node.</returns>
Clockwork.Util.Ajax.getNodeText = function(objNode) {
	var strText;
	if (typeof(objNode.text) == 'string') {
		// IE
		strText = objNode.text;
	} else if (typeof(objNode.textContent) == 'string') {
		// Mozilla
		strText = objNode.textContent;
	} else if (typeof(objNode.innerText) == 'string') {
		// Opera
		strText = objNode.innerText;
	} else if (objNode.childNodes.length == 1) {
		// IE, Mozilla, others?
		strText = objNode.childNodes[0].data;
	}
	// remove CDATA if present
	if (strText && strText.substr(0, 9) == '<![CDATA[') {
		strText = strText.substr(9, strText.length - 12);
	}
	return strText;
}

/// <summary>
/// Creates a querystring with the values of all the fields in the specified form.
/// </summary>
/// <param name="strForm">The name of the form.</param>
/// <param name="objEvent">The event that caused this method to be called (optional, but without this parameter the value of a clicked submit button will not be submitted).</param>
/// <returns>The querystring with the values of all the fields in the form.</returns>
Clockwork.Util.Ajax.formToQuerystring = function(strForm, objEvent) {
	var arrFields = document.getElementById(strForm).elements;
	var strQuerystring = '?';
	for (var i = 0; i < arrFields.length; i++) {
		var strType = arrFields[i].type;
		// no buttons, and radio and checkboxes only when checked
		if ((strType != 'checkbox' && strType != 'radio' && strType != 'button' && strType != 'submit' && strType != 'reset') || arrFields[i].checked) {
			// urlencode, also the '+', because escape does not encode it
			strQuerystring += escape(arrFields[i].name) + '=' + escape(arrFields[i].value).replace(/\+/g, '%2b') + '&amp;';
		}
	}
	if (typeof(objEvent) != 'undefined' && objEvent != null) {
		// add value of submit button
		var objSubmit = objEvent.srcElement;
		if (!objSubmit) {
			objSubmit = objEvent.originalTarget;
		}
		if (objSubmit && objSubmit.name.length != 0) {
			if ((objSubmit.tagName === 'INPUT' || objSubmit.tagName === 'BUTTON') && objSubmit.type == 'submit') {
				strQuerystring += escape(objSubmit.name) + '=' + escape(objSubmit.value).replace(/\+/g, '%2b') + '&amp;';
			} else if (objSubmit.tagName === 'INPUT' && objSubmit.type == 'image') {
				// if we don't know the coordinates just use 1
				strQuerystring += escape(objSubmit.name) + '.x=' + (objEvent.offsetX ? objEvent.offsetX : 1) + '&amp;' + escape(objSubmit.name) + '.y=' + (objEvent.offsetY ? objEvent.offsetY : 1) + '&amp;';
			}
		}
	}
	return strQuerystring.substr(0, strQuerystring.length - 1);
}

/// <summary>
/// Performs an AJAX request and calls the function 'fncOnLoad' when the AJAX request has completed.
/// </summary>
/// <param name="strUrl">The URL of the page to request.</param>
/// <param name="fncOnLoad">
///		The function to be called when the AJAX request has completed, this function must have signature (blnOk, objXmlHttp).
///		Here blnOk specifies if the status of the AJAX request was 200, and objXmlHttp contains the xmlhttp object.
/// </param>
Clockwork.Util.Ajax.ajaxLoad = function(strUrl, fncOnLoad) {
	var objXmlHttp = Clockwork.Util.Ajax.createXmlHttp();
	objXmlHttp.onreadystatechange = function() {
		// state = 4 means that the response of the server is complete
		if (objXmlHttp.readyState == 4) {
			// status = 200 means that the http request was successful
			fncOnLoad(objXmlHttp.status == 200, objXmlHttp);
		}
	};
	// use HTTP GET, and true for as asynchronous.
	objXmlHttp.open('GET', strUrl, true);
	objXmlHttp.setRequestHeader('x-clockwork-ajax', 'delta');
	// send request to server, null arg when using GET
	objXmlHttp.send(null);	
}

/// <summary>
/// Determines if AJAX is possible for this browser.
/// </summary>
/// <returns>true if AJAX is possible, or false if it is not.</returns>
Clockwork.Util.Ajax._isAjaxEnabled = function() {
	var blnAjaxIsEnabled = false;
	if (document.getElementById) {
		var objXmlHttp = Clockwork.Util.Ajax.createXmlHttp();
		var objXmlDoc = Clockwork.Util.Ajax.createXmlDom();
		if (objXmlHttp && objXmlDoc) {
			if (navigator.userAgent.toLowerCase().indexOf('safari') < 0){
				// no ajax in safari
				blnAjaxIsEnabled = true;
			}
		}
		objXmlHttp = null;
		objXmlDoc = null;
	}
	return blnAjaxIsEnabled;
}

/// <summary>
/// Creates an XmlHttp object depending on the browser.
/// </summary>
/// <returns>The new XmlHttp object, or null.</returns>
Clockwork.Util.Ajax.createXmlHttp = function() {
	var objXmlHttp;
	if (typeof(ActiveXObject) == 'function') {
		try {
			objXmlHttp = new ActiveXObject('Msxml2.XMLHTTP');
		} catch(ex) {
			try {
				objXmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
			} catch(ex2) {
				objXmlHttp = null;
			}
		}
	} else if(typeof(XMLHttpRequest) == 'function') {
		objXmlHttp = new XMLHttpRequest();
	}
	return objXmlHttp;
}

/// <summary>
/// Creates an XmlDom object depending on the browser.
/// </summary>
/// <returns>The new XmlDom object, or null.</returns>
Clockwork.Util.Ajax.createXmlDom = function() {
	var objXmlDom;
	if (typeof(ActiveXObject) == 'function') {
		try {
			objXmlDom = new ActiveXObject('Microsoft.XMLDOM');
		} catch(ex) {
			objXmlDom = null;
		}
	} else if (document.implementation && document.implementation.createDocument) {
		objXmlDom = document.implementation.createDocument('', '', null);
	}
	return objXmlDom;
}

/// <summary>
/// Gets the url to the current page without the querystring.
/// </summary>
/// <returns>The url to the current page without the querystring.</returns>
Clockwork.Util.Ajax.getCurrentPageHref = function() {
	var strUrl = document.location.href;
	// remove querystring
	var intPos = strUrl.indexOf('?');
	if (intPos > 0) {
		strUrl = strUrl.substr(0, intPos);
	}
	return strUrl;
}

/// <summary>
/// Contains a value that specifies if AJAX is possible for this browser.
/// </summary>
/// <value>true if AJAX is possible, or false if it is not.</value>
Clockwork.Util.Ajax.isAjaxEnabled = Clockwork.Util.Ajax._isAjaxEnabled();

