/*
	------------------------------------------------------------------------------
	/framework/classes/js/datagrid.js

	Een datagrid toont gegevens uit een datasource (js: naam van rpc functie)

  ------------------------------------------------------------------------------
*/


function DataGrid(_id) {

	// standard properties
	this.id = _id;


	this.containerelementid = "C_" + this.id;
	this.containerelement = document.getElementById(this.containerelementid);
	this.messageelementid = "M_" + this.id;
	this.messageelement = document.getElementById(this.messageelementid);

	/*
	this.errorelementid = "E_" + this.id;
	this.errorelement = document.getElementById(this.errorelementid);
	this.busyelementid = "B_" + this.id;
	this.busyelement = document.getElementById(this.busyelementid);
	*/

	// appearance
	this.width = 0;
	this.visible = true;
	this.noRowsMessage = "";

	// paging
	this.allowPaging = true;
	this.pageSize = 30;
	this.currentPageIndex = 0;
	this.maxResults = 0;
	this.setPageIndex = DataGrid_setPageIndex;

	// events
	this.onclick = "";
	this.onmouseover = "";
	this.onmouseout = "";

	// voor bij meerdere apps op de pagina
	this.appName = "";
	this.appType = "";

	// ingebouwde events
	this.oncustomclick = "";
	this.oneditclick = "";
	this.ondeleteclick = "";
	this.onviewclick = "";
	this.ondatabind = null;

	// extra properties
	this.error = "";
	this.dataSource = "";
	this.dataParams = "";
	this.dataColumns = null;
	this.dataKey = "";
	this.instantEditRequest; 			// RPC-functie die de datagrid dient op te starten na het accepteren van een edit veld
	this.instantEditDataSource;			// bij DropDownBox
	this.instantEditDisplayMember;		// bij DropDownBox + datasource = sql of xmlrequest
	this.instantEditValueMember;		// bij DropDownBox + datasource = sql of xmlrequest
	this.doDatabindOnInstantEdit;

	this.dataTable = null;				// hierin stockeren we de resultaten van de dataSource, zodat we die later nog kunnen gebruiken

	// methods
	this.show = DataGrid_show;
	this.hide = DataGrid_hide;

	this.setRowClass = DataGrid_setRowClass;
	this.setCellClass = DataGrid_setCellClass;

	// events
	this.registerEvents = DataGrid_registerEvents;
	this.addEvent = DataGrid_addEvent;
	this.getEventName = DataGrid_getEventName;

	this.dataClear = DataGrid_dataClear;
	this.dataBind = DataGrid_dataBind;
	this.getValue = DataGrid_getValue;
	this.setValue = DataGrid_setValue;
	this.setDisplay = DataGrid_setDisplay;


	// properties die het eenvoudiger maken om te debuggen
	this.responseText = "";
	this.requestText = "";

	this.xmlResponse = null;



}

function DataGrid_setPageIndex(newPageIndex) {
	this.currentPageIndex = newPageIndex;
	this.dataBind();
}




function DataGrid_dataClear() {
	/*alert(this.containerelement);
	alert(this.containerelement.tBodies);
	alert(this.containerelement.tBodies[0]);*/

	obj = this.containerelement.tBodies[0];
	if (obj) {

		var numrows = obj.rows.length;
		for (i=numrows-1; i>=0; i--) {
			//debug.write("Row " + i);
			obj.deleteRow(i);
			//tr = obj.rows[i];
			//obj.removeChild(tr);
		}
	}
}

function DataGrid_getValue(dataValue, dataColumn) {
	/*
		voorbeeld:
		this.dataKey = ClassID
		dataValue = 24 (dat is dus de classid)
		dataColumn = dcStatus
	*/

	debug.write("Getting value of column " + dataColumn + " where " + this.dataKey + " = " + dataValue);
	dc = eval(dataColumn);
	debug.write("DataColumn's field is " + dc.dataField);
	found = false;
	foundValue = "";
	for(i=0; (i<this.dataTable.length) && (found==false); i++) {
		//debug.write("This is " + this.dataTable[i][this.dataKey]);
		if (this.dataTable[i][this.dataKey] == dataValue) {
			debug.write("The value you want is " + this.dataTable[i][dc.dataField]);
			foundValue = this.dataTable[i][dc.dataField];
			found = true;
		}
	}

	if (found == true) {
		return foundValue;
	}
	else {
		return "";
	}


}

// sets the value of the internal dataTable to fieldValue, and also sets the table the user sees
function DataGrid_setValue(dataValue, dataColumn, fieldValue) {
	/*
		voorbeeld:
		this.dataKey = ClassID
		dataValue = 24 (dat is dus de classid)
		dataColumn = dcStatus
	*/

	debug.write("Getting value of column " + dataColumn + " where " + this.dataKey + " = " + dataValue);
	dc = eval(dataColumn);
	debug.write("DataColumn's field is " + dc.dataField);
	found = false;
	foundValue = "";
	for(i=0; (i<this.dataTable.length) && (found==false); i++) {
		//debug.write("This is " + this.dataTable[i][this.dataKey]);
		if (this.dataTable[i][this.dataKey] == dataValue) {
			debug.write("Yes, it's this row");
			debug.write("The value you want is now " + this.dataTable[i][dc.dataField] + " and you're changing it to " + fieldValue);
			this.dataTable[i][dc.dataField] = fieldValue;

			this.setDisplay(dataValue, dataColumn, fieldValue);

			found = true;
		}
	}

	return 0;

}

// only sets the display of a certain field in the datagrid - can be useful in some situations (instantEdit of a combobox for example)
function DataGrid_setDisplay(dataValue, dataColumn, fieldValue) {
	// getting the id of the table to update the displayed table itself
	// example: I_dgSelectedUsers_2633_dcSelectedName
	td = document.getElementById("I_" + this.id + "_" + dataValue + "_" + dataColumn);
	td.innerHTML = fieldValue;
	//alert("td = " + td.id);


	return 0;
}



