
/* * * * * * * * * * * * * * * * * * * * * * *
 *		CARENZA validator script file		 *
 * 											 *
 * 		(c) Copyright 2010 - CARENZA		 *
 * 			http://www.carenza.nl/			 *
 * 											 *
 * * * * * * * * * * * * * * * * * * * * * * *
 * 
 * 
 * Validator functions. Use these functions to add client-side validation to forms.
 * 
 * Requires javascript and jQuery to run.
 * 
 * Use: call the validate function when you want to validate. For example, when a form is submitted.
 * This function will return true if all tests pass.
 * 
 * Each element can have multiple tests. A test is added to the validation of an element by adding css classes to it.
 * 
 * Currently, these tests are implemented:
 *   lengthn	: test the value to have at least n characters. For example: length3 to test fields for a minumum length of 3.
 *   email		: test the value to be a valid e-mail address. The validator is stricter than the specification, but most of the e-mail providers accept only these e-mail addresses
 *   integer	: test the value to be a positive or negative integer (3 or -12).
 *   decimal	: test the value to be a positive or negative decimal (4.8 or -12,42). Note: both commas and dots are allowed as decimal separator.
 */

/**
 * validate all elements selected with selector. On success, adds passCss to element class. On fail, adds failCss to element class.
 * @param {string} selector CSS3/jQuery selector of all elements to be validated
 * @param {string} passCss the css class to add if an element passes all tests
 * @param {string} failCss the css class to add if an element fails all tests
 * @return {boolean} true iff all tests pass
 */
function validate(selector, passCss, failCss){
    var success = true;
    
	
    var items = $(selector);
    for (var i = 0; i < items.length; i++) {
		var item = items[i];
        var $item = $(item);
        
        success = validateItemCss($item, passCss, failCss) && success;
    }
    return success;
}

/**
 * Validate an alement. On success, adds passCss to element class. On fail, adds failCss to element class
 * @param {Object} $item the jQuery object representing the element to validate
 * @param {string} passCss the css class that has to be added when the element passes all tests
 * @param {string} failCss the css class that has to be added when the element failes one of the tests
 * @return {boolean} true iff all tests pass
 */
function validateItemCss($item, passCss, failCss) {
	var success = validateItem($item.attr('class'), $item.val());
	
	if(success) {
		$item.removeClass(failCss).addClass(passCss);
	} else {
		$item.removeClass(passCss).addClass(failCss);
		$item.bind('keyup', function() {
			var success = validateItem($item.attr('class'), $item.val());
			
			if(success) {
				$item.removeClass(failCss).addClass(passCss);
			} else {
				$item.removeClass(passCss).addClass(failCss);
			}
		});
	}
		
	return success;
}

/**
 * Splits all classes and loops through them, looking for classes that determine how to validate the value
 * @param {string} classString the string containing all classes
 * @param {string} value the value to validate
 * @return {boolean} true iff value passes all tests
 */
function validateItem(classString, value){
    var classes = classString.split(' ');
    
	var valid = true;
	
    for (var i = 0; i < classes.length; i++) {
		var cssClass = classes[i];
        // email
		if (cssClass == 'email') {
            valid = valid && validateItemEmail(value);
        }
		
		// length
		var regex = /^length[1-9][0-9]*$/;
		if(regex.test(cssClass)) {
			var maxLength = parseInt(cssClass.substring(6));
			valid = valid && validateItemLength(value, maxLength);
		}
		
		// integer
		if(cssClass == 'integer') {
			valid = valid && validateItemInteger(value);
		}
		
		// decimal
		if(cssClass == 'decimal') {
			valid = valid && validateItemDecimal(value);
		}
    }
    
    return valid;
}

/**
 * Test whether value is an e-mail address
 * @param {string} value the value to test
 * @return {boolean} true iff value appears to be a valid e-mail address
 */
function validateItemEmail(value) {
	var regex = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
	return regex.test(value);
}

/**
 * Tests whether value has at least maxLength characters 
 * @param {Object} value the value to test
 * @param {Object} minLength the minimum number of characters
 * @return {boolean} true iff value has at least minlength characters
 */
function validateItemLength(value, minLength) {
	return (value.length >= minLength);
}

/**
 * Tests whether value is an integer (positive or negative)
 * @param {string} value the value to test
 * @return {boolean} true iff value is an integer
 */
function validateItemInteger(value) {
	var regex = /^[+-]?[0-9]+$/;
	return regex.test(value);
}

/**
 * Tests whether value is a decimal (positive or negative)
 * @param {string} value the value to test
 * @return {boolean} true iff value is a decimal (at least one digit in the integral part, and, if there is a decimal dot or comma, at lest one decimal digit) 
 */
function validateItemDecimal(value) {
	var regex = /^[+-]?[0-9]+([.,][0-9]+)?$/;
	return regex.test(value);
}

