<!--
/******************************************************/
/*  CUSTOM AJAX CALL                                  */
/******************************************************/

function AjaxRequest(options) {
	//show "action in progress" animation
	if ($('waitanimation')) $('waitanimation').style.visibility = 'visible';
	var _this		= this;												// Save correct scope of "this"
	this.updating	= false;											// Set to true if this object is already working on a request
	this.async		= (options.async == false) ? false : true;			// asynchronous (default: true) or synchronous (false) call
	this.method		= options.method || 'GET';							// GET: fetch data, POST: update data
	this.onSuccess	= options.onSuccess || function () {}				// A post-processing call -- a stub you overwrite
	this.onFailure	= options.onFailure || function () { trace('Error loading data.',1); }	// A post-processing call -- a stub you overwrite
	this.isHTML		= options.HTML == true ? true : false;
	
	var timestamp	= new Date();
	options.data	= (options.data || '') + (options.data ? '&': '') + 'timestamp='+(timestamp*1);
	
	this.send = function() {											// Initiates server call.
		if (_this.updating == true) {
			trace('Action in progress.\nPlease try again.',1);
			return false;												// Abort if we're already processing a call
		}
		_this.updating = true;
		var AJAX = null;
		if (window.XMLHttpRequest) {
			AJAX = new XMLHttpRequest();								// Mozilla
		} else {
			AJAX = new ActiveXObject("Microsoft.XMLHTTP");				// IE
		}
		if (AJAX == null) {												// Error initializing Ajax
			trace('This application makes extensive use of AJAX.\nPlease upgrade your browser.',1);
			return false;												// Abort
		} else {
			AJAX.onreadystatechange = function() {
				if (AJAX.readyState == 4) {
					_this.updating = false;
					if ((AJAX.status >= 200) && (AJAX.status < 300)) {	//  If page could be loaded
						if (options.debug) trace('return value: '+AJAX.responseText);
						
						if (_this.isHTML) {
							//convert HTML to DOM tree
							var container	= breakApartDOM(AJAX.responseText)
							var DOMtree	= container.tree;
							var Events	= container.script;
							
						} else {
							var DOMtree	= '';
							var Events	= '';
						}
						
						_this.onSuccess(AJAX.responseText, DOMtree, Events);				//	Pass response and status to callback
					} else {
						_this.onFailure();
					}
					delete AJAX;										//	delete the AJAX object since it's done
					if ($('waitanimation')) $('waitanimation').style.visibility = 'hidden';
				}
			}
			var uri = options.url + (options.url.indexOf('?') == 0 ? '&' : '?') + options.data;
			if (options.debug) trace('uri: '+uri);
			AJAX.open(this.method, uri, this.async);					// Open url
			AJAX.send(null);											// Send request
			return true;
		}
	}
}

/* Example use of AjaxRequest() */
function doRequest() {
	var myRequest = new AjaxRequest({
		url: 'testajax.asp',
		data: '',
		onSuccess: function(myResult) {
			trace("*"+myResult, 0);
		}
	});
	myRequest.send();
}

function appendHTML(source, scripts, target) {
	var obj		= target.append || target.before || target.after;
	var atIndex	= target.index;
	
	//append tree (fragment) to target
	if (target.index && target.append) {
		obj.parentNode.insertBefore(source, obj.parentNode.childNodes[atIndex]);
	} else if (target.before) {
		obj.parentNode.insertBefore(source, obj);
	} else if (target.after) {
		obj.parentNode.insertBefore(source, obj.nextSibling);
	} else {
		obj.appendChild(source);
	}
	
	if (scripts) {
		for (var scr = 0; scr < scripts.length; scr++) {
			var text = scripts[scr];
			text = text.substring(text.indexOf('>')+1, text.lastIndexOf('<')-1);
			execJS(text);
		}
	}
}

