var imageroot = 'images';

//Required to make the onclick links XHTML1.0 strict.
var amp = "&";

// Zorg ervoor dat document.getElementById werkt zoals zou moeten (alleen matchen op ID)
// Source: http://webbugtrack.blogspot.com/2007/08/bug-152-getelementbyid-returns.html
//use browser sniffing to determine if IE or Opera (ugly, but required)
var isOpera = false;
if(typeof(window.opera) != 'undefined'){isOpera = true;}

//fix both IE and Opera (adjust when they implement this method properly)
if(isOpera || isIE()){
  document.nativeGetElementById = document.getElementById;
  //redefine it!
  document.getElementById = function(id){
    var elem = document.nativeGetElementById(id);
    if(elem){
      //verify it is a valid match!
      if(elem.attributes['id'] && elem.attributes['id'].value == id){
        //valid match!
        return elem;
      } else {
        //not a valid match!
        //the non-standard, document.all array has keys for all name'd, and id'd elements
        //start at one, because we know the first match, is wrong!
        for(var i=1;i<document.all[id].length;i++){
          if(document.all[id][i].attributes['id'] && document.all[id][i].attributes['id'].value == id){
            return document.all[id][i];
          }
        }
      }
    }
    return null;
  };
}


/**
 * @param form
 * @param fnc
 * @param prv
 * @return
 */
function openPanelMode(form1, fnc1, prv1, id, form2, fnc2, prv2) {
	if (!form2 && !fnc2 && !prv2) {
		form2 = form1;
		fnc2 = fnc1;
		prv2 = prv1;
	}
	w = window.open('./Panels.action?panels=true&'+
			'form1=' + form1 +
			'&fnc1=' + fnc1 +
			'&prv1=' + prv1 +
			'&id=' + id +
			'&form2=' + form2 +
			'&fnc2=' + fnc2 +
			'&prv2=' + prv2,
			"_blank",
			"resizable=yes");
	w.focus();
}

function isdefined(variable, object)
{
	if (object == null) object = window;
    return (typeof(object[variable]) == "undefined")?  false: true;
}

/**
 * Executes the function pointer on an enter keypress.
 * @param event The onkey... event.
 * @param method The function which should be executed on enter.
 * @return The result of the executed method or <code>false</code when the method was not executed.
 */
function onEnter(event, method) {
	return onKey(event, 13, method);
}

/**
 * Returns false when the tab key is pressed.
 * @param event
 * @return
 */
function onKey(event, key, method) {
	if (getKey(event) == key)
		if (typeof(method) == "function")
			return method();
		else
			return eval(method);
	return false;
}

function getKey(event) {
	return event.which ? event.which : event.keyCode;
}

/** 
 * @param searchfield id
 * @param keyword
 * @param parentFieldPath, path to field containing id of parent entity (or -1 when insert)
 * @param thisHandlers, this handlers in filter, csv (this_contact_relation)
 */
function doSearch(fieldId, displayFieldName, postfix) {
	if (!postfix) postfix = "";
	if (!displayFieldName) {
		var elems = getEnclosingElem(fieldId, "table").getElementsByTagName("input")
		for (var i = 0; i < elems.length; i++)
			if (elems[i].type != "hidden") {
				fieldId = elems[i].id.replace(/^formfield_(\d+)(_\d+)?_display$/, "$1$2");
				displayFieldName = elems[i].id;
				break;
			}
	}
		
	var id;
	if (document.getElementById("id"))
		id = document.getElementById("id").value;
	else
	{
		var idField = document.getElementById("editIds_" + displayFieldName.replace(/^.*(-?\d+)_display$/, "$1"));
		if (idField)
			id = idField.value;
	}
	
	if (id == -1) id = "";
	
	var keyword = document.getElementById(displayFieldName).value;
	var field = fieldId;
	var width = 800;
	var height = 420;
	
	var regexp = /^formfield_(\d+)(_-?\d+)(_display)?$/;
	if (regexp.test(displayFieldName))
		field = displayFieldName.replace(regexp, "$1$2");
	
	var targetField = displayFieldName.replace(/_display$/, "");
	
	var url = 'SearchField.action?field='+field+'&postfix='+postfix+'&identifier='+id+'&width='+width+'&height='+height+'&keyword='+URLEncode(keyword)+"&popup=true";
	url = addParentParams(url, document.getElementById(targetField)); // From selectbox.js
	
	w = window.open(url,'doSearch','height='+height+',width='+width+',screenX=10,screenY=10,top=10,left=10,resizable=yes,status=no,scrollbars=no');
	w.focus();
	return true;
}
/** 
 */
