// Form Tooltip Validator
/* 

author: scott lenger
last updated: november 2011

instructions:
1. add <head> link to this file
2. add setFormValidation(formid) where formid = the id of the form you want validated
3. add the appropriate class to the input tag (options are: text, email, phone, zip)
4. add class="required" to input tag, forces field to be validated when the form is submitted
5. HTML must include input and label tags wrapped in a container

// getElementsByClassName by Justin Diaz http://www.dustindiaz.com/getelementsbyclass/

*/

// todo: radio validation

// Get Class Function ////////////////////////////////////////////////////////////////
// returns the class name of any xhtml tag
function getElementsByClass(node,tag,searchClass) {
	var classElements = new Array();
	if ( node == null )
		node = document;
	if ( tag == null )
		tag = '*';
	var els = node.getElementsByTagName(tag);
	var elsLen = els.length;
	var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
	for (i = 0, j = 0; i < elsLen; i++) {
		if( searchClass ) {
            if ( pattern.test(els[i].className) ) {
			    classElements[j] = els[i];
			    j++;
		    }
        } else {
			classElements[j] = els[i];
            j++;
        }
	}
	return classElements;
}

var requiredErrorMarkup = ''; //'<span class="error">This Field is Required</span>';

// Remove Valid Item from Error List
function removeValidatedError(usrtxt) {
    var fieldlabel = '';

	if(typeof usrtxt == 'string') {
        fieldlabel = usrtxt;
    } else {
        // get the field label (this is used in the submit function to build the error message list
        fieldlabel = $(usrtxt).parent().find('label').text();
    }
    $(usrtxt).parents('form').find(".error-msg li a:contains('"+fieldlabel+"')").parent('li').css('visibility', 'hidden');
}
// Validation Functions ////////////////////////////////////////////////////////////////////

// Basic Text (requires more than 4 characters) class="text"
function checkText(usrtxt) {
	var container = usrtxt.parentNode;
    var $con = $(container);
    var txt = usrtxt.value;
    fieldlabel = $(usrtxt).parent().find('label').text();
	if (txt.length >= 1 && txt != fieldlabel) {
		if (container.className == 'valid') {return;}
		$con.removeClass('notvalid').addClass('valid');
		//$(usrtxt).siblings('.error').remove();
		//$(usrtxt).parent('li').prepend('<span class="valid-tested">Valid</span>').find(':first').hide().fadeIn();
		removeValidatedError(usrtxt); // removes item from error list
	}
	else {
		if ($con.hasClass('notvalid')) {return;}
		if ($(usrtxt).hasClass('required')) {
			$con.removeClass('valid').addClass('notvalid');
			$(usrtxt).siblings('.valid-tested').remove();
			$(usrtxt).parent('li').prepend(requiredErrorMarkup).find(':first').hide().fadeIn();
		}
	}
}


//Zip (requires 5 digits) class="zip"
function checkZip(usrtxt) {
	var container = usrtxt.parentNode;
    var $con = $(container);
	var num = $.trim( usrtxt.value );
	if ( !(/[a-zA-Z0-9_\s-]{5,}/).test(num) ){
		$con.removeClass('valid').addClass('notvalid');
		$(usrtxt).siblings('.valid-tested').remove();
		$(usrtxt).parent('li').prepend(requiredErrorMarkup).find(':first').hide().fadeIn();
		removeValidatedError(usrtxt); // removes item from error list
	} else {
		usrtxt.value = num.substring(0,5);
		$con.removeClass('notvalid').addClass('valid');
		//$(usrtxt).siblings('.error').remove();
		//$(usrtxt).parent('li').prepend('<span class="valid-tested">Valid</span>').find(':first').hide().fadeIn();
	}
}	

