/**
* This Page contains generic Javascript - DHTML functions to assist in writing consistant javascript funcitons
* 
*/

/**
* This section extends the prototype Element
*/
Object.extend(
	Element, {
		getParentByType: function(obj, objType){
			while(obj.parentNode){
				obj = obj.parentNode;
				if (obj.tagName.toUpperCase() == objType.toUpperCase()) {return obj;}
			}
			return false;
		}
	}
)
Object.extend(
	Form.Element.Methods,{
 		 getCleanValue: function(element) {
		    var parameter = "";
		    parameter = Form.Element.Methods.getValue($(element));
		    if (parameter) {
		      return encodeMyHtml(parameter);
		    } else if (parameter == "") {
		    	return "";
		    }
		 }
	}
)
/**
* This section extends the prototype Form
*/
Object.extend(
	Form,{
		fill:function(obj, val){
			val = decodeHtml(val);
			try{
				if(obj.tagName == "INPUT"){
					if(obj.type == "checkbox"){
						if(obj.value == val){
							obj.checked = true;
						}else{obj.checked = false;}
					}else{
						obj.value = val;
					}
				}else if(obj.tagName == "TEXTAREA"){
					//obj.innerHTML = val;
					obj.value = val;
				}else if(obj.tagName == "SELECT"){
					this.setSelect(obj, val);
				}else if(obj.length > 0){
					if(obj[0].type == "radio"){
						for(var i=0;i<obj.length;i++){
							if(obj[i].value == val){
								obj[i].checked = true;
							}
						}
					}else if(obj[0].type == "checkbox"){
						for(var i=0;i<obj.length;i++){
							obj[i].checked = false;
							for(var j=0;j<val.length;j++){
								if(obj[i].value == val[j]){
									obj[i].checked = true;
								}
							}
						}
					}
				}else{/* alert(obj.tagName)*/}
			}catch(err){//alert(typeof obj)
			}
		},
		setSelect: function(sel, val){
			var values = val.split(',');
			for(var j=0;j<values.length;j++) {
				var valItem = values[j];
				for(var i=0;i<sel.options.length;i++){
					if(iw_String.trim(valItem) == sel.options[i].value) {
						sel.options[i].selected = true;
					}
				}
			}
		}
	}
)

/*--------------------------------------------------------------------------*/
/* should overwrite the $F in prototype
*  Why? To get clean(er) data.  That's why.
* NOT INCLUDED IN COMMONTHREAD AS OF 2008-03-03 
*/
/* 
* Requires prototype 1.6
*/
$F = Form.Element.Methods.getCleanValue;

	function encodeMyHtml(html) {
	
	var encodedHtml = '' + html;
	encodedHtml = chkSmartQuotes(encodedHtml);
	encodedHtml = encodedHtml.replace(/\\\"/gm,"\\ \""); // replace \" with \ "
			// (outside of properly escaping things for the several processes that are going on, 
			// this is the easiest method to avoid a problem with json mis-evaluating \" and 
			// throwing an error
	//encodedHtml = encodedHtml.replace(/-/gm,"%2D");
//	encodedHtml = encodedHtml.replace(/@/gm,"%40"); // replace @ symbol
	encodedHtml = encodedHtml.replace(/=/gm,"%3D"); // replace = 
	encodedHtml = encodedHtml.replace(/&/gm,"%26"); // replace &
//	encodedHtml = encodedHtml.replace(/[^()|<>;,&#%:\-\+\*\$\!\?\s\/\.\w]/gm,""); 
	// remove any character that is not in the list above, which is 
	// ()|<>;,&#%:-+*$!?/.[A-Za-z0-9_] and whitespace 
	// if characters are getting deleted -- this function is why.
															
	//  [] -- these cause a isHexDigit error
	encodedHtml = escape(encodedHtml);
    return encodedHtml;
   }
   
   function decodeHtml(html) {
	
	var encodedHtml = '' + html;
//	encodedHtml = chkSmartQuotes(encodedHtml);
	encodedHtml = encodedHtml.replace(/%3D/gm,"="); // replace = 
	encodedHtml = encodedHtml.replace(/%26/,"&"); // replace &
//	encodedHtml = escape(encodedHtml);
    return encodedHtml;
   }
