/* Forms, simplified by Dan Royer is licensed under a Creative Commons Attribution-Share Alike 2.5 Canada License.
 * Based on a work at http://www.marginallyclever.com/forms/. 
 * Permissions beyond the scope of this license may be available at http://www.marginallyclever.com/forms/. 
 *
 * See notes in forms.php
 */
// What to tell people when they leave a page with a changed, unsaved form.
var __form_abandon_change_warning='You have made changes to this page which will be lost.';
// What to tell people when they hit the cancel button.
var __form_cancel_warning='Are you sure you want to cancel?';

// has a form cancel button been hit?  If so, avoid warnings.
var __form_cancelled=false;


// This includes the datepicker code automatically.
document.write("<script type='text/javascript' src='date.js'></script>");
document.write("<script type='text/javascript' src='jquery.datePicker.js'></script>");


// This is called when the document loads, and is the reason the javascript must be loaded in the <head> of a page.
$(document).ready(function() {
  // bind to any form element change.
  $(':input,:select,:textarea').bind("change select keydown",function(e) {
    // find the element being changed.
  	if (e.target) targ = e.target;
    else if (e.srcElement) targ = e.srcElement;
    if (targ.nodeType == 3) {  // defeat Safari bug
      targ = targ.parentNode;
    }

    // mark the element's block as changed.
    get_block_from_input(targ).addClass('changed');
  });

  // bind to the window before it unloads the page
  window.onbeforeunload=function(e) {
    // has a form cancel/submit button been hit?  If so, avoid warnings.
    if(__form_cancelled) return;

    // find any form with class confirm_unload that has a changed input_block.
    x=$('.confirm_unload > .changed');
    if(x.length>0) {
      // there is at least one, so throw a warning.
      msg=__form_abandon_change_warning;
      var e = e || window.event;
      if (e) { e.returnValue = msg; }
      return msg;
    }
  };
});


// get_block_from_input() - find the parent with class 'input_block'
// x - the element that is a child of input_block.
function get_block_from_input(x) {
  /*
  while(x!=undefined && !$(x).hasClass('input_block')) {
    x=$(x).parent();
  }*/

  // TEMPLATE DEPENDENT - input_block class must be a parent of the input(s).
  return $(x).closest('.input_block');
}


// value_is_empty() - returns true if value is null or empty
// Is not fooled by leading & trailing whitespace.
// x - the input/select/textarea in question
function value_is_empty(x) {
  // check if it is null
  if(x==null) return false;
  // check if it is empty when there is no whitespace.
  compare_to=x.value.replace(/^\s+|\s+$/g,'');  // remove whitespace
  return (compare_to.length==0);
}


// mark_field_invalid() - add the 'invalid' class to the input block for x
// x - the input/select/textarea in question
function mark_field_invalid(x) {
  get_block_from_input(x).addClass('invalid');
}


// mark_field_valid() - remove the 'invalid' class from the input block for x
// x - the input/select/textarea in question
function mark_field_valid(x) {
  get_block_from_input(x).removeClass('invalid');
}


// field_is_required() - Checks if the input block is marked as required.
// x - the input/select/textarea in question
function field_is_required(x) {
  return get_block_from_input(x).hasClass('required');
}

// validate_field()
// Adds 'invalid' class to an empty input if the block is marked as required.
// Removes 'invalid' class from non-empty fields if the block is marked as required.
// Returns false if the input is marked 'invalid'.
// Does nothing and returns true if the block is not marked as required.
// x - the input/select/textarea in question.
function validate_field(x) {
  // is this a required field (cannot be empty)?
  if(field_is_required(x)) {
    // is it empty?
    if(value_is_empty(x)) {
      // field empty
      mark_field_invalid(x);
      return false;
    } else {
      // field not empty
      mark_field_valid(x);
      return true;
    }
  }
  return true;
}


