Login   Register  
PHP Classes
elePHPant
Icontem

File: jquery.validate.js

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Jonas Earendel  >  jForm Validator  >  jquery.validate.js  >  Download  
File: jquery.validate.js
Role: Auxiliary data
Content type: text/plain
Description: A JavaScript/jQuery validator class
Class: jForm Validator
Validate forms with rules defined in form template
Author: By
Last change: Sigh. Another bugfix. Multiple conditions in conditional requirements failed. Now they don't.

If you don't use multiple conditions, don't bother downloading this.

Sorry for the many updates.
Date: 1 year ago
Size: 16,158 bytes
 

Contents

Class file image Download
/**
 * A javascript jQuery form validator.
 *
 * @version 0.9.1.1
 *
 * The class validates form elements based on rules set in the elements' class attribute.
 * Basically an extension of jForm, a PHP form validator found on jform.lagerwall.net or phpclasses.org
 *
 * @changelog
 *
 * 0.9.1.1	2013-02-07	Sigh. Another bugfix. Multiple conditions in conditional requirements failed. Now they don't.
 *
 * 0.9.1	2013-02-07 	Bugfix! Apparently when some browsers autofill peoples username and password they DON'T trigger a change in the field! The buggers!
 *						So now the whole form is validated when the submit button is pressed. Which is slightly slower than the previous
 *						approach, but not as bad as I thought it would be. Probably the regexps were some sort of bottleneck.
 *
 * 0.9.0	2013-02-06	This class has been mostly an afterthought, but now it's becoming a real part of the jForm package.
 * 						So it's got its own version number!
 *
 * @example $("form").validate();
 * @example $("form").validate(1);	The "1" means the form will be validated on load. Useful if you want the pretty icons.
 * 									Beware browsers autofilling passwords and usernames though. They don't always trigger change...
 * @example $("#login-form").validate();
 *
 * @example <input type="text" class="required email" name="username" />
 * @example <input type="password" class="required minlength(5)" name="password" />
 *
 * Advanced usage:
 *
 * @example <input type="text" class="required(username='') email" name="email" /> // required if username is empty
 * @example <input type="text" class="required(email='') minlength(5)" name="username" /> // required if email is empty
 *
 * PLEASE NOTE:
 *
 * If you want immediate validation, that is validation before the form is submitted,
 * and you change the value of a field with javascript,
 * you MUST trigger the "change" event of the object, otherwise this class
 * won't know it needs to validate.
 *
 * @example $(this).val(new_val).change();
 * @example $(this).val(new_val).trigger("change");
 *
 */