function selectEntity(entityId, target, functionId) {
	var id = document.getElementById("id").value;
	if (id == -1) id = "";
	
	var width = 800;
	var height = 420;
	
	var regexp = /^formfield_(\d+)(_\d+)(_display)?$/;
	var url = 'SearchField.action?entityId='+entityId+'&identifier='+id+'&field='+target+'&width='+width+'&height='+height+'&popup=true';
	if (functionId)
		url += '&function=' + functionId;
	
	w = window.open(url,'doSearch','height='+height+',width='+width+',screenX=10,screenY=10,top=10,left=10,resizable=yes,status=no,scrollbars=no');
	w.focus();
	return true;
}

/**
 * Returns the field with name fieldName from the form where the searchFrom element is in.
 * @param searchFrom An element from the same form as the field that is searched.
 * @param fieldName The name of the field.
 * @return The field from the same form as searchFrom with the name which is specified by fieldName.
 */
function getFieldFromForm(searchFrom, fieldName) {
	return getEnclosingElem(searchFrom, "form").elements[fieldName];
}

function getAjaxRequestObject() {  
	// Firefox, Opera 8.0+, Safari 
	try{return new XMLHttpRequest();}catch(e){}   
	// Internet Explorer    
	try{return new ActiveXObject("Msxml2.XMLHTTP");}catch(e){}      
	try{return new ActiveXObject("Microsoft.XMLHTTP");}catch(e){}      
	alert("Your browser does not support AJAX!");        
   	return false;  
}

/**
 * Returns the first parent of the elemToFind kind.
 * @param elem The element from where to search.
 * @param elemToFind The kind of element that needs to be found.
 * @return The parent element of the elemToFind kind. <code>null</code> when elem has no parent of elemToFind.
 */
function getEnclosingElem(elem, elemToFind) {
    while (elem != null) {
        if (elem.tagName.toLowerCase() == elemToFind.toLowerCase())
            break;
        elem = elem.parentNode;
    }
    return elem;
}

function parseXml(xml)
{
	try //Internet Explorer
	{
		parser = new DOMParser();
		xmlDoc = parser.parseFromString(xml, "text/xml");
	} catch (e) {
		try //Firefox, Mozilla, Opera, etc.
		{
			xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
			xmlDoc.async = "false";
			xmlDoc.loadXML(xml);
		} catch (e) {
			alert("Your browser doesn't support AJAX.");
		}
	}
	return xmlDoc;
}

/**
 * Als bij een eerste poging geen fieldObj wordt gevonden dan zal er task. 
 * voor geplakt worden
 * 
 * @param path (this wordt vervangen door formObj.entityalias, _ door .)
 * @param formObj het javascript/html form object
 */
function getFieldObject(path, postfix)
{
	var arr = getFieldObjectArr(path, postfix);
	if (arr.length == 0)
		return null;
	for (var i = arr.length - 1; i >= 0; i--)
		if (arr[i])
			return arr[i];
}

/**
 * GetFieldObject maar dan met alle opties.
 * @param path
 * @param postfix
 * @return
 */
function getFieldObjectArr(path, postfix)
{
	var result = new Array();
	if (!postfix) postfix = "";
	if(path=='undefined' || path==null){return result;}
	//if(formObj.entityalias.value=='task' && path.indexOf('call.')==0){return getFieldObjectInForm('task.'+path,formObj);}
	var fieldObj = null;
	try
	{
		var fieldHandler = pathField[path];
		if (!fieldHandler) return result;
		var fieldHandlers = fieldHandler.split(",");
		for (var i = 0; i < fieldHandlers.length; i++)
		{
			fieldHandler = fieldHandlers[i];
			var fieldObj = document.getElementById(fieldHandler + postfix);
			if(fieldObj==null)
			{
				if (/\.id$/.test(path))
					fieldObj = getFieldObject(path.substring(0, path.length - 3), postfix);
			}
			result.push(fieldObj);
		}
	}
	catch(err){alert(err.message);}
	return result;
}
 
 function getFieldObjects(pathPrefix, postfix)
 {
 	if (!postfix) postfix = "";
 	if(pathPrefix=='undefined' || pathPrefix==null){return null;}
 	

 	var contains = new Object();
 	var result = new Array();
 	var fieldObj = null;
 	for (var key in pathField)
 	{
 		if (startsWith(key, pathPrefix))
 		{
 			var fields = getFieldObjectArr(key, postfix);
 			for (var i = 0; i < fields.length; i++)
 			{
 				var field = fields[i];
	 			if (field && contains[field.id] !== true)
	 			{
	 				result.push(field);
	 				contains[field.id] = true;
	 			}
 			}
 		}
 	}
 		
 	return result;
 }
 
 /**
  * 
  * @param pathPrefix
  * @param postfix
  * @return
  */
 function getFieldObjectsWithPostfix(postfix)
 {
 	if(postfix=='undefined' || postfix==null){return null;}
 	
 	var contains = new Object();
 	var result = new Array();
 	var fieldObj = null;
 	for (var key in pathField)
 	{
 		if (endsWith(key, postfix))
 		{
 			var fields = getFieldObjectArr(key);
 			for (var i = 0; i < fields.length; i++)
 			{
 				var field = fields[i];
 				
	 			if (field && contains[field.id] !== true)
	 			{
	 				result.push(field);
	 				contains[field.id] = true;
	 			}
 			}
 		}
 	}
 		
 	return result;
 }

