<!--
/*
	' /////////////////////////////////////////////////////////////////////////
	' Copyright (c) 1998-2005 Mobigator Technology Group.  ALL RIGHTS RESERVED.
	' 
	' Unauthorized use of any portion of the code below without prior written 
	' authorization of Mobigator Technology Group is straightly prohibited.
	' 
	' For licensing information, please contact info@mobigator.com
	'//////////////////////////////////////////////////////////////////////////
*/
//-->

// this function shows or hides all elements of the same id
// it is useful for showing or hiding rows of the same id
function ShowOrHideElements(element_id, btn)
{
	var bShowing; 
	
	var e = document.all[element_id];
	// document.all will return:
	//  undefined -- if the element does not exist
	//  one element -- if only one element is found
	//  an array -- if multiple elements are found
	
	if (!e) { 
		return false;
	}
	
	if ((navigator.userAgent.indexOf("Firefox")!=-1) && (e.tagName.toLowerCase() == "tr"))  {
		ShowOrHideElementsFireFoxFix(element_id);
	}else if (e.length > 0) { 
		for(var i = 0; i < e.length; i++) {
			bShowing = (e[i].style.display != 'none');
			e[i].style.display = bShowing ? "none" : "block";
		}
	}
	else {
		bShowing = (e.style.display != 'none');
		e.style.display = bShowing ? "none" : "block";
	}
	
	if (btn)
	{
		btn.innerHTML = "<img border=0 hspace=2 align=absmiddle src=/vbinc/images/" + (bShowing ? "open_layer.gif" : "close_layer.gif") + ">";
	}
}

function ShowOrHideElementsFireFoxFix(element_id)
{
	var bShowing;
	var rows = document.getElementsByTagName("tr");
	for (var i = 0; i < rows.length; i++) { 
		var id = rows[i].getAttribute("id"); 
		if (id == element_id) { 
			bShowing = (rows[i].style.display != 'none');
			rows[i].style.display = bShowing ? "none" : "";		
		}
	}
}

function ExpandOrHideLayer(element, btn) 
{    
	ExpandOrHideLayerEx(element, btn, "Show Details", "Hide Details");
}  

function ExpandOrHideLayerEx(element, btn, detailsLabel, hideLabel) 
{    
	if (element.style.display == "block") 
	{
		element.style.display = "none";  
		btn.innerHTML = "<img border=0 hspace=2 align=absmiddle src=/vbinc/images/open_layer.gif>" + detailsLabel;
    } 
    else if (element.style.display == "none") 
    {  
		element.style.display = "block";
		btn.innerHTML = "<img border=0 hspace=2 align=absmiddle src=/vbinc/images/close_layer.gif>" + hideLabel; 
	}
}  

function FormInputError(str, label)
{
	if (Trim(label) == "") 
	{ 
		return 'Data is missing for a required field.  Please enter the data before continuing.'
	}
	else {
		return 'Please enter a value for "' + label + "'"
	}
}

function CheckFormField(field, label){

	var ty, noErr
	
	// this may be a multi-radio, checkbox
	if ( ( field.length > 0 ) && ( !(( field.type == 'select-one' ) || ( field.type == 'select-multiple' )) ) )
	{
		ty = field[0].type;
	}
	else
	{
		ty = field.type;
	}

	noErr = true;

	if (( ty == 'text' ) || ( ty == 'textarea' ) || (ty == 'file') ) {
		noErr = checkStr(field, FormInputError('Please enter a value for ', label ));
	} else if ( ty == 'hidden' ) {
		noErr = checkStr(field, 'Please enter value for ' + label );
	} else if ( ty == 'password' ) {
		noErr = checkStr(field, 'Please enter the password ' );
	} else if (( ty == 'select-one' ) || ( ty == 'select-multiple' )) {
		noErr = checkSel(field, FormInputError('Please select a value for ', label ));
	} else if ( ty == 'checkbox' ) {
		noErr = checkCheckBox(field, FormInputError('Please check a value for ', label ));
	} else if ( ty == 'radio' ) {
		noErr = checkRadio(field, FormInputError('Please check a value for ', label ))
	} else {
		alert( 'require field checking of unknown type: ' + ty + ", name: " & field.name)		
	}

	if (!noErr) {
		if ( field && field.style ) field.style['background'] = '#ffcccc' ;
		focusOnField(field);
	}

	return noErr;
}