(function( $ ){
	$.fn.validate = function(pre_validate) {
		return this.each(function()
		{
			this.validator_errors = {};
			this.validator_values = {};
			var i,elems = this.elements;
			for(i=0;i<elems.length;i++)
			{
				if(elems[i].name)
				{
					$.fn.validate.prepare(elems[i]);
					if(pre_validate)
					{
						$.fn.validate.validate(elems[i]);
					}
				}
			}

			$(this).submit(function(e){

				for(i=0;i<elems.length;i++)
				{
					if(elems[i].name)
					{
						$.fn.validate.validate(elems[i]);
					}
				}

				var errors = [];
				for (i in this.validator_errors)
				{
					str = $.fn.validate.getLabel(this[i])+": "+this.validator_errors[i][1];
					errors.push(str);
				}
				if(errors.length)
				{
					e.preventDefault();
					var error_container=$(".error-container");
					if(error_container[0])
					{
						error_container.html($.fn.validate.messages['there_are_errors']+'<ul><li>'+errors.join('</li><li>')+'</li></ul>');
					}
					else
					{
						str = "*****************************************\n";
						str+="            "+$.fn.validate.messages["there_are_errors"];
						str+= "\n*****************************************\n";
						str+=errors.join('\n');
						alert(str);
					}
				}
//				console.log((new Date()).getTime() - ts);
			});
			// propertychange fucks up ie7. And it doesn't seem to be needed anywho
			$("input, textarea, select",this).on("change keyup input paste",function(e){
				$.fn.validate.validate(this);
			});
		});
	};

	$.extend($.fn.validate,{
		methods:{}
		,messages:{}
		,errors:{}
		,error:function(obj,type,str){
			if(str)
			{
				obj.form.validator_errors[obj.name]=[type,str];
			}
			return obj.form.validator_errors[obj.name];
		}
		,getLabel:function(o,l){
			if(o.name)
			{
				if(o.id)
				{
					l = $("label[for='"+o.id+"']").html();
				}
			}
			else
			{
				o=o[0];
			}
			if(!l){l=$(o).prev('label').html();}
			if(!l){l=o.title;}
			if(!l){
				l=o.name.charAt(0).toUpperCase() + o.name.substring(1);
				l=l.replace(/[\[\]]+/gi," ");
			}
			return l;
		}
		,clear:function(obj){
			delete(obj.form.validator_errors[obj.name]);
		}
		,getErrorContainer:function(obj){

			var id = obj.id || '',
				container = $("#validator-"+id);
			if(!container[0])
			{
				if($(obj).next().hasClass('validator-status'))
				{
					$(obj).next().attr("id","validator-"+id);
					container = $(obj).next();
				}
			}
			return container[0];
		}
		,prepare:function(obj){

			if(!obj.id)
			{
				obj.id='random-id-' +Math.round(Math.random()*1000000000000);
			}
			obj.originalValue=this.val(obj);
			var
				res
				,found = false
				,c = $(obj).attr("class")
				,method
				,rules = {}
				,container = this.getErrorContainer(obj)
				;
				if(c)
				{
					var
						c=c.split(' ')
						,i = c.length;
					while (i--)
					{
						res = /([a-zA-Z0-9_\-]+)( |$|([(]+([^)]+)[)]+))/.exec(c[i]);
						if(res && this.methods[res[1]])
						{
							rules[res[1]]=res[4];
							found = true;
						}
					}
				}

			if(found)
			{
				obj.validator_rules = rules;
				if(container)
				{
					obj.originalError = $(container).html();
					this.error(obj,'serverside',obj.originalError);//so it's alert()ed!
				}
				else
				{
					$(obj).after('<span id="validator-'+obj.id+'" class="validator-status"></span>');
					return false;
				}
			}
			return true;
		}
		,refresh:function(obj){
			if(obj.validator_rules)
			{
				var error = obj.form.validator_errors[obj.name];
				if(error)
				{
					$(obj).addClass("validator-error");
					container =$(this.getErrorContainer(obj));
					container.attr("class","validator-status").addClass("validator-error").addClass(error[0]).html(error[1]).attr("title",error[1]);
				}
				else
				{
					var val = this.val(obj)
						,container = $(this.getErrorContainer(obj))
					;
					container.attr("class","validator-status").html("");
					$(obj).removeClass("validator-error");

					if(obj.type && obj.type=='radio')
					{
						$("input:radio[name='"+obj.name+"']",obj.form).each(function(){
							var container = $.fn.validate.getErrorContainer(this);
							$(container).html("").attr("class","validator-status");
							if(this.value==val)
							{
								$(container).addClass("validator-ok");
							}
						});
					}
					if(val.length)
					{
						container.addClass("validator-ok");
					}
				}
			}
		}
		,val:function(obj){
			if(obj.type=='checkbox')
			{
				if(obj.checked)
				{
					return obj.value;
				}
				else
				{
					return '';
				}
			}
			if(obj.type=='radio')
			{
//				console.debug(obj);
				var vars = obj.form[obj.name];
//				console.debug(vars.length);
				for(var i = 0; i<vars.length;i++)
				{
					if(vars[i].checked)
					{
						return vars[i].value;
					}
				}
				return false;
			}
			return $(obj).val();
		}
		,validate:function(obj,brake){//brake is set to avoid endless recursion
			if(obj.name)
			{
				var  ok = true
					,msg=""
					,type=""
					,par=""
					,val = this.val(obj)
					,res = []
					,rules = obj.validator_rules || {}
					,c = $(obj).attr("class");
				if(obj.validator_rules)
				{
					// so we don't validate unless there's been a change.
					var oldval=obj.form.validator_values[obj.name];
					obj.form.validator_values[obj.name]=val;
					if(
					   oldval!==undefined // if oldval is undefined, it must validate
					   && oldval!==false // if oldval is false, it must validate
					   && oldval==val // if oldval is the same as newval, it doesn't need to validate
					   && !brake)
					{
						return;
					}

					this.clear(obj);

					if(obj.originalError && val==obj.originalValue)
					{
						ok=false;
						type="serverside";
						msg=obj.originalError;
					}

					if(ok && 'required' in rules)
					{
						type="required";
						ok = $.fn.validate.methods.required(obj,rules.required);
					}

					if(ok && val.length)
					{
						for(type in rules)
						{
							if(type!='required')
							{
								method = $.fn.validate.methods[type];
								par = rules[type];
								ok = method(obj,par);
								if(!ok){break;}
							}
						}
					}

					if(!ok)
					{
						msg = msg || this.messages[type];
						if(!msg)
						{
							alert("There is no error message for "+ type);
							msg = 'Missing error message';
						}
						else
						{
							if(par)
							{
								var temp = par.split(',');
								for(var i in temp)
								{
									msg = msg.replace('{'+i+'}',temp[i]);
								}
							}
						}
						this.error(obj,type,msg);
					}
					this.refresh(obj);
				}
				if(obj.dependants && !brake)
				{
					for (var i in obj.dependants)
					{
						this.validate($("#"+i)[0],1);
					}
				}
			}
			else
			{
				return '';
			}
			return this.error(obj);
		}
		,addMethod:function(name,func,message){
			if(message)
			{
				this.messages[name]=message;
			}
			this.methods[name]=func;
		}
		,getVariable:function(obj,val){
			val = val || '';
			if(val.indexOf("'")!==-1)// if it's a 'quoted' string
			{
				val = val.substring(1,val.length-1);
			}
			else
			{
				var i
					,sib = obj.form[val]
					;

				if(sib)
				{
					if(sib.length)
					{
						for(i=0;i<sib.length;i++)
						{
							sib[i].dependants = sib[i].dependants || {};
							sib[i].dependants[obj.id]=obj.name;
						}
						val= $.fn.validate.val(sib[0]);
					}
					else
					{
						sib.dependants = sib.dependants || {};
						sib.dependants[obj.id]=obj.name;
						val = $.fn.validate.val(sib);
					}
				}
			}
			return val;
		}
	});

	$.fn.validate.addMethod("required", function(obj,condition){

		if(condition)
		{
			var
				conditions = condition.split(/&/)
				,res
				,a
				,operator
				,b
				,i=0
				,ok=false
				;

			for(;i<conditions.length;i++)
			{
				res = /^(.*?)(==|!=|=|=|=||)(.*?)$/.exec(conditions[i]);  // bugfix 0.9.1.1 .exec(conditions); => .exec(conditions[i]);
				if(res)
				{
					a 			= $.fn.validate.getVariable(obj,res[1]);
					operator	= res[2];
					b 			= $.fn.validate.getVariable(obj,res[3]);
					switch(operator)
					{
						case "=="	:
						case "="	: ok = a==b;break;
						case "!="	: ok = a!=b;break;
						case ""	: ok = a<b;break;
						case ""	: ok = a>b;break;
						case "="	: ok = a<=b;break;
						case "="	: ok = a>=b;break;
						default		: alert(condition+' '+res+' incorrect syntax in required-condition');
					}
					if(!ok) // condition is NOT triggered, therefore it is not required, return true(==valid);
					{
						return true;
					}
				}
			}
		}
		if(obj.type == "radio")
		{
			var val = $.fn.validate.val(obj);
			return val !== false;
		}
		if(obj.type == "checkbox")
		{
			return obj.checked;
		}
		return $.trim($(obj).val())!=="";
	});
	$.fn.validate.addMethod("range", function(obj,param) {
		var
			val = $(obj).val()
			,ok = true
			,vals = param.split(',');
		if(vals[2])
		{
			var res = (val - vals[0]) % vals[2];
			if(res!==0)
			{
				ok=false;
			}
		}
		return ok;
	});
	$.fn.validate.addMethod("mustmatch", function(obj,param) {
		return $(obj).val() == $.fn.validate.getVariable(obj,param);
	});
	$.fn.validate.addMethod("email", function(obj) {
		return is.email($(obj).val())
	});
	$.fn.validate.addMethod("url", function(obj) {
		return is.url($(obj).val())
	});
	$.fn.validate.addMethod("time", function(obj) {
		return is.time($(obj).val())
	});
	$.fn.validate.addMethod("max", function(obj,param){
		return parseInt($(obj).val()) < param;
	});
	$.fn.validate.addMethod("min", function(obj,param){
		return parseInt($(obj).val()) >= param;
	});
	$.fn.validate.addMethod("minlength", function(obj,param){
		return $(obj).val().length >= param;
	});
	$.fn.validate.addMethod("maxlength", function(obj,param){
		return $(obj).val().length <= param;
	});
	$.fn.validate.addMethod("alphanumeric", function(obj) {
		return is.alphanumeric($(obj).val())
	});
	$.fn.validate.addMethod("number", function(obj) {
		return is.number($(obj).val())
	});
	$.fn.validate.addMethod("integer", function(obj) {
		return is.integer($(obj).val())
	});
	$.fn.validate.addMethod("alphabetic", function(obj) {
		return is.alphabetic($(obj).val())
	});
	$.fn.validate.addMethod("color", function(obj) {
		return is.color($(obj).val())
	});
	$.fn.validate.addMethod("week", function(obj) {
		return is.week($(obj).val())
	});
	$.fn.validate.addMethod("month", function(obj) {
		return is.month($(obj).val())
	});
	$.fn.validate.addMethod("datetime", function(obj) {
		return is.datetime($(obj).val())
	});
	$.fn.validate.addMethod("date", function(obj,param) {
		return is.date($(obj).val(), (param != "undefined" ? param : null))
	});
	$.fn.validate.addMethod("datetime-local", function(obj) {
		return is.datetimeLocal($(obj).val())
	});
	$.fn.validate.addMethod("ipv4", function(obj) {
		return is.ipv4($(obj).val())
	});
	$.fn.validate.addMethod("creditcard", function(obj) {
		return is.creditcard($(obj).val())
	});
	$.fn.validate.addMethod("ipv6", function(obj) {
		return is.ipv6($(obj).val())
	});
	$.fn.validate.addMethod("personnummer", function(obj) {
		return is.personnummer($(obj).val())
	});
	$.fn.validate.addMethod("organisationsnummer", function(obj) {
		return is.organisationsnummer($(obj).val())
	});
	$.fn.validate.addMethod("zipcode", function(obj,param) {
		if(param=="undefined") {return true;} //this really shouldn't happen, but you never know.
		if(obj.form[param])// if the parameter is a reference to an element, fetch the value
		{
			param = $(obj.form[param]).val();
		}
		return is.zipcode($(obj).val(),param)
	});
	$.fn.validate.addMethod("tel", function(obj,param) {
		if(param=="undefined") {return true;} //this really shouldn't happen, but you never know.
		if(obj.form[param])// if the parameter is a reference to an element, fetch the value
		{
			param = $(obj.form[param]).val();
		}
		return is.tel($(obj).val(),param)
	});
	$.extend($.fn.validate.messages, {
		there_are_errors	: "There are errors.",
		required			: "This field is required.",
		email				: "Please enter a valid email address.",
		url					: "Please enter a valid URL.",
		date				: "Please enter a valid date.",
		number				: "Please enter a valid number.",
		digits				: "Please enter only digits.",
		creditcard			: "Please enter a valid credit card number.",
		mustmatch			: "Please enter the same value again.",
		maxlength			: "Please enter no more than {0} characters.",
		minlength			: "Please enter at least {0} characters.",
		range				: "Please enter a value between {0} and {1} in steps of {2}.",
		max					: "Please enter a value less than or equal to {0}.",
		min					: "Please enter a value greater than or equal to {0}.",
		datetime			: "Please enter a valid DateTime.(yyyy-mm-ddThh:mm:ssZ)",
		'datetime-local'	: "Please enter a valid local DateTime.(yyyy-mm-ddThh:mm:ss)",
		time				: "Please enter a valid time.(hh:ss)",
		alphanumeric		: "Please enter only letters, underscores and numbers.",
		color				: "Please enter a valid color. (named, hexadecimal or rgb)",
		week				: "Please enter the week of a year. (e.g. 1974-W43)",
		month				: "Please enter the month of a year. (e.g. 1974-03)",
		alphabetic			: "Please enter only letters.",
		ipv4				: "Please enter a valid IP number (version 4).",
		ipv6				: "Please enter a valid IP number (version 6).",
		personnummer		: "Please enter a valid personnummer. (yyyymmdd-aaaa)",
		organisationsnummer	: "Please enter a valid organisationsnummer. (xxyyzz-aaaa)",
		zipcode				: "Please enter a valid zipcode.",
		tel					: "Please enter a valid phone number."
	});

})( jQuery);