function DataGrid_dataBind() {


	if (this.dataSource != "") {
		debug.write("Starting xml request for " + this.id, "DataGrid_dataBind");
		oXmlRequest = new XmlRequest();

		if (this.appName != "") {
			oXmlRequest.appName = this.appName;
			oXmlRequest.appType = this.appType;
		}
		oXmlRequest.functionName	= this.dataSource;
		// adding the pageSize and the currentPageIndex
		if (!this.dataParams)
			this.dataParams = new Array();

		this.dataParams["CurrentPageIndex"] = this.currentPageIndex;
		this.dataParams["PageSize"] = this.pageSize;
		this.dataParams["CurrentRowIndex"] = this.currentPageIndex * this.pageSize;

		oXmlRequest.params 			= this.dataParams;
		oXmlRequest.callingObject   = this.id;
		oXmlRequest.onsuccess 		= DataGrid_handleXmlResponse;
		oXmlRequest.start();

		this.requestText = oXmlRequest.requestText;
	}

	var tbody = this.containerelement.tBodies[0];
	var dg = this;
	var onDataBind = this.ondatabind; // om eraan te kunnen in de functie hierbeneden
	function DataGrid_handleXmlResponse(oXmlResponse) {
		dg.responseText = oXmlResponse.responseText;
		dg.xmlResponse = oXmlResponse;
		debug.write("Handling xml response for " + oXmlResponse.callingObject, "DataGrid_handleXmlResponse");
		if (oXmlResponse.statusCode == "2000") {
			debug.write("Got valid XmlResponse = " + oXmlResponse.status + ", datarows: " + oXmlResponse.numDataRows, "DataGrid_handleXmlResponse");

			//debug.write(oXmlResponse.responseText);

			// we doen toch beter automatisch een dataClear()
			dg.dataClear();

			var numDataColumns = 0;
			if (dg) {
				if (oXmlResponse.numDataRows == 0) {
					dg.messageelement.style.display = "block";
					dg.messageelement.className = "fw_datagrid_norowsmessage";
					dg.messageelement.innerHTML = dg.noRowsMessage;
					dg.containerelement.style.display = "none";
				}
				else {
					//alert(oXmlResponse.numDataRows);

					dg.dataTable = oXmlResponse.data;

					if (!document.all) {
						dg.containerelement.style.display = "table";
					}
					else {
						dg.containerelement.style.display = "block";
					}

					if (dg.maxResults > 0 && oXmlResponse.numDataRows > dg.maxResults) {
						//alert("ja het zijn er teveel");
						dg.messageelement.style.display = "block";
						dg.messageelement.className = "fw_datagrid_norowsmessage";
						dg.messageelement.innerHTML = dg.tooMuchRowsMessage;
						//dg.containerelement.style.display = "none";
					}
					else {
						dg.messageelement.style.display = "none";
					}



					debug.write("numdataRows = " + oXmlResponse.numDataRows + ", pageSize = " + dg.pageSize);
					var doPaging;
					if (dg.allowPaging == true) {
						// do we have to show the pager?
						if (oXmlResponse.numDataRows < dg.pageSize) {
							doPaging = false;
						}
						else {

							doPaging = true;
						}

					}
					else {
						doPaging = false;
					}
					debug.write("doPaging = " + doPaging + " this.allowPaging = " + this.allowPaging);


					/*
					if (doPaging) {
						var startIndex = dg.pageSize*dg.currentPageIndex;
						var stopIndex = startIndex + dg.pageSize - 1;
						if (stopIndex > oXmlResponse.numDataRows)
							stopIndex = oXmlResponse.numDataRows - 1;
					}
					else {
						var startIndex = 0;
						var stopIndex = oXmlResponse.data.length-1;
					}
					*/
					var startIndex = 0;
					var stopIndex = 0;
					if (dg.maxResults > 0 && oXmlResponse.numDataRows > dg.maxResults) {
						stopIndex = dg.maxResults -1;
					}
					else {
						stopIndex = oXmlResponse.data.length-1;
					}



					//stopIndex--;

					debug.write("Showing rows " + startIndex + " to " + stopIndex);
					//for(i=0; i<oXmlResponse.data.length; i++) {
					for (i=startIndex; i<=stopIndex; i++) {

						//debug.write("Adding row to dg.dataTable");
						//dg.dataTable[i] = new Array();

						var tr = document.createElement("tr");
						tr.id= "R_" + dg.id + "_" + (oXmlResponse.data[i][dg.dataKey]);
						//debug.write("id = " + tr.id);

						// check if the row can be displayed or not...
						// Example:
						// currentPageIndex - 	pageSize - 	i
						// 0					15			 0...14
						// 1					15			15...29
						// 2 					15			30...44
						/*if (doPaging) {
							//debug.write("allowPaging");
							if (i >= (dg.pageSize*dg.currentPageIndex) && i <= (dg.pageSize*dg.currentPageIndex + dg.pageSize)) {
								tr.style.display = "block";
							}
							else {
								tr.style.display = "none";
								tr.style.width = "100%";
							}
						}*/


						//alert(dg.dataColumns.length);
						numDataColumns = 0;
						for (key in dg.dataColumns) {
							numDataColumns++;
							oDataColumn = dg.dataColumns[key];

							//debug.write("key = " + key + ": " + oDataColumn.type);

							// for some reason, to get all fancy stuff going, prototype.js breaks the simple associative array
							//debug.write(dg.dataColumns[key]);

							// dit stond er, maar is blijkbaar niet voldoende voor safari
							//if (String(dg.dataColumns[key]).indexOf(") {") == -1) {

							if ((String(dg.dataColumns[key]).indexOf("(Internal") == -1) && (String(dg.dataColumns[key]).indexOf("{") == -1)) {


								var td = document.createElement("td");

								if (oDataColumn.textAlign != "") {
									td.style.textAlign = oDataColumn.textAlign;
								}

								if (oDataColumn.type == "text") {
									td.id= "I_" + dg.id + "_" + oXmlResponse.data[i][dg.dataKey] + "_" + oDataColumn.id;
								}
								else if (oDataColumn.type == "view") {
									td.id= "I_" + dg.id + "_" + oXmlResponse.data[i][dg.dataKey] + "_OnView";
								}
								else if (oDataColumn.type == "edit") {
									td.id= "I_" + dg.id + "_" + oXmlResponse.data[i][dg.dataKey] + "_OnEdit";
								}
								else if (oDataColumn.type == "delete") {
									td.id= "I_" + dg.id + "_" + oXmlResponse.data[i][dg.dataKey] + "_OnDelete";
								}
								else if (oDataColumn.type == "custom") {
									td.id= "I_" + dg.id + "_" + oXmlResponse.data[i][dg.dataKey] + "_OnCustom";
								}

								if (oDataColumn.jsTemplate != "") {
									var fieldValue = oXmlResponse.data[i][oDataColumn.dataField];
									var functionName = "DataGrid_" + dg.id + "_" + oDataColumn.id;

									var func = "function " + functionName + "() {" + oDataColumn.jsTemplate + "} td.innerHTML = " + functionName + "();";
									eval(func);

									// Als het niet gaat om text, hangt er waarschijnlijk een
									// actie aan vast en tonen we dus een handje
									if (oDataColumn.type != "text") {
										td.style.cursor = "pointer";
									}

								}
								else {
									if (oDataColumn.displayField != "")
										td.innerHTML = oXmlResponse.data[i][oDataColumn.displayField];
									else
										td.innerHTML = oXmlResponse.data[i][oDataColumn.dataField];
									//var tdText = document.createTextNode(oXmlResponse.data[i][oDataColumn.dataField]);
								}
								// einde methode 2

								tr.appendChild(td);

								//debug.write("Adding " + oXmlResponse.data[i][oDataColumn.dataField] + " to " + oDataColumn.id);
								//debug.write("Adding " + oDataColumn.id);
							}
						}
						tbody.appendChild(tr);

					} // for

					debug.write("Done showing rows, now checking doPaging (" + doPaging + ")");
					if (doPaging) {
						debug.write("We need the pager");
						// Create the pager
						var tr = document.createElement("tr");
						var td = document.createElement("td");
						td.id = "P_" + dg.id;
						td.colSpan = numDataColumns;
						//alert("td.colspan = " + td.colSpan);

						//td.innerHTML = "pager!!!";
						tr.appendChild(td);
						tbody.appendChild(tr);
						//alert(td.offsetWidth);
						var div = document.createElement("div");
						if (td.offsetWidth >10) {
							div.style.width = (td.offsetWidth-10) + "px";//"200px";
						}
						//div.style.backgroundColor = "yellow";
						div.style.wordWrap = "break-word";

						// the links in the pager...
						str = "";
						for (i=0; i<oXmlResponse.numDataRows; i+=dg.pageSize) {
							pageNumber = (i/dg.pageSize)+1;
							str += pageNumber + " ";

							elementName = dg.id + "_Pager_" + pageNumber;
							if (pageNumber == (dg.currentPageIndex+1)) {
								span = document.createElement("span");
								span.innerHTML = pageNumber + " ";
								div.appendChild(span);

							}
							else {
								eval(elementName + " = new Button(elementName, pageNumber);");
								eval(elementName + ".onclick = 'DataGrid_handle_Pager_onclick';");
								eval(elementName + ".type = 'text';");
								eval(elementName + ".parentElement = div;");
								eval(elementName + ".render();");
								eval(elementName + ".show();");
							}



						}
						td.appendChild(div);
						//alert(td.offsetWidth);
					}






				} // else


			}


		}
		else {
			debug.write("Response from xml = " + oXmlResponse.status + oXmlResponse.responseText, "DataGrid_handleXmlResponse");
		}

		if (onDataBind) {
			debug.write("Executing databind function: " + onDataBind);
			onDataBind(oXmlResponse);
		}


	}




}