// Phone (requires 10 digits - US only) class="phone"
function checkPhone(usrtxt) {
	var num = $.trim( usrtxt.value+'' );
    if( !num ) return true;

	var container = usrtxt.parentNode;
    var $con = $(container);
	num = num.replace(/[^\d]/g,'');
	if (num.length < 8) {
		usrtxt.value = num.substring(0,3) + num.substring(3, 6) + num.substring(6);
		$con.addClass('notvalid');
		$(usrtxt).siblings('.valid-tested').remove();
		$(usrtxt).parent('li').prepend(requiredErrorMarkup).find(':first').hide().fadeIn();
	} else if (num.length > 9) {
		usrtxt.value = num.substring(0,3) + num.substring(3, 6) + num.substring(6, 10);
		$con.addClass('valid');
		//$(usrtxt).siblings('.error').remove();
		//$(usrtxt).parent('li').prepend('<span class="valid-tested">Valid</span>').find(':first').hide().fadeIn();
	} else if (num.length > 8) {
		usrtxt.value = num.substring(0,3) + num.substring(3, 6) + num.substring(6, 10);
		$con.addClass('notvalid');
		$(usrtxt).siblings('.valid-tested').remove();
		$(usrtxt).parent('li').prepend(requiredErrorMarkup).find(':first').hide().fadeIn();
	}		
}


// Email (requires & and . and at least 2 character extension) class="email"
function checkEmail(usrtxt) {
	var container = usrtxt.parentNode;
    var $con = $(container);
	var txt = usrtxt.value;
	if (/^.+@[^\.].*\.[a-z]{2,}$/.test(txt)) {
		if ($con.hasClass('valid')) {return;}
		$con.removeClass('notvalid').addClass('valid');
		//$(usrtxt).siblings('.error').remove();
		//$(usrtxt).parent('li').prepend('<span class="valid-tested">Valid</span>').find(':first').hide().fadeIn();
		removeValidatedError(usrtxt); // removes item from error list
	} else {
		if ($con.hasClass('notvalid')) {return;}
		$con.removeClass('valid').addClass('notvalid');
		$(usrtxt).siblings('.valid-tested').remove();
		$(usrtxt).parent('li').prepend(requiredErrorMarkup).find(':first').hide().fadeIn();
	}
}

function checkSelect(usrtxt) {
    var $usrtxt = $(usrtxt);
	var container = usrtxt.parentNode;
    var $con = $(container);
    if( !$usrtxt.val() ) {
		if ($con.hasClass('notvalid')) {return;}
		$con.removeClass('valid').addClass('notvalid');
		$(usrtxt).siblings('.valid-tested').remove();
		$(usrtxt).parent('li').prepend(requiredErrorMarkup).find(':first').hide().fadeIn();
	} else {
		if ($con.hasClass('valid')) {return;}
		$con.removeClass('notvalid').addClass('valid');
		//$(usrtxt).siblings('.error').remove();
		//$(usrtxt).parent('li').prepend('<span class="valid-tested">Valid</span>').find(':first').hide().fadeIn();
		removeValidatedError(usrtxt); // removes item from error list
	}
}

function checkTextArea(usrtxt) {
	var container = usrtxt.parentNode;
    var $con = $(container);
	var txt = $.trim( usrtxt.value );
	if (txt.length >= 1) {
		if ($con.hasClass('valid')) {return;}
		$con.removeClass('notvalid').addClass('valid');
		//$(usrtxt).siblings('.error').remove();
		//$(usrtxt).parent('li').prepend('<span class="valid-tested">Valid</span>').find(':first').hide().fadeIn();
		removeValidatedError(usrtxt); // removes item from error list
	}
	else {
		if ($con.hasClass('notvalid')) {return;}
		if ($(usrtxt).hasClass('required')) {
			$con.removeClass('valid').addClass('notvalid');
			$(usrtxt).siblings('.valid-tested').remove();
			$(usrtxt).parent('li').prepend(requiredErrorMarkup).find(':first').hide().fadeIn();
		}
	}
}

