﻿/** Javascript form validation By Josh Pyburn **/
(function(){
	if(!window.attachEvent){	// Extends IE-like attachEvent functionality to other browsers.
		Element.prototype.attachEvent = function(eventname,action){
			eventname = eventname.replace(/^on/,"");
			this.addEventListener(eventname,action,false);
		}
	}
	window.getContained = function(obj,contained){	// Gets ALL elements within the target element, not just the childNodes.
		contained = contained || [];
		if(obj.tagName)contained[contained.length] = obj;
		if(obj.childNodes.length > 0)
			for(var a = 0; a < obj.childNodes.length; a++)
				getContained(obj.childNodes[a],contained);
		return contained;
	}
	window.getByClassName = function(obj,classname){	// Gets children by className independantly of native support.
		obj.getElementsByClassName = obj.getElementsByClassName || function(cname){
			var children = getContained(this);
			this[cname] = [];
			for(var c = 0; c < children.length; c++)
				if(children[c].className == cname)
					this[cname][this[cname].length] = children[c];
			return this[cname];
		}
		return obj.getElementsByClassName(classname);
	}
	window.validate = function(obj){
		if(!obj.tagName){ // radio buttons
			obj.list = true;
			var value = validate.getValue(obj);
			var valid = value.match(obj.validate);
			if(!valid){ obj[0].checker.className = obj[0].checker.className.replace("formcheck","formerror"); }
			else { obj[0].checker.className = obj[0].checker.className.replace("formerror","formcheck"); }
			validate.valAction(obj,valid);
			return valid;
		}
		else if(obj.tagName.toLowerCase() == "form"){
			var message = "";
			var firstError = false;
			for(var v = 0; v < obj.vlist.length; v++)
				if(!validate(obj.vlist[v])){
					if(obj.vlist[v][0])
						message += obj.vlist[v][0].checker.innerHTML+"\n";
					else
						message += obj.vlist[v].checker.innerHTML+"\n";
					firstError = firstError || (obj.vlist[v].list ? obj.vlist[v][0] : obj.vlist[v]);
				}
			if(message != ""){
				if(obj.alert) alert(message);
				if(firstError.type.indexOf("select") < 0){
					firstError.focus();
					firstError.select();
				}
				return obj.passive || false;
			}
		}
		else { // single object
			var value = obj.value;
			var valid = true;			
			if(obj.validate == "/date/"){ // Date validation
				value = validate.formDate(value);
				var d = Date.parse(value); valid = !isNaN(d); if(valid) valid = d < 253400594400000;
				if(valid){
					obj.value = value;
					if(obj.drange) valid = d >= obj.drange[0] && d <= obj.drange[1];
				}
			}
			else valid = !!obj.value.match(obj.validate);
				var o = obj[0] || obj;
			if(!valid){ o.checker.className = o.checker.className.replace("formcheck","formerror"); }
			else { o.checker.className = o.checker.className.replace("formerror","formcheck"); }
			validate.valAction(obj,!!valid);
			return !!valid;
		}
	}
	validate.valAction = function(obj,valid){
		if(valid){if(obj.onpass)try{obj.onpass()}catch(e){}}
		else if(obj.onfail)try{obj.onfail()}catch(e){};
	}
	validate.getValue = function(obj){
	    var value = obj.value || obj.selectedValue;
	    if(value == undefined) for(var v = 0; v < obj.length; v++) if(obj[v].checked) return obj[v].value || v;
	    return value || "";
	}
	validate.vtypes = {
		_name : "^[\\-\\s\\.A-Za-z]+$",
		_phone : "^\\d{3}([\\-\\.\\s])?\\d{3}\\1\\d{4}$|^\\(\\d{3}\\)\\s?\\d{3}\\-\\d{4}$",
		_email : "^[\\-\\._A-Za-z0-9]+@[\\-\\._A-Za-z0-9]+\\.[A-Za-z]{2,3}$",
		_date : "date",
		_ssn : "^\\d{3}\\-?\\d{2}\\-?\\d{4}$",
		_zipcode : "^\\d{5}([\\-\\.\\s]?\\d{4})?$",
		_required : "\\S"
	}
	validate.ftypes = {
		_phone_modern : function(){this.value = this.value.replace(/\D/g,""); this.value = this.value.substring(0,3)+"."+this.value.substring(3,6)+"."+this.value.substring(6,10)},
		_phone_classic : function(){this.value = this.value.replace(/\D/g,""); this.value = "("+this.value.substring(0,3)+") "+this.value.substring(3,6)+"-"+this.value.substring(6,10)},
		_date_mmddyyyy : function(){
			var value = validate.formDate(this.value);
			if(value){
				var date = new Date(value);
				function dd(input){ return input.toString().length < 2 ? ("0"+input) : input; }
				this.value = dd(date.getMonth()+1)+"/"+dd(date.getDate())+"/"+date.getFullYear();
			}
		},
		_date_mdyyyy : function(){
			var value = validate.formDate(this.value);
			if(value){
				var date = new Date(value);
				this.value = (date.getMonth()+1)+"/"+date.getDate()+"/"+date.getFullYear();
			}
		},
		_date_mmddyy : function(){
			var value = validate.formDate(this.value);
			if(value){
				var date = new Date(value);
				var y = date.getFullYear().toString();
				if(y.substring(0,2) == new Date().getFullYear().toString().substring(0,2)) y = y.substring(2);
				function dd(input){ return input.toString().length < 2 ? ("0"+input) : input; }
				this.value = dd(date.getMonth()+1)+"/"+dd(date.getDate())+"/"+y;
			}
		},
		_date_mdyy : function(){
			var value = validate.formDate(this.value);
			if(value){
				var date = new Date(this.value);
				var y = date.getFullYear().toString();
				if(y.substring(0,2) == new Date().getFullYear().toString().substring(0,2)) y = y.substring(2);
				this.value = (date.getMonth()+1)+"/"+date.getDate()+"/"+y;
			}
		},
		_ssn : function(){
			var v = this.value.match(/\d/g).join("");
			this.value = v.substring(0,3)+"-"+v.substring(3,5)+"-"+v.substring(5,9);
		},
		_zipcode : function(){
			var v = this.value.match(/\d/g).join("");
			if(v.length < 6) this.value = v;
			else this.value = v.substring(0,5)+"-"+v.substring(5,9);
		}
	}
	validate.formDate = function(input){
		if(input.match(/^\d{1,2}\/\d{1,2}\/\d{2}$/))
			return input.substring(0,input.lastIndexOf("/")+1)+(new Date()).getFullYear().toString().substring(0,2)+input.substring(input.lastIndexOf("/")+1);
		if(input.match(/^today$|^now$|^immediately$|^current$|^present$/)) return new Date();
		if(input.match(/^tomorrow$/)){ var d = new Date(); d.setDate(d.getDate()+1); return d; }
		if(input.match(/^yesterday$/)){ var d = new Date(); d.setDate(d.getDate()-1); return d; }		
		if(isNaN(Date.parse(input))) return null;
		return input;
	}
	validate.getContext = function(input){ return input.replace(/\D+/g,"<<>>").replace(/^<<>>|<<>>$/g,"").split("<<>>"); }
	validate.vtypes._phone.pre = function(){};
	validate.vtypes._phone.post = function(){};
	window.validInit = function(){
		var vforms = document.getElementsByTagName("form");
		for(var v = 0; v < vforms.length; v++)
			if((" "+vforms[v].className+" ").match(/ validate /)){
				var form = vforms[v];
				form.vlist = [];
				form.alert = (" "+vforms[v].className+" ").match(/ alert /);
				form.passive = (" "+vforms[v].className+" ").match(/ passive /);
				form.onsubmit = function(){return validate(this)};
				var formChildren = getContained(form);
				for(var c = 0; c < formChildren.length; c++){
					var condition = formChildren[c].getAttribute("condition");
					formChildren[c].removeAttribute("condition");
					if(condition){
						condition = condition.split(" when ");
						var args = condition[1].split(" ");
						formChildren[c].method = condition[0];
						formChildren[c].rel = !!args[1].match(/^is$|^equals$|^matches$/);
						if(validate.vtypes[args[2]])
							formChildren[c].reg = new RegExp(validate.vtypes[args[2]]);
						else formChildren[c].reg = new RegExp("^"+args[2]+"$");
						var target = form[args[0]];
						if(target){
							switch(formChildren[c].method){
								case "toggle":
									if(!formChildren[c].className.match(/formaltview|formnormal/))
										formChildren[c].className = (formChildren[c].className + " formnormal").replace(/^\s|\s$/g,"");									
									break;
								case "disable":
									
									break;
							}
							target.conditionals = target.conditionals || [];
							target.conditionals[target.conditionals.length] = formChildren[c];
							target.conditions = function(){
								var obj = window.event ? (event.srcElement || this) : this;
								var value = validate.getValue(obj);
								for(var c = 0; c < obj.conditionals.length; c++){
									var con = obj.conditionals[c];
									var valid;
									switch(con.reg.toString()){
										case "/valid/":
											valid = (obj.validate) ? validate(obj) : false;
											break;
										case "/invalid/":
											valid = (obj.validate) ? !validate(obj) : false;
											break;
										default:
											valid = value.match(con.reg) != null;
											break;
									}
									valid = (!con.rel ^ valid);
										switch(con.method){
											case "toggle":
												if(valid) con.className = con.className.replace("formnormal","formaltview");
												else con.className = con.className.replace("formaltview","formnormal");
												break;
											case "disable":
												if(valid)try{con.disabled = true; }catch(e){}
												else try{con.disabled = false; }catch(e){};
												break;
											default:
												break;
										}
								}
							}
							target.conditions();
							if(!target.tagName){
							    for(var t = 0; t < target.length; t++)
							        target[t].attachEvent("onclick",function(){
							            var obj = window.event ? (event.srcElement || this) : this;
							            obj.form[obj.name].conditions();
							        });
							}
							else target.attachEvent("onchange",function(){
								var obj = window.event ? (event.srcElement || this) : this;
								obj.conditions();
							});
						}
					}
				}
				var checkers = getByClassName(form,"formcheck");
				for(var c = 0; c < checkers.length; c++){
					var tstring = checkers[c].href;
					checkers[c].removeAttribute("href");
					if(tstring){
						var target = tstring.match(/#[\w\d]+/)[0].substring(1);
						if(target){
							if(form[target]){
								 if(form[target].tagName){
									 form[target].attachEvent("onchange",function(){
										var obj = window.event ? (event.srcElement || this) : this;
										if(obj.validate){
											if(obj.format){
												var o = obj.value;
												try{ obj.format(); } catch(e){ obj.value = o; };
											}
											validate(obj);
										}
										else if(obj.format){
											var o = obj.value;
											try{ obj.format(); } catch(e){ obj.value = o; };
										}
									});
									if(!form[target].form)form[target].form = form;
								}
								else for(var t = 0; t < form[target].length; t++)
							            form[target][t].attachEvent("onclick",function(){
							                var obj = window.event ? (event.srcElement || this) : this;
							                validate(obj.form[obj.name]);
							            });
							}
							if(form[target]){
								var args = tstring.match(/\?[^$]+/)[0];
									if(args){
										var vtype = args.match(/[\?&]validate=[^&]+/);
											if(vtype){
												vtype = vtype[0].split("=")[1];
												try{form[target].validate = new RegExp(validate.vtypes[vtype])}
												catch(e){throw("Validation Type: \""+vtype+"\" not found."); return null};
												if(form[target][0])
													form[target][0].checker = checkers[c];
												else
													form[target].checker = checkers[c];
												form.vlist[form.vlist.length] = form[target];
											}
										var ftype = args.match(/[\?&]format=[^&]+/);
											if(ftype){
												ftype = ftype[0].split("=")[1];
												try{form[target].format = validate.ftypes[ftype]}
												catch(e){throw("Format Type: \""+ftype+"\" not found."); return null};
											}
										var drange = args.match(/[\?&]daterange=[^&]+/);
											if(drange){
												drange = drange[0].split("=")[1];
												if(drange == "today"){
													var d = new Date();
													form[target].drange = [Date.parse(d.getMonth()+"/"+d.getDate()+"/"+d.getFullYear())];
													form[target].drange[1] = form[target].drange[0];
												}
												else {
													try{ drange = drange.split("|"); }
													catch(e){throw("Failed to parse date-range."); return null};
													drange = [Date.parse(drange[0]),Date.parse(drange[1])];
													form[target].drange = [Math.min(drange[0],drange[1])];
													if(!isNaN(form[target].drange[0])){
														form[target].drange[1] = Math.max(drange[0],drange[1]);
														if(isNaN(form[target].drange[1])) form[target].drange = null;
													}
													else form[target].drange = null;
												}
											}
										var onpass = args.match(/[\?&]onpass=[^&]+/);
											if(onpass){
												onpass = onpass[0].split("=")[1];
												if(typeof(window[onpass])=="function")
													form[target].onpass = window[onpass];
											}
										var onfail = args.match(/[\?&]onfail=[^&]+/);
											if(onfail){
												onfail = onfail[0].split("=")[1];
												if(typeof(window[onfail])=="function")
													form[target].onfail = window[onfail];
											}
									}
								}
								else throw("form element \""+target+"\" not found.");
						}
					}
				}
			}validate(form);
	}
	try { addEventListener("load",validInit,false); } catch(e){ attachEvent("onload",validInit); }
})();