function DataGrid_setRowClass(newClass, row) {
	obj = document.getElementById("R_" + this.id + "_" + row);
	if (obj) {
		obj.className = newClass;
	}
}
function DataGrid_setCellClass(newClass, row, col) {
	obj = document.getElementById("I_" + this.id + "_" + row + "_" + col);
	if (obj) {
		obj.className = newClass;
	}
}

function DataGrid_hide() {
	if (this.containerelement) {
		this.visible = false;
		this.containerelement.style.display = "none";
	}
}

function DataGrid_show() {
	if (this.containerelement) {
		this.visible = true;
		this.containerelement.style.display = "block";
	}
}


function DataGrid_getEventName(whichevent) {
	//alert("eval dit " + eval("this." + whichevent));
	return (eval("this.on" + whichevent));

}

function DataGrid_registerEvents() {

	if (this.containerelement) {
		if (this.onmouseover.length > 0) {
			this.addEvent('mouseover', DataGrid_handle_datagrid_event);
		}
		if (this.onmouseout.length > 0) {
			this.addEvent('mouseout', DataGrid_handle_datagrid_event);
		}
		//if (this.onclick.length > 0) { // de onclick mag altijd geactiveerd zijn, bijvoorbeeld voor een instantEdit
			this.addEvent('click', DataGrid_handle_datagrid_event);
		//}
		if (this.oncustomclick.length > 0) {
			this.addEvent('click', DataGrid_handle_datagrid_oncustomclick);
		}
		if (this.oneditclick.length > 0) {
			this.addEvent('click', DataGrid_handle_datagrid_oneditclick);
		}
		if (this.ondeleteclick.length > 0) {
			this.addEvent('click', DataGrid_handle_datagrid_ondeleteclick);
		}
		if (this.onviewclick.length > 0) {
			this.addEvent('click', DataGrid_handle_datagrid_onviewclick);
		}
	}

}