/*--------------------------------------------------------------------------*/
function chkSmartQuotes(html)
{	/* Check http://jdstiles.com/java/cct.html for more values.  or use charCodeAt() and fromCharCode() to find your char; */
	if (html.length > 0) {
		var a=''+html;
		var b=a.length;
		/* single quote values */
		var single = '8217'; /* single 'smart quote' */
		var single2 = '8216';
		
		/* double quote values */
		var doub ='8221'; /* single 'double smart quote' */
		var doub2 ='8220';
		
		var i,j;
		var a2="";
		html="";
		for(j=0;j<b;j++)
		{
			var a1=a.substring(j,j+1);
			a2=a.charCodeAt(j);
			//alert(a2);
			if(a2 == single || a2 == single2)
			{
				a2="'";
				html=html+a2;
			}
			else if(a2 == doub || a2 == doub2)
			{
				a2='"';
				html=html+a2;
			}
			else
			{
				html=html+a1;
			}
		}
	}
	return html;
}

function arrayToURI(name, elementArray) {
	var str = "";
	cnt = 0;
	for (i=0; i<elementArray.length; i++) {
		
		if (cnt>0) {
			str += "&";
		}
		str += name +"="+encodeURIComponent(elementArray[i].value);
		cnt++;
		
	}
	return str;
}