function breakApartDOM(source) {
/*
*	source = chunk of html
*/
	var match = source.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
	source = (match) ? match[1] : source;
	var scripts = source.match(/<script[^>]*>([\s\S]*?)<\/script>/gi);
	
	var container = document.createDocumentFragment();
	var root = '<root>' + source + '</root>', doc;
	
	if (window.DOMParser){
		doc = new DOMParser().parseFromString(root, 'text/xml');
	} else {
		doc = new ActiveXObject('Microsoft.XMLDOM');
		doc.async = false;
		doc.loadXML(root);
	}
	root = doc.getElementsByTagName('root')[0];
	for (var i = 0; i < root.childNodes.length; i++){
		var child = root.childNodes[i];
		if (child) {
			if (child.nodeName != 'script') container.appendChild(constructNode(child));
		}
	}
	
	return { tree: container, script: scripts };
}

function constructNode(node) {
	var newNode = document.createElement(node.nodeName);
	var attr = node.attributes;
	
	for (var j = 0; j < attr.length; j++) {
		/*	beware of exceptions:
		*		bgcolor	-> bgColor (in IE)
		*		table	-> requires <tbody> (in IE)
		*		class	-> className
		*		style	-> todo !!
		*		events	-> mousedown, mouseup, click, dblclick, mousemove, mouseover, mouseout, focus, blur
		*				-> mouseenter, mouseleave, contextmenu (IE only)
		*				-> http://www.quirksmode.org/dom/events/index.html
		*				-> DO NOT USE! Use "addEvent"-function
		*/
		var attrName	= attr[j].name.toLowerCase();
		var attrVal		= attr[j].value;
		if (attrName == 'bgcolor') attrName = 'bgColor';
		if (attrName == 'class') newNode.className = attrVal; //attrName = 'classname';
		else if (attrName == 'onmousedown'
			|| attrName == 'onmouseup'
			|| attrName == 'onclick'
			|| attrName == 'ondblclick'
			|| attrName == 'onmousemove'
			|| attrName == 'onmouseover'
			|| attrName == 'onmouseout'
			|| attrName == 'onfocus'
			|| attrName == 'onblur'
			|| attrName == 'onmouseenter'
			|| attrName == 'onmouseleave'
			|| attrName == 'oncontextmenu'
		) {
			if (newNode.addEventListener) {
				/* Add with 'addEvent() {}'
				attrName = attrName.substr(2); //strip 'on'
				//trace(newNode.tagName + ' - ' + attrName + ': ' + attrVal);
				//newNode.addEventListener(attrName, eval(attrVal), false);
				if (attrVal.substr(0,7) == 'return ') {
					trace(attrVal.substr(7));
					newNode.addEventListener(attrName, function(event) { return eval(attrVal.substr(7)) }, false);
					
				} else {
					newNode.addEventListener(attrName, function(event) { eval(attrVal) }, false);
				}
				
				/*	Add as normal attribute (works fine in Mozilla-based browsers)
				* /
				newNode.setAttribute(attrName, attrVal);
			} else if (newNode.attachEvent) {
				/*
				newNode.myHandler = eval(attrVal);
				newNode.attachEvent(attrName, function(e) { newNode[myHandler](e); });
				*/
			}
		} else newNode.setAttribute(attrName, attrVal);
	}
	
	for (var k = 0; k < node.childNodes.length; k++) {
		if (node.childNodes[k].nodeName == '#text') newNode.appendChild(document.createTextNode(node.childNodes[k].nodeValue));
		else if (node.childNodes[k].nodeName != 'script') newNode.appendChild(constructNode(node.childNodes[k]));
		//else newScript.appendChild(nodes.node.childNodes[k]);
	}
	
	return newNode;
}

function execJS(text){
	if (window.execScript){
		window.execScript(text);
	} else {
		var script = document.createElement('script');
		script.setAttribute('type', 'text/javascript');
		script.text = text;
		document.getElementsByTagName('head')[0].appendChild(script);
		document.getElementsByTagName('head')[0].removeChild(script);
	}
}

function UpdateSelect(obj, url, data) {
	var myRequest = new AjaxRequest({
		url: url,
		data: data,
		onSuccess: function(myText, myTree, myJS) {
			empty(obj);
			appendHTML(myTree, myJS, { append: obj });
		},
		HTML: true
	});
	myRequest.send();
}

//-->