/**
 * Encodes a string into a safe encoded representation.
 * @param plaintext The string that needs to be encoded.
 * @return The encoded string.
 */
function URLEncode(plaintext)
{
	// The Javascript escape and unescape functions do not correspond
	// with what browsers actually do...
	var SAFECHARS = "0123456789" +					// Numeric
					"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +	// Alphabetic
					"abcdefghijklmnopqrstuvwxyz" +
					"-_.!~*'()";					// RFC2396 Mark characters
	var HEX = "0123456789ABCDEF";
	var encoded = "";
	for (var i = 0; i < plaintext.length; i++ ) 
	{
		var ch = plaintext.charAt(i);
	    if (ch == " ") 
	    {
		    encoded += "+";				// x-www-urlencoded, rather than %20
		} 
		else if (SAFECHARS.indexOf(ch) != -1) 
		{
		    encoded += ch;
		} 
		else 
		{
		    var charCode = ch.charCodeAt(0);
			if (charCode > 255) 
			{
			    alert( "Unicode Character '" 
                        + ch 
                        + "' cannot be encoded using standard URL encoding.\n" +
				          "(URL encoding only supports 8-bit characters.)\n" +
						  "A space (+) will be substituted." );
				encoded += "+";
			} 
			else 
			{
				encoded += "%";
				encoded += HEX.charAt((charCode >> 4) & 0xF);
				encoded += HEX.charAt(charCode & 0xF);
			}
		}
	} // end for
	return encoded;
}

/**
 * Find the previous sibling which has an innerHTML property.
 * @param lastNode
 * @return
 */
function findPreviousHTMLNode(lastNode) {
	while (lastNode != null && ! (lastNode.innerHTML || lastNode.name || lastNode.tagName)) {
		lastNode = lastNode.previousSibling;
		if (lastNode == null)
			return null;
	}
	return lastNode;
}

/**
 * Find the next sibling which has an innerHTML property.
 * @param lastNode
 * @return
 */
function findNextHTMLNode(lastNode) {
	while (lastNode != null && !(lastNode.innerHTML || lastNode.name || lastNode.className || lastNode.tagName)) {
		lastNode = lastNode.nextSibling;
		if (lastNode == null)
			return null;
	}
	return lastNode;
}

/**
 * Replaces all leading and trailing whitespace characters from the string.
 * @param value
 * @return
 */
function trim(value) {
	if (!value) return "";
	return value.replace(/^\s+/,'').replace(/\s+$/,''); 
}

/**
 * Selects all nodes from the DOM with the specified parameters.
 * @param searchClass
 * @param node
 * @param tag
 * @return
 */
function getElementsByClass(searchClass,node,tag) {
	var classElements = new Array();
	if ( node == null )
		node = document;
	if ( tag == null )
		tag = '*';
	var els = node.getElementsByTagName(tag);
	if (isIE() && els.length == 0 && tag == "*")
		els = node.all;

	var elsLen = els.length;
	var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
	for (i = 0, j = 0; i < elsLen; i++) {
		if ( pattern.test(els[i].className) ) {
			classElements[j] = els[i];
			j++;
		}
	}
	return classElements;
}

/**
 * Returns the input string with the first letter in uppercase.
 * @param input
 * @return
 */
function firstLetterUpper(input) {
	return input.substring(0,1).toUpperCase() + input.substring(1);
}

/**
 * Adds a debug message in the left menu.
 * @param message
 */