// SUBMIT FORM AND VALIDATE /////////////////////////////////////////////////////////////////
// validates all required fields again before sending
function formValidate(formid) {
    //var formid = forms[0];
	var reqfields = getElementsByClass(formid, "*", "required");
	var errors = "";

	for (var i=0; i<reqfields.length; i++) {

		// get class and send to appropriate validating function
		var testclass = reqfields[i].className.split(" ");

		for(j in testclass) {
			if (testclass[j] == 'text') { // if class="text"
				checkText(reqfields[i]);
			} else if (testclass[j] == 'email') { // if class="email"
				checkEmail(reqfields[i]);
			} else if (testclass[j] == 'zip') {
                checkZip(reqfields[i]);
            } else if (testclass[j] == 'message-body') {
                checkTextArea(reqfields[i]);
            }
		} // end test for class

        if( reqfields[i].tagName.toLowerCase() == 'select' ) {
            checkSelect( reqfields[i] );
        }

		if ( $(reqfields[i]).parent().hasClass('notvalid') ) { // read parent class to determine if field is valid
			
			errors += '<li><a href="#' + reqfields[i].id + '">' + reqfields[i].parentNode.getElementsByTagName("label")[0].childNodes[0].nodeValue.replace('(Optional)', '') + "</a></li>\n";
		}
	}

	if (errors == "") {
        return true;
	} else { // if errors
		errors = "\n<div class=\"error-msg\">\n<p>Please correct the following form errors:</p>\n<ol>\n" + errors + "</ol>\n</div>"; // list errors as <li><a href="#input id=name">Label Name</a></li>
		$(formid).find('.error-msg').hide('fast').remove();

		$(formid).prepend(errors); // post error msg
		$(formid).find('.error-msg li:first a').focus(); // give error msg focus * Accessibility
		return false;
	}
}


// Add functions to XHTML Tags /////////////////////////////////////////////////////////////////////////
// keeping things unobtrusive
function setFormValidation(formid, form) {

    // set form submit
    for (var i=0; i<formid.length; i++) {
	if(!document.getElementById(formid[i])) {return;} 
	// make sure the XHTML id matches
	var getform = document.getElementById(formid[i]);
        if( !getform ) continue;
        
        var $submit = $(getform).find('#submitBtn');
	$(getform).submit(function(ev) { 
            $submit.attr('disabled', 'disabled');
            if (formValidate(getform)) {
                return true;
            }
            $submit.attr('disabled', '');
            ev.preventDefault();
            return false;
        });

	    // add text validate function text inputs
	    var textarea = getElementsByClass(getform, "textarea", "message-body");
	    for (var i=0; i<textarea.length; i++) {
		    textarea[i].onkeyup = function() {checkTextArea(this);}
		    textarea[i].onblur = function() {checkTextArea(this);}
	    }

	    // add text validate function text inputs
	    var textinput = getElementsByClass(getform, "*", "text");
	    for (var i=0; i<textinput.length; i++) {
		    textinput[i].onkeyup = function() {checkText(this);}
		    textinput[i].onblur = function() {checkText(this);}
	    }
	    // add zip validate function text inputs
	    var zipinput = getElementsByClass(getform, "*", "zip");
	    for (var i=0; i<zipinput.length; i++) {
		    zipinput[i].onkeyup = function() {checkZip(this);}
		    zipinput[i].onblur = function() {checkZip(this);}
	    }
	    // add phone validate function text inputs
	    var phoneinput = getElementsByClass(getform, "*", "phone");
	    for (var i=0; i<phoneinput.length; i++) {
		    phoneinput[i].onkeyup = function() {checkPhone(this);}
		    phoneinput[i].onblur = function() {checkPhone(this);}
	    }
	    // add email validate function to email inputs
	    var emailinput = getElementsByClass(getform, "input", "email");
	    for (var i=0; i<emailinput.length; i++) {
		    emailinput[i].onkeyup = function() {checkEmail(this);}
		    emailinput[i].onblur = function() {checkEmail(this);}
	    }
		
		// add email validate function to email inputs
	    var selectfield = getElementsByClass(getform, "select", null);
	    for (var i=0; i<selectfield.length; i++) {
		    selectfield[i].onchange = function() {checkSelect(this);}
			selectfield[i].onblur = function() {checkSelect(this);}
	    }
		
	}
}

