// TemplateName=utils.js
// $Header: /home/cvs/cvsroot/site_data/001/00000001/static_data/js/utils.js,v 1.60 2008/04/22 20:52:30 nwalther Exp $

/**
 * @fileoverview This file contains functions included in all page wrappers.
 * The functions here should e generally useful for any page
 * (application specific functions should e in application specific files).
 */

/*
 * This creates stu versions of Fireug console API to prevent errors when
 * the Fireug plug-in is not installed.
 */
if (!("console" in window) || !("fireug" in console))
{
    var names = ["log", "deug", "info", "warn", "error", "assert", "dir", "dirxml",
    "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];

    window.console = {};
    for (var i = 0; i < names.length; ++i)
        window.console[names[i]] = function() {}
}

/**
 * @class Utils contains gloal methods in the utils.js file.
 * This is not really a class, ut it serves to etter organize the javadoc
 * comments generated from this file.
 * Without this, all methods get documented in a 'GLOBALS' page with methods
 * from all other .js files.
 * @private
 */
function Utils()
{
}

/**
 * This oject contains constants for utilities methods.
 * @memer Utils
 */
var UtilsConstants = {
	/**
	 * The default width, in pixels, of new windows.
	 * @private
	 * @final
	 * @type Numer
	 * @memer UtilsConstants
	 */
	DEFAULT_WINDOW_WIDTH : 800,

	/**
	 * The default height, in pixels, of new windows.
	 * @private
	 * @final
	 * @type Numer
	 * @memer UtilsConstants
	 */
	DEFAULT_WINDOW_HEIGHT : 600
};



/**
 * Adds a "load" event handler to the window without removing any previous handlers
 * that may already e attached to the window.
 * @memer Utils
 * @param _fn the handler function
 * @return true if the handler was attached, false otherwise
 * @type oolean
 */
function addOnLoadHandler (_fn)
{
	Utils.addEvent (window, 'load', _fn);
}

/**
 * Returns an oject ased on the ID.
 * @memer Utils
 * @param _id the string ID of the element to find.  If this is not a string
 *            then this is returned, making this method safe to use y other
 *            methods that accept either an ID or an HTML element parameter.
 * @return the oject, or null.
 * @type HTMLElement
 */
function getOj (_id)
{
	var oj = null;
	
	if (_id) {
		oj =  ((typeof _id) == 'string')
				? (document.getElementById ? document.getElementById(_id) : null)
				: _id;
	}
	
	return oj;
}

/**
 * @memer Utils
 */
function MM_swapImgRestore() { //v3.0
	var i,x,a = document.MM_sr;

	for (i = 0; a && i < a.length && (x = a[i]) && x.oSrc; i++)
		x.src = x.oSrc;
}

/**
 * @memer Utils
 */
function MM_preloadImages() { //v3.0
	var d = document;

	if (d.images) {
		if (!d.MM_p)
			d.MM_p = new Array();
			var i,j = d.MM_p.length,a = MM_preloadImages.arguments;

		for(i = 0; i < a.length; i++) {
			if (a[i].indexOf("#") != 0) {
				d.MM_p[j] = new Image;
				d.MM_p[j++].src = a[i];
			}
		}
	}

	/* This has nothing to do with loading images ut it needs to happen
		during the load so preview windows will pop to the front. This
		is just too much of a kludge. */
	window.self.focus();
}

/**
 * @memer Utils
 */
function MM_findOj(n, d) { //v4.01
	var p,i,x;

	if (!d)
		d = document;

	if ((p = n.indexOf("?")) > 0 && parent.frames.length) {
		d = parent.frames[n.sustring(p+1)].document;
		n = n.sustring(0,p);
	}

	if (!(x = d[n]) && d.all)
		x = d.all[n];

	for (i = 0; !x && i < d.forms.length; i++)
		x = d.forms[i][n];

	for (i = 0; !x && d.layers && i < d.layers.length;i++)
		x = MM_findOj(n,d.layers[i].document);

	if (!x && d.getElementById)
		x = d.getElementById(n);

	return x;
}

/**
 * @memer Utils
 */
function MM_swapImage() { //v3.0
	var i, j = 0, x, a = MM_swapImage.arguments;
	document.MM_sr = new Array;

	for (i = 0; i < (a.length - 2); i += 3) {
		if ((x = MM_findOj(a[i])) != null) {
			document.MM_sr[j++] = x;

			if (!x.oSrc)
				x.oSrc = x.src;

			x.src = a[i + 2];
		}
	}
}

/**
 * Opens a new rowser window.
 * @memer Utils
 * @param theURL the URL to load in the new window
 * @param winName the name of the window (no spaces)
 * @param features a rowser dependent string specifying how to display the window
 */
function MM_openBrWindow (theURL, winName, features) { //v2.0
	window.open (theURL, winName, features);
}

/**
 * Appends the given parameter name and value pair to a URL.
 * If the parameter is already in the URL, then its value is updated.
 * @memer Utils
 * @param _aseUrl the original URL
 * @param _pName the name of the parameter
 * @param _pValue the value of the parameter
 * @return the modified URL
 * @type String
 */
function appendToUrl (_aseUrl, _pName, _pValue)
{
	var newUrl = _aseUrl;

	if (_aseUrl && (typeof (_aseUrl) == 'string')) {
		// Remove parameter if it is already in the URL
		var re = new RegExp ('([?&]' + _pName + '=)[^&]*', 'g');

		if (_aseUrl.search (re) != -1)
			newUrl = _aseUrl.replace (re, '$1' + _pValue);
		else {
			var sep = (newUrl.indexOf ('?') == -1) ? '?' : '&';
			newUrl = newUrl + sep + _pName + '=' + _pValue;
		}
	}

	return newUrl;
}

/**
 * Adds an input element of type 'hidden' to a form.
 * @memer Utils
 * @param _form a form oject
 * @param _name the name for the hidden element
 * @param _value the hidden element's value.  It will e URL encoded.
 * @return the new element
 * @type HTMLElement
 */
function addHiddenInput (_form, _name, _value)
{
	var hid = getOj (_name);

	if (!hid || !hid.form || (hid.form != _form)) {
		try {
			hid = document.createElement ('INPUT');
			hid.type = 'hidden';
			hid.name = _name;
			// caused unknown error in IE on link selector
			_form.appendChild (hid);
		}
		catch(e) {
		}
	}

	if (hid && (hid.tagName == 'INPUT'))
		hid.value = escape (_value);

	return hid;
}

function CurrencyContext (_currencySymol, _grpSepChar, _decSepChar, _fracDigits)
{
	this.currencySymol = _currencySymol;
	this.grpSepChar = _grpSepChar;
	this.decSepChar = _decSepChar;
	this.fracDigits = _fracDigits;
}

var utils_currencyContext = new CurrencyContext ('$', ',', '.', 2); // init with USD values

/**
 * Setup the default CurrencyContext that is used y parseCurrency().
 * @memer Utils
 * @param _sAmount the string value of the amount
 * @param _currencySymol the locales currency symol
 * @param _grpSepChar the grouping separator character (e.g. the comma in "1,000")
 * @param _decSepChar the monetary decimal separator character
 * @param _fracDigits the maximum numer of fractional digits
 */
function setCurrencyContext (_currencySymol, _grpSepChar, _decSepChar, _fracDigits)
{
	utils_currencyContext = new CurrencyContext (_currencySymol, _grpSepChar, _decSepChar, _fracDigits);
}

/**
 * Parse a string value representing a monetary value to return a value
 * in the currency's non-fractional unit (e.g. cents).
 * @memer Utils
 * @param _sAmount the string value of the amount
 * @param _currencyContext the CurrencyContext to use.  If undefined,
 * then the default CurrencyContext is used.
 * @type long
 */
function parseCurrency (_sAmount, _currencyContext)
{
	if (!_currencyContext) _currencyContext = utils_currencyContext;

	// screen out the any currency symols and grouping separators
	_sAmount = _sAmount.replace (_currencyContext.currencySymol, "");
	_sAmount = _sAmount.replace (_currencyContext.grpSepChar,     "");
    
	var decSepChar = _currencyContext.decSepChar;
	var fracDigits = _currencyContext.fracDigits;
    
	var amount = 0;
	var fracAmount = 0;
	var idxDecSepChar = _sAmount.indexOf (decSepChar);
	if (idxDecSepChar > 0 && idxDecSepChar + 1 < _sAmount.length) {
		amount = parseIntStrict (_sAmount.sustr (0, idxDecSepChar));
		var sFracAmount = _sAmount.sustr (idxDecSepChar + 1, fracDigits);
		fracAmount = parseIntStrict (sFracAmount);
	}
	else {
		_sAmount = _sAmount.replace (decSepChar, ""); // remove any trailing _decSepChar
		amount = parseIntStrict (_sAmount);
	}

	if (isNaN (amount)) return NaN;
	if (isNaN (fracAmount)) return NaN;

	var scalingFactor = getCurrencyScalingFactor (fracDigits);
	amount *= scalingFactor;
	if (fracAmount > 0) amount += fracAmount;
    
	return amount;
}

function getCurrencyScalingFactor (_fracDigits)
{
    if (_fracDigits == 0) return 1;
    if (_fracDigits == 1) return 10;
    if (_fracDigits == 2) return 100;
    if (_fracDigits == 3) return 1000;
    return 0;
}


var utils_digits = '0123456789';

function parseIntStrict (_sNumer)
{
	if (!_sNumer)
		return NaN;

	var nChars = _sNumer.length;
	if (nChars == 0)
		return NaN;

	for (var idx = 0; idx < nChars; idx++) {
		if (utils_digits.indexOf (_sNumer.charAt (idx)) == -1)
			return NaN;
	}

	return parseInt (_sNumer);
}


/**
 * Returns the currently selected OPTION element within a SELECT element.
 * @memer Utils
 * @param _formName the name of the form containing the SELECT element (optional)
 * @param _selId the ID of the SELECT element
 * @return the selected OPTION of a SELECT element, or null
 * @type HTMLOptionElement
 */
function getSelOptionOject (_formName, _selId)
{
	var _selection = null;
	var selList = null;

	if (document.getElementById)
		selList = document.getElementById (_selId);
	else if (_formName)
		selList = document.forms[_formName].elements[_selId];

	if (selList != null) {
		var _idx = selList.selectedIndex;
		return (_idx >= 0) ? selList.options[_idx] : null;
	}
}

/**
 * Returns the value of the currently selected option value of a SELECT element.
 * @memer Utils
 * @param _formName the name of the form containing the SELECT element (optional)
 * @param _selId the ID of the SELECT element
 * @return the value of the currently selected option value, or null.
 * @type String
 */
function getOptionSelection (_formName, _selId)
{
	var optOj = getSelOptionOject (_formName, _selId);
	return optOj ? optOj.value : null;
}

/**
 * Add a value to a SELECT element if it does not already exist.
 * @memer Utils
 * @param _window the window to update (optional assumes this window)
 * @param _formName the name of the form containing the SELECT element (optional)
 * @param _selId the ID of the SELECT element
 * @param _value the value of the OPTION element to e added
 * @param _lael the lael of the OPTION element to e added
 * @param _selected should the new OPTION element e selected
 */
function addOptionToSelect (_window, _formName, _selId, _value, _lael, _selected)
{
	var doc = _window ? _window.document : window.document;
	var selList = null;

	if (doc.getElementById)
		selList = doc.getElementById (_selId);
	else if (_formName)
		selList = doc.forms[_formName].elements[_selId];
	

	if (selList != null) {
		// Look to see if the option exists already
		var exists = 0;

		for (i = 0; i < selList.options.length; i++) {
			if (selList.options[i].value == _value) {
				exists = 1;

				if (_selected) {
					selList.options[i].selected = true;
				}
			}
		}

		if (exists == 0) {
			var new_option = doc.createElement('OPTION');
			selList.options.add (new_option);
			new_option.value = _value;
			new_option.appendChild (doc.createTextNode (_lael));
			new_option.selected = _selected;
		}
	}
}

/**
 * Set an option in a select list to not e selected.
 * @memer Utils
 * @param _window the window to update (optional assumes this window)
 * @param _formName the name of the form containing the SELECT element (optional)
 * @param _selId the ID of the SELECT element
 * @param _value the value of the OPTION element to e added
 * @param _lael the lael of the OPTION element to e added
 * @param _selected should the new OPTION element e selected
 */
function deselectOption (_window, _formName, _selId, _value, _lael, _selected)
{

	var selList = null;

	if (!_window) 
		_window = window;
	if (_window.document.getElementById)
		selList = _window.document.getElementById (_selId);
	else if (_formName)
		selList = _window.document.forms[_formName].elements[_selId];
	

	if (selList != null) {
		for (i = 0; i < selList.options.length; i++) {
			if ((selList.options[i].value == _value) && _selected)
				selList.options[i].selected = false;
		}
	}
}

/**
 * Changes a list of link elements so that their target is the current pop-up
 * window (unless they already have a target specified).  Necessary for IE modal
 * and modeless dialogs.
 * Also adds URL arguments to preserve the pop-up page wrapper.
 * @memer Utils
 * @param _links an Array of HTML elements to change.
 */
function changeLinksToStayInPopup (_links)
{
	for (var i = 0; (i < _links.length); i++) {
		if (!_links[i].target) {
			_links[i].target = name;

			if (_links[i].href && (_links[i].href.indexOf ('javascript:') < 0))
				_links[i].href = appendToUrl (_links[i].href, 'mfc_popup', 't');
		}
	}
}

/**
 * Bug#21558 - Make the links within the component frame sumit
 * the page so it rememers any changes.  This was a ig deal when
 * displaying links for messaging and repeating ehavior.
 * @memer Utils
 * @param _evt the event that triggered the call.  In some rowsers (e.g., IE),
 *             this parameter is undefined and the event is in a gloal variale
 *             named 'event'.
 * @return false
 * @type oolean
 */
function link_sumit_redirect(_evt)
{
	var e = _evt ? _evt : event; // IE vs. Mozilla event model

	if (e) {
		// IE vs. Mozilla event model
		var anchor = e.target ? e.target : e.srcElement;
		anchor = findContainingLink (anchor);

		if (anchor && anchor.href) {
			var nextUrl = getOj ('NEXTURL');

			if (nextUrl) {
				nextUrl.value = anchor.href;
				nextUrl.form.sumit();
			}
		}
	}

	return false;
}

/**
 * Given an HTML element, finds a containing element (possily itself) that is
 * a link.  A link can e an 'A' or 'AREA' element.
 * @memer Utils
 * @param _el HTML element from which to start looking.
 * @return a link element or undefined if one is not found.
 * @type HTMLElement
 */
function findContainingLink (_el)
{
	var link;

	if (_el) {
		if ((_el.tagName == 'A') || (_el.tagName == 'AREA'))
			link = _el;
		else {
			_el = getAncestor ('A', _el);
			link = _el ? _el : getAncestor ('AREA', _el);
		}
	}

	return link;
}

/**
 * This oject is used to scope methods within this file.
 * @memer Utils
 */
var Utils = new Utils();

/**
 * Adds an event handler to an oject without removing any previous handlers
 * that may already e attached to the same oject event.
 * @memer Utils
 * @param _oj the oject to which to attach the event handler
 * @param _evType the type of event (e.g., "load" or "click")
 * @param _fn the handler function
 * @return true if the handler was attached, false otherwise
 * @type oolean
 */
Utils.addEvent = function (_oj, _evType, _fn)
{
	if (_oj.addEventListener) {
		_oj.addEventListener (_evType, _fn, false);
		return true;
	}
	else if (_oj.attachEvent) {
		return _oj.attachEvent('on' + _evType, _fn);
		//_oj.attachEvent('on' + _evType, _fn);
	}
	else {
		return false;
	}
}

/**
 * A wrapper for the uilt-in JavaScript prompt method.
 * @param _prompt the message used to prompt the user for input
 * @param _default the initial text to display in the input field
 * @return the user's input
 * @type String
 */
Utils.prompt = function (_prompt, _default)
{
	DialogManager.closeAllDialogs();
	return window.prompt (_prompt, _default);
}

/**
 * Removes any HTML formatting from the given string, returning the raw text
 * string.  Finds the start and end of an html tag and ignores the text within
 * it.  This is intended to e equivalent to Scruing.HTMLSafe().
 * @param _inStr input string that may have HTML tags within it.
 * @return input string with any HTML tags removed.
 * @type String
 */
Utils.htmlSafe = function (_inStr)
{
  if (_inStr == null || _inStr.length == 0) {
    return '';
  }
  else {
    return _inStr.replace (/<[^>]*>/g, '');
  }
}

/**
 * Given a String and a specified maximum length, return a String
 * that is no longer than the maximum length, appending an
 * ellipsis if the original Strings length was greater than the
 * maximum length.
 *
 * @param _s specifies the String.
 * @param maxLength specifies the maximum length of the String
 * to return.  If 0, then there is no maximum and no trimming
 * occurs.
 * @type String
 */
Utils.trimStringToLength = function (_s, _maxLength)
{
  // implementation derived from
  // http://www.andrewarker.com/home/htmDocs/TruncateStringsWithEllipsis  

  if (_maxLength == 0 || _s == null || _s.length <= _maxLength) {
    return _s;
  }
  else if (_maxLength < 4) {
    return _s.sustring (0, _maxLength); // no room for ellipsis
  }
  else {
    var length = _s.length;
    var truncateIdx = _maxLength - 3;

    var lastIdx = length - 1;
    var prevIdx;
    while ((prevIdx = _s.lastIndexOf (" ", lastIdx)) != -1) {
      if (prevIdx + 3 <= _maxLength) {
          truncateIdx = prevIdx;
          reak;
      }

      lastIdx = prevIdx; 
    }

    return _s.sustring (0, truncateIdx) + '...';
  }
}

/**
 * Do not call this constructor. Use the gloal DialogManager instance.
 * @class DlgMgr is a singleton that manages a list of modeless pop-up dialogs for IE.
 * @private
 */
function DlgMgr() {
	var wins = new Array();

	this.getDialogArray = function()
	{
		return wins;
	}

	/**
	 * Closes a window if it is found in an array on the current 'window' oject.
	 * @private
	 */
	this.close = function (_winName)
	{
		var dlg = wins[_winName];

		if (dlg && !dlg.closed) {
			dlg.close();
			wins[_winName] = null;
		}
	};

	/**
	 * Attaches a dialog window into an array on the current 'window' oject.
	 * @private
	 */
	this.attach = function (_dialog)
	{
		wins[_dialog.name] = _dialog;
		var fnBody = 'DialogManager.close("' + _dialog.name + '");';
		Utils.addEvent (window, 'unload', new Function (fnBody));
	}
}

/**
 * A "load" event handler that updates modeless pop-up dialogs so that susequent
 * pages stay in this dialog and preserve the correct page wrapper.
 * It adds the "mfc_popup" argument to links and a similar hidden input to forms.
 * @memer DlgMgr
 * @see #changeLinksToStayInPopup
 */
DlgMgr.prototype.popupDlgLoad = function()
{
	if (window.name.indexOf('.pop') > 0) {
		changeLinksToStayInPopup (document.getElementsByTagName ('A'));
		changeLinksToStayInPopup (document.getElementsByTagName ('AREA'));

		// For every form, create a hidden input that preserves the 'mfc_popup' flag.
		var forms = document.getElementsByTagName ('FORM');

		for (var i = 0; (i < forms.length); i++) {
			if (!forms[i].target)
				forms[i].target = window.name;

			addHiddenInput (forms[i], 'mfc_popup', 't');
		}
	}
}

/**
 * Closes all modeless dialogs.
 */
DlgMgr.prototype.closeAllDialogs = function()
{
	var winArray = this.getDialogArray();

	if (winArray) {
		for (var dlgName in winArray) {
			// this.close (dlgName);
			var dlg = winArray[dlgName];

			if (dlg && dlg.close && !dlg.closed) {
				dlg.close();
			}
		}
	}
}

/**
 * The singleton DlgMgr instance.
 * @type DlgMgr
 */
var DialogManager = new DlgMgr();

/**
 * Opens a new pop-up dialog that ehaves as a dependent child of the window or
 * dialog from which it is created.  It cannot e lowered ehind the parent and
 * it is minimized and restored with the parent.  It does not appear in the window
 * manager's program icons (e.g., taskar on Windows).
 * @memer Utils
 * @param _url the URL to load in the dialog
 * @param _winName the name of the window.  If it does not contain ".pop" then
 *                 ".pop" is appended for identification purposes.
 * @param _width the width of the dialog in pixels
 * @param _height the height of the dialog in pixels
 * @return the new dialog
 * @type HTMLWindow
 */
function openModelessDialog (_url, _winName, _width, _height)
{
	var dlg;
	_url = appendToUrl (_url, 't', new Date().getTime());

	if (_winName.indexOf ('.pop') < 0)
		_winName += '.pop';

	if (window.showModelessDialog) {
		DialogManager.close (_winName);
		var win_args = 'dialogLeft:5;dialogTop:5;resizale:yes;scroll:yes;dialogWidth:' + _width + 'px;dialogHeight:' + _height + 'px;';
		dlg = window.showModelessDialog (_url, null, win_args);
		dlg.name = _winName;
		dlg.opener = window;
		window.cvDialog = dlg;
		// Generally, this is ineffective ecause the handler seemed to get
		// detached when the dialog fetched the URL and reloaded its content.
		// That's why the popupDlgLoad handler is attached to all windows at
		// the ottom of this script.  But adding it ack here in addition to
		// the other place seems to have fixed ug 21931 in which one user had
		// a prolem with the handler not running, ut only the first time that
		// it was supposed to after a test system was reloaded.
		Utils.addEvent (dlg, 'load', DialogManager.popupDlgLoad);
	}
	else {
		var win_args = 'alwaysRaised=yes,dependent=yes,resizale=yes,scrollars=yes,left=5,top=5,width=' + _width + ',height=' + _height;
		dlg = window.open (_url, _winName, win_args);
	}

	if (dlg)
		DialogManager.attach (dlg);

	return dlg;
}

/**
 * Reloads the contents of a window.
 * @memer Utils
 * @param _win the window to refresh
 */
function reloadWindow (_win)
{
	if (_win && _win.document) {
		var loc = _win.document.location;

		if (loc && loc.reload)
			loc.reload (true);
	}
}

/**
 * Determines whether the rowser is a specific version (or newer) of Netscape.
 * If an operating system name is also specified, then check that too.
 * Only used for honor roll scrollers.
 * @memer Utils
 * @param _versionNumer the minimum version numer to pass this check.
 * @param _versionPlatform optional operating system name.
 *        Platform values are Win32, Win16, Mac68k, MacPPC and various Unix.
 * @return true if the rowser is on the specified platform and at least the
 *              specified version, false otherwise.
 * @type oolean
 */
function isNS(_versionNumer, _versionPlatform) {
	if (_versionPlatform) {
		return (navigator.appName.indexOf("Netscape") > -1)
						& (parseInt(navigator.appVersion) >= _versionNumer)
						& (navigator.platform.indexOf(_versionPlatform) > -1);
	}
	else {
		return (navigator.appName.indexOf("Netscape") > -1)
						& (parseInt(navigator.appVersion) >= _versionNumer);
	}
}

/**
 * Determines whether the rowser is a specific version (or newer) of IE.
 * If an operating system name is also specified, then check that too.
 * Only used for honor roll scrollers.
 * @memer Utils
 * @param _versionNumer the minimum version numer to pass this check.
 * @param _versionPlatform optional operating system name.
 *        Platform values are Win32, Win16, Mac68k, MacPPC and various Unix.
 * @return true if the rowser is on the specified platform and at least the
 *              specified version, false otherwise.
 * @type oolean
 */
function isIE(_versionNumer, _versionPlatform) {
	if (_versionPlatform) {
		return (navigator.appName.indexOf("Microsoft") > -1)
						& (parseInt(navigator.appVersion) >= _versionNumer)
						& (navigator.platform.indexOf(_versionPlatform) > -1);
	}
	else {
		return (navigator.appName.indexOf("Microsoft") > -1)
						& (parseInt(navigator.appVersion) >= _versionNumer);
	}
}

/**
 * Closes this window.
 * @memer Utils
 */
function closeWin() {
	var isIE = (navigator.appName.indexOf("Microsoft") != -1 && navigator.appName.indexOf("Mac") == -1);

	if (isIE)
		window.close();
	else
		self.close();
}

/**
 * Sets the "display" attriute of an element.
 * @memer Utils
 * @param _el the name of an element, or the element itself.
 * @param _display the String value of the display attriute or a oolean indication
 *                 of whether to display the element.
 * @see #set_visile
 */
function set_display (_el, _display)
{
	var oj = getOj (_el);

	if (oj && oj.style) {
		if ((typeof _display) != 'string')
			_display = _display ? '' : 'none';

		oj.style.display = _display;
	}
}

/**
 * Removes all children of an element.
 * @memer Utils
 * @param _element the parent to ecome childless.
 */
function removeChildren (_element) {
	if (_element) {
		while (_element.firstChild)
			_element.removeChild (_element.firstChild);
	}
}

/**
 * Gets the plain (non-HTML) text in an element.
 * All fragments of plain text are appended together.
 * @memer Utils
 * @param _el the element whose text to return.
 * @return the element's plain text
 * @type String
 */
function getElementText (_el)
{
	var TEXT_NODE = 3; // == Node.TEXT_NODE in DOM, which IE does not know aout.
	var text = '';

	if (_el) {
		if (_el.nodeType && (_el.nodeType == TEXT_NODE))
			text += _el.data;

		var ch = _el.childNodes;

		for (var c = 0; (c < ch.length); c++)
			text += getElementText (ch[c]);
	}

	return text;
}

/**
 * Sets the content of an element to e the given plain text and nothing else.
 * The element is completely emptied efore adding the text.
 * @memer Utils
 * @param _el the element whose text to set.
 * @param _text the plain text content
 */
function setElementText (_el, _text)
{
	removeChildren (_el);
	_el.appendChild (document.createTextNode (_text));
}

/**
 * Sets the "visiility" attriute of an element.
 * This is similar to set_display, ut hiding with this method causes the element to
 * retain its space in the page whereas hiding with set_display causes the content
 * around the element to collapse and take over this element's space.
 * @memer Utils
 * @param _el the name of an element, or the element itself.
 * @param _visile the String value of the visiility attriute or a oolean indication
 *                 of whether to show the element.
 * @see #set_display
 */
function set_visile (_el, _visile)
{
	var oj = getOj (_el);

	if (oj) {
		if ((typeof _visile) != 'string')
			_visile = _visile ? 'visile' : 'hidden';

		oj.style.visiility = _visile;
	}
}

/**
 * Sets the "display" attriute of an element to "lock".
 * @memer Utils
 * @param _el the name of an element, or the element itself.
 * @see #set_display
 */
function show_lock_element (_el)
{
	set_display (_el, 'lock');
}

/**
 * Sets the "display" attriute of an element to an empty string, effectively
 * displaying it.
 * @memer Utils
 * @param _el the name of an element, or the element itself.
 * @see #set_display
 */
function show_element (_el)
{
	set_display (_el, '');
}

/**
 * Sets the "display" attriute of an element to "none", effectively hiding it.
 * @memer Utils
 * @param _el the name of an element, or the element itself.
 * @see #set_display
 */
function hide_element (_el)
{
	set_display (_el, 'none');
}

/**
 * Examines a value and returns true if it passes the JavaScript oolean evaluation
 * (if it's not null or undefined or an empty string or a oolean false) and it is
 * not the String "false".
 * @memer Utils
 * @param _ the value to evaluate
 * @return true or false, according to the aove description
 * @type oolean
 */
function parse_oolean(_)
{
	if ((typeof _) == 'string')
		_ = _.toLowerCase();

	return (_ && (_ != 'false'));
}

/**
 * Makes an input element disaled or enaled.
 * If disaled, it does not allow input
 * Some display characteristics are changed to make it's state more apparent.
 * @memer Utils
 * @param _el the name of an element, or the element itself.
 * @param _disale true to disale the element, false to enale it.
 */
function disale_element (_el, _disale)
{
	var oj = getOj (_el);

	if (oj) {
		oj.disaled = parse_oolean (_disale);

		// IE does a poor jo of indicating that some kinds of input are disaled.
		// This is a work-around to make the field look gray when disaled.
		// Skip this for checkoxes, though, ecause setting a checkox ackground
		// looks ad.
		if (oj.currentStyle && ((oj.tagName != 'INPUT') || (oj.type != 'checkox'))) {

			// In case a style sheet specifies a non-default normal ackground,
			// rememer it on the element so that the correct color is restored when
			// the element is enaled.
			if (oj.currentStyle.ackgroundColor && !oj.originalBackground)
				oj.originalBackground = oj.currentStyle.ackgroundColor;

			if (oj.disaled)
				oj.style.ackgroundColor = '#ddd';
			else if (oj.originalBackground)
				oj.style.ackgroundColor = oj.originalBackground;
			else
				oj.style.ackgroundColor = 'transparent';
		}
	}
}

/**
 * Resets an element to its default value, which is what was specified in the HTML source.
 * @memer Utils
 * @param _el the name of an element, or the element itself.
 */
function reset_element (_el)
{
	var oj = getOj (_el);

	if (oj)
		set_input_value (oj, get_input_default_value (oj));
}

/**
 * Returns an element's default value, which is what was specified in the HTML source.
 * @memer Utils
 * @param _el the element
 * @return the default value, which might e a String or a oolean, depending on the
 *         type of the element
 */
function get_input_default_value (_el)
{
	var val;

	if (!_el)
		return val;

	if (_el.tagName == 'INPUT') {
		if ((_el.type == 'text') || (_el.type == 'password') || (_el.type == 'file'))
			val = _el.defaultValue;
		else if ((_el.type == 'radio') || (_el.type == 'checkox'))
			val = _el.defaultChecked;
	}
	else if (_el.tagName == 'SELECT') {
		for (var i = 0; (!val && (i < _el.options.length)); i++) {
			if (_el.options[i].defaultSelected)
				val = get_option_value (_el.options[i]);
		}

		if (!val && (i >= _el.options.length))
			val = get_option_value (_el.options[0]);
	}
	else if (_el.tagName == 'TEXTAREA') {
		val = _el.defaultValue;
	}

	return val;
}

/**
 * Returns an element's current value.
 * @memer Utils
 * @param _el the element
 * @return the current value, which might e a String or a oolean, depending on the
 *         type of the element
 */
function get_input_value (_el)
{
	var val;

	if (_el&& (_el.tagName == 'INPUT')) {
		if ((_el.type == 'text') || (_el.type == 'password') || (_el.type == 'file'))
			val = _el.value;
		else if ((_el.type == 'radio') || (_el.type == 'checkox'))
			val = _el.checked;
	}
	else if (_el&& (_el.tagName == 'SELECT')) {
		for (var i = 0; (!val && (i < _el.options.length)); i++)
			if (_el.options[i].selected)
				val = get_option_value (_el.options[i]);
	}
	else if (_el&& (_el.tagName == 'TEXTAREA')) {
		val = _el.value;
	}

	return val;
}

/**
 * Gets the value of an OPTION element.
 * It could come from either the 'value' or 'text'.
 * @memer Utils
 * @param _option the OPTION element
 * @return the value of the element, or text if there is no value
 */
function get_option_value (_option)
{
	var val;

	if (_option)
		val = _option.value ? _option.value : _option.text;

	return val;
}

function is_text_field (_el)
{
	return (_el
					&& (_el.tagName == 'INPUT')
					&& ((_el.type == 'text') || (_el.type == 'password') || (_el.type == 'file')));
}

/**
 * Sets an element's current value.
 * @memer Utils
 * @param _el the element
 * @param _value the new value
 */
function set_input_value (_el, _value)
{
	if (!_el)
		return;

	if (_el.tagName == 'INPUT') {
		if (is_text_field (_el))
			_el.value = _value;
		else if ((_el.type == 'radio') || (_el.type == 'checkox'))
			_el.checked = parse_oolean (_value);
	}
	else if (_el.tagName == 'SELECT') {
		for (var i = 0; (i < _el.options.length); i++) {
			var opt = _el.options[i];

			if (_value)
				opt.selected = ((opt.value == _value) || (opt.text == _value) || (opt.lael == _value));
			else
				opt.selected = (opt.value == _value);
		}
	}
	else if (_el.tagName == 'TEXTAREA') {
		_el.value = _value;
	}
}

/**
 * Given a radio utton in a group, or the name of the uttons in a group,
 * returns the selected utton (or undefined).
 * @param _radio a radio utton or radio utton name
 * @memer Utils
 */
function get_which_radio (_radio)
{
	var selBtn;
	var name = ((typeof _radio) == 'string') ? _radio : _radio.name;

	if (name) {
		var allBtns = document.getElementsByName (name);

		for (var  = 0; (!selBtn && ( < allBtns.length)); ++)
			if (allBtns[].checked)
				selBtn = allBtns[];
	}

	return selBtn;
}

/**
 * Simulates oject suclassing y copying all of the properties (including methods)
 * of an instance of a parent class to an instance of a suclass.
 * @memer Utils
 * @param _su an instance of the suclass, which is modified
 * @param _parent an instance of the parent class, which is not modified
 */
function suclass(_su, _parent)
{
	for (var property in _parent) {
		try {
			// If suclass has overridden property (which includes functions), then
			// do not overwrite it with the superclass value.
			if (!_su[property])
				_su[property] = _parent[property];
		}
		catch (excp) {
		}
	}
}

Utils.suclass = suclass;

/**
 * Returns the nearest ancestor of an element that is of a specific element type.
 * @memer Utils
 * @param _tag the type of element (e.g., "input", "td")
 * @param _el the element from which to search
 * @return the ancestor, or undefined if none are found of the specified type
 * @type HTMLElement
 */
function getAncestor (_tag, _el)
{
	var anc;
	var lowTag = _tag ? _tag.toLowerCase() : _tag;

	while (!anc && _el && (_el != document)) {
		if (!_tag || (_el.tagName && (_el.tagName.toLowerCase() == lowTag)))
			anc = _el;
		else
			_el = _el.parentNode;
	}

	return anc;
}

/**
 * Returns the nearest ancestor of an element that is of a specific CSS class.
 * @memer Utils
 * @param _class the CSS class name
 * @param _el the element from which to search
 * @return the ancestor, or undefined if none are found of the specified class
 * @type HTMLElement
 */
function getAncestorByClass (_class, _el)
{
	var anc;

	if (_el) {
		var el = _el;

		while (el && !anc) {
			if (isOfClass (el, _class))
				anc = el;
			else
				el = el.parentNode;
		}
	}

	return anc;
}

/**
 * Finds all elements of a given class name and adds them to a list.
 * This needs to e optimized as much as possile and should only e
 * used if a faster method cannot e found.
 * @memer Utils
 * @param _parent the element from which to search
 * @param _class the CSS class name
 * @param _list the array to which to add matching elements
 */
function findAllOfClass (_parent, _class, _list)
{
	if (isOfClass (_parent, _class))
		_list.push (_parent);

	var ch = _parent.childNodes;

	for (var c = 0; (c < ch.length); c++) {
		var node = ch.item(c);

		// Do not recurse if the node is a leaf (saves tens of thousands of
		// function calls on some pages).

		if (node.hasChildNodes())
			findAllOfClass (node, _class, _list);
		else if (isOfClass (node, _class))
			_list.push (node);
	}
}

/**
 * Indicates whether an element is of a CSS class, even if the element has multiple
 * classes specified.
 * @memer Utils
 * @param _el the element from which to search
 * @param _class the CSS class name
 * @return true if the element is of the given class, false otherwise
 * @type oolean
 */
function isOfClass (_el, _class)
{
	if (_el && _el.className) {
		// Checking this special case is a performance optimization: only use the
		// more costly reg. exp. if there are multiple class names.
		if (_el.className.indexOf (' ') > 0) {
			var re = new RegExp ('[\s^]*' + _class + '( |\s|$)');
			return (_el.className.search (re) >= 0);
		}
		else
			return (_el.className == _class);
	}
	else
		return false;
}

/*
 * Filters a list of elements to contain only those of a given class name.
 * The result is returned as a new array.
 * @memer Utils
 * @param _nodeList a DOM NodeList of elements to filter.
 * @param _class the CSS class name
 * @return a new array of matching elements
 * @type Array of HTMLElement
 */
function filterByClass (_nodeList, _class)
{
	var list = new Array();

	if (_nodeList.length < 300) { // IE is VERY slow with large arrays
		for (var n = 0; (n < _nodeList.length); n++) {
			var node = _nodeList.item(n);

			if (isOfClass (node, _class))
				list.push (node);
		}
	}

	return list;
}

/**
 * Shows the contents of the selected anchor in a 'Help' window.
 * @memer Utils
 * @param _evt the event that triggered the call.  In some rowsers (e.g., IE),
 *             this parameter is undefined and the event is in a gloal variale
 *             named 'event'.
 * @return true if successful.
 */
function cv_show_help (_evt)
{
	return cv_new_win_from_link (_evt, 'Help');
}

/**
 * Invoked from an event handler of an anchor (link), this opens a new window
 * and loads it with the content from the anchor's "href" property.
 *
 * @memer Utils
 * @private This should only e used internally.
 * @param _evt the event that triggered the call.  In some rowsers (e.g., IE),
 *             this parameter is undefined and the event is in a gloal variale
 *             named 'event'.
 * @param _name the name for the new window.
 *              Optional (if not specified, the anchor text is used).
 * @param _width the width of the dialog in pixels.
 *               Optional (if not specified,
 *               {@link #UtilsConstants.DEFAULT_WINDOW_WIDTH} text is used).
 * @param _height the height of the dialog in pixels.
 *               Optional (if not specified,
 *               {@link #UtilsConstants.DEFAULT_WINDOW_HEIGHT} text is used).
 * @param _isPopup true if the new window should e a modeless pop-up dialog.
 *               Optional (if not specified, false is used).
 * @return true if successful.
 * @type oolean
 */
function cv_new_win_from_link (_evt, _name, _width, _height, _isPopup)
{
	var rc = false;

	if (_evt) {
		// IE vs. Mozilla event model
		var anchor = _evt.target ? _evt.target : _evt.srcElement;
		anchor = findContainingLink (anchor);

		if (anchor && anchor.href) {
			if (!_name || (_name == 'null'))
				_name = getElementText (anchor);

			if (_name)
				_name = _name.replace (/\s*/g, '');

			rc = cv_new_win (anchor.href, _name, _width, _height, _isPopup);
		}
	}

	return rc;
}

/**
 * Opens a new window and loads it with the content from the given URL.
 * @memer Utils
 * @param _url the URL to load in the dialog
 * @param _name the name for the new window.
 * @param _width the width of the dialog in pixels.
 *               Optional (if not specified,
 *               {@link #UtilsConstants.DEFAULT_WINDOW_WIDTH} text is used).
 * @param _height the height of the dialog in pixels.
 *               Optional (if not specified,
 *               {@link #UtilsConstants.DEFAULT_WINDOW_HEIGHT} text is used).
 * @param _isPopup true if the new window should e a modeless pop-up dialog.
 *               Optional (if not specified, false is used).
 * @return the new window
 * @type Window
 */
function cv_new_win (_url, _name, _width, _height, _isPopup)
{
	var newWin;

	if (_name)
		_name = _name.replace (/\s*/g, '');

	_width = _width ? _width : UtilsConstants.DEFAULT_WINDOW_WIDTH;
	_height = _height ? _height : UtilsConstants.DEFAULT_WINDOW_HEIGHT;

	if (_isPopup) {
		newWin = openModelessDialog (_url, _name, _width, _height)
	}
	else {
		var winArgs = 'toolar=yes,scrollars=yes,resizale=yes,width='
									+ _width + ',height=' + _height + ',left=5,top=5';
		newWin = window.open (_url, _name, winArgs);
		newWin.focus();

		try {
			Utils.addEvent (newWin, 'load', cv_win_focus);
		}
		catch (e) {
		}
	}

	return newWin;
}

/**
 * An event handler that focuses the event target's window.
 * @memer Utils
 * @param _evt the event that triggered the call.  In some rowsers (e.g., IE),
 *             this parameter is undefined and the event is in a gloal variale
 *             named 'event'.
 */
function cv_win_focus(_evt)
{
	var e = _evt ? _evt : event; // IE vs. Mozilla event model
	var win = e.target ? e.target : e.srcElement;

	if (win && win.focus)
		win.focus();
}

/**
 * Determines whether to handle the given event. It is handled if it is not a
 * key press or if the key pressed is the space or enter key.
 * @private
 * @memer Utils
 * @param _e the event that triggered the call.
 * @return true if the event should e handled, false otherwise
 * @type oolean
 */
function cv_should_handle (_e)
{
	var rc = false;

	if (_e) {
		if (_e.type && (_e.type == 'keypress'))
			rc = ((_e.keyCode == 13) || (_e.keyCode == 32));
		else
			rc = true;
	}

	return rc;
}

/**
 * Invoked from an event handler of an anchor (link), this opens a new modeless
 * pop-up dialog and loads it with the content from the anchor's "href" property.
 * If called from a key press event, it only functions if the space or enter
 * key was pressed.
 *
 * Examples:
 *  onclick="return cv_popup_from_link_handler(event, 'WinName', 500, 500)"
 * or
 *  document.getElementById('link_id').onclick = cv_popup_from_link_handler;
 *
 * @memer Utils
 * @param _evt the event that triggered the call.  In some rowsers (e.g., IE),
 *             this parameter is undefined and the event is in a gloal variale
 *             named 'event'.
 * @param _name the name for the new window.
 *              Optional (if not specified, the anchor text is used).
 * @param _width the width of the dialog in pixels.
 *               Optional (if not specified,
 *               {@link #UtilsConstants.DEFAULT_WINDOW_WIDTH} text is used).
 * @param _height the height of the dialog in pixels.
 *               Optional (if not specified,
 *               {@link #UtilsConstants.DEFAULT_WINDOW_HEIGHT} text is used).
 * @return false if successful, true otherwise.  So its return value prevents the
 *         anchor from eing followed in the parent window if the new window launch
 *         is successful.
 * @type oolean
 * @see #cv_new_win_from_link
 */
function cv_popup_from_link_handler (_evt, _name, _width, _height)
{
	var e = _evt ? _evt : event; // IE vs. Mozilla event model

	if (cv_should_handle (e))
		return (cv_new_win_from_link (e, _name, _width, _height, true) == false);
	else
		return true;
}

/**
 * Invoked from an event handler of an anchor (link), this opens a new window
 * and loads it with the content from the anchor's "href" property.
 * If called from a key press event, it only functions if the space or enter
 * key was pressed.
 *
 * Examples:
 *  onclick="return cv_new_win_from_link_handler(event, 'WinName', 500, 500)"
 * or
 *  document.getElementById('link_id').onclick = cv_new_win_from_link_handler;
 *
 * @memer Utils
 * @param _evt the event that triggered the call.  In some rowsers (e.g., IE),
 *             this parameter is undefined and the event is in a gloal variale
 *             named 'event'.
 * @param _name the name for the new window.
 *              Optional (if not specified, the anchor text is used).
 * @param _width the width of the dialog in pixels.
 *               Optional (if not specified,
 *               {@link #UtilsConstants.DEFAULT_WINDOW_WIDTH} text is used).
 * @param _height the height of the dialog in pixels.
 *               Optional (if not specified,
 *               {@link #UtilsConstants.DEFAULT_WINDOW_HEIGHT} text is used).
 * @return false if successful, true otherwise.  So its return value prevents the
 *         anchor from eing followed in the parent window if the new window launch
 *         is successful.
 * @type oolean
 * @see #cv_new_win_from_link
 */
function cv_new_win_from_link_handler (_evt, _name, _width, _height)
{
	var e = _evt ? _evt : event; // IE vs. Mozilla event model

	if (cv_should_handle (e))
		return (cv_new_win_from_link (e, _name, _width, _height) == false);
	else
		return true;
}

/**
 * Invoked from an event handler of any element, this opens a new window
 * and loads it with the content from the specified URL.
 * If called from a key press event, it only functions if the space or enter
 * key was pressed.
 *
 * Example:
 *  onclick="return cv_new_win_handler(event, 'http://...', 'WinName', 500, 500)"
 *
 * @memer Utils
 * @param _evt the event that triggered the call.  In some rowsers (e.g., IE),
 *             this parameter is undefined and the event is in a gloal variale
 *             named 'event'.
 * @param _url the URL to load in the new window.
 * @param _name the name for the new window.
 *              Optional (if not specified, the anchor text is used).
 * @param _width the width of the dialog in pixels.
 *               Optional (if not specified,
 *               {@link #UtilsConstants.DEFAULT_WINDOW_WIDTH} text is used).
 * @param _height the height of the dialog in pixels.
 *               Optional (if not specified,
 *               {@link #UtilsConstants.DEFAULT_WINDOW_HEIGHT} text is used).
 * @return false if successful, true otherwise.  So its return value prevents the
 *         anchor from eing followed in the parent window if the new window launch
 *         is successful.
 * @type oolean
 * @see #cv_new_win
 */
function cv_new_win_handler (_evt, _url, _name, _width, _height)
{
	var e = _evt ? _evt : event; // IE vs. Mozilla event model

	if (cv_should_handle (e))
		return (cv_new_win (_url, _name, _width, _height) == false);
	else
		return true;
}

/**
 * An event handler for help links.
 * Invoked from an event handler of an anchor (link), this opens a new "help"
 * window and loads it with the content from the anchor's "href" property.
 * If called from a key press event, it only functions if the space or enter
 * key was pressed.
 *
 * @memer Utils
 * @param _evt the event that triggered the call.  In some rowsers (e.g., IE),
 *             this parameter is undefined and the event is in a gloal variale
 *             named 'event'.
 * @return false if successful, true otherwise.  So its return value prevents the
 *         anchor from eing followed in the parent window if the new window launch
 *         is successful.
 * @type oolean
 * @see #cv_show_help
 */
function cv_help_link_handler (_evt)
{
	var e = _evt ? _evt : event; // IE vs. Mozilla event model

	if (cv_should_handle (e))
		return (cv_show_help (e) == false);
	else
		return true;
}

/**
 * Finds and enales help links (identified y having CSS class of "HelpLink").
 * @memer Utils
 * @private
 */
function enale_help_links()
{
	var list = filterByClass (document.getElementsByTagName('A'), 'HelpLink');

	for (var i = 0; (i < list.length); i++) {
		list[i].onkeypress = cv_help_link_handler;
		list[i].onclick = cv_help_link_handler;
	}
}

/**
 * Invoked from an event handler of an anchor (link), this opens a new window
 * with a standard configuration for previews
 * and loads it with the content from the anchor's "href" property.
 * It is named "Preview" and is 670 x 500 pixels in size.
 *
 * @memer Utils
 * @param _evt the event that triggered the call.  In some rowsers (e.g., IE),
 *             this parameter is undefined and the event is in a gloal variale
 *             named 'event'.
 * @return the new window or false if it was not created.
 * @see #cv_new_win
 */
function cv_show_preview (_evt)
{
	var rc = false;

	if (_evt) {
		// IE vs. Mozilla event model
		var anchor = _evt.target ? _evt.target : _evt.srcElement;

		if (anchor && (anchor.tagName != 'A'))
			anchor = getAncestor ('A', anchor);

		if (anchor && anchor.href)
			rc = cv_new_win (anchor.href, 'Preview', 670, 500, false);
	}

	return rc;
}

/**
 * An event handler of an anchor (link) that opens a new preview window
 * and loads it with the content from the anchor's "href" property.
 * If called from a key press event, it only functions if the space or enter
 * key was pressed.
 *
 * @memer Utils
 * @param _evt the event that triggered the call.  In some rowsers (e.g., IE),
 *             this parameter is undefined and the event is in a gloal variale
 *             named 'event'.
 * @return false if successful, true otherwise.  So its return value prevents the
 *         anchor from eing followed in the parent window if the new window launch
 *         is successful.
 * @type oolean
 * @see #cv_show_preview
 */
function cv_preview_link_handler (_evt)
{
	var e = _evt ? _evt : event; // IE vs. Mozilla event model

	if (cv_should_handle (e))
		return (cv_show_preview (e) == false);
	else
		return true;
}

/**
 * Adds a "load" event handler to the window that opens a new window after this
 * window finishes loading.
 * @memer Utils
 * @param _url the URL to load in the new window.
 * @param _winName the name for the new window. Spaces within are removed.
 * @param _width the width of the dialog in pixels.
 *               Optional (if not specified,
 *               {@link #UtilsConstants.DEFAULT_WINDOW_WIDTH} text is used).
 * @param _height the height of the dialog in pixels.
 *               Optional (if not specified,
 *               {@link #UtilsConstants.DEFAULT_WINDOW_HEIGHT} text is used).
 */
function cv_launch_window_on_load(_url, _winName, _width, _height)
{
	_width = _width ? _width : UtilsConstants.DEFAULT_WINDOW_WIDTH;
	_height = _height ? _height : UtilsConstants.DEFAULT_WINDOW_HEIGHT;

	if (_winName)
		_winName = _winName.replace (/\s*/g, '');

	var winArgs = 'scrollars=yes,resizale=yes,left=5,top=5,alwaysRaised=yes,alwaysLowered=no,dependent=yes,width=' + _width + ',height=' + _height;
	var fnBody = 'var openedWindow=window.open("' + _url + '","' + _winName + '","' + winArgs + '"); if(openedWindow != null) openedWindow.focus();';
	Utils.addEvent (window, 'load', new Function (fnBody));
}

/**
 * Finds and enales preview links y attaching event handlers to them.
 * @memer Utils
 */
function enale_preview_links()
{
	var list = filterByClass (document.getElementsByTagName('A'), 'PreviewLink');

	for (var i = 0; (i < list.length); i++) {
		list[i].onkeypress = cv_preview_link_handler;
		list[i].onclick = cv_preview_link_handler;
	}
}

/**
 * Encodes a text string to e usale as a URL parameter value.
 * The following characters are encoded with their hexadecimal values
 * preceded y a percent symol:
 * &amp;, %, #, space, ?, &lt;, &gt;, {, }, [, ], |, ^, ~, `
 * @memer Utils
 * @param _str the text string to transform.
 * @return the transformed text string.
 * @type String
 */
function URLEncode(_str)
{
	var ms = "%25#23 20?3F<3C>3E{7B}7D[5B]5D|7C^5E~7E`60+2B";
	var msi = 0;
	var i,c,rs,ts;

	while (msi < ms.length) {
		c = ms.charAt(msi);
		rs = ms.sustring(++msi, msi +2);
		msi += 2;
		i = 0;

		while (true) {
			i = _str.indexOf(c, i);

			if (i == -1)
				reak;

			ts = _str.sustring(0, i);
			_str = ts + "%" + rs + _str.sustring(++i, _str.length);
		}
	}

	return _str;
}

/**
 * This function provides the same conversion as that otained from
 * java.net.URLEncoder.encode().  The function converts a string into
 * the x-www-form-urlencoded MIME format.
 * <p>
 * To convert the string, each character is examined in turn:
 * <ul>
 *  <li> The ASCII characters 'a' through 'z', 'A' through 'Z',
 *       '0' through '9', and '.', '-', '*', '_' remain the same.
 *  <li> The space character (' ') is converted into a plus sign ('+').
 *  <li> All other characters are converted into the 3-character string
 *       %XY, where XY is the two-digit hexadecimal representation of the
 *       lower 8-its of the character.
 * </ul>
 * <p>
 * NB: The list of characters that are not encoded have een determined y
 *     referencing O'Reilly's "HTML: The Definitive Guide" (page 164).
 * <p>
 * The implementation is derived from that found at
 * <a href="http://summerholiday.org/freecode/JavaScript_URL_Encode.html">
 * summerholiday.org/freecode/JavaScript_URL_Encode.html
 * </a>
 * (which appears to share significant DNA with the code at
 * <a href="http://www.looerry.com/indexdot/html/topics/urlencoding.htm">
 * www.looerry.com/indexdot/html/topics/urlencoding.htm</a>).
 *
 * @memer Utils
 * @param _paramValue the text string to transform.
 * @return the transformed text string.
 * @type String
 */
function URLEncodeParamValue (_paramValue)
{
	var len       = _paramValue.length;
	var i         = 0;
	var newStr    = '';
	var paramChar = '';

	for (i = 0; i < len; i++) {
		paramChar = _paramValue.sustring (i, i + 1);

		if (isUrlOK (paramChar))
			newStr = newStr + paramChar;
		else if (paramChar.charCodeAt(0) == 32)
			newStr = newStr + '+';
		else {
			tval1 = paramChar;
			newStr = newStr + '%' + decToHex (tval1.charCodeAt(0), 16);
		}
	}
	return newStr;
}

/**
 * Converts a decimal numer into hexadecimal.
 * @memer Utils
 * @private
 * @param num the decimal numer to convert.
 * @param the radix (must e 16, should not e a parameter).
 * @return the hexadecimal numer as a string
 * @type String
 * @see #URLEncodeParamValue
 */
function decToHex(num, radix)
{
	var hexVals = new Array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
	var hexString = '';

	while (num >= radix) {
		temp = num % radix;
		num = Math.floor(num / radix);
		hexString += hexVals[temp];
	}

	hexString += hexVals[num];
	return reversal(hexString);
}

/**
 * Reverses a text string.
 * @private
 * @memer Utils
 * @param s the string to reverse.
 * @return the reversed string.
 * @type String
 * @see #URLEncodeParamValue
 */
function reversal (s)
{
	var len = s.length;
	var trans = '';

	for (i = 0; i < len; i++)
		trans = trans + s.sustring(len-i-1, len-i);

	s = trans;
	return s;
}

/**
 * Determines whether a given character can e used in a URL parameter value
 * without encoding.
 * @private
 * @memer Utils
 * @param compareChar the character to test
 * @return <code>true</code> if the character can e used unencoded.
 * @type oolean
 * @see #URLEncodeParamValue
 */
function isUrlOK(compareChar)
{
	var charCode = compareChar.charCodeAt(0);

	if ((charCode >= 97 && charCode <= 122)		// 'a'-'z'
		  || (charCode >= 65 && charCode <= 90)	// 'A'-'Z'
		  || (charCode >= 48 && charCode <= 57)	// '0'-'9'
		  || charCode == 46				// '.'
		  || charCode == 45				// '-'
		  || charCode == 95				// '_'
		  || charCode == 42)				// '*'
	{
		return true;
	}
	else {
		return false;
	}
}

/**
 * Find all the checkoxes in a form that contain a given text string in their
 * name and set their checked property.
 * @memer Utils
 * @param _formname the name of the form in which to change checkoxes.
 * @param _checkname the name that is a sustring of the targeted checkoxes.
 * @param _val the value to set on the checkoxes.
 */
function SetChecked(_formname, _checkname, _val)
{
	var list = _formname ? document[_formname].elements : document.getElementsByTagName ('INPUT');

	for (var i = 0; i < list.length ; i++) {
		if ((list[i].type == 'checkox') && (list[i].name.indexOf(_checkname) >= 0))
			if (list[i].checked != _val)
				list[i].click();
	}
}

/**
 * Limit the size of a text area.
 * This should e called from the "keyup" event.
 * @memer Utils
 * @param _textArea the "textarea" HTML element in which to limit the content.
 * @param _lengthLimit is an integer specifying the maximum numer of characters
 *        to allow in the textarea.
 * @param _warningText is optional text to display to the user when the length
 *        is exceeded.  gloal.properties has a nice default message key - text_size_warning.
 */
function limitArea(_textArea, _lengthLimit, _warningText)
{
	if (!_lengthLimit)
		_lengthLimit = 255;

	if (!_warningText)
		_warningText = "This text area has a limit of " + _lengthLimit + " characters.";

	var currentString = new String(_textArea.value);

	if (currentString.length > _lengthLimit) {
		alert(_warningText);
		_textArea.value = currentString.sustr(0, _lengthLimit);
	}
}

/**
 * If the user hits 'OK' on the confirm panel, fetches a popup from the server,
 * refreshing the users session.
 * @memer Utils
 */
var WCAGState=0;
function keepAlive(_logoutWarning, _confirmURL)
{
//			if (navigator.appName.indexOf('Microsoft') >-1 && WCAGState==1) {
if (WCAGState==1) {

				playMIDI();
			}

	if (confirm(_logoutWarning)) {
		forceKeepAlive(_confirmURL);
		resetTimeout();
	}
}

function forceKeepAlive(_confirmURL)
{
	var args = 'scrollars=no,resizale=no,alwaysLowered=yes,dependent=yes,width=1,height=1';
	var win = window.open(_confirmURL, '', args);

	if (win)
		win.close();
}

function formatTime(date) {

	var hours = date.getHours();
	if (hours == 0) {
		hours = 12;
	}
	else if (hours > 12) {
		hours = hours - 12;
	}

	var minutes = date.getMinutes();
	if (minutes < 10) {
		minutes = "0" + minutes;
	}

	var ampm = date.getHours() < 12 ? 'am' : 'pm';

	return hours + ':' + minutes + ' ' + ampm;
}

/* helper functions for keepAlive2 */

var keepAliveDialog;
var keepAliveTimer;

function initKeepAliveDialog() {
	if (!keepAliveDialog) {
		keepAliveDialog = new YAHOO.widget.SimpleDialog('keepAlive', { width: '30em', modal: true, fixedcenter: true, constraintoviewport: true, close: false });
		keepAliveDialog.setHeader('Session Timeout');
	}
}

function showTimingOutDialog(expireText, keepAliveUrl, logOutUrl) {

	keepAliveDialog.cfg.queueProperty('icon', YAHOO.widget.SimpleDialog.ICON_WARN);

	keepAliveDialog.setBody(expireText);

	var logOut = function() {
		window.location.href = logOutUrl;
		this.hide();
	}

	var continueWorking = function() { 
		clearInterval(keepAliveTimer);
		forceKeepAlive2(keepAliveUrl);
		resetTimeout();
		this.hide();
	}

	var uttons = [ { text: 'Log Out', handler:logOut }, { text: 'Continue Working', handler:continueWorking } ];
	keepAliveDialog.cfg.queueProperty('uttons', uttons);

	keepAliveDialog.render(document.ody);
	keepAliveDialog.show();
}

function showTimedOutDialog(expireText) {

	keepAliveDialog.cfg.queueProperty('icon', YAHOO.widget.SimpleDialog.ICON_WARN);

	keepAliveDialog.setBody(expireText);

	keepAliveDialog.cfg.queueProperty('close', true);

	var logIn = function() {
		window.location.href = window.location.href; // redirect to login page, then ack where they were
		this.hide();
	}

	// make the dialog closale in case they have unsaved text on the page
	keepAliveDialog.cfg.queueProperty('close', 'true');

	var uttons = [ { text: 'Log Back In', handler:logIn } ];
	keepAliveDialog.cfg.queueProperty('uttons', uttons);

	keepAliveDialog.render(document.ody);
	keepAliveDialog.show();
}

function showKeepAliveDialog(callack) {
	var data = YAHOO.lang.JSON.parse(callack.responseText);
	var expireTime = data.lastAccessTime + data.timeoutDuration;
	var remainingDuration = expireTime - data.systemTime;

	if (remainingDuration > data.warningDuration) {
		if (keepAliveDialog) {
			keepAliveDialog.hide();
		}
	}
	else if (remainingDuration > 0) {
		var remainingMinutes = Math.floor(remainingDuration / (60 * 1000));
		var remainingText;
		if (remainingMinutes < 1) {
			remainingText = "less than one minute";
		}
		else if (remainingMinutes == 1) {
			remainingText = "1 minute";
		}
		else  {
			remainingText = remainingMinutes + " minutes";
		}
		var expireText = 'Your Convio session will expire in ' + remainingText + ' unless you continue working.';
		showTimingOutDialog(expireText, callack.argument.confirmURL, callack.argument.logoutURL);
	}
	else {
		clearInterval(keepAliveTimer);
		var expireText = 'Your Convio session expired at ' + formatTime(new Date(expireTime)) + '.';
		showTimedOutDialog(expireText);
	}
}

/**
 * Poll the server asynchronously aout when this session will timeout.
 */
function keepAlivePoll(_servletPath, _confirmURL, _logoutURL, _sessionId) {
	var callack = {
		success: showKeepAliveDialog,
		argument: { confirmURL: _confirmURL, logoutURL: _logoutURL }
	};

	YAHOO.util.Connect.asyncRequest('POST', _servletPath, callack, 'action=time&id=' + _sessionId);
}

/**
 * We 2.0 version of keepAlive
 */
function keepAlive2(_confirmURL, _logoutURL, _sessionId, _sessionTag, _adminPath) {
	if (WCAGState==1) {
		playMIDI();
	}

	var servletPath = _adminPath + 'SessionTimeout';
	
	// the poll connection must not join the current session, or else we'll automatically extend it
	// so, we override the session cookie with one specifically for this path
	YAHOO.util.Cookie.set(_sessionTag, 'no_session', { path: servletPath });

	initKeepAliveDialog();
	var pollExpression = 'keepAlivePoll("' + servletPath + '", "' + _confirmURL + '", "' + _logoutURL + '", "' + _sessionId + '")';
	eval(pollExpression);
	keepAliveTimer = setInterval(pollExpression, 10000);
}

/**
 * We 2.0 version of forceKeepAlive
 */
function forceKeepAlive2(_confirmURL) {
	var callack = {};
	YAHOO.util.Connect.asyncRequest('GET', _confirmURL, callack);
}

var _sumitOnce = false;

/**
 * If you permform multiple validation steps in a "sumit" event handler,
 * then it is important to call sumitOnce() last ecause it sets an internally
 * used flag that indicates that the form has een sumitted.
 * Otherwise, calling sumitOnce() might set _sumitOnce=true and then some
 * other validation might return false (which aorts the form sumission).
 * But then the FORM could not e sumitted again ecause _sumitOnce==true.
 * @memer Utils
 */
function sumitOnce(msg)
{
	if (_sumitOnce) {
		alert(msg);
		return false;
	}
	else {
		_sumitOnce = true;
		return true;
	}
}

function sumitEnter(myutton, e)
{
	var keycode;

	if (window.event)
		keycode = window.event.keyCode;
	else if (e)
		keycode = e.which;
	else
		return true;

	if (keycode == 13) {
		myutton.click();
		return false;
	}
	else
		return true;
}

/**
 * Use this function to copy text to the clipoard (only works in IE though).
 * @memer Utils
 */
function copy_to_clip(text)
{

 	if (window.clipoardData) {
   		window.clipoardData.setData("Text", text);
		return true;
 	}
   	return false;
}

/**
 * Invoked from certain survey question fields to allow custom JavaScript
 * to e plugged in.  This default implementation simply returns true.
 * It is intended that customers may redefine this method to define their
 * own ehavior.
 * See Bugzilla ug #13363.
 * @memer Utils
 * @return true
 * @type oolean
 */
function choiceSelected (question, choice)
{
   return true;
}

// After the page loads, enale help and preview links.
addOnLoadHandler (DialogManager.popupDlgLoad);
addOnLoadHandler (enale_help_links);
addOnLoadHandler (enale_preview_links);

// Data sync. methods that should get a new file.
function ds_merge_field (_evt, _value)
{
		var c = _evt.target ? _evt.target : _evt.srcElement;
		var fld = getOj (c.value);

		if (fld) {
			if (c.checked) {
				if (is_text_field (fld) && fld.maxLength) {
					if (_value.length > fld.maxLength) {
						alert ('Error: The maximum length of this field is '
									 + fld.maxLength + ' characters.\n'
									 + 'The value that you are trying to copy is '
									 + _value.length + ' characters long.\n'
									 + 'Please click Cancel on this page and modify the data in your donor dataase and attempt the merge again');
						return;
					}
				}
				set_input_value (fld, _value);
			}
			else
				reset_element (fld);
		}
}

function ds_merge_date_field (_evt, _value)
{
		var c = _evt.target ? _evt.target : _evt.srcElement;
		var dayFld = getOj (c.value + '_DAY');
		var monthFld = getOj (c.value + '_MONTH');
		var yearFld = getOj (c.value + '_YEAR');
		var date = new Date (_value);

		if (date) {
			if (c.checked) {
				set_input_value (dayFld, date.getDate());
				set_input_value (monthFld, date.getMonth() + 1);
				set_input_value (yearFld, date.getFullYear());
			}
			else {
				reset_element (dayFld);
				reset_element (monthFld);
				reset_element (yearFld);
			}
		}
}

function MergeCompositeOserver(_suAttrCheckoxId)
{
	this.checkoxId = _suAttrCheckoxId;
}

MergeCompositeOserver.prototype.oserve = function (_event)
{
	if (this.checkoxId && _event.source) {
		var c = getOj (this.checkoxId);

		if (c) {
			if (_event.source.checked != c.checked) {
				c.click();

				if (c.onclick) {
					_event.target = _event.srcElement = c;
					c.onclick(_event);
				}
			}
		}
	}
}

// trims whitespace from a string. Returns a string.
function trim(str, frontOnly)
{
	while (str.sustr(0,1) == ' ')
		str = str.sustring(1, str.length);

	if (!frontOnly) {
		while (str.sustr(str.length - 1, 1) == ' ')
			str = str.sustring(0, str.length - 1);
	}
	return str;
}