// make sure field is not empty
function checkStr(field, msg)
{
	
	if (field == null)
	{
		// field does not even exist
		alert(msg);
		return false;
	}
	
	var s = Trim(field.value);
	
	if (s.length == 0)
	{
		alert(msg);
		focusOnField(field);
		
		return false;
	}
	return true;
}

function focusOnField(field)
{
	try {
		field.focus();
	}
	catch (e) {}
}

// make sure field has been selected
function checkSel(field, msg)
{
	if (Trim(field.value) == "")
	{
		alert(msg);
		focusOnField(field);
		return false;
	}
	return true;
}

function checkSearchInput(form)
{
	var min_len = 3
	if (form.search.value.length < min_len)
	{
		alert("Please enter a string (at least with " + min_len + " alphabets) to search for related products.");
		focusOnField(form.search);
		return false;
	}
	return true;
}

// make sure field input is numeric
function checkNumeric(field, msg)
{
	if (isNaN(field.value))
	{
		alert(msg);
		focusOnField(field);
		return false;
	}
	return true;
}

function checkEmptyStr(field, msg)
{
	return checkStrLen(field, 1, 255, msg)
}

// make sure the input (string) has a certain length
// field - the input object
// fieldname - the name we use to ask the user to fill in, e.g. 'your email address'
// minlen - the min length of the input
// maxlen - the max lenght of the input
function checkStrLen(field, minlen, maxlen, msg)
{
	var len = field.value.length;
	
	if (minlen != null)
	{	if (len < minlen)
		{
			alert(msg);
			focusOnField(field);
			return false;
		}
	}	

	if (maxlen != null)
	{	if (len > maxlen)
		{
			alert(msg);
			focusOnField(field);
			return false;
		}
	}
	return true;
}

// make sure the input (numeric) is within a certain range
// field - the input object
// fieldname - the name we use to ask the user to fill in, e.g. 'your email address'
// minlen - the min value of the input
// maxlen - the max value of the input
function checkNumLen(field, fieldname, min_val, max_val)
{
	if (isNaN(field.value))
	{ 
		alert(fieldname + " must be numeric.");
		focusOnField(field);
		return false;
	}
	else 
	{
		if ((min_val != null) && (! checkStr(field, "Please enter '" + fieldname + "'.")))
		{
			return false;
		}
		if ((min_val != null) && (field.value < min_val))
		{
			alert(fieldname + " must not be less than " + min_val + ".");
			focusOnField(field);
			return false;
		}
		if ((max_val != null) && (field.value > max_val))
		{
			alert(fieldname + " must not be greater than " + max_val + "."); 
			focusOnField(field);
			return false;
		}
	}
	return true;
}

// make sure the optional input (numeric) is within a certain range
// field - the input object
// fieldname - the name we use to ask the user to fill in, e.g. 'your email address'
// minlen - the min value of the input
// maxlen - the max value of the input
function checkOptionalNum(field, fieldname, min_val, max_val)
{
	if(field.value.length == 0)
	{
		// optional value is not entered
		return true;
	}
	
	// the optional value is entered, make sure it is valid
	return checkNumLen(field, fieldname, min_val, max_val);
}

// check for valid email address
// email - the input string
// multiple - if we allow multiple emails, separated by ","
// email_msg - the error message
function checkEmailEx(email, multiple, email_msg)
{
	var emailv, len, ATindex, DOTindex, SPindex, email_array;
	emailv = email.value
	email_array = emailv.split(",");

	if (!multiple && email_array.length > 1)
	{
		alert ("Only 1 email address can be entered.");
		return false;
	}
	
	for (var i=0; i < email_array.length; i++) 
	{
		emailv = email_array[i];
		len = emailv.length;
		SPindex = emailv.indexOf(' ', 0);
		ATindex = emailv.indexOf('@',1);
		DOTindex = emailv.indexOf('.',ATindex);

		// no space
		// minimal is x@y.zzz
		if ((SPindex == -1) && 
			(ATindex > 0) && 
			(DOTindex > (ATindex + 1)) && 
			(len > (DOTindex + 2)) && 
			(emailv.charAt(ATindex - 1) != ".") &&
			(emailv.charAt(len-1) != '.'))
		{
			return true;
			
		}
		alert (email_msg);
		focusOnField(email);
		return false;
	}
	
	return true;
}	