function DataGrid_addEvent(eventtype, eventhandler) {

	//W3C
	if(this.containerelement.addEventListener) {
		//alert('W3C event added');
		this.containerelement.addEventListener(eventtype, eventhandler, false);
	}

	//Microsoft
	else if(this.containerelement.attachEvent){
		//alert("MS event added");
		this.containerelement.attachEvent("on" + eventtype, eventhandler);
	}
}



/* op het eigenlijke element (div/input/select/...) wordt niet de uiteindelijke
   event opgeroepen, maar deze functie.
   Deze functie zorgt ervoor dat de eigenlijke eventfunctie enkele parameters mee
   krijgt die nuttig zijn: het framework-object waar het om gaat, en de event zelf
   (in alle browsers, dus ook in IE-browsers)
   De eigenlijke eventfunctie kan zich zo concentreren op zijn echte taak, nl.
   het opvangen van wat die event moet doen.
*/
function DataGrid_handle_datagrid_event(ev) {
	var targetElement;

	// event bij MS
	if (!ev) var ev = window.event;

	// target element W3C
	if (ev.target) targetElement = ev.target;
	// target element MS
	else if (ev.srcElement) targetElement = ev.srcElement;

	//debug.write('Het event (type = ' + ev.type + ') is opgetreden op ' +targetElement.id);

	// in safari gebeurt er ook een event op de textnode in de td, maar die heeft geen id
	// dus moeten we in dat geval naar de parent ervan gaan
	if (!targetElement.id) {
		//debug.write("targetElement is undefined, proceeding to parent element: " + targetElement.parentNode);
		targetElement = targetElement.parentNode;
	}





	// We willen dat de eventhandling functie opgeroepen wordt en dat als parameters volgende waarden worden meegegeven:
	// function eventhandler_name(ev, el, row, col) --> col en row zijn de kolom en rij waarin geklikt is

	// framework element opzoeken (R_dgName_1003_DisplayName -> dgName)
	var ar = targetElement.id.split("_");
	if (ar.length >=2) {
		var frameworkElementId = ar[1]; // de datagrid zelf dus
		var frameworkElement = eval(frameworkElementId);
		// het is vreemd, maar na een onchange van een dropdownbox gebeurt er nog een event, en ik weet niet van wat
		if (frameworkElement == undefined) {
		}
		else {

			//debug.write("targetElement = " + targetElement.id + " ??? P_" + frameworkElementId);
			// we are not interested in events on the pager row
			/*if (targetElement.id == "P_" + frameworkElementId) {
				//alert("Event in the pager row - returning");
				return;
			}
			else */if (targetElement.id.indexOf(frameworkElementId + "_Pager") >= 0) {
				//debug.write("Event on a element in the pager row - returning");
				return;
			}
			else {
				//debug.write("Valid event, continuing");
			}


			var row = 0;
			var col = 0;
			if (ar.length >= 3)
				row = ar[2];
			if (ar.length >= 4)
				col = ar[3];

			if ((row != 0) && (col != 0)) {
				//debug.write("eventtype = " + ev.type);
				eventfunction = frameworkElement.getEventName(ev.type);
				//debug.write("eventfunction = " + eventfunction);


				if (ev.type == "click") {
					debug.write(eventfunction + "(" + ev + ", " + frameworkElement + ", " + row + ", " + col + ");");
					if(frameworkElement.dataColumns) {
						debug.write("Er zijn datacolumns");
						if(frameworkElement.dataColumns[col]) {
							debug.write("De datacolumn die ik nodig heb bestaat");
							if (frameworkElement.dataColumns[col].instantEditType == "TextBox") {
								debug.write("De datacolumn heeft als editType een Textbox");

								elementName = frameworkElement.id + '_txtInstantEdit';
								// om goed te zijn mogen we niet de innerHTML van het targetElement nemen om als value te dienen
								// eigenlijk moeten we de dataSource gaan opzoeken van de datagrid en kijken wat deze kolom als waarde heeft op deze row
								// hiervoor moet een extra functie gebruikt worden!
								//debug.write("getvalue = " + frameworkElement.getValue(row, col));

								eval(elementName + " = new TextBox(frameworkElement.id + '_txtInstantEdit', frameworkElement.getValue(row, col));");
								eval(elementName + ".onclick = 'DataGrid_handle_txtInstantEdit_onclick';");
								eval(elementName + ".onkeyup = 'DataGrid_handle_txtInstantEdit_onkeyup';");
								eval(elementName + ".onblur= 'DataGrid_handle_txtInstantEdit_onblur';");
								eval(elementName + ".tag= frameworkElement.getValue(row, col);");
								eval(elementName + ".editorType = 'none'");
								eval(elementName + ".parentElement = targetElement;");

								targetElement.innerHTML = "";
								eval(elementName + ".render();");
								eval(elementName + ".show();");
								eval(elementName + ".focus();");


							}
							else if (frameworkElement.dataColumns[col].instantEditType == "DropDownBox") {
								debug.write("De datacolumn heeft als editType een DropDownBox");

								elementName = frameworkElement.id + '_cboInstantEdit';

								eval(elementName + " = new DropDownBox(frameworkElement.id + '_cboInstantEdit');");
								eval(elementName + ".onchange = 'DataGrid_handle_cboInstantEdit_onchange';");
								eval(elementName + ".onblur = 'DataGrid_handle_cboInstantEdit_onblur';");
								eval(elementName + ".tag= frameworkElement.getValue(row, col);");
								eval(elementName + ".dataSource = frameworkElement.dataColumns[col].instantEditDataSource;");
								eval(elementName + ".parentElement = targetElement;");

								targetElement.innerHTML = "";
								eval(elementName + ".render();");
								eval(elementName + ".show();");
								eval(elementName + ".setSelectedValue(frameworkElement.getValue(row, col));");
								eval(elementName + ".focus();");


							}
						}
					}

				}
				if (eventfunction != "") {
					eval(eventfunction + "(ev, frameworkElement, row, col);");
				}

				//alert(eval(parent_element_id).getevent("onclick"));
			}
		}
	}
}



