/**
 * $Source: /home/cvs/cvsroot/cms/integration/web/components/form/form.js,v $
 * $Author: marick $
 * $Revision: 1.30 $
 * $Date: 2009/05/20 00:16:46 $
 **/

var MONTH_LENGTH = 
  new Array(0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

var RESERVED_NAMES = 
  new Array('totalcomments', 'lastcommentdate', 'firstcommentdate');

// CAPTCHA - begin

/**
 * Issues a new image CAPTCHA challenge.
 */
function changeCaptcha(captchaType) {
  var img = document.getElementById("captcha-image");
  if (img) {
    img.style.display = '';

    var now = new Date();
    var millis = Date.parse(now);
    img.src = "/system/servlet/captcha?nocache=" + millis;
  }

  var audioPlayer = document.getElementById('captcha-audio');
  if (audioPlayer) {
    audioPlayer.style.display = 'none';
  }

  if (window.event) {
    window.event.returnValue = false;
  } 
  
  return false;
}

/**
 * Issues a new audio CAPTCHA challenge.
 */
function changeAudioCaptcha() {

  var img = document.getElementById("captcha-image");
  if (img) {
    img.style.display = 'none';
  }

  var audioPlayer = document.getElementById('captcha-audio');
  if (audioPlayer) {
    audioPlayer.style.display = '';

    var now = new Date();
    var millis = Date.parse(now);
    var captchaURL = '/system/servlet/captcha?type=sound&nocache=' + millis;

    // Use a different audio player depending on the browser.
    //   - Apple QuickTime for Opera and Safari.
    //   - Windows Media Player for everything else.
    if (YAHOO.env.ua.opera || YAHOO.env.ua.webkit) {
      audioPlayer.innerHTML = '<OBJECT'
	+ ' CLASSID="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"'
	+ ' WIDTH="160" HEIGHT="50"'
	+ ' CODEBASE="http://www.apple.com/qtactivex/qtplugin.cab">'
	+ '<PARAM name="SRC" value="' + captchaURL + '" /> ' 
	+ '<PARAM name="AUTOPLAY" VALUE="true">'
	+ '<PARAM name="CONTROLLER" VALUE="false">'
	+ '<PARAM name="VOLUME" VALUE="100">'
	+ '<PARAM name="ENABLEJAVASCRIPT" VALUE="true">'
	+ '<PARAM name="TYPE" VALUE="audio/wav">'
	+ '<embed classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"' 
	+ ' name="sound" id="sound"' 
	+ ' src="' + captchaURL + '"' 
	+ ' pluginspage="http://www.apple.com/quicktime/download/"'
	+ ' volume="100" enablejavascript="true" '
	+ ' type="audio/wav" width="160" height="50" autostart="true"'
	+ '> </embed>'
	+ '</OBJECT>';

    } else {

      audioPlayer.innerHTML='<OBJECT'
        + ' CLASSID="CLSID:22D6F312-B0F6-11D0-94AB-0080C74C7E95"'
        + ' WIDTH="160" HEIGHT="50"'
        + ' CODEBASE="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701"'
        + ' STANDBY="Loading Microsoft® Windows® Media Player components..."'
        + ' type="application/x-oleobject" align="middle">'
        + '<PARAM name="FileName" value="' + captchaURL + '" />'
        + '<PARAM name="AutoStart" value="True" />'
        + '<PARAM name="ShowStatusBar" value="True" />'
        + '<PARAM name="ShowPositionControls" value="False">'
        + '<PARAM name="Volume" value="1">'
        + '<PARAM name="Mute" value="False">'
        + '<PARAM name="DefaultFrame" value="mainFrame" />'
        + '<embed id="captcha_embed" type="application/x-mplayer2"'
        + ' pluginspage="http://www.microsoft.com/Windows/MediaPlayer/"'
        + ' width="160" height="50" showstatusbar="true"'
        + ' src="' + captchaURL + '"></embed>'
        + '<br /><a href="' + captchaURL + '" target="_blank" title="Opens a new window">Click here for standalone player</a>'
        + '</object>';
    }
  }

  if (window.event) {
    window.event.returnValue = false;
  } 
  
  return false;
}

function validateCaptcha(formName) {

  var form = document.forms[formName];
  if (! form) { return true; }
  
  var captcha = form.elements["captcha"];
  
  if (! captcha) { return true; }
  
  RPCHandler.setResponseHandler("CAPTCHA_VALID", 
    new Function("handleValidCaptcha('" + formName + "')"));
  RPCHandler.setResponseHandler("CAPTCHA_INVALID", 
    new Function("handleInvalidCaptcha('" + formName + "')"));
    
  RPCHandler.submit("/system/actions/captcha-verify.jsp?answer=" + 
    captcha.value);
    
  if (window.event) {
    window.event.returnValue = false;
  }
  
  return false;
}

function handleValidCaptcha(formName) {

  var form = document.forms[formName];
  if (! form) { return; }

  form.submit();
}

function getCaptchaType() {
  var img = document.getElementById("captcha-image");
  var audioPlayer = document.getElementById('captcha-audio');

  var type = null;
  if (img && img.style.display != 'none') {
    type = 'image';
  } else if (audioPlayer && audioPlayer.style.display != 'none') {
    type = 'audio';
  } else {
    throw('Invalid captcha type.');
  }

  return type;
}

function handleInvalidCaptcha(formName) {

  var form = document.forms[formName];
  if (! form) { return; }

  var captcha = form.elements["captcha"];
  if (! captcha) { return; }


  var captchaType = getCaptchaType();

  if (captchaType == 'audio') {
    alert("Your answer to the challenge does not match the audio sample. " +
          "Please try again.");
    changeAudioCaptcha();
  }

  if (captchaType == 'image') {
    alert("Your answer to the challenge does not match the image. " +
          "Please try again.");
    changeCaptcha();
  }

  captcha.value = '';
  
  try {
    captcha.focus();
  } catch (e) {}

  // Make sure submit buttons are enabled if an invalid CAPTCHA answer
  // prevented a form submit.
  toggleSubmitButtons(false);
}

// CAPTCHA - end


function isLeapYear(year){
  return (year % 4 == 0 && ((year % 100 != 0) || (year % 400 == 0)));
}

function isButtonGroup(element) {

  return (! element.tagName && element.length);
}

function isSelect(element) {
  return (element.type == "select-one");
}

function check4KLengths(formName) {

  var form = document.forms[formName];
  
  if (! form) { return; }

  var elements = form.elements;

  for (var i = 0; i < elements.length; i++) {
    var element = elements[i];

    if (element.name == "body" || element.id == "body") { continue; }

    if (element.tagName == 'INPUT' && element.type == "hidden") {
      continue;
    }

    if (! element.value) {
      continue;
    }

    if (element.value.length > 4000) {
      alert("The text of field '" + element.name + 
	    "' is longer than the limit of 4000 characters " +
	    "(current width " + element.value.length + ")");
      element.focus();
      if (window.event) {
		window.event.returnValue = false;
      }
      return false;
    }
  }

  return true;
}


/**
 * Validates a form for duplicate fields. Form fields includes
 * WYSIWYG editor fields.
 *
 * @param form The form
 * @param element The form field
 * @param name The name of the field
 * @return false if a dupe field is found, otherwise true
 */
function checkDupeFieldName(element, name, form) {
  if (! form) {
    form = element.form;
  }

  if (form) {

    // Search for a form field with the same name.
    // Note: form.elements[name] did not work for radio buttons,
    //       so instead, we iterate over each form element.
    var testElement;
    var fields = form.elements;
    for (var i=0; i<fields.length; i++) {
      if (fields[i].name && fields[i].name == name) {
        testElement = fields[i];
        break;
      }
    }

    if (! testElement) {
      // Check for WYSIWYG editor.
      testElement = form.document.getElementById(name);
    }

    if (testElement && testElement.name && testElement != element) {
      if ((element.type == "radio" || element.type == "checkbox") && element.type == testElement.type) {
        // Exceptions:
        // Radio buttons can share names with radio buttons.
        // Checkboxes can share names with checkboxes.
      } else {
        alert("The name '" + name + "' has already been applied to another " +
              "form element.  Please choose another name.");
        return false;
      }
    }
    
    if (isNameReserved(name)) {
      alert("The name '" + name + "' is reserved and can't be used as the name of a " + 
            "form element.  Please choose another name.");
      return false;
    }
  }

  return true;
}

function isNameReserved(name) {
  for (var i=0; i<RESERVED_NAMES.length; i++) {
    if (name.toLowerCase() == RESERVED_NAMES[i].toLowerCase()) {
      return true;
    }
  }
  return false;
}
  


function checkValue(formName, elementName, message) {

  var element = document.forms[formName].elements[elementName];

  if (! element) {
    alert("Could not find element " + elementName + " in form " + formName);
    return;
  }

  var isGroup = isButtonGroup(element);
  if (isGroup) {
    var value = getCheckedValue(elementName);
  } else {
    if (isSelect(element)) {
      var value = getSelectedValue(formName, elementName);
    } else {
      var value = element.value;
    }
  }
  if (! value || value == "") {
    if (message != "") {
      alert(message);
    }
    if (! isGroup && (! element.type || (element.type != "hidden"))) {
      element.focus();
    }
    if (window.event) { window.event.returnValue = false; }
    return false;
  }
  return true;
}

function checkIntRange(formName, elementName, min, max, message) {

  intPattern = /^\d+$/;

  var element = document.forms[formName].elements[elementName];
  if (! element) {
    alert("Could not find element " + elementName + " in form " + formName);
    return;
  }

  var value = element.value;

  if (! intPattern.exec(value)) {
    if (message != "") {
      alert(message);
    }
    element.focus();
    if (window.event) { window.event.returnValue = false; }
    return false;
  }

  if (value < min || value > max) {
    if (message != "") {
      alert(message);
    }
    element.focus();
    if (window.event) { window.event.returnValue = false; }
    return false;
  }

  return true;
}

function checkEmailValue(s) {

   var emailPattern = /^.+@.+\..{2,}$/;
   if (! emailPattern.test(s)) { 
     return false;
   }

   var illegalChars= /[\(\)\<\>\,\;\:\\\/\"\ \[\]]/
   if (s.match(illegalChars)) {
      return false;
   }

   return true;
} 

function checkEmail(formName, elementName, message) {

  return checkFunction(formName, elementName, message, checkEmailValue);
}

function checkFileName(formName, elementName, fileType) {

   if (! checkPattern(formName, elementName,
      "The " + fileType + " must begin with a letter or digit", 
		      /^[a-z0-9A-Z]/)) {
     return false;
   }

   return checkPattern(formName, elementName,
      "The " + fileType + 
      " can only contain letters, digits, dashes and underscores", 
		       /^[a-z0-9A-Z\-_]+$/);
}

function checkImageFileName(formName, elementName, fileType) {

  if (!checkFileName(formName, elementName, fileType)) {
    return;
  }

  if (! checkPattern(formName, elementName,
		     "The " + fileType + 
		     " filename must end with '.jpg', '.jpeg', '.gif' or '.png'", 
		     /^(.*)(.(gif|jpg|jpeg|png))$/, true)) {
    return;
  }

  return true;
}

function checkDate(formName, elementName, message) {

  var datePattern = /^(0?\d|\d\d)\/(0?\d|\d\d)\/(\d\d\d\d)$/;

  return checkPattern(formName, elementName, message, datePattern);
}

function checkInt(formName, elementName, message) {

  var intPattern = /^\d+$/;

  return checkPattern(formName, elementName, message, intPattern);
}

function checkNum(formName, elementName, message) {

  var numPattern = /^(\d+(\.\d*)?|\.\d+)$/;

  return checkPattern(formName, elementName, message, numPattern);
}

function checkRelativeURL(formName, elementName, message) {
  var pathPattern = /\/([a-zA-Z0-9_?&=%,\-\.\/]*$)/;

  return checkPattern(formName, elementName, message, pathPattern);
}

function checkURL(formName, elementName, message) {

  var urlPattern = /^(ftp|https?):\/\/(?:[a-zA-Z0-9](?:[-a-z-A-Z0-9]*[a-zA-Z0-9])?)+\b(?:\d+)?(?:\/[^;"'<>()\[\]{}\s\x7f-\xff]*(?:[.,?]+[^;"'<>()\[\]{}\s\x7f-\xff]+)*)?/;

  return checkPattern(formName, elementName, message, urlPattern);
}

function checkTime(formName, elementName, message) {

  var timePattern = /\d{1,2}:\d\d\ ([aA][mM]|[pP][mM])/;

  return checkPattern(formName, elementName, message, timePattern);
}

function checkPattern(formName, elementName, message, pattern, ignoreCase) {

  var element = getElement(formName, elementName);
  if (element == null) { 
    alert("Element " + elementName + " not found.");
    if (window.event) { window.event.returnValue = false; }
    return false;  
  }

  var value = element.value;
  if (ignoreCase) {
    value = value.toLowerCase();
  }

  if (! pattern.exec(value)) {
    alert(message);
    element.focus();
    if (window.event) { window.event.returnValue = false; }
    return false;
  }

  return true;
}

function checkFunction(formName, elementName, message, f) {

  var element = getElement(formName, elementName);
  if (element == null) { 
    alert("Element " + elementName + " not found.");
    if (window.event) { window.event.returnValue = false; }
    return false;  
  }

  if (element.tagName == "INPUT" && element.type == "hidden") {
    return true;
  }

  var value = element.value;

  if (! f(value)) {
    alert(message);
    element.focus();
    if (window.event) { window.event.returnValue = false; }
    return false;
  }

  return true;
}

// Function that checks that a pair of form elements is either both
// set or both unset.

function checkValuePair(formName, elementOne, elementTwo, message) {

  var element1 = document.forms[formName].elements[elementOne];
  var element2 = document.forms[formName].elements[elementTwo];

  if (! element1) {
    alert("Could not find element " + elementOne + " in form " + formName);
    return;
  }
  if (! element2) {
    alert("Could not find element " + elementTwo + " in form " + formName);
    return;
  }

  if (isButtonGroup(element1)) {
    var value1 = getCheckedValue(elementOne);
  } else {
    if (isSelect(element1)) {
      var value1 = getSelectedValue(formName, elementOne);
    } else {
      var value1 = element1.value;
    }
  }
  if (isButtonGroup(element2)) {
    var value2 = getCheckedValue(elementTwo);
  } else {
    if (isSelect(element2)) {
      var value2 = getSelectedValue(formName, elementTwo);
    } else {
      var value2 = element2.value;
    }
  }
  if ((value1 == "" && value2 != "") || (value1 != "" && value2 == "")) {
    alert(message);
    if (value1 == "") {
      element1.focus();
    } else {
      element2.focus();
    }
    if (window.event) { window.event.returnValue = false; }
    return false;
  }
  return true;
}

function getCheckedValue(elementName, elements) {
  
  if (! elements) {
    elements = document.getElementsByName(elementName);
  }

  for (i = 0; i < elements.length; i++) {
    var element = elements.item(i);
    if (element.checked) {
      return element.value;
    }
  }
  return "";
}

function getCheckedValues(elementName) {

  var elements = document.getElementsByName(elementName);
  var values = new Array();
  var valueCount = 0;
  for (i = 0; i < elements.length; i++) {
    if (elements.item(i).checked) {
      values[valueCount++] = elements.item(i).value;
    }
  }
  return values;
}

function getSelectedValue(formName, elementName) {
  
  var element = document.forms[formName].elements[elementName];
  if (element.selectedIndex != -1) {
    return element.item(element.selectedIndex).value;
  }
  return "";
}

// form data takes the form [ [elementName, whichTest, errorMessage], ... ]
// valid tests are "notnull" and "date"

function checkValues(formName, formData) {

  for (i = 0; i < formData.length; i++) {

    var elementData = formData[i];
    var elementName = elementData[0];
    var whichTest = elementData[1];
    var errorMessage = elementData[2];

    if (whichTest == "notnull") {

      if (! checkValue(formName, elementName, errorMessage)) 
        return false; 
    }
  }

  return true;
}

function getElement(formName, elementName, ignoreCase) {

  var form = document.forms[formName];
  if (! form) { 
    alert("No such form " + formName);
    return null;
  }

  var element = null;
  if (! ignoreCase) {
    element = form.elements[elementName];
  } else {
    elementName = elementName.toLowerCase();
    for (var i = 0; i < form.elements.length; i++) {
      if (form.elements[i].name == elementName) {
	element = form.elements[i];
	break;
      }
    }
  }

  if (! element) { 
    alert("No such element " + elementName);
    return null;
  }

  return element;
}

function getValue(formName, elementName) {

  var element = getElement(formName, elementName);
  if (element == null) { return; }

  if (element.tagName == "SELECT") {
    return getSelectedValue(formName, elementName);
  }

  if (element.length) {
    return getCheckedValue(elementName, element);
  }

  return element.value;
}

function setValue(formName, elementName, value) {

  var element = getElement(formName, elementName);
  if (element == null) { return; }

  if (element.length && element.tagName != "SELECT") {
    setCheckedValue(element, value);
    return;
  }

  if (element.tagName == "SELECT") {
    setSelectedValue(element, value);
  }

  element.value = value;
}

function setCheckedValue(elements, value) {
  
  for (var i = 0; i < elements.length; i++) {
    var element = elements[i];
    element.checked = (element.value == value);
  }
}

function setSelectedValue(element, value) {
  
  var options = element.options;
  for (var i = 0; i < options.length; i++) {
    var option = options[i];
    option.selected = (option.value == value);
  }
}

function setCheckedValues(formName, elementName, values) {

  var element = getElement(formName, elementName);
  if (element == null) { return; }

  var elements = element;
  if (! element.length) {
    elements = new Array();
    elements[0] = element;
  }

  for (var i = 0; i < values.length; i++) {
    var value = values[i];
    for (var j = 0; j < elements.length; j++) {
      var element = elements[j];
      if (element.value == value) element.checked = true;
    }
  }
}

function focusElement(formName, elementName, selectAll) {

  if (! elementName) { return; }

  var element = getElement(formName, elementName);
  if (element == null) { return; }

  element.focus();
  if (selectAll)
    element.select();
}

function Validator(type, required) {

  this.type = type;
  this.required = required;

  this.validate = validateValue;
  this.checkType = checkType;
  this.checkLength = checkLength;
  this.checkChars = checkChars;
  this.checkRange = checkRange;
  this.toString = toString;
}

function validateValue(value) {

  if (value == "") {
    if (this.required) {
      this.message = "A value is required for the field '" + this.label + "'";
      return false;
    } else {
      return true;
    }
  }

  switch (this.type) {
    case "text":
      if (! this.checkLength(value)) { return false; }
      if (! this.checkChars(value)) { return false; }
      break;
    case "integer":
      if (! this.checkType(value)) { return false; }
      var intValue = parseInt(value);
      if (! this.checkRange(intValue)) { return false; }
      break;
    case "number":
      if (! this.checkType(value)) { return false; }
      var numValue = parseFloat(value);
      if (! this.checkRange(numValue)) { return false; }
      break;
    case "date":
      if (! this.checkType(value)) { return false; }
      break;
    case "email":
      if (! this.checkType(value)) { return false; }
      break;
    case "filename":
      if (! this.checkType(value)) { return false; }
      break;
  }

  return true;
}

function checkType(value) {

  switch (this.type) {

    case "integer":

      var pattern = /^\d+$/;
      if (! pattern.exec(value)) {
        this.message = "'" + value + "' is not a valid integer.";
        return false;
      }
      break;

    case "number":

      var numPattern = /^(\d+(\.\d*)?|\.\d+)$/;

      if (! numPattern.exec(value)) {
        this.message = "'" + value + "' is not a valid number.";
        return false;
      }

      if (this.decimalPlaces) {

	if (this.decimalPlaces > 0) {
	  numPattern = new RegExp("^(\\d+(\\.\\d{0," + this.decimalPlaces +
            "})?|\\.\\d{1," + this.decimalPlaces + "})$");
	} else {
	  numPattern = /^\d+$/;
	}

        if (! numPattern.exec(value)) {
          this.message = "'" + value + "' has more than " +
          this.decimalPlaces + " digits after the decimal point.";
          return false;
        }
      }
      break;

    case "date":

      var datePattern = /^(0?\d|\d\d)\/(0?\d|\d\d)\/(\d\d\d\d)$/;
      var ary = datePattern.exec(value);
      if (ary == null) {
        this.message = "'" + value + "' is not a valid date (MM/dd/YYYY).";
        return false;
      }

      var month = parseInt(ary[1].replace(/^0/, ""));
      var date = parseInt(ary[2].replace(/^0/, ""));
      var year = parseInt(ary[3]);

      if (month < 1 || month > 12) {
        this.message = "Please enter a month between 1 and 12.";
        return false;
      } 

      var monthLength = MONTH_LENGTH[month];
      if (month == 2 && isLeapYear(year)) { monthLength++; }

      if (date < 1 || date > monthLength) {
        this.message = "Please enter a date between 1 and " + monthLength;
        return false;
      } 

      if (year < 1000 || year > 2100) {
        this.message = "Please enter a year between 1000 and 2100.";
        return false;
      }

      break;

    case "email":

      if (! checkEmailValue(value)) {
        this.message = "'" + value + "' is not a valid e-mail address.";
        return false;
      }
      break;

    case "filename":

      var filePattern = /^[a-zA-Z0-9_\-]+$/;
      if (! filePattern.exec(value)) {
        this.message = "'" + value + "' is not a valid file name.  Only letters, digits, underscores and dashes are allowed.";
        return false;
      }
      break;
  }

  return true;
}

function checkRange(value) {

  var nVal = parseFloat(value);

  if (this.minValue) {

    var nMin = parseFloat(this.minValue);

    if (! this.minBound) this.minBound = "ge";

    if (this.minBound == "gt" && nVal <= nMin) {
      this.message = "Value must be greater than " + this.minValue + ".";
      return false;
    }

    if (this.minBound == "ge" && nVal < nMin) {
      this.message = "Value must be greater than or equal to " +
                     this.minValue + ".";
      return false;
    }
  }

  if (this.maxValue) {

    var nMax = parseFloat(this.maxValue);

    if (! this.maxBound) this.maxBound = "le";

    if (this.maxBound == "lt" && nVal >= nMax) {
      this.message = "Value must be less than " + this.maxValue + ".";
      return false;
    }

    if (this.maxBound == "le" && nVal > nMax) {
      this.message = "Value must be less than or equal to " +
                     this.maxValue + ".";
      return false;
    }
  }

  return true;
}

function checkLength(value) {

  var length = value.length;

  if (this.minLength && length < this.minLength) {
    this.message =
      "Value of " + this.label + " cannot be less than " + this.minLength + " characters long " +
      "(current length is " + length + " characters)";
    return false;
  } 

  if (this.maxLength && length > this.maxLength) {
    this.message =
      "Value of " + this.label + " cannot be more than " + this.maxLength + " characters long." +
      "(current length is " + length + " characters)";
    return false;
  } 

  return true;
}

function checkChars(value) {

  if (! this.allowChars) { return true; }

  var chars = this.allowChars.split(",");

  var isDigit = false;
  var isLetter = false;
  var isSpace = false;

  for (var i = 0; i < chars.length; i++) {
    var c = chars[i];
    if (c == 'digit') {
      isDigit = true;
    } else if (c == 'white') {
      isSpace = true;
    } else if (c == 'letter') {
      isLetter = true;
    }
  }

  var digPat = /\d/;
  if (! isDigit && value.search(digPat) != -1) {
    this.message = "Value cannot contain digits.";
    return false;
  }

  var letPat = /[a-zA-Z]/;
  if (! isLetter && value.search(letPat) != -1) {
    this.message = "Value cannot contain letters.";
    return false;
  }

  var spacePat = /\s/;
  if (! isSpace && value.search(spacePat) != -1) {
    this.message = "Value cannot contain spaces.";
    return false;
  }

  return true;
}

function toString() {

  var s = "";
  var i = 0;

  for (var name in this) {
    var value = this[name];
    if (! value || value instanceof Function) { continue; }
    if (i++ > 0) { s += ";"; }
    s += name + ":" + value;
  }

  return s;  
}

function validateForm(formName) {

  var form = document.forms[formName];
  if (! form) { 
    alert("No form named '" + formName + "' to validate.");
    return; 
  }

  // disables submit button
  toggleSubmitButtons(true);

  var elements = form.elements;

  // Re-enables submit button when we leave page (so it's available on 'Back' tt# 106790)
  // Only re-enable the submit button if there is no file upload field, otherwise
  // multiple copies of files are uploaded.
  var hasFileUpload = false;
  for (var i = 0; i < elements.length; i++) {
    var element = elements[i];
    if (element.type && element.type == "file") {
      hasFileUpload = true;
      break;
    }
  }

  if (! hasFileUpload) {
    document.onunload = toggleSubmitButtons(false);
  }



  for (var i = 0; i < elements.length; i++) {
    var element = elements[i];
    if (element.tagName == "INPUT" &&
        (element.type == "hidden" || element.type == "submit")) {
      continue;
    }

    var validation = element.getAttribute("validation");
    if (! validation) { continue; }

    var validator = createValidator(validation);
    validator.label = element.title ? element.title : element.name;

    var isButton = (element.tagName == "INPUT" && 
		    element.type == "checkbox" || element.type == "radio");
    var selectionMissed = false;

    if (isButton && validator.required) {
      selectionMissed = ! element.checked;
      var a = elements[element.name];
      if (a.length) {
	for (var j = 0; j < a.length; j++) {
	  if (a[j].checked) {
	    selectionMissed = false;
	    break;
	  }
	}
      } 
    }

    var value = element.value;
    if (element.style.display == "none" ||
        element.style.visibility == "hidden") { 

      var hiddenElements = form.getElementsByTagName("INPUT");
      for (var j = 0; j < hiddenElements.length; j++) {
        var he = hiddenElements[j];
        if (he.type != "hidden" || he.name != element.name) { continue; }
        if (he.value) {
          value = he.value;
          break;
        }
      }
    }

    if (selectionMissed || ! validator.validate(value)) {

      var msg = selectionMissed ? 
	"Please make at least one selection for " + element.name : 
	validator.message;

      alert(msg);

      if (element.style.display != "none" &&
	element.style.visibility != "hidden") { 
        element.focus();
      } 

      toggleSubmitButtons(false);

      if (window.event) {
	    window.event.returnValue = false;
      }
      return false;
    }
  }
  
  return validateCaptcha(formName);
}

function highlightForm(formName) {

  var form = document.forms[formName];

  if (! form) { return; }

  var elements = form.elements;

  for (var i = 0; i < elements.length; i++) {

    var element = elements[i];

    if (element.tagName == "TEXTAREA") {
      element.innerText = trimString(element.innerText);
    }

    if (element.tagName == "SELECT" && element.size > 1 &&
	(! element.validation || 
	 element.validation.indexOf("required:true") == -1)) {
      var option = document.createElement("OPTION");
      option.innerText = "None";
      option.value = "";
      element.insertBefore(option, element.firstChild);
    }

    if (! element.validation) { continue; }

    var validator = createValidator(element.validation);

    var isButton = (element.tagName == "INPUT" && 
		    element.type == "checkbox" || element.type == "radio");

    if (validator.required && ! isButton) {
      element.className = "formWidgetRequired";
    }

    if (validator.standard && window.user && validator.defaultRule == "user") {
      
      if (window.user[validator.standard]) {
        element.value = window.user[validator.standard];
      }
    }
  }
}

function createValidator(parameterString) {

  if (! parameterString) { parameterString = ""; }

  var validator = new Validator("text", false);

  var params = parameterString.split(";");
  for (var i = 0; i < params.length; i++) {
    var param = params[i].split(":");
    validator[param[0]] = param[1];
  }

  return validator;
}

function objectToString(object) {

  var s = "";
  var i = 0;

  for (var name in object) {
    var value = object[name];
    if (! value || value instanceof Function) { continue; }
    if (i++ > 0) { s += ";"; }
    if (typeof value == "object") {
      s += name + ": { " + objectToString(value) + " }";
    } else {
      s += name + ":" + value;
    }
  }

  return s;
}

function stringToObject(str, obj) {

  if (! obj) {
    obj = new Object();
  }

  var params = str.split(";");
  for (var i = 0; i < params.length; i++) {
    var param = params[i].split(":");
    obj[param[0]] = param[1];
  }

  return obj;
}

function trimString(s) {

  if (s == null) return "";

  s = s.replace(/^\s*(.*)/, "$1");
  s = s.replace(/(.*?)\s*$/, "$1");

  return s;
}

/**
 * Updates the element label in the common situation where
 * a 2-column table is used to layout the form.
 **/
function updateLabel(element, label) {

   var cell = element.parentNode;
   if (cell.tagName == "TD" && cell.previousSibling) {
     cell = cell.previousSibling;
     if (cell.innerHTML && cell.innerHTML == "&nbsp;" ||
         cell.innerHTML == element.title) {
       cell.innerHTML = label;
     }
   }
}

function setFieldName(label, formName) {

  if (! label) { return; }

  var name = getValue(formName, "name");
  if (name != "" && ! name.match(/^field/)) { return; }

  name = labelToName(label);

  setValue(formName, "name", name);
}

function labelToName(label) {

  var name = label.toLowerCase();
  name = name.replace(/\s/g, "_");
  name = name.replace(/\W/g, "");

  return name;
}

function labelToFileName(label, separator) {

  if (! separator) {
    separator = "-";
  }

  var name = label.toLowerCase();
  name = name.replace(/\s/g, separator);
  name = name.replace(/[^a-zA-Z0-9-_]/g, "");

  return name;
}

// truncates the string "s" to a maximum of "maxLength" characters
// if "cleanBreak" is not false, the break occurs between words (at a ' ' at least)
// "trailer" is appended to the truncated string
function truncate(s, maxLength, cleanBreak, trailer) {
  if (s == null) return "";
  if (cleanBreak) {
    return (s.length < maxLength) ? s : 
      s.substring(0, s.substring(0,maxLength).lastIndexOf(' ')) + trailer;
  } else {
    return (s.length < maxLength) ? s : 
      s.substring(0, maxLength - 3) + trailer;
  }
}

function tabToElement(formName, tabIndex) {

  var elements = document.forms[formName].elements;

  for (var i = 0; i < elements.length; i++) {
    var element = elements[i];
    if (element.tabIndex == tabIndex) {
      element.focus();
      break;
    }
  }
}

function showContextHelp(contextPath, path, anchor) {

  path = contextPath + "/admin/help/context/" + path + ".html";
  if (anchor) { path += "#" + anchor; }

  helpWin = window.showHelp(path);
}

function getValues(formName) {

  var values = new Array();

  var form = document.forms[formName];
  if (! form) { 
    alert("No form named " + formName); 
    return;
  }

  var elements = form.elements;

  for (var i = 0; i < elements.length; i++) {
    var element = elements[i];
    var value = element.value;
    if (element.type && element.type =="hidden" && 
	element.htmlEditor) {
      value = element.htmlEditor.value;
    }
    if (element.tagName == "INPUT" && 
	(element.type == "checkbox" || element.type == "radio") &&
	! element.checked) { continue; }
    if (element.tagName == "SELECT" && element.multiple) {
      var selectValues = new Array();
      for (var j = 0; j < element.options.length; j++) {
        var option = element.options[j];
        if (option.selected) { selectValues.push(option.value); }
      }
      value = selectValues.join(' ');
    }
    values.push(value);
  }

  return values;
}

var gRecordFormName = "record";
var gRecordParam = "com.frontleaf.record.RecordID";

function doFormLoad() {

  highlightForm(gRecordFormName);

  var form = document.forms[gRecordFormName];
  if (form == null) { return; }

  var cookie = getCookie("submittedRecords");

  var recordID = getValue(gRecordFormName, gRecordParam);

  if (cookie) {
    var re = new RegExp("\\b" + recordID + "\\b");
    if (cookie.match(re)) {
      window.location.reload(true);
    }
  }
}

function toggleSubmitButtons(isDisabled) {
  var elements = document.getElementsByTagName("INPUT");
  for (var i = 0; i < elements.length; i++) {
    var element = elements[i];
    if (element.type && 
	(element.type == "submit" || element.type == "button")) {
      element.disabled = isDisabled;
    }
  }
}

function doImageChoose(formName, widgetName, folderID) {

  var item = 
    showDialog("/admin/components/explorer/dialog.jsp?folderID=" + folderID, 
	       null, 600, 400);

  if (item == null) {
    return;
  }

  var div = document.getElementById("thumbnail-" + widgetName);
  if (div == null) { return; }

  div.style.border = "0 none";
  div.innerHTML = "<img ondblclick=\"doImageChoosePreview()\" src=\"" + 
    item.thumbnailURL + "\" id=\"thumbnail-" + item.id + 
    "\" align=absmiddle><p>" + item.fileName + "</p>";

  setValue(formName, widgetName, item.id);
}

function doImageChooseClear(formName, widgetName, folderID) {

  var div = document.getElementById("thumbnail-" + widgetName);
  if (div == null) { return; }

  div.style.border = "white inset 2";
  div.style.height = div.clientHeight;
  div.style.width = div.clientWidth;
  div.innerHTML = "No<br>image<br>selected";

  setValue(formName, widgetName, "");
}

function doImageChoosePreview() {
  
  var image = event.srcElement;
  if (image == null || image.tagName != "IMG" || ! image.id) { return; }

  var idData = image.id.split("-");
  var itemID = idData[1];
  
  showDialog("/admin/components/explorer/image-preview.jsp?itemID=" + itemID);
}

function doRelatedItemsChoose(formName, widgetName, folderID) {

  var path = "/admin/components/related/dialog.jsp?folderID=" + folderID;

  var itemIDs = new Array();
  var select = getElement(formName, widgetName);
  for (var i = 0; i < select.options.length; i++) {
    itemIDs.push(select.options[i].value);
  }

  if (itemIDs.length > 0) {
    path += "&itemIDs=" + itemIDs.join(",");
  }

  var items = showDialog(path, null, 600, 400);

  if (items == null) {
    return;
  }

  var select = getElement(formName, widgetName);
  select.innerHTML = "";

  var div = document.getElementById("relatedItems-" + widgetName);
  if (div == null) { return; }

  if (items.length == 0) {
    div.innerHTML = "<div><em>No items selected</em></div>";
    return;
  }

  div.innerHTML = "";  

  for (var i = 0; i < items.length; i++) {
    
    var item = items[i];
    var itemDiv = document.createElement("DIV");
    itemDiv.innerHTML = "<img align=absmiddle src='" + item.iconURL +
      "'><span>&nbsp;" + item.title + "</span>";
    itemDiv.id = item.id;

    div.appendChild(itemDiv);

    var option = 
      document.createElement("<OPTION selected value=" + item.id + ">");
    select.options.add(option);
  }
}

function populateForm(formName) {

  var form = document.forms[formName];
  if (! form) { 
    alert("No form named '" + formName + "' to populate.");
    return; 
  }

  var elements = form.elements;

  for (var i = 0; i < elements.length; i++) {
    var element = elements[i];
    if (element.tagName == "INPUT" &&
        (element.type == "hidden" || element.type == "submit")) {
      continue;
    }

    if (element.tagName == "INPUT" && 
        (element.type == "radio" || element.type == "checkbox")) {

      var valueElement = document.getElementById(element.name + "Value");
      if (valueElement) {
        element.checked = false;

        if (valueElement.innerHTML == element.value) {
          element.checked = true;
        } else {

          for (var j = 0; j < valueElement.childNodes.length; j++) {
            var value = valueElement.childNodes[j];
            if (value.innerHTML == element.value) {
              element.checked = true;
              break;
            }
          }
        }
      }

      valueElement = document.getElementById(element.id + "Value");
      if (valueElement) {
        element.checked = true;
      }

    } else {
      var valueElement = document.getElementById(element.name + "Value");
      if (! valueElement) { continue; }
      if (element.tagName == "SELECT") {

        if (element.style.visibility == "hidden") { continue; }

	var values = new Array();
	
	if (valueElement.firstChild &&
	    valueElement.firstChild.nodeType == 1) {

	  for (var j = 0; j < valueElement.childNodes.length; j++) {
	    var value = valueElement.childNodes[j].innerHTML;
	    values[value] = true;
	  }

	} else if (valueElement.firstChild && 
	           valueElement.firstChild.nodeType == 3) {
	  
	  values[valueElement.innerHTML] = true;
	  
	} else if (valueElement.innerHTML == '') {
	  values[''] = true;
	}

	for (var j = 0; j < element.options.length; j++) {
	  var option = element.options[j];
	  
	  if (values[option.value] && ! option.selected) {
	    option.selected = true;
	  }
	}

      } else if (element.tagName == "TEXTAREA") {
        element.innerText = valueElement.innerHTML;
      } else {
	element.value = valueElement.innerText;
      }
    }
  }
}

function addOptions(retrieveDoc, elementID, selectorID, defaultValue) {
  
  var data = retrieveDoc.getElementById(elementID);
  if (data == null) {
    alert("addOptions: No data retrieved for menu " + selectorID);
    return;
  }

  var selector = document.getElementById(selectorID);
  if (selector == null) {
    alert("addOptions: No such menu " + selectorID);
    return;
  }

  selector.innerHTML = "";
  var divs = data.getElementsByTagName("DIV");
  var hasData = (divs.length == 0) ? false : true;

  var option = document.createElement("OPTION");
  option.value = "";
  option.innerHTML = (! hasData) ? "None available" : "Choose...";
  selector.appendChild(option);
  selector.disabled = (! hasData);
 
  if (divs.length == 0) {
    return;  
  }

  for (var i = 0; i < divs.length; i++) {
    var div = divs[i];
    var spans = div.getElementsByTagName("SPAN");
    var option = document.createElement("OPTION");
    option.value = spans[0].innerHTML;
    if (option.value == defaultValue) {
      option.selected = true;
    }
    option.innerHTML = spans[1].innerHTML;
    selector.appendChild(option);
  }
}

function addButton(elementID, label, clickHandler) {
  
  var element = document.getElementById(elementID);

  var button = document.createElement("<INPUT TYPE=BUTTON>");
  button.className = "button";
  button.style.marginLeft = "24px";
  button.value = label;
  button.onclick = clickHandler;

  element.parentNode.insertBefore(button, element.nextSibling);
}

function FormData(formName) {
  this.name = formName;
  this.form = document.forms[formName];
  if (! this.form) {
    alert("No form named " + formName);
  }
}

FormData.prototype.getElement = function(elementName) {
  return this.form.elements[elementName];
}

FormData.prototype.getValues = function(name) {

  var values = new Array();

  for (var i = 0; i < this.form.elements.length; i++) {
    var element = this.form.elements[i];
    if (element.name == name && element.checked) {
      values.push(element.value);
    }
  }

  return values;
}

FormData.prototype.getElementsByName = function(name) {

  var elements = new Array();

  for (var i = 0; i < this.form.elements.length; i++) {
    if (this.form.elements[i].name == name) {
      elements.push(this.form.elements[i]);
    }
  }

  return elements;
}

FormData.prototype.getValue = function(elementName) {

  var element = this.form.elements[elementName];
  if (! element) {
    alert("No element named " + elementName + " in form " + this.name);
    return undefined;
  }

  if (element.tagName != "SELECT" && element.length) {
    
    for (var i = 0; i < element.length; i++) {

      var e = element[i];
      if (e.tagName == "INPUT" && 
	  (e.type == "checkbox" || e.type =="radio")) {
	if (e.checked) { return e.value; }
      } else {
	return e.value;
      }
    }

  } else {

    return element.value;
  }
}

FormData.prototype.getDate = function(elementName) {

  var value = this.getValue(elementName);
  
  return Date.parse(value);
}

FormData.prototype.trimValue = function(elementName) {

  var element = this.form.elements[elementName];
  if (! element) {
    alert("No element named " + elementName + " in form " + this.name);
    return undefined;
  }

  if (element.value) {
    element.value = element.value.replace(/^\s+/, "");
    element.value = element.value.replace(/\s+$/, "");
  }
}

FormData.prototype.isNull = function(elementName, msg) {

  var cond = function(value) {
    return (value == undefined || value == null || value == "");
  }

  return this.checkValue(elementName, msg, cond);
}

FormData.prototype.isNotInteger = function(elementName, msg) {

  this.trimValue(elementName);

  return this.isNotMatch(elementName, /^\d+$/, msg);
}

FormData.prototype.isNotBetween = function(elementName, min, max, msg) {

  var cond = new Function("value", 
    "return (value < " + min + " || value > " + max + ")"
  );

  return this.checkValue(elementName, msg, cond);
}

FormData.prototype.isLongerThan = function(elementName, length, msg) {

  var cond = new Function("value", 
    "return (value && value.length && value.length > " + length + ")");

  return this.checkValue(elementName, msg, cond);
}

FormData.prototype.isWhitespace = function(elementName, msg) {

  var cond = new Function("value", 
    "return (! value || value.match(/^\\s*$/))");

  return this.checkValue(elementName, msg, cond);
}

FormData.prototype.isNotMatch = function(elementName, pattern, msg) {

  var cond = new Function("value", 
    "return (value && ! value.match(" + pattern + "))");

  return this.checkValue(elementName, msg, cond);
}

FormData.prototype.isNotImageFileName = function (elementName, msg) {

  if (! msg) {
    msg = "Please choose a GIF, JPEG or PNG image file to upload.";
  }

  var cond = function(value) {
    var re = /^(.*)(.(gif|jpg|jpeg|png))$/i;
    return ! re.exec(value);
  }

  return this.checkValue(elementName, msg, cond);
}

FormData.prototype.isNotURLName = function (elementName, msg) {

  var cond = function(value) {
    var re = /^[\.\-_a-z0-9A-Z]+$/;
    return ! re.exec(value);
  }

  return this.checkValue(elementName, msg, cond);
}

FormData.prototype.isMarkup = function (elementName, msg) {

  var cond = function(value) {
    var re = /^[ \.\-_a-z0-9A-Z]+$/;
    return ! re.exec(value);
  }

  return this.checkValue(elementName, msg, cond);
}

FormData.prototype.isNotURL= function (elementName, msg) {

  var cond = function(value) {
    var re = /^(ftp|https?):\/\/(?:[a-zA-Z0-9](?:[-a-z-A-Z0-9]*[a-zA-Z0-9])?)+\b(?:\d+)?(?:\/[^;"'<>()\[\]{}\s\x7f-\xff]*(?:[.,?]+[^;"'<>()\[\]{}\s\x7f-\xff]+)*)?/;
    return ! re.exec(value);
  }

  return this.checkValue(elementName, msg, cond);
}

FormData.prototype.checkValue = function(elementName, msg, cond) {

  var element = this.form.elements[elementName];
  if (! element) {
    alert("No element named " + elementName + " in form " + this.name);
    if (window.event) { window.event.returnValue = false; }
    return true;
  }
  
  if (cond(element.value)) {
    this.cancelSubmit(msg, elementName);
    return true;
  }

  return false;
}

FormData.prototype.cancelSubmit = function(msg, elementName) {

  if (elementName) {
    var element = this.form.elements[elementName];
    if (! element) {
      alert("No element named " + elementName + " in form " + this.name);
      if (window.event) { window.event.returnValue = false; }
      return false;
    }
    
    if (! element.disabled && ! element.readonly) {
      element.focus(); 
    }

    if (element.tagName == "INPUT" && element.type == "text") {
      element.select();
    }
  } 

  alert(msg);
  if (window.event) { window.event.returnValue = false; }

  return false;
}

FormData.prototype.setValue = function(elementName, value) {

  var element = this.form.elements[elementName];
  if (! element) {
    alert("No element named " + elementName + " in form " + this.name);
    return null;
  }

  element.value = value;
}

FormData.prototype.setChecked = function(elementName, value) {

  var element = this.form.elements[elementName];
  if (element == null) { return; }

  var elements = element;
  if (! element.length) {
    elements = new Array();
    elements[0] = element;
  }

  var values = value;
  if (! (values instanceof Array)) {
    values = new Array();
    values[0] = value;
  }

  for (var i = 0; i < values.length; i++) {
    var value = values[i];
    for (var j = 0; j < elements.length; j++) {
      var element = elements[j];
      if (element.value == value) element.checked = true;
    }
  }
}

FormData.prototype.setEnabled = function(elementName, isEnabled) {

  var element = this.form.elements[elementName];
  if (element == null) { return; }

  var labels = this.form.getElementsByTagName("LABEL");

  var elements = element;
  if (element.tagName == "SELECT" || ! element.length) {
    elements = new Array();
    elements.push(element);
  }

  for (var i = 0; i < elements.length; i++) {
    elements[i].disabled = ! isEnabled;
    var label = this.getLabel(elements[i], labels);
    if (label) {
      label.disabled = ! isEnabled;
    }
  }
}

FormData.prototype.getLabel = function(element, labels) {

  if (! element.id) { return; }
  for (var i = 0; i < labels.length; i++) {
    if (labels[i].htmlFor == element.id) { return labels[i]; }
  }

  return null;
}


