﻿// JavaScript Document/** * exValidation * * @version   : 1.3.0 * @author    : nori (norimania@gmail.com) * @copyright : 5509 (http://5509.me/) * @license   : The MIT License * @link      : http://5509.me/log/exvalidation * @modified  : 2011-10-01 01:28 */;(function($, window, undefined) {	$.exValidationRules = $.exValidationRules || {};	var exValidation = function(form, conf) {		if ( form.length > 1 ) {			alert("You cannot select any forms");			return false;		}		this.form = form;		// for browse		var _this = this,			b = $("body");				conf = this.conf = $.extend({			errInsertPos       : "body", // "body" or after(before)			err                : null,			ok                 : null,			errFocus           : false,			errHoverHide       : false,			stepValidation     : false,			scrollToErr        : true,			scrollDuration     : 500,			scrollAdjust       : -10,			customScrollAdjust : false,			errPosition        : "absolute", // fixed			errOpacity         : undefined,			errTipPos          : "right", // left			errTipCloseBtn     : true,			errTipCloseLabel   : "×",			errZIndex          : 500,			errMsgPrefix       : "\* ",			customAddError     : null, // function(){}			customClearError   : null, // function(){}			customSubmit       : null, // function(){}			customListener     : "blur keyup change focus",			customBind         : null,			/* Using this conf, you can bind validation func to any element				{					object: $(button),					listener: "blur keyup change focus",					callback: function() {}				}			*/			customGetErrHeight  : null,			firstValidate       : false,			// default checking targets			inputs: [				"input:text",				"input:password",				"input:hidden",				"input:file",				"textarea",				"select",				"input[type=email]",				"input[type=url]",				"input[type=tel]",				"input[type=date]",				"input[type=datetime]",				"input[type=month]",				"input[type=week]",				"input[type=time]",				"input[type=datetime-local]",				"input[type=number]",				"input[type=range]",				"input[type=color]",				"[class*=group]",				"[class*=radio]",				"[class*=checkbox]"			],			// default checking targets in groups			groupInputs: [				"input:text",				"input:password",				"input:checkbox",				"input:radio",				"input[type=email]",				"input[type=url]",				"input[type=tel]",				"input[type=date]",				"input[type=datetime]",				"input[type=month]",				"input[type=week]",				"input[type=time]",				"input[type=datetime-local]",				"input[type=number]",				"input[type=range]",				"input[type=color]",				"select",				"textarea"			]		}, conf);		conf.inputs = conf.inputs.join(",");		conf.groupInputs = conf.groupInputs.join(",");		this.errFocus = function(id) {			if ( !conf.errFocus ) return false;			errFocus(id, conf.errZIndex);		};		this.errFocusClear = function() {			if ( !conf.errFocus ) return false;			errFocusClear(conf.errZIndex);		};		if ( fnConfirmation(conf.customSubmit) ) {			form.submit(function() {				return false;			});		}		$("input:checkbox,input:radio,input:button,input:submit,input:reset").click(function() {			_this.errFocusClear();		});		// addClasses for each inputs by validation rules		for ( var c in conf.rules ) {			$("#" + c).addClass(conf.rules[c]);		}		// If this form doesn"t have ID, formID for error tips is to be decided by random integer		var formID = form.attr("id")			? "form_" + form.attr("id")			: "form_" + randomInt()*randomInt();		var inputs = $(conf.inputs, form)			.filter(function() { return !$(this).parents().hasClass("chkgroup"); }),			classReg = returnReg(),			bindValidateFuncs = function(target, group) {				var self = group ? group : target;				target.bind(conf.customListener, function() {					_this.basicValidate(group ? group : this, conf.err, conf.ok);					_this.errFocus("#err_" + self.attr("id"));				}).blur(function() {					_this.errFocusClear();				});			};		inputs.each(function() {			var self = $(this),				cl = this.className,				id = this.id,				reg1 = undefined,				reg2 = undefined,				toggleTarget = undefined;			if ( conf.errTipPos === "right" ) {				self.addClass("errPosRight");			}			// if target has one of classRegulations			if ( classReg.test(cl) ) {				if ( conf.errInsertPos === "body" ) {					b.append(_this.generateErr(id, formID));				} else {					self[conf.errInsertPos](_this.generateErr(id, formID));					self.addClass(conf.errInsertPos);				}				if ( conf.errHoverHide ) {					$("#err_"+id).mouseenter(function() {						$(this).fadeOut();					});				}				if ( conf.errTipCloseBtn ) {					$("#err_"+id).append(						$("<span></span>")							.addClass("formErrorClose")							.text(conf.errTipCloseLabel)							.click(function() {								$(this).parent().fadeOut();							})					);				}				if ( conf.errOpacity !== undefined ) {					$("#err_"+id).children().css("opacity", conf.errOpacity);				}				if ( conf.errPosition === "absolute" ) {					if ( fnConfirmation(conf.customGetErrHeight) ) {						_this.customGetErrHeight(id);					} else {						_this.getErrHeight(id, conf.errZIndex);					}					// Reget the position					$(window).resize(function() {						if ( fnConfirmation(conf.customGetErrHeight) ) {							_this.customGetErrHeight(id);						} else {							_this.getErrHeight(id, conf.errZIndex);						}					});				}				$("#err_"+id).hide();			}		});		// Checkboxによる分岐		inputs.each(function() {			var _self = $(this),				reg1 = undefined,				reg2 = undefined,				toggleTarget = undefined;			if ( this.className.match(/chktoggle_([^_]+)_([^ ]+)/) ) {				reg1 = "#" + RegExp.$1;				reg2 = "#" + RegExp.$2;				toggleTarget = $(reg2).removeClass("chkrequired");				$(reg1).click(function() {					console.log(toggleTarget);					if ( this.checked ) {						toggleTarget.addClass("chkrequired");					} else {						toggleTarget.removeClass("chkrequired");					}					_this.laterCall(toggleTarget);				});			}			if ( conf.firstValidate ) return;			if ( _self.hasClass("chkgroup") ) {				bindValidateFuncs($(conf.groupInputs, _self), _self);			} else {				bindValidateFuncs(_self);			}		});		// You call this func everytime you like after init		this.laterCall = function(t) {			_this.basicValidate(t, conf.err, conf.ok);		};		function _exeValidation(customBindCallback) {			if ( conf.firstValidate ) {				inputs.unbind("blur keyup change click");				conf.firstValidate = false;			}			inputs.each(function() {				var self = $(this);				_this.basicValidate(this, conf.err, conf.ok, true);				if ( self.hasClass("chkgroup") ) {					bindValidateFuncs($(conf.groupInputs, self), self);				} else {					bindValidateFuncs(self);				}			});			var err = $(".formError:visible[class*='"+formID+"']");			// if errs are displayed			if ( err.length > 0 ) {				if ( fnConfirmation(conf.customAddError) ) {					conf.customAddError();				}				if ( conf.scrollToErr ) {					var reverseOffsetTop,						infoErr, errTop,						scrollTarget = $.support.boxModel							? navigator.appName.indexOf("Opera") !== -1 ?								"html" : "html,body"							: "body";					if ( !conf.customScrollAdjust ) {						reverseOffsetTop = $(err[0]).offset().top;						errTop = $(err[0]);						for ( var i=0, l=err.length; i<l; i++ ) {							infoErr = $(err[i]);							reverseOffsetTop = infoErr.offset().top < reverseOffsetTop								? infoErr.offset().top : reverseOffsetTop;							errTop = infoErr.offset().top < reverseOffsetTop								? infoErr : errTop;						}						if ( conf.errPosition === "fixed" ) {							reverseOffsetTop -= $("#"+errTop.attr("id").replace("err_", "")).get(0).offsetHeight;						}					} else {						reverseOffsetTop = fnConfirmation(conf.customScrollAdjust)							? parseFloat(conf.customScrollAdjust()) : parseFloat(conf.customScrollAdjust);					}					$(scrollTarget).animate({						scrollTop: reverseOffsetTop + conf.scrollAdjust					}, {						easing: $.easing.easeInOutCirc ? "easeInOutCirc" : "swing",						duration: conf.scrollDuration					});				}				return false;			// if no err is displayed			} else {				if ( fnConfirmation(conf.customClearError) ) {					// falseが返ってきた場合はキャンセルする					var result = conf.customClearError();					if ( !result ) return false;					// if ( result == false ) return false;				}				// CustomBindCallBack				if ( fnConfirmation(customBindCallback) ) {					customBindCallback();					return false;				} else {					// customSubmit					if ( fnConfirmation(conf.customSubmit) ) {						conf.customSubmit();						return false;					// Default Postback					} else {						// OK						return true;					}				}			}		}		// When the form is submited		form.submit(_exeValidation);		// Add the Validation		if ( conf.customBind ) {			conf.customBind.object.bind(conf.customBind.listener, function() {				_exeValidation(conf.customBind.callback);				return false;			});		}		// Return the instance		return this;	};		// Common prototype functions	exValidation.prototype = {		// Errtip content		// this HTML source code from "A jQuery inline form validation, because validation is a mess"		// thanks to http://bit.ly/onlNv (http://www.position-relative.net/)		generateErr: function(id, formID) {			return [				'<div id="err_'+id+'" class="formError userformError'+' '+formID+' '+this.conf.errPosition+'">',					'<div class="formErrorMsg formErrorContent"></div>',					'<div class="formErrorArrow">',						'<div class="line10"></div>',						'<div class="line9"></div>',						'<div class="line8"></div>',						'<div class="line7"></div>',						'<div class="line6"></div>',						'<div class="line5"></div>',						'<div class="line4"></div>',						'<div class="line3"></div>',						'<div class="line2"></div>',						'<div class="line1"></div>',					'</div>',				'</div>'			].join("");		},		// Insert error message		insertErrMsg: function(t, id, c, errMsg) {			var msgs = $(".errMsg", "#err_"+id),				returnFlg = true;			if ( msgs.length > 0 ) {				$.each(msgs, function() {					if ( $(this).hasClass(c) ) {						returnFlg = false;					}				});			}			if ( !returnFlg ) return false;			$(".formErrorMsg", "#err_"+id).append(				$("<span></span>")					.addClass("errMsg")					.addClass(c)					.text(errMsg)				);			this.getErrHeight(id);		},		// Basic get error height		getErrHeight: function(id, zIndex) {			if ( this.conf.errPosition !== "absolute" ) return false;			var input = $("#"+id),				err = $("#err_"+id),				target = input.is(":hidden") ? input.next() : input,				pos = target.offset();						if ( !!pos ) {				var left = target.hasClass("errPosRight")						? pos.left + target.get(0).offsetWidth - 40						: pos.left - 20;										err.css({					position: "absolute",					top: pos.top - err.get(0).offsetHeight,					left: left				});			}						if ( zIndex ) {				err.css("zIndex", zIndex);			}		},		// Basic validation		basicValidate: function(t, err, ok) {			var _t = $(t),				CL = _t.attr("class"),				chk = $.exValidationRules,				id = _t.attr("id"),				txt = "",				_this = this;						if ( _t.hasClass("chkgroup") ) {				var groupInputs = $(_this.conf.groupInputs, t);				groupInputs.each(function(i) {					var self = $(this);					txt += self.val();					if( CL.indexOf("chkemail") !== -1 && i==0 && self.val().length > 0 )						txt += "@";				});			} else {				txt = _t.val();			}			var check = {				isError: false,				failed: function(t, c) {					var msg = chk[c][0];					if ( c.match(/chkmin/i) && CL.match(/chkmin(\d+)/i) ) {						msg = RegExp.$1 + msg;					} else					if ( c.match(/chkmax/i) && CL.match(/chkmax(\d+)/i) ) {						msg = RegExp.$1 + msg;					}										if( fnConfirmation(err) ) {						err(t, id, _this.conf.errMsgPrefix + msg);					} else {						_t.addClass("err");						$("."+c, "#err_"+id).show();						$("#err_"+id).fadeIn();						_this.insertErrMsg(t, id, c, _this.conf.errMsgPrefix + msg);						_this.getErrHeight(id);					}					this.isError = true;				}			};			var c;			for ( c in chk ) {				if ( _t.hasClass(c)				|| (c === "chkmin" && CL.match(/(?:\s+|^)chkmin\d+(?:\s+|$)/) )				|| (c === "chkmax" && CL.match(/(?:\s+|^)chkmax\d+(?:\s+|$)/) )				|| ( CL.indexOf(c) !== -1 && CL.indexOf("chkretype") !== -1 ) ) {					if ( typeof(chk[c][1]) !== "function" ) {						if ( !txt.match(chk[c][1]) ) {							check.failed(t, c);						} else						if ( _this.conf.stepValidation ) {							if ( $(".errMsg:visible", "#err_"+id).length > 1 ) {								$("."+c, "#err_"+id).hide();								_this.getErrHeight(id);							}						}					} else {						if ( !chk[c][1](txt, t) ) {							check.failed(t, c);						} else						if ( _this.conf.stepValidation ) {							if ( $(".errMsg:visible", "#err_"+id).length > 1 ) {								$("."+c, "#err_"+id).hide();								_this.getErrHeight(id);							}						}					}				}			}						if ( !check.isError ) {				if ( fnConfirmation(ok) ) {					ok(t, id);				} else {					_t.removeClass("err");					$("#err_"+id).fadeOut();				}			}		}	}		// Common functions	function returnReg() {		var validationClasses = "";		for( var c in $.exValidationRules ) {			validationClasses += "(?:\\s+|^)"+c+"(?:\\s+|$)|";		}		validationClasses += "(?:\\s+|^)chkmin\\d+(?:\\s+|$)|";		validationClasses += "(?:\\s+|^)chkmax\\d+(?:\\s+|$)|";		validationClasses = validationClasses.replace(/\|$/,"");		return new RegExp(validationClasses);	}	function errFocusClear(errZIndex) {		$(".formError")			.removeClass("fadeOut")			.css("zIndex", errZIndex)	}	function errFocus(id, errZIndex) {		var formError = $(".formError");		formError.removeClass("fadeOut").css("zIndex", errZIndex);		formError.not(id).addClass("fadeOut");		$(id).css({			zIndex: errZIndex + 100		});	}	function fnConfirmation(fn) {		return fn && typeof fn === "function";	}	function randomInt() {		return Math.floor(Math.random()*10)+1;	}		// Extense the namespace of jQuery as method	// This function returns instance	$.fn.exValidation = function(options) {		return new exValidation(this, options);	};	if ( !$.fn.validation ) {		$.fn.validation = $.fn.exValidation;	}})(jQuery, this);