function DataGrid_handle_Pager_onclick(ev,el) {
	//alert("hello");
	debug.write("Click on " + el + " with value " + el.getValue());

	var newPageIndex = parseInt(el.getValue()) - 1;

	var ar = el.id.split("_");
	if (ar.length >= 2) {
		var frameworkElementId = ar[0]; // de datagrid zelf dus
		var frameworkElement = eval(frameworkElementId);
		// het is vreemd, maar na een onchange van een dropdownbox gebeurt er nog een event, en ik weet niet van wat
		if (frameworkElement == undefined) {
		}
		else {
			//alert("frameworkElement is defined: " + frameworkElement.currentPageIndex + " ??? " + newPageIndex);
			if (frameworkElement.currentPageIndex != newPageIndex) {
				frameworkElement.setPageIndex(newPageIndex);
			}


		}
	}

}


function DataGrid_handle_txtInstantEdit_onkeyup(ev,el) {
	debug.write("onkeyup on " + el + " with keycode " + ev.keyCode);
	if (ev.keyCode == 13) { // Enter
		DataGrid_handle_txtInstantEdit_onblur(ev,el);
	}
	else if (ev.keyCode == 27) {  // Escape
		debug.write("Hiding textbox without saving results...");
		var fieldValue = el.tag;
		el.hideBusy();
		el.destroy();
		el.parentElement.innerHTML = fieldValue;
		el = null;
	}

	// TODO bij escape nog de oude waarde terugzetten
}
function DataGrid_handle_txtInstantEdit_onclick(ev,el) {
	debug.write("DataGrid_handle_instantEdit_onclick on " + el);


}
function DataGrid_handle_txtInstantEdit_onblur(ev,el) {
	debug.write("DataGrid_handle_instantEdit_onblur on " + el.id + " - " + el.getValue());

	var parentElement = el.parentElement;
	var fieldValue = el.getValue();

	var ar;
	var elementValue;
	var dataKey;
	var instantEditRequest;
	var dgID;
	var dg;
	var dcID;
	var dc;


	// eerst moeten we de row id opvragen
	ar = parentElement.id.split("_");
	if (ar.length >=3) {
		dataValue = ar[2];
		dcID = ar[3]; // id van de datacolumn
		dc = eval(dcID);
		debug.write(dc.dataField);
	}




	var ar = el.id.split("_");

	if (ar.length >=1) {
		dgID = ar[0];

		dg = eval(dgID);
		dataKey = dg.dataKey;
		instantEditRequest = dg.instantEditRequest;

		el.showBusy();

		var params = new Array();
		params[dataKey] = dataValue;			// dataKey is bv. CourseID, dataValue is de id (b.v. 25)
		params["FieldKey"] = dc.dataField;			// De naam van het veld, bijvoorbeeld Name
		params["FieldValue"] = fieldValue;			// De waarden van het veld, bijvoorbeeld 2de leerjaar

		var oXmlRequest = new XmlRequest();
		oXmlRequest.functionName= instantEditRequest;
		oXmlRequest.onsuccess = DataGrid_handle_txtInstantEdit_onblur_success;
		oXmlRequest.params 	= params;
		oXmlRequest.start();

	}





	function DataGrid_handle_txtInstantEdit_onblur_success(oXmlResponse) {
		if (oXmlResponse.statusCode != 2000) {
			//alert("Er is een fout gebeurd bij het opslaan: " + oXmlResponse.statusCode + " - " + oXmlResponse.status);
		}

		debug.write("DataGrid_handle_txtInstantEdit_onblur_success = " + oXmlResponse.responseText);
		debug.write("message = " + oXmlResponse.message["nl"]);
		el.hideBusy();
		el.destroy();
		el = null;


		if (dc.jsTemplate != "") {
			debug.write("restoring field with template");
			var functionName = "DataGrid_" + dg.id + "_" + dc.id;
			// fieldvalue (gebruikt in de template) is hier al ingevuld
			var func = "function " + functionName + "() {" + dc.jsTemplate + "} parentElement.innerHTML = " + functionName + "();";
			debug.write(func);
			eval(func);
		}
		else {
			parentElement.innerHTML = fieldValue;
		}

		// ook de dataTable updaten
		dg.setValue(dataValue, dcID, fieldValue);
		if (dg.doDatabindOnInstantEdit == true) {
			dg.dataBind();
		}

	}

}


function DataGrid_handle_cboInstantEdit_onchange(ev,el) {
	debug.write("<b>ONCHANGE</b>");
	DataGrid_handle_cboInstantEdit_onblur(ev, el);
}