function $2(obj){
	try{
		return $(obj)
	}catch(err){
		alert("Error:\n" + err + "\n" + obj)
		return null;
	}
}
var iw_DHTML = {
	/**
	* adapted from an article found at http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
	*/
	windowScroll:function(){
		var scrOfX = 0, scrOfY = 0;
		if( typeof( window.pageYOffset ) == 'number' ) {
		    //Netscape compliant
		    scrOfY = window.pageYOffset;
		    scrOfX = window.pageXOffset;
		} else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
		    //DOM compliant
		    scrOfY = document.body.scrollTop;
		    scrOfX = document.body.scrollLeft;
		} else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
		    //IE6 standards compliant mode
		    scrOfY = document.documentElement.scrollTop;
		    scrOfX = document.documentElement.scrollLeft;
		}
	  return [ scrOfX, scrOfY ];
	},
	/**
	* adapted from an article found at http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
	*/
	windowSize:function(){
		var myWidth = 0, myHeight = 0;
		if( typeof( window.innerWidth ) == 'number' ) {
			//Non-IE
			myWidth = window.innerWidth;
			myHeight = window.innerHeight;
		} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
		    //IE 6+ in 'standards compliant mode'
			myWidth = document.documentElement.clientWidth;
		    myHeight = document.documentElement.clientHeight;
		} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
		    //IE 4 compatible
		    myWidth = document.body.clientWidth;
		    myHeight = document.body.clientHeight;
		}
	    return [myWidth, myHeight];
	},
	swap: function (obj1, obj2, caller){
		if($2(caller).type == "checkbox"){
			if($(caller).checked){
				$2(obj1).style.display = "none";
				$2(obj2).style.display = "block";
			}else{
				$2(obj2).style.display = "none";
				$2(obj1).style.display = "block";
			}
		}else{
			$2(obj1).style.display = "none";
			$2(obj2).style.display = "block";
		}
		return true;		
	},
	toggle: function (obj1, caller){
		if($(caller).type == "checkbox"){
			if($(caller).checked){
				$(obj1).style.display = "block";
			}else{
				$(obj1).style.display = "none";
			}
		}else{
			if($(obj1).style.display == "none"){
				$(obj1).style.display = "block";
			}else{
				$(obj1).style.display = "none";
			}
		}
		return true;		
	},
	showPopUp : function(obj, text, myClass){
		//call to prototype
		var popUp = this.singleton("singlePopUp", "DIV")
		this.removeChildren(popUp);
		popUp.appendChild(document.createTextNode(text));
		document.body.appendChild(popUp);
		if(myClass != null || myClass != ""){popUp.className = myClass;}
		popUp.myObj = obj;
		this.placeOnTop(obj, popUp);
		window.status=text;
		return popUp;
		//try{popUp.filters.alpha.opacity = 0;}catch(err){}
		//this.fadeIn(popUp, 10);
		//iw_DHTML.parentInfo(obj);
	},
	hidePopUp: function(){
		if(document.getElementById("singlePopUp")){
			var popUp = document.getElementById("singlePopUp");
			this.removeChildren(popUp);
			popUp.className = "noDisplay";
			this.showBleed(popUp);
			window.status="";
			//try{popUp.filters.alpha.opacity = 0;}catch(err){}
		}
	},
	placeOnTop: function(source, target){
		source = $(source);
	    target = $(target);
	    target.style.position = 'absolute';
	    var offsets = Position.cumulativeOffset(source);
	    var scroll = this.windowScroll();
	    var size = this.windowSize();
	    var roomFromEdge = size[0] - offsets[0] + scroll[0];
	    if(roomFromEdge < 200){
	    	//iw_DHTML.alert("scrollLeft " + document.documentElement.scrollLeft)
	    	//iw_DHTML.alert("clientWidth " + (document.body.clientWidth - offsets[0]))
	    	target.style.left = (offsets[0] -  (200 - roomFromEdge)) + 'px';
	    }else{
	    	target.style.left = offsets[0] + 'px';
	    }
	    target.style.top = offsets[1] - target.offsetHeight - 2 + 'px';
	    this.hideBleed(target);
	},
	_w : null,
	alert : function(errtxt){
		try{if(this._w == null){this._w = window.open('',"alertWriter","toolbar=0,location=0,directories=0,status=0,menubar=0,scrollbars=1,resizable=0,width=300,height=600");}}catch(err){}
		var innerT = "";
		try{innerT = this._w.document.body.innerHTML}catch(err){}
		this._w.document.open()
		this._w.document.write(innerT + "<br>" + errtxt);
		this._w.document.close();
	},
	parentInfo: function(obj){
		while(obj.offsetParent){
			iw_DHTML.alert(obj.tagName + " - " + obj.id + " - " + obj.offsetLeft)
			obj = obj.offsetParent
		}
	},
	singleton: function(obj, type){
		if(!$(obj)){
			var name = obj;
			obj = document.createElement(type);
			obj.id = name
		}
		return $(obj);
	},
	removeChildren: function(obj){
		while(obj.childNodes[0]){
			obj.removeChild(obj.childNodes[0]);
		}
	},
	getFirstChildByName: function(obj, type){
		for (var i = 0; i < obj.childNodes.length; i++) {
			var node = obj.childNodes[i];
			if (node.tagName == type){
				return obj.childNodes[i];
			}
		}
		return false;
	},
	fadeIn: function(obj){
		obj = $(obj);
		if(obj.id == null || obj.id == ""){
			var mytime = new Date();
			obj.id = mytime.getTime();
			obj = $(obj);
		}
	   /* try{
			var opacity = obj.style.MozOpacity;
			alert(opacity)
			if(opacity >= 91){opacity = 100;}else if(opacity < 91){opacity += 10;}
			alert(opacity)
			obj.style.MozOpacity = opacity/100; 
	    }catch(err){}*/
	    try{ 
	    	var opacity = obj.filters.alpha.opacity;
			if(opacity >= 91){opacity = 100;}else if(opacity < 91){opacity += 10;}
	    	obj.filters.alpha.opacity = opacity;
	    	setTimeout("iw_DHTML.fadeIn('"+obj.id+"');",50);
	    }catch(err){}
		if(opacity != 100){
	    	//setTimeout("iw_DHTML.fadeIn('"+obj.id+"');",50);
	    }else{
	    	return false;
	    }
	},
	//loops through the Document and hides all elements that will bleed through DHTML
	hideBleed: function(obj){
		var offsets = Position.cumulativeOffset(obj);
		var eT = offsets[1];
		var eH = obj.offsetHeight;
		var eL = offsets[0];
		var eW = obj.offsetHeight;
		var val_ArraySelect = new Array;
		var ctr = 0;
		for (var j=0; j < document.forms.length; j++){
			if(document.forms[j].name != "doNotScan"){
				for (var i=0; i < document.forms[j].elements.length; i++){
					var el = document.forms[j].elements[i];
					if (el.type=="select-one"||el.type=="textarea"||el.type=="select-multiple"){
						offsets = Position.cumulativeOffset(el);
						var thisT = offsets[1];
						var thisH = obj.offsetHeight;
						var thisL = offsets[0];
						var thisW = obj.offsetHeight;
						if(thisT > (eT-thisH) && thisT < (eT+eH)){
							if(thisL+thisW>eL&&thisL<eL+eW){
								if(el.style.visibility != 'hidden'){
									el.style.visibility = 'hidden';
									val_ArraySelect[ctr++]=el;
									obj.hideArray = val_ArraySelect;
								}
							}
						}
					}
				}
			}
		}
	},
	//Shows hidden elements
	showBleed: function(obj){
		if(obj.hideArray){
			val_ArraySelect = obj.hideArray
			for(var i=0;i<val_ArraySelect.length;i++){
				val_ArraySelect[i].style.visibility = 'visible';
			}
			obj.hideArray = null;
		}
	},
	jsonEval:function(json){
		//alert('JSON' + json);
		//alert(json.indexOf('{'));
		//WTB - to catch the script tags
		//if(json.indexOf('[') > 0){
		//	json = json.substr(json.indexOf('['));
		//}else{
		//	json = json.substr(json.indexOf('{'));
		//}
		//alert('JSON2' + json);
		try{
		//	alert('JSON2' + json);
			var obj = eval('(' + json + ')');
		}catch(err){
			var obj = {};
			obj.errMSG = err;
			//alert('error' + err);
		}
		return obj;
	}
}