function debugMsg(message) {
	var div = document.createElement("div");
	div.innerHTML = message;
	document.getElementById("leftMenu").appendChild(div);
}
/**
 * Clears the left menu so that debug messages can be put there.
 */
function debugClear() {
	document.getElementById("leftMenu").innerHTML = "";
}

/**
 * Iterates over all form fields and generates a POST string.
 * @param fobj The form over which the function should iterate.
 * @param valFunc The function which is used to validate the field input.
 * @return The POST string for the form.
 */
function getFormValues(fobj, valFunc) {
	var str = "";
	var valueArr = null;
	var val = "";
	var cmd = "";
	for ( var i = 0; i < fobj.elements.length; i++) {
		if (valFunc) {
			// use single quotes for argument so that the value of
			// fobj.elements[i].value is treated as a string not a literal
			cmd = valFunc + "(" + 'fobj.elements[i].value' + ")";
			val = eval(cmd)
		}
		str += fobj.elements[i].name + "=" + escape(fobj.elements[i].value)
				+ "&";
	}
	str = str.substr(0, (str.length - 1));
	return str;
}

/**
 * Maps a function over all elements of an array.
 * @param arr The array with elements.
 * @param fnc The function which is applied to all elements. Signature: function(element, index)
 */
function map(arr, fnc) {
	for (var i = 0; i < arr.length; i++)
		fnc(arr[i], i);
}

/**
 * Return either the IE or Firefox string for the style.display property of a table row. 
 */
function tableRow() {
	if (document.all)
		return "";
	return "table-row";
}

/**
 * Return either the IE or Firefox string for the style.display property of a table cell. 
 */
function tableCell() {
	if (document.all)
		return "";
	return "table-cell";
}

/**
 * Adds a class to a HTML object.
 * @param object The object.
 * @param className The class which is added.
 */
function addClass(object, className) {
	var pattern = new RegExp("(^|\\s)"+className+"(\\s|$)");
	if (!object || (object.className != "" && pattern.test(object.className)))
		return;
	object.className = trim(object.className + " " + className);
}

/**
 * Removes a class from a HTML object.
 * @param object The object from which the classname is stripped.
 * @param className The classname which will be stripped.
 */
function stripClass(object, className) {
	if (!object || !object.className) return;
	
	object.className = trim(object.className.replace(new RegExp("(^|\\s)"+className+"(\\s|$)", "g"), " "));
}

/**
 * Checks if the given object has the specified classname.
 * @param object The object on which the test will be done.
 * @param className The classname to check.
 * @return If the object has the classname.
 */
function hasClass(object, className) {
	return new RegExp("(^|\\s)"+className+"(\\s|$)").test(object.className);
}

/**
 * Checks if an item is in the given array.
 * @param arr The array which is searched.
 * @param item The item.
 * @return <code>true</code> when the item is found.
 */
function in_array(arr, item) {
	for (var i = 0; i < arr.length; i++) {
		if (arr[i] == item)
			return true;
	}
	return false;
}
 
/**
 * Concatenates 2 arrays
 * @param arr1
 * @param arr2
 * @return
 */
function arr_concat(arr1, arr2) {
	var result = new Array();
	for (var i = 0; i < arr1.length; i++)
		result.push(arr1[i]);
	for (var i = 0; i < arr2.length; i++)
		result.push(arr2[i]);
	return result;
}

/**
 * Applies a filter to an array.
 * @param arr The array which should be filtered.
 * @param filterF The filter function (function(elem, index):boolean).
 * @return
 */
function filter(arr, filterF) {
	var target = new Array();
	for (var i = 0; i < arr.length; i++)
		if (filterF(arr[i], i))
			target.push(arr[i]);
	return target;
}

/**
 * Performs the onsubmit function of a form (if present) and submits the form if the onsubmit function returns true.
 * @param form
 * @return
 */
function submitForm(form) {
	if (form.onsubmit && form.onsubmit() === false)
		return false;
	form.submit();
	return true;
}

/**
 * Get the source of an event.
 * @param event
 * @return
 */
function getEventSource(event) {
	if (event == null || event == undefined)
		event = window.event;
	
	if (event.target)
		return event.target;
	else
		return event.srcElement;
}

function isInputElement(elem) {
	return /input|textarea|select/i.test(elem.tagName);
}

function setSelectOption(select, optionLabel) {
	var regex = new RegExp("^" + optionLabel + "$", "i");
	for (var i = 0; i < select.options.length; i++)
		if (regex.test(select.options[i].text))
			return select.selectedIndex = i; 
}

