/*	name			: ClassBehaviours, the javascript framework based on class-name parsing	update			: 9.3.17	author			: Maurice van Creij	dependencies	: jquery.classbehaviours.js	info			: http://www.classbehaviours.com/    This file is part of jQuery.classBehaviours.    ClassBehaviours is a javascript framework based on class-name parsing.    Copyright (C) 2008  Maurice van Creij    ClassBehaviours is free software: you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation, either version 3 of the License, or    (at your option) any later version.    ClassBehaviours is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with ClassBehaviours. If not, see http://www.gnu.org/licenses/gpl.html.*/	// create the jQuery object if it doesn't already exist	if(typeof(jQuery)=='undefined') jQuery = function(){};	// create the root classbehaviours object if it doesn't already exist	if(typeof(jQuery.classBehaviours)=='undefined') jQuery.classBehaviours = function(){};	// create the handlers child object if it doesn't already exist	if(typeof(jQuery.classBehaviours.handlers)=='undefined') jQuery.classBehaviours.handlers = function(){}	// blinks	jQuery.classBehaviours.handlers.validateForm = {		// properties		name: 'validateForm',		focused: null,		// methods		start: function(node){			// find the root of the form and set its onsubmit event			formNode = jQuery.classBehaviours.utilities.rootNode(node, 'FORM');			formNode.onsubmit = this.submitted;			// for all elements of this form			allNodes = node.getElementsByTagName('*');			for(var a=0; a<allNodes.length; a++){				// if this element is a row add the default class name				if(allNodes[a].nodeName=='TR') allNodes[a].className += (allNodes[a].className.indexOf('passive')<0) ? ' passive' : '' ;				// if this element is a submit button, hijack the form submit				if(allNodes[a].type=='submit' || allNodes[a].type=='image') allNodes[a].onclick  = this.submitted;				// if this element is marked with the test_* class				if(allNodes[a].className.indexOf('test_')>-1){					// set the default validation class					allNodes[a].className += (allNodes[a].className.indexOf('passive')<0) ? ' passive' : '' ;					// test properties					testName = jQuery.classBehaviours.utilities.getClassParameter(allNodes[a], 'test', null);					testApplied = null;					// for all tests, check if this is the name and make it apply itsself to the form element					for(b in this.tests) if(this.tests[b].name == testName) testApplied = this.tests[b].apply(allNodes[a]);					// if it wasn't found assume it's the id to a regExp, apply the custom regexp handler					if(testApplied==null) testApplied = this.custom.apply(allNodes[a]);				}			}		},		summary: function(node){			// get all elements of this form			rootNode = jQuery.classBehaviours.utilities.rootNode(node, 'FIELDSET');			allRows = rootNode.getElementsByTagName('TR');			// for all rows, if the row is an error, remember its label			errorMessage = '';			for(var a=0; a<allRows.length; a++){				if(allRows[a].className.indexOf('error')>-1 && allRows[a].innerHTML.indexOf(' test_')>-1){					errorLabels = allRows[a].getElementsByTagName('LABEL');					if(errorLabels.length>0) errorMessage += '<li>'+ errorLabels[0].innerHTML +'</li>';				}			}			// get the summary field			validationSummaries = jQuery.classBehaviours.utilities.getElementsByClassName('summary', rootNode);			if(validationSummaries.length>0){				// construct the summary message				validationTextId = jQuery.classBehaviours.utilities.getClassParameter(validationSummaries[0], 'failure', '');				validationText = document.getElementById(validationTextId).value;				validationSummaries[0].innerHTML = validationText.replace('{labels}', '<ul>' + errorMessage + '</ul>');				validationSummaries[0].style.display = (errorMessage!='') ? 'block' : 'none' ;			}			// return if the form passed the tests			return (errorMessage=='');		},		update: function(node, status){			// is this a mandatory field			mandatoryId = jQuery.classBehaviours.utilities.getClassParameter(node, 'required', 'no');			mandatory = (mandatoryId!='yes' && mandatoryId!='no') ? document.getElementById(mandatoryId).checked : (mandatoryId=='yes');			// is this an empty field			empty = (node.value == '' || node.value == node.title);			// adjust the status for non-mandatory empty field			ignore = (!mandatory && empty);			// adjust the classname of the form element to reflect the validation status			node.className = (ignore) ?				node.className.replace('success', 'passive').replace('error', 'passive') :				(status) ?					node.className.replace('passive', 'success').replace('error', 'success') :					node.className.replace('passive', 'error').replace('success', 'error') ;			// get the root of this row			rootNode = jQuery.classBehaviours.utilities.rootNode(node, 'TR');			// adjust the classname of the form row to reflect the validation status			rootNode.className = (ignore) ?				rootNode.className.replace('success', 'passive').replace('error', 'passive') :				(status) ?					rootNode.className.replace('passive', 'success').replace('error', 'success') :					rootNode.className.replace('passive', 'error').replace('success', 'error') ;			// pass back the status			return (status || ignore);		},		ajaxWait: function(waitStatus, waitNode, waitError){			var vfo = jQuery.classBehaviours.handlers.validateForm;			// update the status//			waitNode.innerHTML = (waitStatus>-1) ? 'Loading: ' + Math.round(waitStatus * 100) + '%' : 'Error: ' + waitError ;			// show the element (it may have been hidden by default)//			waitNode.style.display = 'block';		},		ajaxReplace: function(replaceXml, replaceNode, replaceText){			var vfo = jQuery.classBehaviours.handlers.validateForm;			// update the content			replaceNode.innerHTML = replaceText.split('<root>')[1].split('</root>')[0];			// restore the focus			focussedNode = document.getElementById(vfo.focused);			if(focussedNode!=null) focussedNode.focus();			// re-apply the classbehaviours			jQuery.classBehaviours.parser.parseNode(replaceNode.parentNode.parentNode);		},		// events		submitted: function(that, override){			var node = (typeof(this.nodeName)=='undefined') ? that : this ;			var vfo = jQuery.classBehaviours.handlers.validateForm;			var queryString = '';			// get all elements of this form			formNode = jQuery.classBehaviours.utilities.rootNode(node, 'FORM');			rootNode = jQuery.classBehaviours.utilities.rootNode(node, 'FIELDSET');			allNodes = rootNode.getElementsByTagName('*');			// override the checks if asked			if(override==true){				allNodes = new Array();				testValidated = true;			}			// for all elements			for(var a=0; a<allNodes.length; a++){				// assume the test failed				testValidated = false;				// if the element is marked with the test_* class, trigger its onchange event				if(allNodes[a].nodeName=='INPUT' || allNodes[a].nodeName=='SELECT' || allNodes[a].nodeName=='TEXTAREA')					if(allNodes[a].className.indexOf('test_')>-1)						if(typeof(allNodes[a].onchange)!='undefined')							testValidated = allNodes[a].onchange();			}			// update the summary			summaryResult = vfo.summary(rootNode);			// check how the form is to be submitted			replySubmit = jQuery.classBehaviours.utilities.getClassParameter(rootNode, 'submit', null);			if(replySubmit=='ajax'){				// submit the form using ajax				referingId = jQuery.classBehaviours.utilities.getClassParameter(rootNode, 'target', null);				referingId = jQuery.classBehaviours.utilities.getClassParameter(node, 'target', referingId);				referingObject = (referingId==null) ? node : document.getElementById(referingId) ;				post = 'ajax=' + node.getAttribute('id') + '&section=' + jQuery.classBehaviours.utilities.getClassParameter(node, 'section', '');				if(summaryResult) jQuery.classBehaviours.ajax.addSubmit(node, vfo.ajaxReplace, vfo.ajaxWait, post, referingObject);				return false;			}else{				// allow the form to submit normally				return summaryResult;			}/* TODO:	- submit via iframe*/		}	}		jQuery.classBehaviours.handlers.validateForm.tests = {			resubmit: {				name: 'resubmit',				apply: function(node){					node.onchange = this.validate;					node.onfocus = this.store;					return true;				},				store: function(that){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					vfo.focused = node.id;				},				validate: function(that){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					return vfo.submitted(node, true);				}			},			email: {				name: 'email',				apply: function(node){					node.onchange = this.validate;					return true;				},				validate: function(that){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					return vfo.update(node, node.value.match(/^[\w\.\-\,\+]+@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/)!=null);				}			},			nlPhone: {				name: 'nlPhone',				apply: function(node){					node.onchange = this.validate;					return true;				},				validate: function(that){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					return vfo.update(node, node.value.match(/(^\+[0-9]{2}|^\+[0-9]{2}\(0\)|^\(\+[0-9]{2}\)\(0\)|^00[0-9]{2}|^0)([0-9]{9}$|[0-9\-\s]{10}$)/)!=null);				}			},			nlPostal: {				name: 'nlPostal',				apply: function(node){					node.onchange = this.validate;					return true;				},				validate: function(that){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					return vfo.update(node, node.value.match(/^[0-9]{4}\s{0,1}[a-zA-Z]{2}$/)!=null);				}			},			isoDate: {				name: 'isoDate',				apply: function(node){					node.onchange = this.validate;					return true;				},				validate: function(that){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					return vfo.update(node, node.value.match(/^\d{4}\-\d{1,2}\-\d{1,2}$/)!=null);				}			},			numeric: {				name: 'numeric',				apply: function(node){					node.onchange = this.validate;					return true;				},				validate: function(that){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					return vfo.update(node, node.value.match(/^[0-9]+$/)!=null);				}			},			currency: {				name: 'currency',				apply: function(node){					node.onchange = this.validate;					return true;				},				validate: function(that){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					return vfo.update(node, node.value.match(/^[0-9]+(\.[0-9]{1,2})?$/)!=null);				}			},			alphaNumeric: {				name: 'alphaNumeric',				apply: function(node){					node.onchange = this.validate;					return true;				},				validate: function(that){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					return vfo.update(node, node.value.match(/^[a-zA-Z0-9]/)!=null);				}			},			nlBank: {				name: 'nlBank',				apply: function(node){					node.onchange = this.validate;					return true;				},				validate: function(that){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					inputValue = node.value;					if (inputValue.length!=9){						return vfo.update(node, false);					}else{						numericTotal = 0;						for (a=0; a<inputValue.length; a++) numericTotal += inputValue.substr(a, 1) * (9 - a);						return vfo.update(node, numericTotal%11==0);					}				}			},			anyRadio: {				name: 'anyRadio',				apply: function(node){					// if this node contains inputs					allInputs = node.getElementsByTagName('INPUT');					if(allInputs.length==0) allInputs = new Array(node);					// apply the event handler and classname to all child nodes					for(var a=0; a<allInputs.length; a++){						if(allInputs[a].type=='radio'){							allInputs[a].className = node.className;							allInputs[a].onclick = (navigator.userAgent.indexOf('MSIE ')>-1) ? this.delay : this.validate ;							allInputs[a].onchange = (navigator.userAgent.indexOf('MSIE ')>-1) ? this.delay : this.validate ;						}					}					// report success					return true;				},				delay: function(id){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					// trigger the validation					setTimeout('jQuery.classBehaviours.handlers.validateForm.tests.anyRadio.validate(document.getElementById("'+node.id+'"))', 200);				},				validate: function(that){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					// default validation					anyChecked = false;					// get all inputs with this name					allInputs = document.getElementsByTagName('input');					// for all inputs, if the input has the same name, if the input is checked set the validator to true					for(var a=0; a<allInputs.length; a++) if(allInputs[a].name == node.name && allInputs[a].type == 'radio') if(allInputs[a].checked) anyChecked = true;					// return the result					return vfo.update(node, anyChecked);				}			},			anyCheckbox: {				name: 'anyCheckbox',				apply: function(node){					// if this node contains inputs					allInputs = node.getElementsByTagName('INPUT');					if(allInputs.length==0) allInputs = new Array(node);					// apply the event handler and classname to all child nodes					for(var a=0; a<allInputs.length; a++){						if(allInputs[a].type=='checkbox'){							allInputs[a].className = node.className;							allInputs[a].onclick = (navigator.userAgent.indexOf('MSIE ')>-1) ? this.delay : this.validate ;							allInputs[a].onchange = (navigator.userAgent.indexOf('MSIE ')>-1) ? this.delay : this.validate ;						}					}					// report success					return true;				},				delay: function(id){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					// trigger the validation					setTimeout('jQuery.classBehaviours.handlers.validateForm.tests.anyCheckbox.validate(document.getElementById("'+node.id+'"))', 200);				},				validate: function(that){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					// default validation					anyChecked = false;					// get all inputs from the parentnode					parentNode = jQuery.classBehaviours.utilities.rootNode(node, 'TR');					allInputs = parentNode.getElementsByTagName('input');					// for all inputs, if this checkbox is checked remember is					for(var a=0; a<allInputs.length; a++) if(allInputs[a].checked) anyChecked = true;					// return the result					return vfo.update(node, anyChecked);				}			},			notEmpty: {				name: 'notEmpty',				apply: function(node){					node.onchange = this.validate;					return true;				},				validate: function(that){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					return vfo.update(node, node.value!="");				}			},			password: {				name: 'password',				apply: function(node){					node.onchange = this.validate;					node.onblur = this.validate;					return true;				},				validate: function(that){					var node = (typeof(this.nodeName)=='undefined') ? that : this ;					var vfo = jQuery.classBehaviours.handlers.validateForm;					// default validation					wasRepeated = false;					// get the target field to compare					repeatedId = jQuery.classBehaviours.utilities.getClassParameter(node, "clone", null);					// if the id is valid					if(repeatedId!=null){						repeatedValue = document.getElementById(repeatedId).value;						wasRepeated = (repeatedValue==node.value && repeatedValue!='' && node.value!='');					}					// report back					return vfo.update(node, wasRepeated);				}			}		}		jQuery.classBehaviours.handlers.validateForm.custom = {			apply: function(node){				node.onchange = this.validate;				return true;			},			validate: function(that){				var node = (typeof(this.nodeName)=='undefined') ? that : this ;				var vfo = jQuery.classBehaviours.handlers.validateForm;				customRegId = jQuery.classBehaviours.utilities.getClassParameter(node, 'test', null);				customRegString = document.getElementById(customRegId).value;				customRegExp = new RegExp(customRegString);				return vfo.update(node, node.value.match(customRegExp)!=null);			}		}	// add this addon to the jQuery object	if(typeof(jQuery.fn)!='undefined'){		// extend jQuery with this method		jQuery.fn.validateForm = function(){			return this.each(				function(){					jQuery.classBehaviours.handlers.validateForm.start(this);				}			);		};		// set the event handler for this jQuery method		$(document).ready(			function(){				$(".validateForm").validateForm();			}		);	}