	////////////////////////////////////////////////////////////////////
//
// Title : Required Fields for JavaScript Illiterati
// Author : Matthew Quinlan  (mquinlan@loopfuse.com)
// Version : 1.3
// File : required.js
//
// Purpose : Simplify the validation of required HTML form fields.
//
// Functionality : Prevents forms from being submitted to server-side when required fields are empty.
//                 Annotates the required fields with an asterisk as a hint to the user (default = before).
//                 Highlights the empty required fields for user (default = red).
//
// Usage : Mark each INPUT,TEXTAREA,SELECT,INPUT:RADIO field tag in your HTML that you wish to be a required field with class="required".
//				 If you wish to override the default color of missing fields (red) set "invalidColor" attribute 
//         on FORM tag (e.g. <form invalidColor="blue").
//				 If you wish to override the position (before) of the asterisk indicator in relation to the field label 
//         set "asterisk" attribute on FORM tag to either "after" or "none" (e.g. <form asterisk="after").
//
// Requires : jQuery (dynamically loaded if not already in use on webpage)
//
// Limitations : You CANNOT mark checkboxes required because an unchecked box is a valid value (false)
//
// License : This code is licensed under Creative Commons Attribution 3.0 Unported License.  
//           http://creativecommons.org/licenses/by/3.0/
//           This means that you can use it and modify it as long as you do not remove my name from these comments.
//
// Disclaimer : This code is offered as-is and without warranty expressed or implied.
//              This code is a community contribution that is maintained by the author, not by the author's employer (LoopFuse).
//
////////////////////////////////////////////////////////////////////

// set debug=1 here if you wish to see console debugging output
var debug=0;
if (typeof(window.console) == "undefined") debug=0;


// Load jQuery if not present 
if (typeof jQuery === "undefined" ) 
		{
		if (debug) console.log("loading jQuery");
    var script_tag = document.createElement('script');
    script_tag.setAttribute("type","text/javascript");
    script_tag.setAttribute("src",
      "http://code.jquery.com/jquery-latest.min.js")
    script_tag.onload = jQueryReadyCallback; // Run jQueryReadyCallback() once jQuery has loaded
    script_tag.onreadystatechange = function () { // Same thing but for IE
      if (this.readyState == 'complete' || this.readyState == 'loaded') jQueryReadyCallback();
    }
    document.getElementsByTagName("head")[0].appendChild(script_tag);
		if (debug) console.log("jQuery loaded");
} else 
		{
		if (debug) console.log("jQuery already present");		
    jQueryReadyCallback();
		}


// Place any logic here that cannot be executed until JQuery is loaded
function jQueryReadyCallback()
	{
	if (debug) console.log("page ready: mark required fields and set form onsubmit handler");
	// After document is loaded mark the required fields with an asterisk and alter form's onsubmit (if undefined)
	$(document).ready(function() {
	  markRequireds();
	  setFormOnSubmitHandler();
	});
	}

	
// Mark the labels of required form fields with an asterisk
// position :   "before" or "after" or "none"  (default is before)
function markRequireds()
	{
	if (debug) console.log("markRequireds()");
	$("form .required").each(function(i) 
		{
		var position=$(this).closest("form").attr("asterisk") || "after"; //default position of asterisk to "before"
		var elementId=$(this).context.id;
		var labels = $("label[for="+ elementId +"]");
		if (labels[0] != null) 
			if (position=="after")
				labels[0].innerHTML = labels[0].innerHTML + " *";					
			else if (position=="before")
				labels[0].innerHTML = "* "+labels[0].innerHTML;					
		}); 
	}


// Find FORM tags who have descendents whose class="required" and set onSubmit handler if it does not already exist
function setFormOnSubmitHandler()
	{
	if (debug) console.log("setFormOnSubmitHandler()");
	$(".required").closest("form").each(function(i){	
		if ($(this).attr('onsubmit') == null) // don't modify existing onSubmit handlers if they exist
			{
			$(this).submit(function() {
		  	return validateRequireds('red');
				});
			}
		});
	}


function validateRequireds()
// Determine whether all form fields marked with class="required" are populated.
// usage: <form onsubmit="return validateRequireds();" .............
	{
	if (debug) console.log("validateRequireds()");
	requiredPopulated = true; //default return value to true
	$("form .required").each(function(i) // iterate through each form element where class="required"
		{
		var invalidColor=$(this).closest("form").attr("invalidColor") || "red"; //default background of missing field to red if not specified
		var labels = $("label[for="+ $(this).context.id +"]");
		var label = labels[0];
		if (debug) console.log(label);

		// use fieldValue to abstract the logic for handling multiple types of form fields
		var fieldValue = $(this).val(); // standard INPUTs, TEXTAREAs, and SELECTS
		if ((fieldValue instanceof Array)==true) fieldValue = fieldValue[0]; //capture 1st value from MULTI-SELECT box
		if ($(this).context.type=="radio") fieldValue= $('input:radio[name='+$(this).context.name+']:checked').val(); // RADIO BUTTONS
		if (debug) console.log("fieldValue:"+fieldValue);		

		if ((fieldValue == null) ||  (jQuery.trim(fieldValue)=="")) // if form field is blank
			{
			if ((label!=null)&&(label.orig_color == null)) label.orig_color = label.style.color; //save original color
			if (label!=null) label.style.color = invalidColor;  // highlight missing field label in form
			requiredPopulated=false; // if we find even one missing field, set return value to false
			}
		else if ((label!=null)&&(label.orig_color != null)) // if form field is not blank and orig_color was saved
			label.style.color = label.orig_color; //reset label to original color
		}); // end each(function(i)
		
	return requiredPopulated; // return true if all required fields are populated, otherwise return false
	}
