// (c) 2002 LANSA
// XHTML Standard Scripts
// $Workfile::   std_script_v2.js          $
// $Revision::   1.24.1.1                  $

//////////////////////////////////////////////////////////////////////////////////////////
//
// Assorted updates to standard object prototypes
//
//////////////////////////////////////////////////////////////////////////////////////////
if (document.all && !document.getElementById)
{
	document.prototype.getElementById = function(id)
	{
		return document.all[id];
	}
}
// Return the string padded with leading zeros
String.prototype.zeropad = function(l)
{ 
	var s = '', i = this.length;
	while (i++ < l) { s += '0'; }
	return s + this;
}
String.prototype.ltrim = function() { return this.replace(/^\s+/g, ""); }
String.prototype.rtrim = function() { return this.replace(/\s+$/g, ""); }
String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ""); }

// Return the number as a string padded with leading zeros
Number.prototype.zeropad = function(l) { return this.toString().zeropad(l); }
// Return the index of the first array item matching the supplied value
Array.prototype.indexOf = function(toFind)
{
	for (var i=0, item; item=this[i]; i++)
	{
		if (item == toFind) return i;
	}
	return -1;
}
// Set the value of the date object to the supplied ISO8601 string
Date.prototype.setISO8601 = function (dateStr) {
	if (dateStr.length == 0)
	{
		this.sqlNull = true;
		return;
	}
	var regexp = /(\d\d\d\d)(?:-?(\d\d)(?:-?(\d\d)(?:[T ](\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(?:Z|(?:([-+])(\d\d)(?::?(\d\d))?)?)?)?)?)?/
	var d = dateStr.match(regexp);
	var offset = 0;
	if (!d || !d[1]) { return null; }
	var date = new Date(d[1], 0, 1);
	if (d[2]) { date.setMonth(d[2] - 1); }
	if (d[3]) { date.setDate(d[3]); }
	if (d[4]) { date.setHours(d[4]); }
	if (d[5]) { date.setMinutes(d[5]); }
	if (d[6]) { date.setSeconds(d[6]); }
	if (d[7]) { date.setMilliseconds(Number("0." + d[7]) * 1000); }
	if (d[8]) {
		offset = (Number(d[9]) * 60) + Number(d[10]);
		offset *= ((d[8] == '-') ? 1 : -1);
	}
	// date plus offset = UTC time.  Need to subtract TimezoneOffset to convert to local browser time
	offset -= date.getTimezoneOffset();
	time = (Number(date) + (offset * 60000));
	this.setTime(Number(time));
	this.sqlNull = false;
}
// Returns the date as an ISO8601 string
Date.prototype.toISO8601String = function (includeTime, useLocalTime) {
	if (includeTime == undefined) { var includeTime = true; }
	if (useLocalTime == undefined) { var useLocalTime = true; }
	var date = this;
	var nY = 0, nM = 0, nD = 0, nH = 0, nMin = 0, nS = 0, nMs = 0, nOffset = 0;
	if (useLocalTime) {
		nY = date.getFullYear();
		nM = date.getMonth() + 1;
		nD = date.getDate();
		nH = date.getHours();
		nMin = date.getMinutes();
		nS = date.getSeconds();
		nMs = date.getMilliseconds();
		nOffset = -date.getTimezoneOffset();
	}
	else
	{
		nY = date.getUTCFullYear();
		nM = date.getUTCMonth() + 1;
		nD = date.getUTCDate();
		nH = date.getUTCHours();
		nMin = date.getUTCMinutes();
		nS = date.getUTCSeconds();
		nMs = date.getUTCMilliseconds();
		nOffset = 0;   
	}
	var str = nY + "-" + nM.zeropad(2) + "-" + nD.zeropad(2);
	if (includeTime)
	{
		str += "T" + nH.zeropad(2) + ":" + nMin.zeropad(2) + ":" + nS.zeropad(2);
		if (nMs > 0)
		{
			str += "." + nMs.zeropad(3);
		}
	}
	if (nOffset == 0)
	{
		str += "Z";
	}
	else
	{
		if (nOffset >= 0) { str += "+"; }
		str += Math.round(nOffset / 60).zeropad(2) + ":" + (nOffset % 60).zeropad(2);
	}
	 return str;
}
// Attach the Localised month and date name arrays to the Date object
// Implimented as functions because the arrays are not defined until 
// std_script.messages.js is loaded.
Date.prototype.arrayMstringDays = function () { return stdGetMTextMessageTextArr("DaysOfWeek"); }
Date.prototype.arrayMstringMonths = function() { return stdGetMTextMessageTextArr("Months"); }
// Returns the date as a string formatted according to the supplied format mask.
Date.prototype.toFormattedString = function(f)
{
	var d = this;
	return f.replace(/(YYYY|YY|Y|MMMM|MM|M|DDD|DD|D|HH|H|hh|h|mm|m|sss|ss|s|t)/g,
		function($1)
		{
			switch ($1)
			{
				case 'YYYY': return d.getFullYear();
				case 'YY':   return (d.getFullYear() % 100).zeropad(2);
				case 'MMMM': return d.arrayMstringMonths()[d.getMonth()];
				case 'MM':   return (d.getMonth() + 1).zeropad(2);
				case 'M':    return (d.getMonth() + 1);
				case 'DDD': return d.arrayMstringDays()[d.getDay()];
				case 'DD':   return d.getDate().zeropad(2);
				case 'D':	 return d.getDate();
				case 'HH':   return d.getHours().zeropad(2);
				case 'H':    return d.getHours();
				case 'hh':   return ((h = d.getHours() % 12) ? h : 12).zeropad(2);
				case 'h':    return ((h = d.getHours() % 12) ? h : 12);
				case 'mm':   return d.getMinutes().zeropad(2);
				case 'm':    return d.getMinutes();
				case 'ss':   return d.getSeconds().zeropad(2);
				case 's':    return d.getSeconds();
				case 'sss':  return d.getMilliseconds().zeropad(3);
				case 't':	 return d.getHours() < 12 ? 'A.M.' : 'P.M.';
			}
		} );
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// Assorted utility functions
//
//////////////////////////////////////////////////////////////////////////////////////////
function trapError(errorMsg, url, line)
{
	jslog.error(errorMsg + "\n" + url + ", line " + line);
	return true;
}
function getParentForm(formElement)
{
	var f = null;
	try
	{
		f = formElement.form;
	}
	catch(ex)
	{
		f = null;
	}
	if( f == null )
	{
		f = getParentElement(formElement, "form");
	}
	return f;
}
function getParentElement(child, parentTagName) {
	var e = child;
	var tn = parentTagName.toUpperCase();
	while (e.parentNode)
	{
		if (e.nodeName == tn)
		{
			return e;
		}
		else
		{
			e = e.parentNode;
		}
	}
	return null;
}
function getRelativeMouseX(relTo, evt)
{
	var mouseX = 0;
	if (evt.pageX)
	{
		mouseX = evt.pageX;
	}
	else if (evt.clientX)
	{
		mouseX = evt.clientX + document.body.scrollLeft;
	}
	mouseX -= getAbsoluteLeft(relTo);
	return mouseX;
}
function getRelativeMouseY(relTo, evt) {
	var mouseY = 0;
	if (evt.pageY)
	{
		mouseY = evt.pageY;
	}
	else if (evt.clientY)
	{
		mouseY = evt.clientY + document.body.scrollTop;
	}
	mouseY -= getAbsoluteTop(relTo);
	return mouseY;
}
function getAbsoluteTop(obj) {
	var top = obj.offsetTop;
	var p = obj.offsetParent;
	while (p != null)
	{
		top += p.offsetTop;
		p = p.offsetParent;
	}
	return top;
}
function getAbsoluteLeft(obj) {
	var left = obj.offsetLeft;
	var p = obj.offsetParent;
	while (p != null)
	{
		left += p.offsetLeft;
		p = p.offsetParent;
	}
	return left;
}
function getCurrentStyle(el,styleProp)
{
	var x = (typeof el == 'string') ? document.getElementById(el) : el;
	if (x.currentStyle)
		var y = x.currentStyle[styleProp.replace( /(-)([a-z])/g, function(t,a,b) { return b.toUpperCase(); } )];
	else if (window.getComputedStyle)
		var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp);
	return y;
}
function getElementsByClassAndTag(parent, theClass, theTag)
{
	if (!parent) parent = document;
	if (!theTag) theTag = "*";
	var all = !theClass;
	var tags = parent.getElementsByTagName(theTag);
	var a = new Array();
	for (var i=0, t; t = tags[i]; i++)
	{
		if (all || (t.className == theClass)) a[a.length] = t;
	}
	return a;
}
function addEvent(obj, type, fn)
{
	if (obj.addEventListener)
		obj.addEventListener( type, fn, false );
	else if (obj.attachEvent)
	{
		obj["e"+type+fn] = fn;
		obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
		obj.attachEvent( "on"+type, obj[type+fn] );
	}
}
function removeEvent(obj, type, fn)
{
	if (obj.removeEventListener)
		obj.removeEventListener( type, fn, false );
	else if (obj.detachEvent)
	{
		obj.detachEvent( "on"+type, obj[type+fn] );
		obj[type+fn] = null;
		obj["e"+type+fn] = null;
	}
}
function cancelEvent(e) {
    e.cancelBubble = true; // for IE
    if (typeof e.stopPropagation == 'function')
        e.stopPropagation();

    e.returnValue = false; // for IE
    if (typeof e.preventDefault == 'function')
        e.preventDefault();
}
function addCSSRule(theSS, theSelector, theRule) {
	if (theSS.insertRule) {
         theSS.insertRule( theSelector + ' {' + theRule + '}', theSS.cssRules.length);
    } else if (theSS.addRule) {
    	theSS.addRule(theSelector, theRule);
    }
}
function fixTarget(theTarget)
{
	// If using client-side xslt transformation on IE then this page
	// will be inside an iframe and the target needs to be modified
	// to compensate
	var t = (theTarget) ? theTarget : "";
	if (parent.g_clientXSLTiframe)
	{
		switch (t)
		{
			case "":
			case "_self":
				return "_parent";
			case "_parent":
				// Really needs to be _parent._parent._parent but there is
				// no such thing
				var name = window.parent.parent.parent.name;
				if (name != "") return name;
				return "_parent";
		}
	}
	return t;		
}
function createStdHiddenForm(WAMName, WRName, formName, protocol, target)
{
	var f = null;
	if (formName && formName.length > 0)
	{
		if (formName.indexOf('.') >= 0) {
			f = eval("document." + formName);
		} else {
			f = document.forms[formName];
		}
	}
	if (f == null)
	{
		f = document.createElement('form');
		f.name = formName;
		var action = "";
		if( protocol && protocol.length > 0 )
		{
			action += protocol;
			if( protocol.search(new RegExp("//", "g")) < 0 )
			{
				action += "//" + document.location.host;
			}
		}
		action += g_lxmlAR + "?webapp=" + WAMName + "+webrtn=" + WRName
				  + "+ml=" + g_lxmlTs + "+partition=" + g_lxmlPartition + "+language=" + g_lxmlLang;
		if (g_lxmlTransform  && g_lxmlTransform.length > 0) action += "+transform=" + g_lxmlTransform;
		if( g_debug && g_debug.length > 0 ) action += "+debug=" + g_debug;
		if( g_lxmlSK != null ) action += "+sid=" + g_lxmlSK;
		if (location.href.match(/\?.*enablejslog/)) action += "+enablejslog";

		f.setAttribute("action", action);
		f.style.display = "none";
		f.setAttribute("method", "POST");
		insertHiddenField(f, "_SERVICENAME", g_lxmlServiceName);
		insertHiddenField(f, "_WEBAPP", g_lxmlWAMName);
		insertHiddenField(f, "_WEBROUTINE", g_lxmlWRName);
		insertHiddenField(f, "_PARTITION", g_lxmlPartition);
		insertHiddenField(f, "_LANGUAGE", g_lxmlLang);
		
		if (g_lxmlSK) insertHiddenField(f, "_SESSIONKEY", g_lxmlSK);
		insertHiddenField(f, "_LW3TRCID", g_lw3Trace);
		f.target = fixTarget(target);
		document.body.appendChild(f);
	}
	return f;
}
function insertHiddenField(form, fieldName, fieldValue)
{
	if( form == null ) return null;
	var field = form.elements[fieldName];
	if (field == null)
	{
		try
		{
			field = form.ownerDocument.createElement('<input type="hidden" name="' + fieldName + '" value="' + fieldValue + '" />');
		}
		catch (e)
		{
			field = form.ownerDocument.createElement('input');
			field.setAttribute("type", "hidden");
			field.setAttribute("name", fieldName);
			field.setAttribute("value", fieldValue);
		}
		form.appendChild(field);
	}
	else
	{
		field.value = fieldValue;
	}
	return field;
}
function submitForm(theForm, WAM, WebRoutine, optTarget, optProtocol)
{
	var action="";
	var backupAction = theForm.action;
	var backupTarget = theForm.target;
	if( optProtocol != null && optProtocol.length > 0 )
	{
		action += optProtocol;
		if( optProtocol.search(new RegExp("//", "g")) < 0 )
		{
			action += "//" + stdGetOwnerDocument(theForm).location.host;
		}
	}
	action += g_lxmlAR + "?webapp=" + WAM + "+webrtn=" + WebRoutine + "+ml=" + g_lxmlTs + "+partition=" + g_lxmlPartition + "+language=" + g_lxmlLang;
	if (g_lxmlTransform  && g_lxmlTransform.length > 0) action += "+transform=" + g_lxmlTransform;
	if( g_debug != null && g_debug.length > 0 ) action += "+debug=" + g_debug;
	if( g_lxmlSK != null ) action += "+sid=" + g_lxmlSK;
	if (location.href.match(/\?.*enablejslog/)) action += "+enablejslog";
	theForm.action = action;
	theForm.target = fixTarget(optTarget);
	theForm.submit();
	theForm.action = backupAction;
	theForm.target = backupTarget;
}
function createReentryFields(f, spansParent)
{
	if (f != null)
	{
		var spans = spansParent.getElementsByTagName('span');
		var reentryField;
		var reentryValue = '';
		for (var i=0, s; s=spans[i]; i++)
		{
			if (s.className == "reentryfield") reentryField = s.innerHTML.replace(/(<!---->)$/, "");
			if (s.className == "reentryvalue") reentryValue = s.innerHTML.replace(/(<!---->)$/, "");
		}
		if (reentryField) insertHiddenField(f, reentryField, reentryValue);
	}
}
function isDblClick(elem)
{
	var t = new Date().getTime();
	if ((elem.__lastClickedTime) && ((t - elem.__lastClickedTime) < 1000))
	{
		return true;
	}
	elem.__lastClickedTime = t;
	return false;
}
function stdFieldOnChangeHandler(fld) {
	switch (fld.getAttribute("__FormatType"))
	{
		case 'alpha':
		case 'char':
		case 'varchar':
			return isValidText(fld, fld.getAttribute("__KeyboardShift"));
		case 'packed':
		case 'signed':
			return isValidNumber(fld, fld.getAttribute("__TotalDigits"), fld.getAttribute("__FractionDigits"), fld.getAttribute("__DecimalSeparator"))
		case 'integer':
			return isValidInteger(fld, fld.getAttribute("__MaxLength"))
		case 'float':
			return isValidFloat(fld, fld.getAttribute("__MaxLength"));
		case 'date':
			return isValidDate(fld);
		case 'time':
			return isValidTime(fld);
		case 'datetime':
			return isValidDateTime(fld, fld.getAttribute("__MaxLength"));
		case 'boolean':
			return isValidBoolean(fld);
	}
	return true;
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// JavaScript support for std_messages weblet
//
//////////////////////////////////////////////////////////////////////////////////////////
function stdTransferMessages(targetWindowName, msgElemId)
{
	if (msgElemId == null || msgElemId.length <= 0 ) return;
	if (targetWindowName == null || targetWindowName.length == 0) targetWindowName = "_top";
	
	var targetWindow = null;
	switch (targetWindowName)
	{
		case "_top":
			targetWindow = window.top;
			break;
		case "_self":
			targetWindow = window;
			break;
		case "_blank":
		case "_media":
		case "_search":
			return;
		case "_parent":
			targetWindow = window.parent;
			break;
		default:
			var w = window;
			do
			{
				frames = w.document.getElementsByTagName("frame");
				for (var i=0, f; f=frames[i]; i++)
				{
					if (f.name == targetWindowName)
					{
						targetWindow = f;
						break;
					}
				}
				w = w.parent;
			} while (w != w.parent || targetWindow == null)
	}
	if (targetWindow != null)
	{
		var srcElem = document.getElementById(msgElemId);
		var tgtElem = targetWindow.document.getElementById(msgElemId);
		if (srcElem && tgtElem && (srcElem != tgtElem))
		{
			var html = srcElem.innerHTML;
			tgtElem.innerHTML = html;
			tgtElem.style.display = "";
		}
	}
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// Javascript support for std_menu_item
//
/////////////////////////////////////////////////////////////////////////////////////////
function stdMenuItemClicked(e, menuItem, WAMName, WRName, formName, protocol, target)
{
	return stdAnchorClicked(e, menuItem, WAMName, WRName, formName, protocol, target, null, null)
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// Javascript support for image mouseovers
//
//////////////////////////////////////////////////////////////////////////////////////////
function stdImageMouseOver(theImg)
{
	var newSrc = theImg.getAttribute("__moImage");
	var oldSrc = theImg.getAttribute("__stdImage");
	if ((newSrc) && (!oldSrc))
	{
	   theImg.setAttribute("__stdImage", theImg.src);
	   theImg.src = newSrc;
	}
}
function stdImageMouseOut(theImg)
{
   var oldSrc = theImg.getAttribute("__stdImage");
   if (oldSrc)
   {
      theImg.src = oldSrc;
      theImg.setAttribute("__stdImage", "");
   }
}
function stdImagePreloadMO(theImg)
{
	var src = theImg.getAttribute("__moImage");
	if (src != "")
	{
		var img = new Image();
		img.src = src;
	}
}
function preloadStdImageMouseOvers()
{
	var image = document.getElementsByTagName("IMG");
	for(var i=0, img; img=images[i]; i++)
	{
		stdImagePreloadMO(img);
	}
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// Javascript support for std_anchor
//
//////////////////////////////////////////////////////////////////////////////////////////
function stdAnchorClicked(e, elem, WAMName, WRName, formName, protocol, target, currentrowhfield, currentrownumval)
{
	if(!e) { if( window.event ) { e = window.event; } else { return; } }
	elem.target = fixTarget(elem.target);
	if (WRName != '')
	{
		var f = createStdHiddenForm(WAMName, WRName, formName, protocol, target);
		if (f != null)
		{
			createReentryFields(f, elem);
			if (currentrowhfield && currentrowhfield.length > 0) insertHiddenField(f, currentrowhfield, currentrownumval);
			submitForm(f, WAMName, WRName, target, protocol);
		}
		cancelEvent(e);
		return false;
	}
	return true;
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// Javascript support for std_button
//
//////////////////////////////////////////////////////////////////////////////////////////
function stdButton_clicked(e, elem, WAMName, WRName, formName, protocol, target, currentrowhfield, currentrownumval)
{
	if(!e) { if( window.event ) { e = window.event; } else { return; } }
	var f = (!formName) ? getParentForm(elem) : createStdHiddenForm(WAMName, WRName, formName, protocol, target);
	if (f != null)
	{
		createReentryFields(f, elem.parentNode);
		if (currentrowhfield && currentrowhfield.length > 0) insertHiddenField(f, currentrowhfield, currentrownumval);
		submitForm(f, WAMName, WRName, target, protocol);
	}
	cancelEvent(e);
	return false;
}
function stdButton_setDefault(btnType, formName, btn, onSubmitFunc)
{
	if (!btn)
	{
		// if the button is not specified, use the last one in the document
		// (i.e. the one created just before the call to this function)
		var btns = document.getElementsByTagName(btnType);
		if (btns.length > 0) btn = btns[btns.length-1];
	}
	if (btn)
	{
		var f = (!formName) ? getParentForm(btn) : document.forms[formName];
		if (f)
		{
			f.__defaultSubmitButton = btn;
			f.onsubmit = onSubmitFunc;
		}
	}
}
function stdForm_Submit(form, WAMName, WRName, protocol, target)
{
	createReentryFields(form, form.__defaultSubmitButton.parentNode);
	submitForm(form, WAMName, WRName, target, protocol);
	return false;
}

//////////////////////////////////////////////////////////////////////////////////////////
//
// Javascript support for std_checkbox
//
/////////////////////////////////////////////////////////////////////////////////////////
function stdCheckboxClicked(checkBox, WAMName, WRName, formName, protocol, target, RFld, chkValue, unchkValue)
{
	var f = getParentForm(checkBox);
	if (f != null)
	{
		var fld = f.elements[RFld];
		if( fld != null )
		{
			fld.value = checkBox.checked ? chkValue : unchkValue;
		}
	}
	if ((WAMName != '') && (WRName != ''))
	{
		if (formName != '') f = createStdHiddenForm(WAMName, WRName, formName, protocol, target);
		if (f != null)
		{
			createReentryFields(f, checkBox.parentNode);
			submitForm(f, WAMName, WRName, target, protocol);
		}
	}
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// Javascript support for std_rad_button and std_radbuttons
//
/////////////////////////////////////////////////////////////////////////////////////////
function stdRadioBtn_onClick(radioBtn, WAMName, WRName, formName, protocol, target, RFld)
{
	var f;
	if (formName)
	{
		f = createStdHiddenForm(WAMName, WRName, formName, protocol, target);
	} else {
		f = getParentForm(radioBtn);
	}
	if (f != null)
	{
		createReentryFields(f, radioBtn.parentNode);
		submitForm(f, WAMName, WRName, target, protocol);
	}
}
function stdRadioBtnGrp_onClick(radioBtn, WAMName, WRName, formName, protocol, target, RFld)
{
	var f;
	if (formName)
	{
		f = createStdHiddenForm(WAMName, WRName, formName, protocol, target);
	} else {
		f = getParentForm(radioBtn);
	}
	if (f != null)
	{
		createReentryFields(f, radioBtn.parentNode.parentNode);
		submitForm(f, WAMName, WRName, target, protocol);
	}
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// Javascript support for std_float
//
/////////////////////////////////////////////////////////////////////////////////////////
function stdFloatFixValues(fieldName, justLast)
{
	var elemList = document.getElementsByName(fieldName);
	for (var i = elemList.length-1; i>=0; i--)
	{
		var e = elemList[i];
		if (e.nodeName == 'INPUT')
		{
			e.value = new Number(e.value);
			if (justLast) return;
		}
	}
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// Javascript support for std_datetime
//
/////////////////////////////////////////////////////////////////////////////////////////

function stdDateTimeIFrameLoaded(contentWindow)
{
	var iframe = document.getElementById("stdDateTimeCalendarFrame");
	iframe.__loaded = true;
	contentWindow.Init(stdDateTimeGetValueForCalendar, stdDateTimeSetValueFromCalendar, stdDateTimeIFrameSetSize, stdDateTimeIFrameLostFocus);
	if (!iframe.contentWindow) iframe.contentWindow = contentWindow;
	iframe.style.display = "block";
	iframe.focus();
	iframe.contentWindow.focus();
}
function stdDateTimeIFrameSetSize(width, height)
{
	var iframe = document.getElementById("stdDateTimeCalendarFrame");
	if (iframe)
	{
		iframe.style.width = width + "px";
		iframe.style.height = height + "px";
	}
}
function stdDateTimeIFrameClose()
{
	var iframe = document.getElementById("stdDateTimeCalendarFrame");
	if (iframe != null)
	{
		if (iframe.__closeMeTO)
		{
			clearTimeout(iframe.__closeMeTO);
			iframe.__closeMeTO = null;
		}
		iframe.__dtContainer = null;
		iframe.style.display = "none";
	}
}
function stdDateTimeIFrameLostFocus()
{
	var iframe = document.getElementById("stdDateTimeCalendarFrame");
	if (iframe.style.display != "none")
	{
		if (!iframe.__closeMeTO) iframe.__closeMeTO = setTimeout(stdDateTimeIFrameClose, 50);
	}
}
function stdDateTimeGetValueForCalendar()
{
	var iframe = document.getElementById("stdDateTimeCalendarFrame");
	return stdDateTimeGetDateValue(iframe.__dtContainer)
}
function stdDateTimeSetValueFromCalendar(dateValue)
{
	var iframe = document.getElementById("stdDateTimeCalendarFrame");
	stdDateTimeSetDateValue(iframe.__dtContainer, dateValue);
	iframe.__dtContainer.__dtProxyInput.focus();
	stdDateTimeIFrameClose();
}
function stdDateTimeGetDateValue(dtContainer)
{
	var dateVal = new Date();
	dateVal.setISO8601(dtContainer.__dtMasterInput.value);
	if (dtContainer.__displayInUTC)
	{
		// Functions that call this are unaware of the DisplayInUTC option and utilise the 
		// local date methods of the Date object.  So we need to shift the value by the
		// TimezoneOffset to that they will work with the right value.
		dateVal.setTime(dateVal.getTime() + (dateVal.getTimezoneOffset() * 60000));
	}
	if( ( dateVal == null ) || isNaN(dateVal.valueOf()) )
	{
		dateVal = new Date();
		dateVal.sqlNull = true;
	}
	return dateVal;
}
function stdDateTimeSetDateValue(dtContainer, dateVal)
{
	var masterDateVal = null;
	if ((dateVal == null) || dateVal.sqlNull)
	{
		dtContainer.__dtMasterInput.value = "";
	}
	else
	{
		masterDateVal = new Date(dateVal.getTime());
		if (dtContainer.__displayInUTC)
		{
			// The value being supplied is in the "local" part of the date object
			// but it is supposed to represent a UTC value so we need to shift it back
			masterDateVal.setTime(dateVal.getTime() - (dateVal.getTimezoneOffset() * 60000));
		}
		switch (dtContainer.__inputType)
		{
			case "timeonly":
				dtContainer.__dtMasterInput.value = masterDateVal.toFormattedString("HH:mm:ss");
				break;
			case "dateonly":
				dtContainer.__dtMasterInput.value = masterDateVal.toFormattedString("YYYY-MM-DD");
				break;
			default:
				dtContainer.__dtMasterInput.value = masterDateVal.toISO8601String(true, false);
				break;
		}
	}
	stdDateTimeUpdateProxyValue(dtContainer, masterDateVal);
}
function stdDateTimeUpdateProxyValue(dtContainer, dateValue)
{
	if ((dateValue == null) || dateValue.sqlNull)
	{
		dtContainer.__dtProxyInput.value = "";
		return;
	}
	var displayDate = new Date(dateValue.getTime());
	if (dtContainer.__displayInUTC) displayDate.setTime(displayDate.getTime() + (dateValue.getTimezoneOffset() * 60000));
	var proxyVal = "";
	switch (dtContainer.__inputType)
	{
		case "timeonly":
			proxyVal = (dtContainer.__timeMask == "") ? displayDate.toLocaleTimeString() : displayDate.toFormattedString(dtContainer.__timeMask);
			break;
		case "dateonly":
			proxyVal = (dtContainer.__dateMask == "") ? displayDate.toLocaleDateString() : displayDate.toFormattedString(dtContainer.__dateMask);
			break;
		case "datetime":
			proxyVal = displayDate.toFormattedString(dtContainer.__dateMask + " " + dtContainer.__timeMask);
			if (dtContainer.__dateMask == "") proxyVal = displayDate.toLocaleDateString() + proxyVal;
			if (dtContainer.__timeMask == "") proxyVal += displayDate.toLocaleTimeString();
			break;
	}
	if (dtContainer.__displayMode == "output")
	{
		dtContainer.__dtProxyInput.innerHTML = proxyVal;
	}
	else
	{
		dtContainer.__dtProxyInput.value = proxyVal;
	}
}
function stdDateTimeParser(dateStr, dateMask, timeMask)
{
	this.dateValue = NaN;
	this.dateStr = dateStr;
	this.matchIndex = -1;
	this.matchLength = 0;
	if ((dateMask == "") && (timeMask == ""))
	{
		// Let JavaScript have a go at it
		this.dateValue = new Date(dateStr);
		if (!isNaN(this.dateValue.valueOf()))
		{
			this.matchIndex = 0;
			this.matchLength = dateStr.length;
		}
		return;
	}
	var dm = dateMask.replace(/(\/|\(|\[|\^|\$|\.|\||\?|\*|\+|\(|\)|\\)/g, "\\$1");
	var tm = timeMask.replace(/(\/|\(|\[|\^|\$|\.|\||\?|\*|\+|\(|\)|\\)/g, "\\$1");
	var mask = dm;
	if ((dm != "") && (tm != "")) mask += "\\s+";
	mask += tm;
	var nYPos = 0, nMPos = 0, nDPos = 0, nMStrPos = 0, nDStrPos = 0;
	var nHPos = 0, nMinPos = 0, nSPos = 0, nMsPos = 0, nAPPos = 0;
	var aMonthNames = new Array();
	var aDayNames = new Array();
	var count = 1;
	var regExStr = mask.replace(/(\\s\+|YYYY|YY|Y|MMMM|MM|M|DDD|DD|D|HH|H|hh|h|mm|m|sss|ss|s|t)/g,
		function($1)
		{
			switch ($1)
			{
				case '\\s+': return '\\s+';
				case 'YYYY': nYPos = count++;return "(\\d{2,4})";
				case 'YY':   nYPos = count++;return "(\\d{2,4})";
				case 'MMMM':
					nMStrPos = count++;
					var names = Date.arrayMstringMonths().join("|").toLowerCase();
					aMonthNames = names.split("|");
					return "(" + names + ")";
				case 'MM':   nMPos = count++;return "(\\d{1,2})";
				case 'M':    nMPos = count++;return "(\\d{1,2})";
				case 'DDD':
					nDStrPos = count++;
					var names = Date.arrayMstringDays().join("|").toLowerCase();
					aDayNames = names.split("|");
					return "(" + names + ")";
				case 'DD':   nDPos = count++;return "(\\d\\d)";
				case 'D':	 nDPos = count++;return "(\\d{1,2})";
				case 'HH':   nHPos = count++;return "(\\d\\d)";
				case 'H':    nHPos = count++;return "(\\d{1,2})";
				case 'hh':   nHPos = count++;return "(\\d\\d)";
				case 'h':    nHPos = count++;return "(\\d{1,2})";
				case 'mm':   nMinPos = count++;return "(\\d\\d)";
				case 'm':    nMinPos = count++;return "(\\d{1,2})";
				case 'ss':   nSPos = count++;return "(\\d\\d)";
				case 's':    nSPos = count++;return "(\\d{1,2})";
				case 'sss':  nMsPos = count++;return "(\\d\\d\\d)";
				case 't':	 nAPPos = count++;return "([AaPp]\.?[Mm]?\.?)";
			}
		} );
	
	var d = dateStr.match(new RegExp(regExStr, "i"));
	if (d)
	{
		var today = new Date();
		var nY = (nYPos > 0) ? Number(d[nYPos]) : today.getFullYear();
		var nM = (nMPos > 0) ? (Number(d[nMPos]) - 1) : today.getMonth();
		var nD = (nDPos > 0) ? Number(d[nDPos]) : today.getDate();
		if ((nMPos == 0) && (nMStrPos > 0)) { nM = aMonthNames.indexOf(d[nMStrPos]); }
		if ((nDPos == 0) && (nDStrPos > 0)) { nD = aDayNames.indexOf(d[nDStrPos]); }
		var nH = (nHPos > 0) ? Number(d[nHPos]) : 0;
		var nMin = (nMinPos > 0) ? Number(d[nMinPos]) : 0;
		var nS = (nSPos > 0) ? Number(d[nSPos]) : 0;
		var nMs = (nMsPos > 0) ? Number(d[nMsPos]) : 0;
		if (nAPPos > 0)
		{
			if ((d[nAPPos].substr(0,1).toLowerCase() == "p") && (nH < 12)) nH += 12;
			if ((d[nAPPos].substr(0,1).toLowerCase() == "a") && (nH == 12)) nH = 0;
		}
		if ((nY > 0) && (nM >= 0) && (nM < 12) && (nD >= 0) && (nH < 24) && (nMin < 60) && (nS < 60))
		{
			this.dateValue = new Date(nY, nM, nD, nH, nMin, nS, nMs);
			// if nD is more than the days in the month, getDate() will return a different value;
			if (this.dateValue.getDate() != nD) this.dateValue = NaN;
		}
		this.matchIndex = d.index;
		this.matchLength = d[0].length;
	}
	if (this.dateValue == NaN)
	{
		jslog.warning("stdDateTimeParser unable to parse " + dateStr + " with mask " + dateMask + " " + timeMask);
	}
	return;
}
function stdDateTimeProxyChanged(proxyInp)
{
	var dtContainer = getParentElement(proxyInp, 'div');
	var hiddenInp = dtContainer.__dtMasterInput;
	var dateStr = proxyInp.value.toLowerCase();
	
	if (dateStr.length == 0)
	{
		if (dtContainer.__allowSQLNull)
		{
			stdDateTimeSetDateValue(dtContainer, null);
			return true;
		}
		else
		{
			alert(g_StdLocaleMgr.getMessageText("BlankDate2"));
			stdDateTimeUpdateProxyValue(dtContainer, new Date().setISO8601(dtContainer.__dtMasterInput.value));
			return false;
		}
	}
	var newDate = NaN;
	if (dtContainer.__timeMask == "")
	{
		// Fix firefox bug
		dateStr = dateStr.replace(/([AaPp])\.([Mm])\./g, "$1$2");
	}
	switch (dtContainer.__inputType)
	{
		case 'timeonly':
			newDate = (new stdDateTimeParser(dateStr, "", dtContainer.__timeMask)).dateValue;
			break;
		case 'dateonly':
			newDate = (new stdDateTimeParser(dateStr, dtContainer.__dateMask, "")).dateValue;
			break;
		case 'datetime':
			if ((dtContainer.__dateMask == "") == (dtContainer.__timeMask == ""))
			{
				// Both masks are empty or both are set
				newDate = (new stdDateTimeParser(dateStr, dtContainer.__dateMask, dtContainer.__timeMask)).dateValue;
			}
			else if (dtContainer.__dateMask == "")
			{
				dp = new stdDateTimeParser(dateStr, "", dtContainer.__timeMask);
				if (dp.matchIndex > 1)
				{
					var datePart = dateStr.substring(0, dp.matchIndex - 1);
					if (isNaN(datePart.valueOf()))
					{
						newDate = new Date(datePart);
						if (!isNaN(newDate))
						{
							newDate.setHours(dp.dateValue.getHours());
							newDate.setMinutes(dp.dateValue.getMinutes());
							newDate.setSeconds(dp.dateValue.getSeconds());
							newDate.setMilliseconds(dp.dateValue.getMilliseconds());
						}
					}
				}
			}
			else
			{
				// timeMask must be blank
				dp = new stdDateTimeParser(dateStr, dtContainer.__dateMask, "");
				if (dp.matchIndex >= 0)
				{
					// JavaScript will not recognise a string that is time only
					newDate = new Date(dp.dateValue.toLocaleDateString() + " " + dateStr.substring(dp.matchIndex + dp.matchLength));
				}
			}
			break;
	}
	if (isNaN(newDate.valueOf()))
	{
		if (dtContainer.__inputType == "timeonly") {
			alert(proxyInp.value + g_StdLocaleMgr.getMessageText("BadTime1"));
		} else {
			alert(proxyInp.value + g_StdLocaleMgr.getMessageText("BadDate1"));
		}
		return false;
	}
	stdDateTimeSetDateValue(dtContainer, newDate);
	return true;
}
function stdDateTimeInitDiv(fieldName, displayMode, inputType, dateMask, timeMask, displayInUTC, allowSQLNull)
{
	// This is called just after the DIV is completed.  So find the last instance
	// of the field with the required name.
	var dtContainer = null;
	var masterValue = "";
	if (displayMode == "output")
	{
		var e = document.getElementById(fieldName)
		dtContainer = getParentElement(e, 'div');
		if (dtContainer && dtContainer.className == 'std_datetime')
		{
			dtContainer.__dtProxyInput = e;
			dtContainer.__dtMasterInput = e;
			masterValue = e.getAttribute("__isovalue");
		}
		else
		{
			dtContainer = null;
		}
	}
	else
	{
		var elemList = document.getElementsByName(fieldName);
		for (var i = elemList.length-1; i>=0; i--)
		{
			var e = elemList[i];
			if (e.nodeName == 'INPUT')
			{
				dtContainer = getParentElement(e, 'div');
				if (dtContainer && dtContainer.className == 'std_datetime')
				{
					var inputs = dtContainer.getElementsByTagName('input');
					for (var j=0,input; input=inputs[j]; j++)
					{
						if (input.getAttribute('name').lastIndexOf('_PROXY') >= 0)
						{
							dtContainer.__dtProxyInput = input;
						} else {
							dtContainer.__dtMasterInput = input;
						}
					}
					masterValue = dtContainer.__dtMasterInput.value;
					break;
				}
			}
			dtContainer = null;
		}
	}
	if (dtContainer)
	{
		dtContainer.__displayMode = displayMode;
		dtContainer.__inputType = inputType;
		dtContainer.__dateMask = dateMask;
		dtContainer.__timeMask = timeMask;
		dtContainer.__displayInUTC = displayInUTC;
		dtContainer.__allowSQLNull = allowSQLNull;
		var dateVal;
		switch (dtContainer.__inputType)
		{
			case "timeonly":
				dateVal = (new stdDateTimeParser(masterValue, "", "HH:mm:ss")).dateValue;
				break;
			case "dateonly":
				dateVal = (new stdDateTimeParser(masterValue, "YYYY-MM-DD", "")).dateValue;
				break;
			case "datetime":
				dateVal = new Date();
				dateVal.setISO8601(masterValue);
				break;
		}
		stdDateTimeUpdateProxyValue(dtContainer, dateVal);
	}
}
function stdDateTimeInitIFrame() {
	var iframe = document.getElementById("stdDateTimeCalendarFrame");
	if (iframe == null)
	{
		iframe = document.createElement('iframe');
		iframe.id = "stdDateTimeCalendarFrame";
		iframe.src = g_lweb_images_path + '/calendar_panel.htm';
		iframe.setAttribute("frameborder", "0");
		iframe.style.position = "absolute";
		iframe.style.display = "none";
		iframe.style.width = "1px";
		iframe.style.height = "1px";
		iframe.style.overflow = "hidden";
		iframe.__dtContainer = null;
		iframe.__loaded = false;
		// I don't like doing browser detection like this but there's not feature to detect for this one.
		// Safari does not generate onBlur events for the frame content.  On the other hand, other browsers
		// will generate an onblur for the frame when it's content gets focus (which we don't want).
		if (navigator.userAgent.match(/AppleWebKit/))
		{
			iframe.onblur = stdDateTimeIFrameLostFocus;
		}
		document.body.appendChild(iframe);
	}
	return iframe;
}
function stdDateTimeBtnClick(theBtn)
{
	if (theBtn.className == "disabled") return;
	var dtContainer = getParentElement(theBtn, 'div');
	var iframe = stdDateTimeInitIFrame();
	if ((iframe.__dtContainer != dtContainer) || (iframe.style.display == "none"))
	{
		if (iframe.__closeMeTO)
		{
			clearTimeout(iframe.__closeMeTO);
			iframe.__closeMeTO = null;
		}
		iframe.style.display = "none";
		iframe.__dtContainer = dtContainer;
		iframe.style.left = getAbsoluteLeft(theBtn) + theBtn.offsetWidth + "px";
		iframe.style.top = getAbsoluteTop(theBtn) + "px";
		iframe.style.display = "block";
		if (iframe.__loaded && iframe.contentWindow)
		{
			iframe.contentWindow.SetDialogHTML();
			iframe.style.display = "block";
			iframe.focus();
			iframe.contentWindow.focus();
		}
	}
	else
	{
		stdDateTimeIFrameClose();
	}
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// JavaScript support for std_list_textarea
//
//////////////////////////////////////////////////////////////////////////////////////////
function stdLTA_ItemsToForm(theForm, theItems, listName, listField, maxRows)
{
	var i = 0;
	var l = theItems.length;
	if (isNaN(maxRows)) maxRows = 0;
	if ((maxRows > 0) && (maxRows < l)) l = maxRows;
	for (i=1; i<=l; i++)
	{
		var fieldName = listName.concat(".",i.zeropad(4),".",listField);
		insertHiddenField(theForm, fieldName, theItems[i-1].rtrim());
	}
	var field = theForm.elements[listName.concat(".",(i++).zeropad(4),".",listField)];
	while (field)
	{
		theForm.removeChild(field);
		field = theForm.elements[listName.concat(".",(i++).zeropad(4),".",listField)];
	}
}
function stdLTAv1_TextAreaToList(theTA, listName, listField, formName, maxRows)
{
	var f = theTA.form;
	if (formName) f = document.forms[formName];
	var theText = theTA.value;
	var items = new Array();
	var arrayIndex = 0;
	var charPos = 0;
	var itemLen = theTA.cols;
	while (charPos < theText.length)
	{
		var endPos = charPos + itemLen;
		items[items.length] = theText.substring(charPos, endPos);
		charPos = endPos;
	}
	stdLTA_ItemsToForm(f, items, listName, listField, maxRows);
}
function stdLTA_TextAreaToList(theTA, listName, listField, wordWrap, maxLineLength, maxRows)
{
	var f = theTA.form;
	var theText = theTA.value;
	var l = maxLineLength;
	if (wordWrap && theTA.cols < maxLineLength) l = theTA.cols;
	var regExpStr = "(^.{0,[cols]})(?: +|$)|(.{1,[cols]})".replace(/\[cols\]/g, l);
	var re = new RegExp(regExpStr, "mg");
	theText = theText.replace(/\r\n/g,"\n");
	var items = theText.match(re);
	while ((items.length > 0) && (items[items.length-1] == ""))
		items.pop();
	stdLTA_ItemsToForm(f, items, listName, listField, maxRows);
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// JavaScript support for std_list and std_grid_v2
//
//////////////////////////////////////////////////////////////////////////////////////////

function cursorInElement(elem, evt) {
	var mouseX = getRelativeMouseX(elem, evt);
	if ((mouseX >= 0) && (mouseX <= elem.offsetWidth))
	{
		var mouseY = getRelativeMouseY(elem, evt);
		if ((mouseY >= 0) && (mouseY <= elem.offsetHeight))
		{
			return true;
		}
	}
	return false;
}

var std_grids;

function stdGridColumn()
{
	this.tsmlDecimalSeparator=".";
	this.tsmlType="";
	this.tsmlMode="output";
	this.NumberParser = new StdNumberParser(this.tsmlDecimalSeparator);
	this.parseValString = function(valStr) {return valStr;}
	this.prevVisible = null;
	
	this.setTsmlDecimalSeparator = function(val)
	{
		this.tsmlDecimalSeparator = val;
		this.NumberParser = new StdNumberParser(this.tsmlDecimalSeparator);
		this.setTsmlType(this.tsmlType);
	}
	this.setTsmlType = function(val)
	{
		this.tsmlType = val;
	  switch (this.tsmlType)
		{
			case "packed":
			case "signed":
				this.parseValString = function(valStr) {return this.NumberParser.parseDecimal(valStr);}
				break;
			case "integer":
				this.parseValString = function(valStr) {return this.NumberParser.parseInt(valStr);}
				break;
			case "float":
				this.parseValString = function(valStr) {return this.NumberParser.parseFloat(valStr);}
				break;
			default:
				this.parseValString = function(valStr) {return valStr;}
		}
	}
}
function stdGrid(gridID, columns)
{
	this.id = gridID;
	this.allowSort = false;
	this.allowColResize = false;
	this.rowHeaderCol = '';
	this.sortFixedRows = true;
	this.rowHeaderCol = '';
	this.cols = new Array(columns);
	
	this.connectToHTML = function()
	{
		this.outerDiv = document.getElementById(this.id + "_wrap");
		this.table = document.getElementById(this.id);
		this.headRow = (this.table.tHead) ? this.table.tHead.rows[0] : null;
		this.tBody = this.table.tBodies[0];
		var lastVis = null;
		this.fixedWidth = this.outerDiv.style.width;
		this.fixedHeight = this.outerDiv.style.height;
		//this.fixWrapperSize();
		if (this.headRow)
		{
		//Some versions of Safari return incorrect values for cellIndex. Can't sort or resize on these browsers
		var cellIndexBug = ((this.headRow.cells.length > 1) && (this.headRow.cells[1].cellIndex == 0));
		this.allowSort = this.allowSort && !cellIndexBug;
		this.allowColResize = this.allowColResize && ((!cellIndexBug && ((document.addEventListener) || (this.table.setCapture))) ? true : false);
		if (this.allowColResize)
		{
			this.table.onmousemove = stdGrid_onMouseMove;
			this.table.onmousedown = stdGrid_onMouseDown;
		}
		for (var i=0, headCell; headCell = this.headRow.cells[i]; i++)
		{
			var col = new stdGridColumn();
			// The cellIndex value returned by some browsers(IE) is not always the cells position
			// in the cells collection.  We need a 2-way connection between the cell and the colls array
			// so the header cell is stored in the array at the position indicated by it's cellIndex
			// and a cellIndex is added to the col indicating the correct cellIndex.
			this.cols[headCell.cellIndex] = col;
			col.cellIndex = i;
			col.setTsmlDecimalSeparator(headCell.getAttribute("__DecimalSeparator"));
			col.setTsmlType(headCell.getAttribute("__FormatType"));
			col.tsmlMode = headCell.getAttribute("__Mode");
			col.AllowSort = headCell.getAttribute("__AllowSort") == "true" ? true : false;
			col.headerCell = headCell;
			col.prevVisible = lastVis;
			if (getCurrentStyle(headCell, "display") != 'none')
			{ 
				if (this.allowColResize)
				{
					headCell.onmousemove = stdGrid_hdr_onMouseMove;
					headCell.onmousedown = stdGrid_hdr_onMouseDown;
					headCell.onmouseup = stdGrid_hdr_onMouseUp;
				}
				if (this.allowSort && col.AllowSort)
				{
					headCell.onclick = stdGrid_hdr_onClick;
				}
				lastVis = col;
			}
		}
		if (this.allowSort)
		{
			this.rows = new Array(this.tBody.rows.length);
			if ((!this.sortFixedRows) && (this.rowHeaderCol != '')) this.fixedCells = new Array(this.tBody.rows.length);
			for (var i=0, r; r=this.tBody.rows[i]; i++)
			{
				this.rows[i] = r;
				if (this.fixedCells) this.fixedCells[i] = r.cells[0];
			}
			this.sortCol = -1;
			this.sortIndicator = null;
			this.sortDir = 1;
		}
		}
		if (!document.addEventListener)
		{
			// IE doesn't support :focus pseudo class so we need to do in in code
			var inputs = this.tBody.getElementsByTagName("input");
			var focusHandler = function(e) { e.srcElement.className += " focus"; };
			var blurHandler = function(e) { var cn = e.srcElement.className; e.srcElement.className = cn.replace(/ focus/, ""); };
			for (var i=0, inp; inp=inputs[i]; i++)
			{
				if ((inp.type == "text") || (inp.type == "password"))
				{
					inp.attachEvent("onfocus", focusHandler);
					inp.attachEvent("onblur", blurHandler);
				}
			}
		}
	}
	this.fixWrapperSize = function()
	{
		if (!this.fixedWidth)
		{
			var outerW = this.table.offsetWidth
			if (this.outerDiv.clientWidth > 0)
			{
				outerW += (this.outerDiv.offsetWidth - this.outerDiv.clientWidth);
			}
			this.outerDiv.style.width = outerW + "px";
		}
		if (!this.fixedHeight)
		{
			var outerH = this.table.offsetHeight
			if (this.outerDiv.clientHeight > 0)
			{
				outerH += (this.outerDiv.offsetHeight - this.outerDiv.clientHeight);
			}
			this.outerDiv.style.height = outerH + "px";
		}
	}
	this.getCellValueString = function(row, colNum)
	{
		var td = row.cells[colNum];
		return td.getAttribute("__cellValue");
	}
	this.getCellValue = function(row, colNum)
	{
		var strVal = this.getCellValueString(row, colNum);
		return this.cols[colNum].parseValString(strVal);
	}
	this.setSortIndicator = function(dir)
	{
		var cn = this.sortIndicator.className;
		cn = cn.replace(/((?:^| )std_grid_sort_indicator)(_up|_down)?($| )/g, "$1" + dir + "$3");
		this.sortIndicator.className = cn;
	}
	this.sort = function(headerCell)
	{
		window.stdGrid_current_sort = this;
		
		if (this.sortCol != headerCell.cellIndex)
		{
			if (this.sortIndicator) this.setSortIndicator("");
			this.sortCol = headerCell.cellIndex;
			this.sortIndicator = headerCell;
			this.sortDir = 1;
		}
		else
		{
			this.sortDir *= -1;
		}
		if(this.sortDir == 1)
		{
			this.rows.sort(stdGrid_SortCompareA);
			this.setSortIndicator("_up");
		} else {
			this.rows.sort(stdGrid_SortCompareD);
			this.setSortIndicator("_down");
		}
		var tbdy = this.table.removeChild(this.table.tBodies[0]);
		for (var i=0, r; r=this.rows[i]; i++)
		{
			if (this.fixedCells)
			{
				 r.insertBefore(this.fixedCells[i], r.firstChild);
			}
			tbdy.appendChild(r);
			r.className = (i % 2) == 0 ? r.getAttribute("__oddrc") : r.getAttribute("__evenrc");
		}
		this.table.appendChild(tbdy);
	}
}
function stdGrid_SortCompareA(a,b)
{
	var g = window.stdGrid_current_sort;
	var aVal = g.getCellValue(a,g.sortCol);
	var bVal = g.getCellValue(b,g.sortCol);
	return aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
}
function stdGrid_SortCompareD(a,b)
{
	return stdGrid_SortCompareA(b,a);
}
function register_std_grid(gridID, columns)
{
	if (!std_grids)
	{
		std_grids = new Object();
		addEvent(window, "load", stdGrid_initGrids);
	}
	std_grids[gridID] = new stdGrid(gridID, columns);
	return std_grids[gridID];
}
function stdGrid_initGrids()
{
	for (var gridID in std_grids)
	{
		std_grids[gridID].connectToHTML();
	}
}
function stdGrid_getContainingList(elem)
{
	var r = elem;
	while (r.parentNode) {
		if (r.className == "std_grid")
		{
			return std_grids[r.getAttribute('id')];
		} else {
			r = r.parentNode;
		}
	}
	return null;
}
function stdGrid_cursorInResizeZone(cell, evt)
{
	var mouseX = getRelativeMouseX(cell, evt);
	if (cell.offsetWidth - mouseX <= 5) return 1;
	if ((cell.cellIndex > 0) && (mouseX <= 4)) return -1;
	return 0;
}
function stdGrid_onMouseMoveInDrag(e)
{
	if(!e) { if( window.event ) { e = window.event; } else { return; } }
	var l = document.stdGrid_currentDrag;
	var rsDiv = document.getElementById('StdListColResize');
	if (rsDiv)
	{
		 var w = getRelativeMouseX(rsDiv, e) + l.resizeMouseOffset;
		 if (w > 0) rsDiv.style.width = w + "px";
	}
}
function stdGrid_onMouseUpInDrag(e)
{
	if(!e) { if( window.event ) { e = window.event; } else { return; } }
	document.removeEventListener('mousemove',stdGrid_onMouseMoveInDrag,true);
	document.removeEventListener('mouseup',stdGrid_onMouseUpInDrag,true);
	
	var l = document.stdGrid_currentDrag;
	if (l && l.resizeCol)
	{
		stdGrid_EndDrag(e);
	}
	document.stdGrid_currentDrag = null;
}
function stdGrid_StartDrag(l, e)
{
	var headCell = l.resizeCol.headerCell;
	document.stdGrid_currentDrag = l;
	if (document.addEventListener)
	{
		document.addEventListener('mousemove',stdGrid_onMouseMoveInDrag,true);
		document.addEventListener('mouseup',stdGrid_onMouseUpInDrag,true);
	}
	else
	{
		if (headCell.setCapture) { headCell.setCapture(); };
	}
	var nextCellLeft = l.table.offsetWidth;
	for (var i=headCell.cellIndex+1,c; c=l.cols[i]; i++)
	{
		if (getCurrentStyle(c.headerCell, "display") != 'none')
		{
			nextCellLeft = c.headerCell.offsetLeft;
			break;
		}
	}
	var cellRight = headCell.offsetLeft + headCell.offsetWidth;
	var centerLine = headCell.offsetWidth + Math.round((nextCellLeft - cellRight) / 2);
	l.resizeStartX = getRelativeMouseX(headCell, e);
	l.resizeMouseOffset = centerLine - l.resizeStartX;

	var rsDiv = document.getElementById('StdListColResize');
	if (rsDiv) document.body.removeChild(rsDiv);
	rsDiv = document.createElement('div');
	rsDiv.id = "StdListColResize";
	rsDiv.className = "std_grid_col_resize";
	var s = rsDiv.style;
	var top = getAbsoluteTop(l);
	var bottom = getAbsoluteTop(l) + l.offsetHeight;
	s.position = "absolute";
	s.left = getAbsoluteLeft(headCell) + "px";
	s.top = getAbsoluteTop(l.table) + "px";
	s.width = centerLine + "px";
	s.height = l.table.offsetHeight + "px";
	document.body.appendChild(rsDiv);
}
function stdGrid_EndDrag(e)
{
	var l = document.stdGrid_currentDrag;
	document.stdGrid_currentDrag = null;
	var headCell = l.resizeCol.headerCell;
	// Browsers are very inconsistent in their ideas of what "width" exactly means
	// so try to do everything using a difference rather than an absolute size.
	var diff = getRelativeMouseX(headCell, e) - l.resizeStartX;
	var newWidth = headCell.offsetWidth + diff;
	if (newWidth < 0) { diff -= newWidth; newWidth = 0; }
	
	if (l.tBody.rows.length > 0)
	{
		// cellIndex returned by the browser is unreliable so we have our own
		var cellIndex = l.cols[headCell.cellIndex].cellIndex
		if (diff > 0)
		{
			stdGrid_adjustHeadCellWidth(headCell, diff);
			stdGrid_ResizeCollContent(l.tBody, cellIndex, diff);
		}
		else if (diff < 0)
		{
			var firstCellContent = stdGrid_GetCellContentforResize(l.tBody.rows[0].cells[cellIndex]);
			var startHeadW = headCell.offsetWidth;
			var startContentW = 0;
			if (firstCellContent)
			{
				startContentW = firstCellContent.offsetWidth;
				stdGrid_ResizeCollContent(l.tBody, cellIndex, diff);
			}
			stdGrid_adjustHeadCellWidth(headCell, diff);
			if (headCell.offsetWidth != newWidth)
			{
				// Browser wouldn't go to the size we wanted. Cell contents may need correcting
				if (firstCellContent)
				{
					var cDelta = startContentW - firstCellContent.offsetWidth;
					var hDelta = startHeadW - headCell.offsetWidth;
					stdGrid_ResizeCollContent(l.tBody, cellIndex, cDelta - hDelta);
				}
				stdGrid_adjustHeadCellWidth(headCell, null);
			}
		}		
	}
	else
	{
		stdGrid_adjustHeadCellWidth(headCell, diff);
	}
	l.fixWrapperSize();
	l.resizeCol = null;
	l.table.style.cursor = 'default';
	var rsDiv = document.getElementById('StdListColResize');
	if (rsDiv) document.body.removeChild(rsDiv);
}
function stdGrid_onMouseMove(e)
{
	if(!e) { if( window.event ) { e = window.event; } else { return; } }
	var l = std_grids[this.getAttribute('id')];
	if (l.resizeCol == null) {
		var mouseY = getRelativeMouseY(l.headRow, e);
		if ((mouseY >= 0) && (mouseY <= l.headRow.offsetHeight))
		{
			// Header cells stop this event so the mouse must be over the cellspacing area
			var mouseX = getRelativeMouseX(l.headRow.cells[0], e);
			if (mouseX > 0)
			{
				this.style.cursor = 'e-resize';
				this.style.cursor = 'col-resize';
			}
			else
			{
				this.style.cursor = 'default';
			}
		}
		else
		{
			this.style.cursor = 'default';
		}
	}
}
function stdGrid_onMouseDown(e)
{
	if(!e) { if( window.event ) { e = window.event; } else { return; } }
	var l = std_grids[this.getAttribute('id')];
	if (l.resizeCol == null) {
		var mouseY = getRelativeMouseY(l.headRow, e);
		if ((mouseY >= 0) && (mouseY <= l.headRow.offsetHeight))
		{
			// Header cells stop this event so the mouse must be over the cellspacing area
			// Need to work out which cell is to the left.
			l.resizeCol = null;
			for (var i=0, c; c = l.cols[i]; i++)
			{
				if (getRelativeMouseX(c.headerCell, e) <= 0) break;
				l.resizeCol = c;
			}
			if (l.resizeCol != null) stdGrid_StartDrag(l, e);
			e.returnValue = false;
			if (e.preventDefault) e.preventDefault();
		}
	}
}
function stdGrid_hdr_onMouseDown(e)
{
	if(!e) { if( window.event ) { e = window.event; } else { return; } }
	var l = stdGrid_getContainingList(this);
	l.ignoreNextClickIn = null;
	
	var btn = -1;
	if( typeof( e.which ) == 'number' ) { btn = e.which; } else { if( typeof( e.button ) == 'number' ) { btn = e.button; } else { btn = 1; } }
	l.inResize = false;
	if (btn == 1) {
		switch (stdGrid_cursorInResizeZone(this,e))
		{
			case -1:
				l.resizeCol = l.cols[this.cellIndex].prevVisible;
				break;
			case 1:
				l.resizeCol = l.cols[this.cellIndex];
				break;
			default:
				l.resizeCol = null;
		}
		if (l.resizeCol != null)
		{
			l.ignoreNextClickIn = this;
			stdGrid_StartDrag(l, e);
		}
	}
	cancelEvent(e);
}
function stdGrid_hdr_onMouseMove(e)
{
	if(!e) { if( window.event ) { e = window.event; } else { return; } }
	var l = stdGrid_getContainingList(this);
	if (l.resizeCol == null)
	{
		if(stdGrid_cursorInResizeZone(this,e) != 0)
		{
			l.table.style.cursor = 'e-resize';
			// Browsers that don't support this should ignore it and use e-resize
			l.table.style.cursor = 'col-resize';
		} else {
			l.table.style.cursor = 'default';
		}
	} else {
		stdGrid_onMouseMoveInDrag(e);
	}
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
}
function stdGrid_hdr_onMouseUp(e)
{
	if(!e) { if( window.event ) { e = window.event; } else { return; } }
	var l = stdGrid_getContainingList(this);
	if (l.resizeCol != null)
	{
		var headCell = l.resizeCol.headerCell;
		if (headCell.releaseCapture) { headCell.releaseCapture(); }
		stdGrid_EndDrag(e);
	}
}
function stdGrid_hdr_onClick(e)
{
	if(!e) { if( window.event ) { e = window.event; } else { return; } }
	var l = stdGrid_getContainingList(this);
	if (l.ignoreNextClickIn != this) {
		l.sort(this);
	}
	l.ignoreNextClickIn = null;
}
function stdGrid_adjustHeadCellWidth(cell, adjustBy)
{
	var elem = cell;
	var elems = getElementsByClassAndTag(cell, "std_grid_cell_sizer", "div");
	if (elems) elem = elems[0];
	var currentW = 0;
	if (document.defaultView && document.defaultView.getComputedStyle)
	{
		currentW = parseInt(document.defaultView.getComputedStyle(elem,"").getPropertyValue("width"));
	}
	else
	{
		currentW = elem.offsetWidth;
	}
	if (adjustBy)
	{
		newW = currentW + adjustBy;
		elem.style.width = (newW < 0) ? "0px" : newW + "px";
	} else {
		elem.style.width = "100%";
	}
}
function stdGrid_ResizeCollContent(tBody, col, diff)
{
	var r; var c;
	if ((r = tBody.rows[0]) && (c = r.cells[col]))
	{
		var elem = stdGrid_GetCellContentforResize(c);
		if (elem)
		{
			var w = elem.offsetWidth + diff;
			var ws = (w < 0) ? "0px" : w + "px";
			// Although the css width property normally has different meanings depending on the browser
			// and box model being used, it seems that this doesn't apply in JavaScript.  Provided the
			// element is not a table cell, setting style.width is like setting the offsetWidth.
			elem.style.width = ws;
			for (var i=1; r=tBody.rows[i]; i++)
			{
				elem = stdGrid_GetCellContentforResize(r.cells[col]);
				if (elem) elem.style.width = ws;
			}
		}
	}
}
function stdGrid_GetCellContentforResize(cell)
{
	var child = null;
	var childCount = 0;
	for (var j=0, cn; cn=cell.childNodes[j]; j++)
	{
		if ((cn.nodeType != 3) && (cn.nodeType != 8) && (cn.nodeName != "SCRIPT"))
		{
			child = cn;
			childCount++;
		}
	}
	if (childCount == 1) return child;
	return null;
}

//////////////////////////////////////////////////////////////////////////////////////////
//
// Javascript support for std_dropdown and std_listbox
//
//////////////////////////////////////////////////////////////////////////////////////////
function std_DD_ListBoxOnChange(elem, WAMName, WRName, formName, target, sUniquePrefix, bAllowMultiSel, bSubmitTagFields, sTagFld1, sTagFld2, sTagFld3)
{
	var f = createStdHiddenForm(WAMName, WRName, formName, null, target);
	var reentryfld = elem.getAttribute("reentryfld");

	if ( (f != null) && (reentryfld != '') )
	{
      insertHiddenField(f, reentryfld, elem.getAttribute("reentryval"));
	}

	if ( bSubmitTagFields  ) 
	{
		var oSelOption = elem.options[elem.selectedIndex];

		if (sTagFld1 != '') insertHiddenField(f, sTagFld1, oSelOption.getAttribute("tag_" + sTagFld1));
   		if (sTagFld2 != '') insertHiddenField(f, sTagFld2, oSelOption.getAttribute("tag_" + sTagFld2));
		if (sTagFld3 != '') insertHiddenField(f, sTagFld3, oSelOption.getAttribute("tag_" + sTagFld3));
	}
   
	if (bAllowMultiSel) 
	{
		eval(sUniquePrefix + "_insertMultiSelectList(f)");
	}
   
	if (WRName != '') HandleEvent(WAMName, WRName, f, target);
}

function std_DD_ListBoxOnKeyDown(oForm)
{
	if (event.keyCode == 13) setTimeout(function(){{_HandleDefaultSubmit(oForm);}}, 0);
}