function DataGrid_handle_cboInstantEdit_onblur(ev,el) {

	debug.write("<b>ONBLUR</b>");
	debug.write("DataGrid_handle_cboInstantEdit_onblur on " + el.id + " - " + el.getSelectedValue());

	var parentElement = el.parentElement;
	var fieldValue = el.getSelectedValue();
	var displayValue = el.getSelectedDisplay();

	var ar;
	var elementValue;
	var dataKey;
	var instantEditRequest;
	var dgID;
	var dg;
	var dcID;
	var dc;


	// eerst moeten we de row id opvragen
	debug.write("parentElement = " + parentElement.id);
	ar = parentElement.id.split("_");
	if (ar.length >=3) {
		dataValue = ar[2];
		dcID = ar[3]; // id van de datacolumn
		dc = eval(dcID);
		debug.write("Datafield = " + dc.dataField);
	}




	var ar = el.id.split("_");
	debug.write("ar.length = " + ar.length);
	if (ar.length >=1) {
		dgID = ar[0];
		debug.write("dgID = " + dgID);
		dg = eval(dgID);
		dataKey = dg.dataKey;
		instantEditRequest = dg.instantEditRequest;

		// if the value is the same, why update?
		if (dg.getValue(dataValue, dcID) == fieldValue) {
			debug.write("Update not needed, value is unchanged!");
			restoreField();
			return;
		}

		debug.write("Updating " + dataValue + " - " + instantEditRequest + " - " + dataKey + " by using " + instantEditRequest);

		el.showBusy();

		var params = new Array();
		params[dataKey] = dataValue;				// dataKey is bv. CourseID, dataValue is de id (b.v. 25)
		params["FieldKey"] = dc.dataField;			// De naam van het veld, bijvoorbeeld Name
		params["FieldValue"] = fieldValue;			// De waarden van het veld, bijvoorbeeld 2de leerjaar
		var oXmlRequest = new XmlRequest();
		oXmlRequest.functionName	= instantEditRequest;
		oXmlRequest.onsuccess = DataGrid_handle_cboInstantEdit_success;
		oXmlRequest.params 	= params;
		oXmlRequest.start();


	}





	function DataGrid_handle_cboInstantEdit_success(oXmlResponse) {
		debug.write("DataGrid_handle_cboInstantEdit_success = " + oXmlResponse.responseText);

		if (oXmlResponse.statusCode != 2000) {
			alert("Er is een fout gebeurd bij het opslaan: " + oXmlResponse.statusCode + " - " + oXmlResponse.status);
		}
		restoreField();

	}

	function restoreField() {
		el.hideBusy();
		el.destroy();
		el = null;

		// ook de dataTable updaten
		dg.setValue(dataValue, dcID, fieldValue);



		//alert("fieldValue = " + fieldValue);
		if (dc.jsTemplate != "") {
			debug.write("restoring field with template");
			var functionName = "DataGrid_" + dg.id + "_" + dc.id;
			// fieldvalue (gebruikt in de template) is hier al ingevuld
			var func = "function " + functionName + "() {" + dc.jsTemplate + "} parentElement.innerHTML = " + functionName + "();";
			debug.write(func);
			eval(func);
		}
		else {
			// why do we do this??
			parentElement.innerHTML = fieldValue;

			// PF: added this on 20060215 - we want a combo box to show the displayed value, not the fieldValue
			dg.setDisplay(dataValue, dcID, displayValue);

		}

	}


}

// dit is een speciale event handler, die ook op de click event reageert, maar enkel op de click event van een bepaalde kolom
// en hij roept ook een speciale eventhandler functie op, die de programmeur kan gebruiken om rechtstreeks naar de details van
// een bepaalde row te gaan
function DataGrid_handle_datagrid_onviewclick(ev) {
	var targetElement;

	// event bij MS
	if (!ev) var ev = window.event;

	// target element W3C
	if (ev.target) targetElement = ev.target;
	// target element MS
	else if (ev.srcElement) targetElement = ev.srcElement;

	debug.write("te = " + targetElement);
	debug.write("te.id = " + targetElement.id)

	if (!targetElement) {
		debug.write("Target element is undefined, returning...");
		return;
	}

	// We willen dat de eventhandling functie opgeroepen wordt en dat als parameters volgende waarden worden meegegeven:
	// function eventhandler_name(ev, el, row, col) --> col en row zijn de kolom en rij waarin geklikt is
	// in safari gebeurt er ook een event op de textnode in de td, maar die heeft geen id
	// dus moeten we in dat geval naar de parent ervan gaan
	if (!targetElement.id && targetElement.parentNode) {
		//alert("targetElement is undefined, proceeding to parent element: " + targetElement.parentNode);
		targetElement = targetElement.parentNode;
	}

	debug.write("te = " + targetElement);
	debug.write("te.id = " + targetElement.id)


	// if the id is still empty, just return
	if ((!targetElement) || (!targetElement.id)) {
		debug.write("TargetElement still undefined, returning...");
		return;
	}

	debug.write('Het onviewclick event (type = ' + ev.type + ') is opgetreden op ' +targetElement.id);

	// framework element opzoeken (R_dgName_1003_DisplayName -> dgName)
	var ar = targetElement.id.split("_");
	if (ar.length >=2) {
		var frameworkElementId = ar[1];
		var frameworkElement = eval(frameworkElementId);
		// het is vreemd, maar na een onchange van een dropdownbox gebeurt er nog een event, en ik weet niet van wat
		if (frameworkElement == undefined) {
		}
		else {
			var row = 0;
			var col = 0;
			if (ar.length >= 3)
				row = ar[2];
			if (ar.length >= 4)
				col = ar[3];

			if (col == "OnView") {
				// eigenlijk moeten we ook nog een mouseout van de huidige rij voorzien (anders is die nog gehighlight soms)
				if (frameworkElement.getEventName("mouseout")) {
					mouseoutfunction = frameworkElement.getEventName("mouseout");
					eval(mouseoutfunction + "(ev, frameworkElement, row, col);");
				}

				//alert(eventfunction + "(ev, frameworkElement, row);");


				//eventfunction = frameworkElement.getEventName(ev.type);
				eventfunction = frameworkElement.getEventName("viewclick");

				//alert(eventfunction + "(ev, frameworkElement, row);");
				eval(eventfunction + "(ev, frameworkElement, row);");
			}

			//alert(eval(parent_element_id).getevent("onclick"));
		}
	}
}