function URLEncode(plaintext)
{
	// The Javascript escape and unescape functions do not correspond
	// with what browsers actually do...
	var SAFECHARS = "0123456789" +					// Numeric
					"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +	// Alphabetic
					"abcdefghijklmnopqrstuvwxyz" +
					"-_.!~*'()";					// RFC2396 Mark characters
	var HEX = "0123456789ABCDEF";
	var encoded = "";
	for (var i = 0; i < plaintext.length; i++ ) 
	{
		var ch = plaintext.charAt(i);
	    if (ch == " ") 
	    {
		    encoded += "+";				// x-www-urlencoded, rather than %20
		} 
		else if (SAFECHARS.indexOf(ch) != -1) 
		{
		    encoded += ch;
		} 
		else 
		{
		    var charCode = ch.charCodeAt(0);
			if (charCode > 255) 
			{
			    alert( "Unicode Character '" 
                        + ch 
                        + "' cannot be encoded using standard URL encoding.\n" +
				          "(URL encoding only supports 8-bit characters.)\n" +
						  "A space (+) will be substituted." );
				encoded += "+";
			} 
			else 
			{
				encoded += "%";
				encoded += HEX.charAt((charCode >> 4) & 0xF);
				encoded += HEX.charAt(charCode & 0xF);
			}
		}
	} // end for
	return encoded;
}

function URLDecode(encoded)
{
   // Replace + with ' '
   // Replace %xx with equivalent character
   // Put [ERROR] in output if %xx is invalid.
   var HEXCHARS = "0123456789ABCDEFabcdef"; 
   var plaintext = "";
   var i = 0;
   while (i < encoded.length) 
   {
       var ch = encoded.charAt(i);
	   if (ch == "+") 
	   {
	       plaintext += " ";
		   i++;
	   } 
	   else if (ch == "%") 
	   {
			if (i < (encoded.length-2) 
					&& HEXCHARS.indexOf(encoded.charAt(i+1)) != -1 
					&& HEXCHARS.indexOf(encoded.charAt(i+2)) != -1 ) 
			{
				plaintext += unescape( encoded.substr(i,3) );
				i += 3;
			} 
			else 
			{
				alert( 'Bad escape combination near ...' + encoded.substr(i) );
				plaintext += "%[ERROR]";
				i++;
			}
		} 
		else 
		{
		   plaintext += ch;
		   i++;
		}
	} // end while
   return plaintext;
}