// HotForm Abstract script for adding, form filling, deleting, clearing, of forms and results table building.

/**
* Current Problems / Issues 
* 	User feeback isn't great, but it's no worse than before for CRUD processes
*		there is no user feedback for a record that returns a response from the process; but the process returns an invalid id or error message
*   In order to fill the table with a saved record (or an edited record) the response is pulled back from the db.
*      It seems a little strange to add a record to the db, and then select that record back from the db.  This whole thing seems like it could be a little tough on busy (or old) servers
*      However, thinking about this one -- this is not unsual in this software (although the list method of saving records did not have this problem)
*   There is an oddity with the way the 'add' must work from the UI jsp.  For some reason, after we add a record, 
*		then attempt to pull the record back from the db, we will retrieve the old record
*		this problem goes away if a short delay is added before attempting to retreive the new record
*/ 

/**
* object hold information regarding form elements
*/
function Form_Var(name) { 
	this.name=name;
	this.isFormVar = true;
	this.domLocation= null;
	this.objValue=null;
	this.display = true; 
	this.defaultValue = "";
	this.clearField = false;
	this.isInnerHTML = false;

	this.stringArray = false; // for using fields where there are multiple instances of the same name/id
	
}
// information regarding the overall display; fields are the fields in general for the display (although the names will match the specific items
function HotDisplay(frmName, listName, url, uniqueFieldName) {
	this.frm = document.getElementById(frmName);
	this.list = document.getElementById(listName);
	this.uniqueFieldName = uniqueFieldName;
	this.feedback = document.getElementById("hf_process_feedback");
	this.fields = Array();
	this.url = url;
	this.uniqueID = null;
	this.postFillFunction; /* a function called after the fill ajax event handled by the form */
	this.postAddFunction; /* a function called after the add ajax event handled by the form */
	this.postDeleteFunction; /* a function called after the delete ajax event handled by the form */
	
	if (document.getElementById("IDHolder") != null) {
		this.IDHolder = document.getElementById("IDHolder");
	} else {
		this.IDHolder = "";
	}
	
	
	this.setPostFillFunction = function(jsFunction) {
		this.postFillFunction = jsFunction;
	}
	this.setPostAddFunction = function(jsFunction) {
		this.postAddFunction = jsFunction;
	}
	this.setPostDeleteFunction = function(jsFunction) {
		this.postDeleteFunction = jsFunction;
	}
	/**
	* setVar needs to be called first when setting up the HotForm
	* defaultVal does not need to be set, but if it is set then realize 
	* 	that setting the default value in setVarClear will overwrite a value that is set here.
	*/
	
	
	this.setVar = function (name, clearField, defaultVal) {// this.setVar = function (name, display) {
		var display;
		if ((document.getElementById(name) != null) || (this.frm[name] != null)){
			this.fields[name] = new Form_Var(name);
			this.fields[name].domLocation = this.frm[name];
			if (display != null) {
				this.fields[name].display = display;
			}
			if (this.fields[name].domLocation == null) {
				this.fields[name].domLocation = document.getElementById(name); // check to see if an element of this id exists somewhere on the page.
			}
			
			if (defaultVal != null){
				this.fields[name].defaultValue = defaultVal;
			}
			if (clearField) {
				this.fields[name].clearField = true;
			}
		}
	
	}
	
	/*
	* this will explictly set the field to be cleared
	* setting the default here will overwrite any previously set value of the defaultValue, ie from setVar
	*/
	this.setVarClear = function (name, defaultVal) {
		this.fields[name].clearField = true;
		if (defaultVal != null) {
			this.fields[name].defaultValue = defaultVal;
		}
	}
	this.unsetVarClear = function (name) {
		this.fields[name].clearField = false;
	}
	
}
/**
* Hold an array of specific item elements, and provides a method for setting those elements
*/
function HFTableVars () {
	this.fields = Array();
	this.setVar = function (name,value, display) {
		this.fields[name] = new Form_Var(name);
		this.fields[name].objValue = value;
		if (display == "") {
			this.fields[name].display = true;
		} else {
			this.fields[name].display = display;
		}
	}
	
}
/** DEBUGGING
*	 - If it is returning the table properly, but to a blank page => Make sure the button is a "button" not a "submit"
*/


