/*

FORM VALIDATOR
Stephen B. Schreiber, 4/2/08
This is a generic form validator that can be dropped into any web application.
Requires Dojo 1.1 (dojotoolkit.org) & dijit.Tooltip module.

1) Assign any forms to be validated class="validate"
2) To run a custom function onsubmit, assign it to yourForm.customFunction
3) Set each field to validate with setValidation(node,validator,msg,required):
	node - the form element to be validated.  Accepts DOM node or ID string
	validator - function to run validation against.  Accepts user defined function, regExp, or false (false sets required to true and validates against null value)
	msg - message to be displayed on field focus after failed validation.  Accepts string
	required (default true) - indicates whether field is required (blank value = invalid).  Accepts boolean
		Example: setValidation("myField",/$\d/,"Must start with a digit");
			--assigns validation to DOM element with id "myField"
			--validation function is a regular expression that requires the first character to be a digit
			--if the value does not validate onchange, the field is set to invalid and the message "Must start with a digit" is displayed on field focus
			--since the 'required' boolean was left out, required defaults to true and a blank value does not validate
4) Set css to style validation errors:
	.validationError - unfocused field style
	.validationErrorFocused - focused field style

All validatable fields are initially set to isValid=false and validated live onchange.  Focused fields show tooltip with error message.
On form submission, if any form elements are !isValid they are highlighted and the first invalid field is focused.

*/

//Load dojo tooltip module

dojo.require("dijit.Tooltip");

//Run init on load

dojo.addOnLoad(initValidation);

//Find all forms with class validate and attach the onsubmit validation event

function initValidation() {
	dojo.query("form.validate").forEach(function(item){
		item.isValid = false;
		dojo.connect(item,'onsubmit',validateForm);
	});
}

//Called from pages with forms to set validation for a field

function setValidation(node,validator,msg,required) {
	var field = (typeof node == "string") ? dojo.byId(node) : node;
	//if validator is not set to false, determine whether its a function or a regular expression and validate accordingly
	if(validator) {
		var validationFunction = (String(validator).match(/^\//)) ? function (e) { e.target.value.match(validator) ? makeValid(e.target) : makeInvalid(e.target); } : validator;
		//if required is not set to false, set isRequired to true
		field.isRequired = (typeof required != "undefined" && !required) ? false : true;
	}
	//if validator is set to false, set isRequired to true and validate against null value
	else {
		var validationFunction = function(e) { (e.target.value == '') ? makeInvalid(e.target) : makeValid(e.target);};
		field.isRequired = true;
	}
	//set error message if field does not validate
	field.msg = msg;
	//set isValid to false if field has no content (if it has preloaded content it is assumed to be valid)
	(field.value == '') ? field.isValid = false : field.isValid = true;
	field.mustValidate = true;
	dojo.connect(field,'onfocus',isFocused);
	dojo.connect(field,'onblur',isNotFocused);
	dojo.connect(field,'onblur',validationFunction);
}

//Trigger an event programatically, necessary if updating a DOM node w/js

function triggerEvent(targ,type) {
	var node = (typeof targ == "string") ? dojo.byId(targ) : targ;
	var ie_evt = (!type.match(/^on/)) ? 'on' + type : type;
	var ff_evt = (type.match(/^on/)) ? type.replace(/on/,'') : type;
	//For IE
	if(node.fireEvent) node.fireEvent(ie_evt);
	//For Gecko
	if(document.createEvent) {
		var evt = document.createEvent('HTMLEvents');
		if(evt.initEvent) evt.initEvent(ff_evt, true, true);
		if(node.dispatchEvent) node.dispatchEvent(evt);
	}
}

//set isValid to true and assign remove any error classes

function makeValid(node) {
	node.isValid = true;
	dojo.removeClass(node,"validationError");
	dojo.removeClass(node,"validationErrorFocused");
}

//set isvalid to false and assign error classes

function makeInvalid(node) {
	node.isValid = false;
	if(node.isFocused) {
		dojo.addClass(node,"validationErrorFocused");
		//trigger focus event--since the field was already focused when the class is assigned the tooltip won't be fired
		triggerEvent(node,"focus");
	}
	else dojo.addClass(node,"validationError");
}

//set isFocused to true, update class, and display tooltip if there's a validation error

function isFocused(e) {
	var node = e.currentTarget;
	node.isFocused = true;
	if(node.className && node.className.match(/validationError/) && !node.className.match(/validationErrorFocused/)) {
		dojo.addClass(node,"validationErrorFocused");
		dojo.removeClass(node,"validationError");
	}
	if(node.className && node.className.match(/validationErrorFocused/)) {
		dijit.showTooltip(node.msg, node);
	}
}

//set isFocused to false, update class, and kill any displaying tooltips

function isNotFocused(e) {
	var node = e.currentTarget;
	node.isFocused = false;
	if(node.className && node.className.match(/validationErrorFocused/)) {
		dojo.addClass(node,"validationError");
		dojo.removeClass(node,"validationErrorFocused");
	}
	dijit.hideTooltip(node);
}

//validate all fields in form and highlight first error--if there are none, either submit the form or run customFunction

function validateForm(e) {
	//prevent form from submitting
	e.preventDefault();
	var fm = e.currentTarget;
	var el = fm.elements;
	var errorFields = [];
	//loop through form elements and validate one by one
	for(var i = 0; i < el.length; i++) {
		//if field is blank and not required, go ahead and make valid
		if(!el[i].isRequired && el[i].value == '') makeValid(el[i]);
		//otherwise, if field is set to mustValidate, check validity and add invalid fields to errorFields array
		else if(el[i].mustValidate) {
			if(!el[i].isValid) {
				makeInvalid(el[i]);
				errorFields.push(el[i]);
			}
		}
	}
	//if errorFields has any kids, highlight them all as errors and focus/select the first one
	if(errorFields[0]) {
		errorFields[0].focus();
		if(errorFields[0].value != '') errorFields[0].select();
	}
	//if a custom function has been defined for the form, run it, otherwise submit
	else (fm.customFunction) ? fm.customFunction(e) : fm.submit();
}