function entityDecode(value) {
	  value = value.replace(/&#x([0-9A-F]+)/ig, function() {return String.fromCharCode(RegExp.$1, 16);})
	  return value;
}

/**
 * will parse a value to float 
 * or retreive the value of the field a path and parse it
 */ 
function parseValueOrPathToFloat(valueOrPath)
{
	// retreive first field content
	fieldObj = getFieldObject(valueOrPath);
//	alert(fieldObj);
	
	// no fieldObj, fixed value (always config as 1.50)
	if(fieldObj==null)
	{
		if(isFloat(valueOrPath))
		{
			return parseFloat(valueOrPath);
		}
		return null;
	}
	
	// field object retreived, get value and parse it
	if(isEmpty(fieldObj.value)){return null;}
	
	// retreive value text
	var valueText = null;
	
	// use option alias(configurable in manager) as value for select types
	if(fieldObj.type=='select-one' || fieldObj.type=='select-multiple')
	{
		valueText = fieldObj.options[fieldObj.selectedIndex].alias;
	}
	else
	{
		valueText = fieldObj.value;
	}
//	alert(fieldObj.name + valueText);
	// Parse valueText to Float
	if(isEmpty(valueText)){return null;}
	return parseStringToFloat(valueText);
}

function isFloat(val) 
{
	var digits="1234567890.,";
	for (var i=0; i < val.length; i++) 
	{
		if (digits.indexOf(val.charAt(i))==-1){return false;}
	}
	return true;
}
/**
 * locale dependend parseFloat (user can enter 1,50 as nl_NL)
 */
function parseStringToFloat(value)
{
	// english, parsing==normal javascript parse
	if(locale=='en_EN')
	{
		return parseFloat(value)
	}
	// dutch, remove all . and replace , with .
	value = value.replace(/\./g,'');
	value = value.replace(',','.');
	return parseFloat(value);
}

function parseFloatToString(value)
{
	if(locale=='en_EN')
	{
		return value
	}
	value = ''+value;
	value = value.replace('\.',',');
	return value;
}

function getInt(str,i,minlength,maxlength) 
{
	for (var x=maxlength; x>=minlength; x--) 
	{
		var token=str.substring(i,i+x);
		if (token.length < minlength) { return null; }
		if (isInt(token)) { return token; }
	}
	return null;
}

/**
 * Inserts some text in the object at the cursor position.
 * @param obj
 * @param text
 * @return
 */
function insertAtCaret(obj, text, fromPopup) {
	if(document.selection) {
		obj.focus();
		var orig = obj.value.replace(/\r\n/g, "\n");
		var doc = fromPopup ? opener.document : document;
		var range = doc.selection.createRange();

		if(range.parentElement() != obj) {
			alert(":(");
			return false;
		}

		range.text = text;
		
		var actual = tmp = obj.value.replace(/\r\n/g, "\n");

		for(var diff = 0; diff < orig.length; diff++) {
			if(orig.charAt(diff) != actual.charAt(diff)) break;
		}

		for(var index = 0, start = 0; 
			tmp.match(text) 
				&& (tmp = tmp.replace(text, "")) 
				&& index <= diff; 
			index = start + text.length
		) {
			start = actual.indexOf(text, index);
		}
	} else if(obj.selectionStart) {
		var start = obj.selectionStart;
		var end   = obj.selectionEnd;

		obj.value = obj.value.substr(0, start) 
			+ text 
			+ obj.value.substr(end, obj.value.length);
	}
	
	if(start != null) {
		setCaretTo(obj, start + text.length);
	} else {
		obj.value += text;
	}
}

/**
 * Sets the selection to the given position
 * @param obj
 * @param pos
 * @return
 */
function setCaretTo(obj, pos) {
	if(obj.createTextRange) {
		var range = obj.createTextRange();
		range.move('character', pos);
		range.select();
	} else if(obj.selectionStart) {
		obj.focus();
		obj.setSelectionRange(pos, pos);
	}
}

function formatCurrency(result) 
{
	var num = new NumberFormat();
	num.setInputDecimal('.');
	num.setNumber(result);
	num.setPlaces('2', false);
	num.setCurrencyValue('');
	num.setCurrency(true);
	num.setCurrencyPosition(num.LEFT_OUTSIDE);
	num.setNegativeFormat(num.LEFT_DASH);
	num.setNegativeRed(false);
	if(locale=='en_EN') {
		num.setSeparators(true, ',', '.');
	}
	else {
		num.setSeparators(true, '.', ',');
	}
	
	return num.toFormatted().replace(/[,\.]00$/, "");
}

/**
 * String value: the value to check for empty
 * Returns true if value is null or value.length==0
 */
function isEmpty(value)
{
	if (value==null) return true;
	if (value.length==0) return true;
	return false;
}

/**
 * @param str
 * @return
 */
function nonNullString(str) {
	if (str == "null") return "";
	if (!str) return "";
	return str;
}
/**
 * Replaces the {x} in a string with the rx parameter.
 * @param msg
 * @param rx
 * @return
 */
function getMessage(msg, r1, r2, r3, r4, r5, r6, r7, r8, r9)
{
	return msg.replace(/\{1\}/g, nonNullString(r1))
			  .replace(/\{2\}/g, nonNullString(r2))
			  .replace(/\{3\}/g, nonNullString(r3))
			  .replace(/\{4\}/g, nonNullString(r4))
			  .replace(/\{5\}/g, nonNullString(r5))
			  .replace(/\{6\}/g, nonNullString(r6))
			  .replace(/\{7\}/g, nonNullString(r7))
			  .replace(/\{8\}/g, nonNullString(r8))
			  .replace(/\{9\}/g, nonNullString(r9));
}

/**
 * Returns the text content from a node.
 * @param node
 * @return
 */
function getTextFromNode(node) {
	if (document.all)
		return trim(node.innerText);
	else
		return trim(node.textContent);
}

/**
 * Creates an HTML node.
 * @param tag
 * @param type
 * @param name
 * @param id
 * @return
 */
function createElement(tag, type, name, id, doc) {
	if (!doc) doc = document;
	var elem = doc.createElement(tag);
	if (type) elem.type = type;
	if (name) elem.name = name;
	if (id) elem.id = id;
	return elem;
}
 
/**
 * Maak een element met eigenschappen.
 * @param tag
 * @return
 */
function createElementEx(tag)
{
	var element = document.createElement(tag);
	var i = 1;
	while (i < arguments.length) 
	{
		var attrib = arguments[i++];
		var value = arguments[i++];
		
		
		if (attrib == "onclick" && typeof(value) == "function")
			$(element).click(value);
		else if (attrib == "class")
		{
			element.className = value;
		}
		else
		{
			element[attrib] = value;
			element.setAttribute(attrib, value);
		}
	}
 	return element;
}

/**
 * Navigate to an url.
 * @param url
 * @return
 */
function navigate(url, check) {
	if (/export=/.test(url))
		check = false;
	
	if (check !== false) 
		if (!confirmOnFormChanged())
			return;
	
	if (/panels=true/.test(location.href)) {
		// Get the target panel.
		url += "&panels=true";

		if (/^left/.test(window.name))
			parent.frames['left'].location.href = url;
		else
			parent.frames['right'].location.href = url;
		return;
	}
	if (/popup=true/.test(location.href))
		url += "&popup=true";
	location.href = url;
}

/**
 * Cookie methods from http://www.quirksmode.org/js/cookies.html
 */
function createCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}
function eraseCookie(name) {
	createCookie(name,"",-1);
}