function checkEmail(email, multiple)
{
	return checkEmailEx(email, multiple, "The email address you entered is invalid.  Please enter your email address.");
}

// validate email in a text box input
function ValidateEmail( objTextBox )
{	
	// don't check check if empty string
	if ( objTextBox.value == '' ) return true;
	
	if ( !checkEmail(objTextBox, false) )
	{	
		objTextBox.select();
		focusOnField(objTextBox);
		return false;
	}
	
	return true;
}
	 
function checkCountryCode(tel, msg)
{
	return true;
	var ndx, len, c_code, phone_no
	ndx = tel.value.indexOf('-',0);
	len = tel.value.length;
		
	if (ndx == -1)
	{
		alert (msg);
		focusOnField(tel);
		return false;
	}
	c_code = tel.value.substr(0,ndx);
	phone_no = tel.value.substr(ndx+1, len);
	if ((ndx == len - 1) || isNaN(c_code) || isNaN(phone_no))
	{
		alert("The phone number is invalid.");
		focusOnField(tel);
		return false;
	}
	return true;
}

function checkAddress(f)
{
	if (! (checkStrLen(f.addr1, "your address (line 1)", 1, 64) &&
		checkStrLen(f.addr2, "your address (line 2)", null, 64) &&
		checkStrLen(f.city, "your city", null, 64) &&
		checkStrLen(f.state, "your state / province", null, 64) &&
		checkStrLen(f.zip, "your zip / postal code", null, 64) &&
		checkSel(f.country_id, "Please select a country.") &&
		checkStrLen(f.tel, "home telephone number", 1, 24) &&
		checkCountryCode(f.tel, "Please include country code in your home number.") &&
		checkStrLen(f.day_tel, "day time telephone number", 1, 24) &&
		checkCountryCode(f.day_tel, "Please include country code in your day time number.")))
		return false;
		
	return true;
			
}

function checkDateSel(day, month, year, checkbox)
{
	if ( checkbox.checked == "1" ) 
	{
		return checkSel(day, "Please select day of due date.") &&
			checkSel(month, "Please select month of due date.") &&
			checkSel(year, "Please select year of due date.");
	}
	return true;
}

function checkRadio(field, msg)
{	
	if ( !(field.length) )
	{
		// single radio
		if (field.checked) return true;
	}
	else
	{	
		var len = field.length;
		for (var i = 0; i < len; i++) 
		{
			if (field[i].checked)
				return true;
		}
	}
	alert(msg);
	return false;
}

function checkCheckBox(field, msg)
{	
	if ( !(field.length) )
	{
		// single checkbox
		if (field.checked) return true;
	}
	else
	{	
		var len = field.length;
		for (var i = 0; i < len; i++) 
		{
			if (field[i].checked)
				return true;
		}
	}
	
	alert(msg);
	return false;
}

function checkAccInfo(f)
{
	if	((f.first_name == null || checkStrLen(f.first_name, "your first name", 1, 32)) &&
		(f.last_name == null || checkStrLen(f.last_name, "your last name", 1, 32)) &&
		(f.country_id == null || checkSel(f.country_id, "Please select a country.")) &&
		(f.have_baby.checked == false || checkSel(f.month, "Please select due/birth month")) &&
		(f.have_baby.checked == false || checkSel(f.year, "Please select due/birth year")) &&
		(f.info_from_type == null || checkSel(f.info_from_type, "Please select the way you hear about us.")))
	{

		return true;
	}
	return false;
}