// dit is een speciale event handler, die ook op de click event reageert, maar enkel op de click event van een bepaalde kolom
// en hij roept ook een speciale eventhandler functie op, die de programmeur kan gebruiken om rechtstreeks naar de details van
// een bepaalde row te gaan
function DataGrid_handle_datagrid_oneditclick(ev) {


	var targetElement;

	// event bij MS
	if (!ev) var ev = window.event;

	// target element W3C
	if (ev.target) targetElement = ev.target;
	// target element MS
	else if (ev.srcElement) targetElement = ev.srcElement;

	debug.write("te = " + targetElement);
	debug.write("te.id = " + targetElement.id)

	if (!targetElement) {
		debug.write("Target element is undefined, returning...");
		return;
	}

	// We willen dat de eventhandling functie opgeroepen wordt en dat als parameters volgende waarden worden meegegeven:
	// function eventhandler_name(ev, el, row, col) --> col en row zijn de kolom en rij waarin geklikt is
	// in safari gebeurt er ook een event op de textnode in de td, maar die heeft geen id
	// dus moeten we in dat geval naar de parent ervan gaan
	if (!targetElement.id && targetElement.parentNode) {
		//alert("targetElement is undefined, proceeding to parent element: " + targetElement.parentNode);
		targetElement = targetElement.parentNode;
	}

	debug.write("te = " + targetElement);
	debug.write("te.id = " + targetElement.id)


	// if the id is still empty, just return
	if ((!targetElement) || (!targetElement.id)) {
		debug.write("TargetElement still undefined, returning...");
		return;
	}

	debug.write('Het oneditclick event (type = ' + ev.type + ') is opgetreden op ' +targetElement.id);


	// framework element opzoeken (R_dgName_1003_DisplayName -> dgName)
	var ar = targetElement.id.split("_");
	if (ar.length >=2) {
		var frameworkElementId = ar[1];
		var frameworkElement = eval(frameworkElementId);
		// het is vreemd, maar na een onchange van een dropdownbox gebeurt er nog een event, en ik weet niet van wat
		if (frameworkElement == undefined) {
		}
		else {
			var row = 0;
			var col = 0;
			if (ar.length >= 3)
				row = ar[2];
			if (ar.length >= 4)
				col = ar[3];

			if (col == "OnEdit") {
				// eigenlijk moeten we ook nog een mouseout van de huidige rij voorzien (anders is die nog gehighlight soms)
				if (frameworkElement.getEventName("mouseout")) {
					mouseoutfunction = frameworkElement.getEventName("mouseout");
					eval(mouseoutfunction + "(ev, frameworkElement, row, col);");
				}

				//alert(eventfunction + "(ev, frameworkElement, row);");


				//eventfunction = frameworkElement.getEventName(ev.type);
				eventfunction = frameworkElement.getEventName("editclick");

				//alert(eventfunction + "(ev, frameworkElement, row);");
				eval(eventfunction + "(ev, frameworkElement, row);");
			}

			//alert(eval(parent_element_id).getevent("onclick"));
		}
	}

}

// dit is een speciale event handler, die ook op de click event reageert, maar enkel op de click event van een bepaalde kolom
// en hij roept ook een speciale eventhandler functie op, die de programmeur kan gebruiken om rechtstreeks naar de details van
// een bepaalde row te gaan
function DataGrid_handle_datagrid_ondeleteclick(ev) {


	var targetElement;

	// event bij MS
	if (!ev) var ev = window.event;

	// target element W3C
	if (ev.target) targetElement = ev.target;
	// target element MS
	else if (ev.srcElement) targetElement = ev.srcElement;

	debug.write("te = " + targetElement);
	debug.write("te.id = " + targetElement.id)

	if (!targetElement) {
		debug.write("Target element is undefined, returning...");
		return;
	}

	// We willen dat de eventhandling functie opgeroepen wordt en dat als parameters volgende waarden worden meegegeven:
	// function eventhandler_name(ev, el, row, col) --> col en row zijn de kolom en rij waarin geklikt is
	// in safari gebeurt er ook een event op de textnode in de td, maar die heeft geen id
	// dus moeten we in dat geval naar de parent ervan gaan
	if (!targetElement.id && targetElement.parentNode) {
		//alert("targetElement is undefined, proceeding to parent element: " + targetElement.parentNode);
		targetElement = targetElement.parentNode;
	}

	debug.write("te = " + targetElement);
	debug.write("te.id = " + targetElement.id)



	// framework element opzoeken (R_dgName_1003_DisplayName -> dgName)
	var ar = targetElement.id.split("_");
	if (ar.length >=2) {
		var frameworkElementId = ar[1];
		var frameworkElement = eval(frameworkElementId);
		// het is vreemd, maar na een onchange van een dropdownbox gebeurt er nog een event, en ik weet niet van wat
		if (frameworkElement == undefined) {
		}
		else {
			var row = 0;
			var col = 0;
			if (ar.length >= 3)
				row = ar[2];
			if (ar.length >= 4)
				col = ar[3];

			if (col == "OnDelete") {
				debug.write('Het ondeleteclick event (type = ' + ev.type + ') is opgetreden op ' +targetElement.id);

				//eventfunction = frameworkElement.getEventName(ev.type);
				eventfunction = frameworkElement.getEventName("deleteclick");

				//alert(eventfunction + "(ev, frameworkElement, row);");
				eval(eventfunction + "(ev, frameworkElement, row);");
			}

			//alert(eval(parent_element_id).getevent("onclick"));
		}
	}

}