/**
* provides the methods needed to submit form vars to a process script.  
*/
function HotForm (hDisplay) { 
	this.frm = hDisplay.frm;
	this.uniqueFieldName = hDisplay.uniqueFieldName;
	this.url = hDisplay.url;
	this.fields = hDisplay.fields;
	this.feedback = hDisplay.feedback;
	this.hDisplay = hDisplay;
	this.IDHolder = hDisplay.IDHolder;
	this.deleteMessage = "Are you sure you want to delete this entry?";
	this.useDeleteOption = false;
	// if use Delete Option is true the user will be presented with a second confirmation form.  
	// if the user selects 'OK' for this confirmation form, 'deleteOption=true' will be appended to the form submission.
	this.deleteOptionMessage = "";

	
	this.clear = function() 
		{
		for (var elementName in this.fields) {
			if (this.fields[elementName].clearField == true) {
				Form.fill(this.fields[elementName].domLocation, this.fields[elementName].defaultValue);
			}
		}
		// this.frm.IDHolder.value = "";  we only want to clear this value after a form row is added.
	}
	this.addResponse = function(t) {
		var obj = iw_DHTML.jsonEval(t.responseText);
		for (var elementName in this.fields) {
			this.fields[elementName].objValue = obj[elementName];
		}
	}
	this.setVars = function(fields) 
		{
		this.fields = fields;
		}

		
	// the fillForm/addRow can be a little hard to follow; so here's a quick explaination
	// the HotForm object will call the process function.
	// after the HotForm object calls the process function a new HotForm object must be created.
	// this new object must first be populated with the Fields of the original HotForm.  
	// The new object will then be populated with the return values of the process function.
	// Any action on these returned values must be completed within the object containing the actual values.
	// note: It is also possible that these functions could return the array of Fields for processing by another object.
	// The reason a new object needs to be created has to do with the way javascript works. There is no way around it.  (The call to an new page means that the original javascript object is out of scope during the process)
	// 
	
	// TODO 
	// 1. create a hook to allow the addition of post functions  (ie, after a record is added to the form I want to set X, y, and delete z)
	// 2. create a function to explicitly clear certain items (different from the default clear settings)
		
	// function to fill a row of the results table with a record from the db
	this.fillRow = function(id, addQuery) { // id should be a java object id
		var fields = this.fields;
		var hDisplay = this.hDisplay;
		var id = id; // if we know the id, great, use it.
		if (id == null) { // if we don't know the id, look for it in the DOM
			id = this.IDHolder.value;
		}
		if (addQuery == null) {
			addQuery = "";
		}
		
		if ((id == null) || (id == 0)) {
			return; // we are dealing with an invalid record.  This should not be added to the table.
		}
		var success = function(transport,json){
						var HF = new HotForm(hDisplay); 
						HF.fillRow_ret(transport);
						}
		var failure = function(transport){
					var HF = new HotForm(hDisplay); 
					HF.fillRow_fail(transport);
					}
		var pars = "action=Get" +"&"+this.uniqueFieldName+"=" + id + addQuery;
		var myAjax = new Ajax.Request(this.url, {
								method:'post', 
								postBody:pars, 
								onSuccess:success, 
								onFailure:failure}); 
								
		}
		
	this.fillRow_ret = function(t)	
		{
		this.addResponse(t); 
		var hTable = new HFTable(hDisplay);
		hTable.addRow(this.fields);
		eval(this.hDisplay.postFillFunction);
	}
	this.fillRow_fail = function(t) 
		{
		alert("This process failed: Refresh the page to continue");
		this.clear();
		}
	
	// function to fill the form
	this.fillForm = function(id, addQuery) { // id should be a java object id
		var fields = this.fields;
		var hDisplay = this.hDisplay;
		if (this.IDHolder.value != null) { // if a record is already in the form, then switch the two records.
			this.fillRow(this.IDHolder.value);
		}
		if (addQuery == null) {
			addQuery = "";
		}
		var success = function(transport,json){
						var HF = new HotForm(hDisplay); 
						HF.fillForm_ret(transport);
						}
		var failure = function(transport){
					var HF = new HotForm(hDisplay); 
					HF.fillForm_fail(transport);
					}
		var pars = "action=Get" +"&"+this.uniqueFieldName+"=" + id + addQuery;
		var myAjax = new Ajax.Request(this.url, {
								method:'post', 
								postBody:pars, 
								onSuccess:success, 
								onFailure:failure}); 
								
		}
		
	this.fillForm_ret = function(t)	
		{
		this.addResponse(t); 
		// foreach element of the vars
		
		for (var elementName in this.fields) {
			if (this.fields[elementName].isFormVar == true) {
				if (this.fields[elementName].isInnerHTML == true) {
					this.fields[elementName].domLocation.innerHTML = this.fields[elementName].objValue;
				} else {
					Form.fill(this.fields[elementName].domLocation, this.fields[elementName].objValue);
				}
			}
		}
		Form.fill(this.hDisplay.IDHolder,this.fields[this.uniqueFieldName].objValue);  // b/c of js scope this.frm.IDHolder.value is different than the instance of this.frm.IDHolder within the instance of HotForm which called the fillForm function.  These two differences are not reconciled until the javascript page is finished (or so it seems)
		eval(this.hDisplay.postFillFunction);
	}
	this.fillForm_fail = function(t) 
		{
		alert("This process failed: Refresh the page to continue");
		this.clear();
		}
		
	// function to call a process that will add a record
	this.add = function(){
	//	$("DoCsave").style.visibility="hidden";
										
		var success = function(t){
					var HF = new HotForm(hDisplay); 
					HF.add_ret(t);}
 		var failure = function(t){
 					var HF = new HotForm(hDisplay); 
 					HF.add_fail(t);
 					}
 		// set the value of each field from the form values
 		for (var fieldName in this.fields) {
 			if ((this.fields[fieldName].isFormVar == true) && (this.fields[fieldName].isInnerHTML == false)) {
 					
 					if ((this.fields[fieldName].domLocation.length>0) && (this.fields[fieldName].domLocation[0].type == "checkbox")) { //sets multiple variable checkboxes, selects, etc
	 					this.fields[fieldName].objValue = Form.getValueFromList(this.fields[fieldName].domLocation);
	 				} else {
	 					if (this.fields[fieldName].domLocation.type == "checkbox") {
	 						this.fields[fieldName].objValue = this.fields[fieldName].domLocation.checked?1:0;
 						} else {
							this.fields[fieldName].objValue = $F(this.fields[fieldName].domLocation); // get the value of the form element named fieldName
						}
					}
					// just in case the $F function doesn't work we'll try a few other methods of grabbing the data.
					if (this.fields[fieldName].objValue == null)  {
						this.fields[fieldName].objValue = this.fields[fieldName].domLocation.value;
					}
					if (this.fields[fieldName].objValue == null)  {
						this.fields[fieldName].objValue = document.getElementById(fieldName).value;
					}
					
					
			}
		}
		var pars = "action=Save";
		 	for (var elementName in this.fields) {
		 		if ((this.fields[elementName].isFormVar == true) && (this.fields[elementName].isInnerHTML == false)) {
		 			if (this.fields[elementName].objValue != null) {
			 			pars = pars + "&" + this.fields[elementName].name +"="+ this.fields[elementName].objValue;
			 		} else  {
			 			pars = pars + "&" + this.fields[elementName].name +"=";
			 		}
		 		}
		 	}
		// alert(pars);
		var myAjax = new Ajax.Request(this.url, {method:'post', postBody:pars, onSuccess:success, onFailure:failure});
	}
	this.add_ret = function(t){
	//	this.feedback.innerHTML = "Saved"; // iw_String.trim(t.responseText);
	//	this.feedback.style.display="inline";
		hDisplay.list.innerHTML = iw_String.trim(t.responseText);
	//	var obj = iw_DHTML.jsonEval(t.responseText);
	//	this.fillRow(obj[this.uniqueFieldName]);
	//	this.IDHolder.value = obj[this.uniqueFieldName];
	//	this.IDHolder.value = "";
	forEach(document.getElementsByTagName('table'), function(table) {
		//	alert(table.id);
	      if (table.className.search(/\bsortable\b/) != -1) {
    		    sorttable.makeSortable(table);
      		}
    	})
		this.clear();
	eval(this.hDisplay.postAddFunction);		
	}
	this.add_fail = function(t){
		alert("This process failed: Refresh the page to continue");
		this.clear();
		return false;
	}
	
	// delete a record
	this.del = function(id, addQuery){
		if(confirm(this.deleteMessage)){
			if (addQuery == null) {
				addQuery = "";
			}
			var success = function(t){
				var HF = new HotForm(hDisplay); 
				HF.del_ret(t);
				}
			var failure = function(t){
				var HF = new HotForm(hDisplay); 
				HF.del_fail(t, id);}
			var pars = "action=Delete" + "&"+this.uniqueFieldName+"=" + id + addQuery;
			if (this.useDeleteOption) {
				if (confirm(this.deleteOptionMessage)) {
					pars = pars + "&deleteOption=true";
					// delete option is true if user selects 'OK' on additional question
				}
			}
			var myAjax = new Ajax.Request(this.url, {method:'post', postBody:pars, onSuccess:success, onFailure:failure});
		}
	}
	this.del_ret = function(t){
		hDisplay.list.innerHTML = iw_String.trim(t.responseText);
		this.clear();
		eval(this.hDisplay.postDeleteFunction);
	}
	this.del_fail = function(t){
		this.clear();
	}
}
String.prototype.trim=function(){
    return this.replace(/^\s*|\s*$/g,'');
}

String.prototype.ltrim=function(){
    return this.replace(/^\s*/g,'');
}

String.prototype.rtrim=function(){
    return this.replace(/\s*$/g,'');
}