function checkSignIn(f)
{
	return	checkStr(f.email, "Please enter your email address.") &&
			checkEmail(f.email, "The email address you entered is not a valid email address.  Please try again.") &&
			checkStr(f.password, "Please enter your ebabyasia password.");
}

function checkClassified(f)
{
	if (! checkStrLen(f.name, "your name", 1, 32))
		return false;
	
	if (f.email.value.length == 0 && f.contact.value.length == 0)
	{
		alert("Please enter either your email address or your telephone/fax number");
		focusOnField(f.email);
		return false;
	}
	
	if (f.email.value.length > 0 && !checkEmail(f.email, false))
	{
		focusOnField(f.email);
		return false;
	}
		
	return 	checkSel(f.country, "Please select where you're posting from.") &&
			checkStrLen(f.city, "your city", null, 40) &&
			checkStrLen(f.title, "one-line summary for your listing", 1, 80) &&
			checkStr(f.msg, "Please enter some description for your listing.");
}

function CheckSubstringMatch(str_val, substr_val, msg)
{   
	if (str_val.search(substr_val) != -1)
	{
		alert(msg);
		return false;
	}
	return true;
}


function CheckPasswordHint(hint_field, password_field)
{   
	if (! CheckSubstringMatch(hint_field.value, password_field.value, "Your password should not be included in the password hint."))
	{
		focusOnField(hint_field);
		return false;
	}
	return true;
}
 
function Popup(name, url, width, height)
{
	window.open(url,name,"dependent=yes,width=" + width + ", height=" + height + ", resizable=yes,scrollbars=yes");
}

function CheckCombo(val, field_label)
{
	if(val == "")
	{ 
		alert("please enter " + field_label);
		return false;
	}
	return true;
}

function replaceSubstring(inputString, fromString, toString) {
   // Goes through the inputString and replaces every occurrence of fromString with toString
   var temp = inputString;
   if (fromString == "") {
      return inputString;
   }
   
   if (toString.indexOf(fromString) == -1) { // If the string being replaced is not a part of the replacement string (normal situation)
      while (temp.indexOf(fromString) != -1) {
         var toTheLeft = temp.substring(0, temp.indexOf(fromString));
         var toTheRight = temp.substring(temp.indexOf(fromString)+fromString.length, temp.length);
         temp = toTheLeft + toString + toTheRight;
      }
   } else { // String being replaced is part of replacement string (like "+" being replaced with "++") - prevent an infinite loop
      var midStrings = new Array("~", "`", "_", "^", "#");
      var midStringLen = 1;
      var midString = "";
      // Find a string that doesn't exist in the inputString to be used
      // as an "inbetween" string
      while (midString == "") {
         for (var i=0; i < midStrings.length; i++) {
            var tempMidString = "";
            for (var j=0; j < midStringLen; j++) { tempMidString += midStrings[i]; }
            if (fromString.indexOf(tempMidString) == -1) {
               midString = tempMidString;
               i = midStrings.length + 1;
            }
         }
      } // Keep on going until we build an "inbetween" string that doesn't exist
      // Now go through and do two replaces - first, replace the "fromString" with the "inbetween" string
      while (temp.indexOf(fromString) != -1) {
         var toTheLeft = temp.substring(0, temp.indexOf(fromString));
         var toTheRight = temp.substring(temp.indexOf(fromString)+fromString.length, temp.length);
         temp = toTheLeft + midString + toTheRight;
      }
      // Next, replace the "inbetween" string with the "toString"
      while (temp.indexOf(midString) != -1) {
         var toTheLeft = temp.substring(0, temp.indexOf(midString));
         var toTheRight = temp.substring(temp.indexOf(midString)+midString.length, temp.length);
         temp = toTheLeft + toString + toTheRight;
      }
   } // Ends the check to see if the string being replaced is part of the replacement string or not
   return temp; // Send the updated string back to the user
} // Ends the "replaceSubstring" function

function ClearForm(f)
{
	for(var i = 0; i < f.elements.length; i++)
	{
		var e = f.elements[i]
		var ty = e.type

		if ( ty == "hidden" || ty == "submit" || ty == "reset" || ty == "button") 
		{
		}
		else {
			// alert(e.name + ' ' + e.type);

			if (ty == "select-one" || ty == "select-multiple") {
				e.selectedIndex = 0
			}
			else if (ty == "checkbox" || ty == "radio") {
				e.checked = false;
			}
			else {
				e.value = ""
			}
		}
	}
}