// validate_email() - calls validate_field() first, then verifies that the contents of the text field look like a valid email.
// x - the input in question.  Does not apply to select or textareas, though I suppose it could.
function validate_email(x) {
  mark_field_valid(x);

  if(validate_field(x)) {
    compare_to=x.value.replace(/^\s+|\s+$/g,'');  // remove whitespace
    if(!compare_to.match(/^[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)*@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)*(\.[a-zA-Z]{2,4})$/)) {
      mark_field_invalid(x);
      return false;
    }
  }
  return true;
}


// validate_url() - calls validate_field() first, then verifies that the contents of the text field look like a valid URL.
// x - the input in question.  Does not apply to select or textareas, though I suppose it could.
function validate_url(x) {
  mark_field_valid(x);

  if(validate_field(x)) {
    compare_to=x.value.replace(/^\s+|\s+$/g,'');  // remove whitespace
    if(!compare_to.match(/^(([\w]+:)?\/\/)?(([\d\w]|%[a-fA-f\d]{2,2})+(:([\d\w]|%[a-fA-f\d]{2,2})+)?@)?([\d\w][-\d\w]{0,253}[\d\w]\.)+[\w]{2,4}(:[\d]+)?(\/([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)*(\?(&?([-+_~.\d\w]|%[a-fA-f\d]{2,2})=?)*)?(#([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)?$/)) {
      mark_field_invalid(x);
      return false;
    }
  }
  return true;
}


// validate_checkbox() - verifies that the checkbox is checked if the field is required.
// x - the input in question.
function validate_checkbox(x) {
  mark_field_valid(x);
  
  // is this a required field (cannot be unchecked)?
  if(field_is_required(x) && x.checked===false) {
    mark_field_invalid(x);
    return false;
  }
  return true;
}


// validate_select() - verifies that the value of the option currently selected is not '', 0, or null if the field is required.
// x - the select in question.
function validate_select(x) {
  mark_field_valid(x);

  // Is this a required field (cannot be left to an option with a value of '', 0, or null)?
  if(field_is_required(x)) {
    // selectedIndex==-1 if nothing is selected
    if(x.selectedIndex==-1 || value_is_empty(x.options[x.selectedIndex])) {
      mark_field_invalid(x);
      return false;
    }
    if(x.options.length==0) {
      mark_field_invalid(x);
      return false;
    }
  }
  return true;
}


// validate_form() - called automatically when a form submits.
// Touches all validatable fields, then verifies there are no invalid inputs.
// Returns true if there are no input blocks with the 'invalid' class.
function validate_form(f) {
  // has a form cancel button been hit?  If so, skip validation.
  if(__form_cancelled===true) {
    // Shut off the warning for this form
    $(f).removeClass('confirm_unload');
    return true;
  }

  // In case people didn't touch the fields, check that the required fields have been filled in.
  w=false;
  x=$('input, textarea, select',f);
  for(i=0;i<x.length;++i) {
    y=get_block_from_input(x[i]);
    if(y.hasClass('email')) {
      z=validate_email(x[i]);
    } else if(y.hasClass('url')) {
      z=validate_url(x[i]);
    } else if(y.hasClass('checkbox')) {
      z=validate_checkbox(x[i]);
    } else if(y.hasClass('select')) {
      z=validate_select(x[i]);
    } else {
      z=validate_field(x[i]);
    }
    if(!w && !z) {
      // set focus to the first element that has an error.
      (x[i]).focus();
      w=true;
    }
  }

  // if there are any invalid fields, prevent the form form submitting.
  x=$('.invalid');
  if(x.length>0) return false;

  // The form data looks good!

  // Shut off the warning for this form
  $(f).removeClass('confirm_unload');

  return true;
}


// cancel_form() - Called when a cancel button is hit.
function cancel_form() {
  if(confirm(__form_cancel_warning)) {
    // turn off form validation.  We're cancelling so what do we care if it's filled out right?
    __form_cancelled=true;
    return true;
  }
  return false;
}