function isArray(obj) {
   if (obj.constructor.toString().indexOf("Array") == -1)
      return false;
   else
      return true;
}

function objectsToMap(objects) {
	var result = new Object();
	for ( var i = 0; i < objects.length; i++) {
		if (!objects[i].name) continue;
		if (isdefined(objects[i].name, result)) {
			if (typeof (result[objects[i].name]) != "object")
				result[objects[i].name] = new Array(result[objects[i].name]);

			result[objects[i].name].push(objects[i].value);
		} else
			result[objects[i].name] = objects[i].value;
	}
	return result;
}

/**
 * Include een Javascript bestand na page load.
 * @param scriptpath
 * @param functions
 * @return
 */
var includedFiles = new Array();
function include(file){
	// include een bestand maar 1 keer.
	for (var i = 0; i < includedFiles.length; i++) if (includedFiles[i] == file) return;
	includedFiles.push(file);
	var oXML = getAjaxRequestObject();
	oXML.open('GET', file, false);
	oXML.send('');
	eval(oXML.responseText);
	for(var i=0; i<functions.length; i++)
		window[functions[i]] = eval(functions[i]);
}

function startsWith(haystack, needle)
{
	return (haystack.match("^"+needle)==needle)
}

function endsWith(haystack, needle)
{
	return (haystack.match(needle + "$")==needle)
}

function disableField(field, empty)
{
	var display = document.getElementById(field.id + "_display");
	field.disabled = true;
	addClass(field, "readonly");
	stripClass(field, "required");
	if (empty) field.value = "";
	if (display) {
		addClass(display, "readonly");
		display.disabled = true;
		if (empty) display.value = "";
	}
	
	var label = document.getElementById(field.id + "_label");
	if (label)
	{
		if (hasClass(label, "required"))
			addClass(label, "wasrequired");
		stripClass(label, "required");
	}
	
	var table = getEnclosingElem(field, "table");
	if (hasClass(table), "nestedTable")
		map(table.getElementsByTagName("img"), function(a){getEnclosingElem(a, "td").style.display = "none";});
}

function requireField(field, required)
{
	if (typeof(field) == 'string')
		field = getFieldObject(field);
	var fnc = required ? addClass : stripClass;
	var display = document.getElementById(field.id + "_display");
	var label = document.getElementById(field.id + "_label");

	if (field)   fnc(field, "required");
	if (display) fnc(display, "required");
	if (label)   fnc(label, "required");
}

function enableField(field)
{
	var display = document.getElementById(field.id + "_display");
	var label = document.getElementById(field.id + "_label");
	field.disabled = false;
	stripClass(field, "readonly");
	if (display) {
		display.disabled = false;
		stripClass(display, "readonly");
	}
	
	if (hasClass(label, "wasrequired"))
	{
		addClass(label, "required");
		addClass(field, "required");
	}
	
	var table = getEnclosingElem(field, "table");
	if (hasClass(table), "nestedTable")
		map(table.getElementsByTagName("img"), function(a){getEnclosingElem(a, "td").style.display = tableCell();});
}

/**
 * Haal een icoon object op.
 * @param name
 * @return
 */
function getIcon(name)
{
	var icons = document.getElementById("iconbar").getElementsByTagName("img")
	var a = "";
	for (var i = 0; i < icons.length; i++)
	{
	  if (icons[i].src.match('/' + name + "."))
	    return icons[i];
	}
	return null;
}

/**
 * Disable een icoon.
 * @param icon
 * @return
 */