// bring focus to the first editable element of a form
// this does not work if the first editable element is not visible
function FocusForm(f)
{
	for(var i = 0; i < f.elements.length; i++)
	{
		var e = f.elements[i]
		var ty = e.type

		if ( ty == "hidden" || ty == "submit" || ty == "reset" || ty == "button") 
		{
		}
		else {
			focusOnField(e);
			return false;
		}
	}
}

// this will create a URL string for the form data
function EncodeForm(f)
{
	var res = '';
	
	for(var i = 0; i < f.elements.length; i++)
	{
		var e = f.elements[i]
		var ty = e.type

		if ( ty == "submit" || ty == "reset" || ty == "button") 
		{
		}
		else 
		{
			res = res + "&" + e.name + "=" + URLEncode(e.value);
		}
	}
	return res;
}

// this is to avoid the problem that some user will double click a button and trigger two events
// so when a button is clicked, we disable all the buttons
function ShowHideCommands(f, bShow)
{
	var cmds

	try {
		bShow ? hideProgressBar() : showProgressBar(true);
	}
	catch (e)
	{
	}	

	
	if ( f ) 
	{
		cmds = document.getElementsByName(f.name)
	}
	else
	{
		cmds = document.getElementsByName('dbfrm_cmds')
	}	

	for (var i=0;i < cmds.length;i++) {
		var buttons = cmds[i].getElementsByTagName("INPUT")
		for(var j in buttons)
		{
			if ((buttons[j].type == "submit") || (buttons[j].type == "button") )			
				buttons[j].disabled = !bShow;
		}
	}
	return;
}

function HideCommands(f)
{
	ShowHideCommands(f, false)
}

function ShowCommands(f)
{
	ShowHideCommands(f, true)
}

/**********************************************************************
	IN:
		NUM - the number to format
		decimalNum - the number of decimal places to format the number to
		bolLeadingZero - true / false - display a leading zero for
										numbers between -1 and 1
		bolParens - true / false - use parenthesis around negative numbers
		bolCommas - put commas as number separators.
 
	RETVAL:
		The formatted number!
 **********************************************************************/
function FormatNum(num,decimalNum)
{
	return FormatNumEx(num,decimalNum,false,false,false)
}

// return NaN if the input is not numeric
function FormatNumEx(num,decimalNum,bolLeadingZero,bolParens,bolCommas)
{ 
    if (isNaN(parseInt(num))) 
    {
		//alert("Input should be numeric")
		return "NaN";
	}	

	var tmpNum = num;
	var iSign = num < 0 ? -1 : 1;		// Get sign of number
	
	// Adjust number so only the specified number of numbers after
	// the decimal point are shown.
	tmpNum *= Math.pow(10,decimalNum);
	tmpNum = Math.round(Math.abs(tmpNum))
	tmpNum /= Math.pow(10,decimalNum);
	tmpNum *= iSign;					// Readjust for sign
	
	// Create a string object to do our formatting on
	var tmpNumStr = new String(tmpNum);
	
	//' padding zero after decimal place
	if ( decimalNum > 0)	{
		var inde = tmpNumStr.indexOf(".")		
		if ( inde < 0 ) {			
			tmpNumStr = tmpNumStr + '.'		
			for (var i = 0; i<decimalNum; i++) {			
				tmpNumStr  = tmpNumStr  + '0'	
			}
		} else if (( inde + decimalNum + 1) != tmpNumStr.length) {				
			var remain = decimalNum - (tmpNumStr.length - inde -1)
			for (var i = 0; i<remain; i++) {			
				tmpNumStr  = tmpNumStr  + '0'	
			}	
		}
	}
	
	// See if we need to strip out the leading zero or not.
	if (!bolLeadingZero && num < 1 && num > -1 && num != 0)	
		if (num > 0)
			tmpNumStr = tmpNumStr.substring(1,tmpNumStr.length);
		else
			tmpNumStr = "-" + tmpNumStr.substring(2,tmpNumStr.length);

	// See if we need to put in the commas
	if (bolCommas && (num >= 1000 || num <= -1000)) {
		var iStart = tmpNumStr.indexOf(".");
		if (iStart < 0)
			iStart = tmpNumStr.length;

		iStart -= 3;
		while (iStart >= 1) {
			tmpNumStr = tmpNumStr.substring(0,iStart) + "," + tmpNumStr.substring(iStart,tmpNumStr.length)
			iStart -= 3;
		}		
	}

	// See if we need to use parenthesis
	if (bolParens && num < 0)
		tmpNumStr = "(" + tmpNumStr.substring(1,tmpNumStr.length) + ")";

	// Return the formatted string
	return tmpNumStr;		
}