// dit is een speciale event handler, die ook op de click event reageert, maar enkel op de click event van een bepaalde kolom
// en hij roept ook een speciale eventhandler functie op, die de programmeur kan gebruiken om rechtstreeks naar de details van
// een bepaalde row te gaan
function DataGrid_handle_datagrid_oncustomclick(ev) {
	var targetElement;

	// event bij MS
	if (!ev) var ev = window.event;

	// target element W3C
	if (ev.target) targetElement = ev.target;
	// target element MS
	else if (ev.srcElement) targetElement = ev.srcElement;

	debug.write("te = " + targetElement);
	debug.write("te.id = " + targetElement.id)

	if (!targetElement) {
		debug.write("Target element is undefined, returning...");
		return;
	}

	// We willen dat de eventhandling functie opgeroepen wordt en dat als parameters volgende waarden worden meegegeven:
	// function eventhandler_name(ev, el, row, col) --> col en row zijn de kolom en rij waarin geklikt is
	// in safari gebeurt er ook een event op de textnode in de td, maar die heeft geen id
	// dus moeten we in dat geval naar de parent ervan gaan
	if (!targetElement.id && targetElement.parentNode) {
		//alert("targetElement is undefined, proceeding to parent element: " + targetElement.parentNode);
		targetElement = targetElement.parentNode;
	}

	debug.write("te = " + targetElement);
	debug.write("te.id = " + targetElement.id)


	// if the id is still empty, just return
	if ((!targetElement) || (!targetElement.id)) {
		debug.write("TargetElement still undefined, returning...");
		return;
	}

	debug.write('Het oncustomclick event (type = ' + ev.type + ') is opgetreden op ' +targetElement.id);

	// framework element opzoeken (R_dgName_1003_DisplayName -> dgName)
	var ar = targetElement.id.split("_");
	if (ar.length >=2) {
		var frameworkElementId = ar[1];
		var frameworkElement = eval(frameworkElementId);
		// het is vreemd, maar na een onchange van een dropdownbox gebeurt er nog een event, en ik weet niet van wat
		if (frameworkElement == undefined) {
		}
		else {
			var row = 0;
			var col = 0;
			if (ar.length >= 3)
				row = ar[2];
			if (ar.length >= 4)
				col = ar[3];

			if (col == "OnCustom") {
				// eigenlijk moeten we ook nog een mouseout van de huidige rij voorzien (anders is die nog gehighlight soms)
				if (frameworkElement.getEventName("mouseout")) {
					mouseoutfunction = frameworkElement.getEventName("mouseout");
					eval(mouseoutfunction + "(ev, frameworkElement, row, col);");
				}

				//alert(eventfunction + "(ev, frameworkElement, row);");


				//eventfunction = frameworkElement.getEventName(ev.type);
				eventfunction = frameworkElement.getEventName("customclick");

				//alert(eventfunction + "(ev, frameworkElement, row);");
				eval(eventfunction + "(ev, frameworkElement, row);");
			}

			//alert(eval(parent_element_id).getevent("onclick"));
		}
	}
}

function DataGrid_handle_exportPdf(dgId) {
	var dg = eval(dgId);
	if (dg == undefined) {
		// maybe it doesn't exist
	}
	else {
		debug.write("Starting export request for " + dgId, "DataGrid_handle_export");

		strRequest = "format_type=pdf&app_name=" + appName + "&app_type=" + appType + "&function_name=" + dg.dataSource;
		for (key in dg.dataParams) {

			if (String(dg.dataParams[key]).indexOf(") {") == -1) {
				strRequest = strRequest + "&param" + key + "=" + dg.dataParams[key];
			}
		}
		openWindow(webroot + "/rpc.php?" + strRequest, "export_" + dgId, 800, 600);

	}
}


function DataGrid_handle_exportExcel(dgId) {
	var dg = eval(dgId);
	if (dg == undefined) {
		// maybe it doesn't exist
	}
	else {
		debug.write("Starting export request for " + dgId, "DataGrid_handle_export");

		strRequest = "format_type=excel&app_name=" + appName + "&app_type=" + appType + "&function_name=" + dg.dataSource;
		for (key in dg.dataParams) {

			if (String(dg.dataParams[key]).indexOf(") {") == -1) {
				if (key == "PageSize") {
					dg.dataParams[key] = 999999; // we tonen steeds alle records (meer dan een miljoen zullen het er wel niet zijn)
				}
				strRequest = strRequest + "&param" + key + "=" + dg.dataParams[key];
			}
		}
		//alert(strRequest);
		document.location = webroot + "/rpc.php?" + strRequest, "export_" + dgId, 800, 600;
	}
}





function DataColumn(_id) {

	// standard properties
	this.id = _id;


	/*this.containerelementid = "C_" + this.id;
	this.containerelement = document.getElementById(this.containerelementid);
	this.formelementid = "F_" + this.id;
	this.formelement = document.getElementById(this.formelementid);
	this.errorelementid = "E_" + this.id;
	this.errorelement = document.getElementById(this.errorelementid);
	this.busyelementid = "B_" + this.id;
	this.busyelement = document.getElementById(this.busyelementid);
	*/

	// appearance
	this.width = 0;
	this.visible = true;

	// events


	// extra properties
	this.type = "text";
	this.caption = "";
	this.jsTemplate = "";
	this.dataField = "";
	this.displayField = "";
	this.width = "";
	this.textAlign = "";

	// methods

	// events

}