function disableIcon(icon)
{
	if (typeof(icon) == "string") return disableIcon(getIcon(icon));
	if (icon == null) return;
	if (/_na\.gif/.test(icon.src)) return;
	icon.src = icon.src.replace(/\.gif$/, "_na.gif");
	getEnclosingElem(icon, 'button').disabled = true
}
 
 /**
  * function for set a value to a field
  * @param field: html dom field object
  * @param valueStr: value to set
  * @param readOnlyFlag: should field be readOnly after this action?
  */
function setValueToField(field, valueStr, readOnlyFlag) {
	if (field == null) {
		return;
	}
	if (valueStr != null) {
		field.value = valueStr;
	}
		// alert(field.name+': ' + field.value);
	if (field.tagName == 'select' || field.type == 'select-one' || field.type == 'select-multiple') {
		if (!isEmpty(readOnlyFlag)) {
			field.disabled = readOnlyFlag;
		}
		doUpdateOptionsChildField(field);
	} else if (field.type != 'hidden' && !isEmpty(readOnlyFlag)) {
		field.readOnly = readOnlyFlag;
	}
}
  
function isVisible(element, depth)
{
	if (element.style.display == 'none' || element.style.visibility == 'hidden')
		return false;
	
	if (!element.parentNode || depth === 0)
		return true;
	
	if (!depth)
		return isVisible(element.parentNode, null);
	else
		return isVisible(element.parentNode, depth-1);
}

function getUrlContent(theUrl, postData, method)
{
	if (!method) method = "GET";
	theUrl = theUrl.substring(0,6) + theUrl.substring(6).replace(/\/+/g, '/');
	
	if (postData && typeof(postData) != "object") eval("postData = " + postData);
	return $.ajax(
	               {
	            	   url : theUrl
	            	 , async : false
	            	 , data : postData
	            	 , type : method
	               }
	).responseText;
}

function getUrlContentEx(url, method)
{
	var data = new Object();
	var i = 2;
	while (i < arguments.length) 
	{
		var attrib = arguments[i++];
		var value = arguments[i++];
		
		data[attrib] = value;
	}
	return getUrlContent(url, data, method);
}

/**
 * Toggled zichtbaarheid van een element. Gaat er vanuit dat de standaard display block is (dit is niet het geval bij bv. een span element).
 * @param element
 * @return
 */
function toggleVisibility(element)
{
	if (typeof(element) == "string")
		element = document.getElementById(element);
	
	if (element.style.display == "none")
	{
		if (element.tagName == "td") element.style.display = tableCell();
		else if (element.tagName == "tr") element.style.display = tableRow();
		else element.style.display = "block";
	}
	else
		element.style.display = "none";
}

/**
 * Voor gebruik in OnBlur scripts. Kopieert de waarde van het veld naar het doel.
 * @param source Het bron veld. In onblur scripts altijd this
 * @param target Het pad van het doel veld. Bijvoorbeeld: 'call.gesprokenmet.email'
 */
function copyValueToField(source, target)
{
	var field = getFieldObject(target);
	if (!field) return;
	field.value = source.value;
}

/**
 * Maakt alle inputs, textarea's en select's leeg in het opgegeven object.
 * @param object
 * @return
 */
function clearFieldValues(object)
{
	$(object).find("input,textarea,select").each(function(a,obj) {
		if (obj.type == 'hidden' && obj.id != obj.name) return; // TODO: Betere filter.
		if (obj.type == 'checkbox') obj.checked = false;
		obj.value = '';
		$(obj).trigger('change');
		$(obj).trigger('blur');
	});
}

/**
 * Geeft alle velden met hetzelfde pad, dezelfde waarde.
 * @return
 */
function updateAllValues(fld) {
    if (/_display$/.test(fld.id))
	    fld = document.getElementById(fld.id.replace(/_display$/, ''));

    var dSrc = document.getElementById(fld.id + "_display");
    var disp;
    if (dSrc)
    	disp = dSrc.value;
    
    if (/select/i.test(fld.tagName))
    	disp = $(fld).find(":selected").text()

    var flds = pathField[pathField[fld.id]].split(",");
    for (var i = 0; i < flds.length; i++) {
    	var tFld = document.getElementById(flds[i]);
    	var dFld = document.getElementById(flds[i] + "_display");
        if (tFld != fld)
        	if (tFld && fld.type == "checkbox")
        		tFld.checked = fld.checked;
        	else if (tFld)
        		tFld.value = fld.value;
        if (dFld) dFld.value = disp;
    }
}