// =============================================================================
// Input filter functions
// =============================================================================


// Only allow input 1234567890+-
// e.g. <INPUT TYPE="text" NAME="numeric" onKeyPress="return IntergerOnly(event)">
function IntergerOnly(evt) 
{
  evt = (evt) ? evt : window.event
  var charCode = (evt.which) ? evt.which : evt.keyCode
  if ( !IsIntegerCode(charCode) )
  {
    status = "This field accepts integer only";
    return false;
  }
  status = "";
  return true;
}
// Only allow input 1234567890+-
// e.g. <INPUT TYPE="text" NAME="numeric" onKeyPress="return NumOnly(event)">
function NumOnly(evt) 
{
  evt = (evt) ? evt : window.event
  var charCode = (evt.which) ? evt.which : evt.keyCode 
  if ( !IsNumCode(charCode) )
  {
    status = "This field accepts numbers only";
    return false;
  }
  status = "";
  return true;
}

// Only allow input 1234567890+-
function IsIntegerCode( charCode )
{
	if (charCode > 31 && (charCode < 48 || charCode > 57) && ( charCode != 45 ) && ( charCode != 43 ) )
	{
		return false;
	}
	return true;
}

// Only allow input 1234567890+-.
// e.g. <INPUT TYPE="text" NAME="numeric" onKeyPress="return NumOnly(event)">
function IsNumCode(charCode)
{
	if ( charCode != 46 && !IsIntegerCode( charCode ) )
	{
		return false;
	}
	return true;	
}

// autoformat of 
// numeric: <input type=text onKeyPress="return NumOnly(event)" onchange="AutoFormatNum(this,2)" >
// integer: <input type=text onKeyPress="return IntergerOnly(event)" onchange="AutoFormatNum(this,0)" >
function AutoFormatNum( formObj, decimalNum )
{	
	if ( IfEmptyString(formObj.value) ) return true;
	
	var formated = FormatNumEx( RemoveNumComma(formObj.value), decimalNum, false, false, true)

	if ( isNaN(RemoveNumComma(formated)) )
	{	
		alert("Input should be numeric !!!");
		//formObj.value = "";
		focusOnField(formObj);
		formObj.select();
		return false;
	}
	else
	{
		formObj.value = formated
	}
	return true;
}

// remove the commas in a comma numeric
function RemoveNumComma(numString){	
	var tmpString = new String(numString)		
	var commaIndex = tmpString.indexOf(",")				
	while (commaIndex > 0){
		tmpString = tmpString.substring(0, commaIndex) + tmpString.substring(commaIndex+1, tmpString.length)		
		commaIndex = tmpString.indexOf(",")
	}
	
	return tmpString
}

function IfEmptyString(s)
{
	if (( s == null ) || ( Trim(s).length == 0 ) ) return true;
	else return false;
}

function URLEncode(plaintext)
{
	// The Javascript escape and unescape functions do not correspond
	// with what browsers actually do...
	var SAFECHARS = "0123456789" +					// Numeric
					"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +	// Alphabetic
					"abcdefghijklmnopqrstuvwxyz" +
					"-_.!~*'()";					// RFC2396 Mark characters
	var HEX = "0123456789ABCDEF";

	var encoded = "";
	for (var i = 0; i < plaintext.length; i++ ) {
		var ch = plaintext.charAt(i);
	    if (ch == " ") {
		    encoded += "+";				// x-www-urlencoded, rather than %20
		} else if (SAFECHARS.indexOf(ch) != -1) {
		    encoded += ch;
		} else {
		    var charCode = ch.charCodeAt(0);
			if (charCode > 255) {
			    alert( "Unicode Character '" 
                        + ch 
                        + "' cannot be encoded using standard URL encoding.\n" +
				          "(URL encoding only supports 8-bit characters.)\n" +
						  "A space (+) will be substituted." );
				encoded += "+";
			} else {
				encoded += "%";
				encoded += HEX.charAt((charCode >> 4) & 0xF);
				encoded += HEX.charAt(charCode & 0xF);
			}
		}
	} // for

	return encoded;
};

function URLDecode(encoded)
{
   // Replace + with ' '
   // Replace %xx with equivalent character
   // Put [ERROR] in output if %xx is invalid.
   var HEXCHARS = "0123456789ABCDEFabcdef"; 
   var plaintext = "";
   var i = 0;
   while (i < encoded.length) {
       var ch = encoded.charAt(i);
	   if (ch == "+") {
	       plaintext += " ";
		   i++;
	   } else if (ch == "%") {
			if (i < (encoded.length-2) 
					&& HEXCHARS.indexOf(encoded.charAt(i+1)) != -1 
					&& HEXCHARS.indexOf(encoded.charAt(i+2)) != -1 ) {
				plaintext += unescape( encoded.substr(i,3) );
				i += 3;
			} else {
				alert( 'Bad escape combination near ...' + encoded.substr(i) );
				plaintext += "%[ERROR]";
				i++;
			}
		} else {
		   plaintext += ch;
		   i++;
		}
	} // while
   return plaintext;
}

// insert at the current cursor position
function insertAtCursor(field, str) {
	return insertAtCursorEx(null, field, str); 
}

// not that selectionCreateRange would work in most normal cases
// however, for a text area, once it loses the focus, the range may be off
// for those cases, use the storeCaret and insertAtCaret below instead.
function insertAtCursorEx(doc, field, str) {

  //IE support
  if (!doc) { 
	doc = document;
  }
  if (doc.selection) {
    field.focus();
    sel = doc.selection.createRange();
    sel.text = str;
  }
  //MOZILLA/NETSCAPE support
  else if (field.selectionStart || field.selectionStart == '0') {
    var startPos = field.selectionStart;
    var endPos = field.selectionEnd;
    field.value = field.value.substring(0, startPos)
                  + str
                  + field.value.substring(endPos, field.value.length);
  } else {
    field.value += str;
  }
}

// -------------------------------------------------------------------------
// if you use the following pair of functions, you need to setup the control 
//  to store the caret position before lossing focus
// -------------------------------------------------------------------------

// save the caret position
function storeCaret (e) {

	if (e.createTextRange) { 
		e.caretPos = document.selection.createRange().duplicate();
	}
}

function insertAtCaret (e, str) 
{
	e.focus();
	if (e.createTextRange && e.caretPos) {
		var caretPos = e.caretPos;
		caretPos.text = str + ' ';
		caretPos.select();
	}
	else {
		// no previous text range, then append at the end
		e.value += str + ' ';
	}
}

// call this function to setup the storeCaret handling
// a typical func can look like 
//  -- it is a bit silly, but since we can't pass parameters in the "func"
// function xxxCaret()
// {	
//	 var e = document.getElementById('xxx');
//	 storeCaret(e);
// }

function AddCaretHandlers(element_id, func)
{
	var obj = document.getElementById(element_id); 
	
	if (!obj) {
		alert('warning: missing element: ' + element_id);
		return;
	}
	
	obj.onselect = func;
	obj.onchange = func;
	obj.onkeyup = func;
	obj.onclick = func;
}

// this will trigger the update of the html editor to the hidden field
function UpdateEditor(id)
{
var oEditor = FCKeditorAPI.GetInstance(id) ;
oEditor.UpdateLinkedField();
}
