| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885 | /* * Inline Form Validation Engine 2.5.5.1, jQuery plugin * * Copyright(c) 2010, Cedric Dugas * http://www.position-absolute.com * * 2.0 Rewrite by Olivier Refalo * http://www.crionics.com * * Form validation engine allowing custom regex rules to be added. * Licensed under the MIT License */ (function($) {	 "use strict";	 var methods = {		 /**		 * Kind of the constructor, called before any action		 * @param {Map} user options		 */		 init: function(options) {			 var form = this;			 if (!form.data('jqv') || form.data('jqv') == null ) {				 options = methods._saveOptions(form, options);				 // bind all formError elements to close on click				 $(".formError").on("click", function() {					 $(this).fadeOut(150, function() {						 // remove prompt once invisible						 $(this).parent('.formErrorOuter').remove();						 $(this).remove();					 });				 });			 }			 return this;		 },		/**		* Attachs jQuery.validationEngine to form.submit and field.blur events		* Takes an optional params: a list of options		* ie. jQuery("#formID1").validationEngine('attach', {promptPosition : "centerRight"});		*/		attach: function(userOptions) {			if(!$(this).is("form")) {				alert("Sorry, jqv.attach() only applies to a form");				return this;			}						var form = this;			var options;			if(userOptions)				options = methods._saveOptions(form, userOptions);			else				options = form.data('jqv');			options.validateAttribute = (form.find("[data-validation-engine*=validate]").length) ? "data-validation-engine" : "class";			if (options.binded) {				// bind fields				form.find("["+options.validateAttribute+"*=validate]").not("[type=checkbox]").not("[type=radio]").not(".datepicker").bind(options.validationEventTrigger, methods._onFieldEvent);				form.find("["+options.validateAttribute+"*=validate][type=checkbox],["+options.validateAttribute+"*=validate][type=radio]").bind("click", methods._onFieldEvent);				form.find("["+options.validateAttribute+"*=validate][class*=datepicker]").bind(options.validationEventTrigger,{"delay": 300}, methods._onFieldEvent);			}			if (options.autoPositionUpdate) {				$(window).bind("resize", {					"noAnimation": true,					"formElem": form				}, methods.updatePromptsPosition);			}			// bind form.submit			form.bind("submit", methods._onSubmitEvent);			return this;		},		/**		* Unregisters any bindings that may point to jQuery.validaitonEngine		*/		detach: function() {						if(!$(this).is("form")) {				alert("Sorry, jqv.detach() only applies to a form");				return this;			}			var form = this;			var options = form.data('jqv');			// unbind fields			form.find("["+options.validateAttribute+"*=validate]").not("[type=checkbox]").unbind(options.validationEventTrigger, methods._onFieldEvent);			form.find("["+options.validateAttribute+"*=validate][type=checkbox],[class*=validate][type=radio]").unbind("click", methods._onFieldEvent);			// unbind form.submit			form.unbind("submit", methods.onAjaxFormComplete);			// unbind live fields (kill)			form.find("["+options.validateAttribute+"*=validate]").not("[type=checkbox]").die(options.validationEventTrigger, methods._onFieldEvent);			form.find("["+options.validateAttribute+"*=validate][type=checkbox]").die("click", methods._onFieldEvent);			// unbind form.submit			form.die("submit", methods.onAjaxFormComplete);			form.removeData('jqv');			if (options.autoPositionUpdate)				$(window).unbind("resize", methods.updatePromptsPosition);			return this;		},		/**		* Validates either a form or a list of fields, shows prompts accordingly.		* Note: There is no ajax form validation with this method, only field ajax validation are evaluated		*		* @return true if the form validates, false if it fails		*/		validate: function() {			if($(this).is("form"))				return methods._validateFields(this);			else {				// field validation				var form = $(this).closest('form');				var options = form.data('jqv');  				var r = methods._validateField($(this), options);				if (options.onSuccess && options.InvalidFields.length == 0)					options.onSuccess();				else if (options.onFailure && options.InvalidFields.length > 0)					options.onFailure();				return r;			}		},		/**		*  Redraw prompts position, useful when you change the DOM state when validating		*/		updatePromptsPosition: function(event) {			if (event && this == window) {				var form = event.data.formElem;				var noAnimation = event.data.noAnimation;			}			else				var form = $(this.closest('form'));			var options = form.data('jqv');			// No option, take default one			form.find('['+options.validateAttribute+'*=validate]').not(":disabled").each(function(){				var field = $(this);				var prompt = methods._getPrompt(field);				var promptText = $(prompt).find(".formErrorContent").html();				if(prompt)					methods._updatePrompt(field, $(prompt), promptText, undefined, false, options, noAnimation);			});			return this;		},		/**		* Displays a prompt on a element.		* Note that the element needs an id!		*		* @param {String} promptText html text to display type		* @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)		* @param {String} possible values topLeft, topRight, bottomLeft, centerRight, bottomRight		*/		showPrompt: function(promptText, type, promptPosition, showArrow) {			var form = this.closest('form');			var options = form.data('jqv');			// No option, take default one			if(!options)				options = methods._saveOptions(this, options);			if(promptPosition)				options.promptPosition=promptPosition;			options.showArrow = showArrow==true;			methods._showPrompt(this, promptText, type, false, options);			return this;		},		/**		* Closes form error prompts, CAN be invidual		*/		hide: function() {			 var form = $(this).closest('form');			 if(form.length == 0)				return this;			 var options = form.data('jqv');			 var closingtag;			 if($(this).is("form")) {				 closingtag = "parentForm"+methods._getClassName($(this).attr("id"));			 } else {				 closingtag = methods._getClassName($(this).attr("id")) +"formError";			 }			 $('.'+closingtag).fadeTo(options.fadeDuration, 0.3, function() {				 $(this).parent('.formErrorOuter').remove();				 $(this).remove();			 });			 return this;		 },		 /**		 * Closes all error prompts on the page		 */		 hideAll: function() {			 var form = this;			 var options = form.data('jqv');			 var duration = options ? options.fadeDuration:0.3;			 $('.formError').fadeTo(duration, 0.3, function() {				 $(this).parent('.formErrorOuter').remove();				 $(this).remove();			 });			 return this;		 },		/**		* Typically called when user exists a field using tab or a mouse click, triggers a field		* validation		*/		_onFieldEvent: function(event) {			var field = $(this);			var form = field.closest('form');			var options = form.data('jqv');			options.eventTrigger = "field";			// validate the current field			window.setTimeout(function() {				methods._validateField(field, options);				if (options.InvalidFields.length == 0 && options.onSuccess) {					options.onSuccess();				} else if (options.InvalidFields.length > 0 && options.onFailure) {					options.onFailure();				}			}, (event.data) ? event.data.delay : 0);		},		/**		* Called when the form is submited, shows prompts accordingly		*		* @param {jqObject}		*            form		* @return false if form submission needs to be cancelled		*/		_onSubmitEvent: function() {			var form = $(this);			var options = form.data('jqv');			options.eventTrigger = "submit";			// validate each field 			// (- skip field ajax validation, not necessary IF we will perform an ajax form validation)			var r=methods._validateFields(form);			if (r && options.ajaxFormValidation) {				methods._validateFormWithAjax(form, options);				// cancel form auto-submission - process with async call onAjaxFormComplete				return false;			}			if(options.onValidationComplete) {				// !! ensures that an undefined return is interpreted as return false but allows a onValidationComplete() to possibly return true and have form continue processing				return !!options.onValidationComplete(form, r);			}			return r;		},		/**		* Return true if the ajax field validations passed so far		* @param {Object} options		* @return true, is all ajax validation passed so far (remember ajax is async)		*/		_checkAjaxStatus: function(options) {			var status = true;			$.each(options.ajaxValidCache, function(key, value) {				if (!value) {					status = false;					// break the each					return false;				}			});			return status;		},				/**		* Return true if the ajax field is validated		* @param {String} fieldid		* @param {Object} options		* @return true, if validation passed, false if false or doesn't exist		*/		_checkAjaxFieldStatus: function(fieldid, options) {			return options.ajaxValidCache[fieldid] == true;		},		/**		* Validates form fields, shows prompts accordingly		*		* @param {jqObject}		*            form		* @param {skipAjaxFieldValidation}		*            boolean - when set to true, ajax field validation is skipped, typically used when the submit button is clicked		*		* @return true if form is valid, false if not, undefined if ajax form validation is done		*/		_validateFields: function(form) {			var options = form.data('jqv');			// this variable is set to true if an error is found			var errorFound = false;			// Trigger hook, start validation			form.trigger("jqv.form.validating");			// first, evaluate status of non ajax fields			var first_err=null;			form.find('['+options.validateAttribute+'*=validate]').not(":disabled").each( function() {				var field = $(this);				var names = [];				if ($.inArray(field.attr('name'), names) < 0) {					errorFound |= methods._validateField(field, options);					if (errorFound && first_err==null)						if (field.is(":hidden") && options.prettySelect)                first_err = field = form.find("#" + options.usePrefix + field.attr('id') + options.useSuffix);            else                first_err=field;					if (options.doNotShowAllErrosOnSubmit)						return false;					names.push(field.attr('name'));				}			});			// second, check to see if all ajax calls completed ok			// errorFound |= !methods._checkAjaxStatus(options);			// third, check status and scroll the container accordingly			form.trigger("jqv.form.result", [errorFound]);			if (errorFound) {				if (options.scroll) {					var destination=first_err.offset().top;					var fixleft = first_err.offset().left;					//prompt positioning adjustment support. Usage: positionType:Xshift,Yshift (for ex.: bottomLeft:+20 or bottomLeft:-20,+10)					var positionType=options.promptPosition;					if (typeof(positionType)=='string' && positionType.indexOf(":")!=-1)						positionType=positionType.substring(0,positionType.indexOf(":"));					if (positionType!="bottomRight" && positionType!="bottomLeft") {						var prompt_err= methods._getPrompt(first_err);						//destination=prompt_err.offset().top;					}					// get the position of the first error, there should be at least one, no need to check this					//var destination = form.find(".formError:not('.greenPopup'):first").offset().top;					if (options.isOverflown) {						var overflowDIV = $(options.overflownDIV);						if(!overflowDIV.length) return false;						var scrollContainerScroll = overflowDIV.scrollTop();						var scrollContainerPos = -parseInt(overflowDIV.offset().top);						destination += scrollContainerScroll + scrollContainerPos - 5;						var scrollContainer = $(options.overflownDIV + ":not(:animated)");						scrollContainer.animate({ scrollTop: destination }, 1100, function(){							if(options.focusFirstField) first_err.focus();						});					} else {						$("html:not(:animated),body:not(:animated)").animate({							scrollTop: destination,							scrollLeft: fixleft						}, 1100, function(){							if(options.focusFirstField) first_err.focus();						});					}				} else if(options.focusFirstField)					first_err.focus();								if (options.onFailure) {					options.onFailure();				}				return false;			}			return true;		},		/**		* This method is called to perform an ajax form validation.		* During this process all the (field, value) pairs are sent to the server which returns a list of invalid fields or true		*		* @param {jqObject} form		* @param {Map} options		*/		_validateFormWithAjax: function(form, options) {			var data = form.serialize();                        	var type = (options.ajaxmethod) ? options.ajaxmethod : "GET";			var url = (options.ajaxFormValidationURL) ? options.ajaxFormValidationURL : form.attr("action");                        	var dataType = (options.dataType) ? options.dataType : "json";			$.ajax({				type: type,				url: url,				cache: false,				dataType: dataType,				data: data,				form: form,				methods: methods,				options: options,				beforeSend: function() {					return options.onBeforeAjaxFormValidation(form, options);				},				error: function(data, transport) {					methods._ajaxError(data, transport);				},				success: function(json) {					if (json !== true) {						// getting to this case doesn't necessary means that the form is invalid						// the server may return green or closing prompt actions						// this flag helps figuring it out						var errorInForm=false;						for (var i = 0; i < json.length; i++) {							var value = json[i];							var errorFieldId = value[0];							var errorField = $($("#" + errorFieldId)[0]);							// make sure we found the element							if (errorField.length == 1) {								// promptText or selector								var msg = value[2];								// if the field is valid								if (value[1] == true) {									if (msg == ""  || !msg){										// if for some reason, status==true and error="", just close the prompt										methods._closePrompt(errorField);									} else {										// the field is valid, but we are displaying a green prompt										if (options.allrules[msg]) {											var txt = options.allrules[msg].alertTextOk;											if (txt)												msg = txt;										}										methods._showPrompt(errorField, msg, "pass", false, options, true);									}								} else {									// the field is invalid, show the red error prompt									errorInForm|=true;									if (options.allrules[msg]) {										var txt = options.allrules[msg].alertText;										if (txt)											msg = txt;									}									methods._showPrompt(errorField, msg, "", false, options, true);								}							}						}						options.onAjaxFormComplete(!errorInForm, form, json, options);					} else						options.onAjaxFormComplete(true, form, "", options);				}			});		},		/**		* Validates field, shows prompts accordingly		*		* @param {jqObject}		*            field		* @param {Array[String]}		*            field's validation rules		* @param {Map}		*            user options		* @return false if field is valid (It is inversed for *fields*, it return false on validate and true on errors.)		*/		_validateField: function(field, options, skipAjaxValidation) {			if (!field.attr("id")) {				field.attr("id", "form-validation-field-" + $.validationEngine.fieldIdCounter);				++$.validationEngine.fieldIdCounter;			}			if (field.is(":hidden") && !options.prettySelect || field.parent().is(":hidden"))				return false;			var rulesParsing = field.attr(options.validateAttribute);			var getRules = /validate\[(.*)\]/.exec(rulesParsing);			if (!getRules)				return false;			var str = getRules[1];			var rules = str.split(/\[|,|\]/);			// true if we ran the ajax validation, tells the logic to stop messing with prompts			var isAjaxValidator = false;			var fieldName = field.attr("name");			var promptText = "";			var promptType = "";			var required = false;			options.isError = false;			options.showArrow = true;			var form = $(field.closest("form"));			for (var i = 0; i < rules.length; i++) {				// Fix for adding spaces in the rules				rules[i] = rules[i].replace(" ", ""); 				var errorMsg = undefined;				switch (rules[i]) {					case "required":						required = true;						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._required);						break;					case "custom":						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._custom);						break;					case "groupRequired":						// Check is its the first of group, if not, reload validation with first field						// AND continue normal validation on present field						var classGroup = "["+options.validateAttribute+"*=" +rules[i + 1] +"]";						var firstOfGroup = form.find(classGroup).eq(0);						if(firstOfGroup[0] != field[0]){							methods._validateField(firstOfGroup, options, skipAjaxValidation); 							options.showArrow = true;							continue;						}						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._groupRequired);						if(errorMsg)  required = true;						options.showArrow = false;						break;					case "ajax":						// AJAX defaults to returning it's loading message						errorMsg = methods._ajax(field, rules, i, options);						if (errorMsg) {							promptType = "load";						}						break;					case "minSize":						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._minSize);						break;					case "maxSize":						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._maxSize);						break;					case "min":						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._min);						break;					case "max":						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._max);						break;					case "past":						errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._past);						break;					case "future":						errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._future);						break;					case "dateRange":						var classGroup = "["+options.validateAttribute+"*=" + rules[i + 1] + "]";						options.firstOfGroup = form.find(classGroup).eq(0);						options.secondOfGroup = form.find(classGroup).eq(1);						//if one entry out of the pair has value then proceed to run through validation						if (options.firstOfGroup[0].value || options.secondOfGroup[0].value) {							errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._dateRange);						}						if (errorMsg) required = true;						options.showArrow = false;						break;					case "dateTimeRange":						var classGroup = "["+options.validateAttribute+"*=" + rules[i + 1] + "]";						options.firstOfGroup = form.find(classGroup).eq(0);						options.secondOfGroup = form.find(classGroup).eq(1);						//if one entry out of the pair has value then proceed to run through validation						if (options.firstOfGroup[0].value || options.secondOfGroup[0].value) {							errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._dateTimeRange);						}						if (errorMsg) required = true;						options.showArrow = false;						break;					case "maxCheckbox":						field = $(form.find("input[name='" + fieldName + "']"));						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._maxCheckbox);						break;					case "minCheckbox":						field = $(form.find("input[name='" + fieldName + "']"));						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._minCheckbox);						break;					case "equals":						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._equals);						break;					case "funcCall":						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._funcCall);						break;					case "creditCard":						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._creditCard);						break;					case "condRequired":						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._condRequired);						if (errorMsg !== undefined) {							required = true;						}						break;					default:				}				if (errorMsg !== undefined) {					promptText += errorMsg.replace('* ', '') + " ";					options.isError = true;				}				//if option set, stop checking validation rules after one error is found				if(options.showOneMessage === true && options.isError === true)					break;			}			// If the rules required is not added, an empty field is not validated			if(!required && field.val().length < 1) options.isError = false;			// Hack for radio/checkbox group button, the validation go into the			// first radio/checkbox of the group			var fieldType = field.prop("type");			if ((fieldType == "radio" || fieldType == "checkbox") && form.find("input[name='" + fieldName + "']").size() > 1) {				field = $(form.find("input[name='" + fieldName + "'][type!=hidden]:first"));				options.showArrow = false;			}			if(field.is(":hidden") && options.prettySelect) {				field = form.find("#" + options.usePrefix + field.attr('id') + options.useSuffix);			}			if (options.isError){				methods._showPrompt(field, promptText, promptType, false, options);			}else{				if (!isAjaxValidator) methods._closePrompt(field);			}			if (!isAjaxValidator) {				field.trigger("jqv.field.result", [field, options.isError, promptText]);			}			/* Record error */			var errindex = $.inArray(field[0], options.InvalidFields);			if (errindex == -1) {				if (options.isError)				options.InvalidFields.push(field[0]);			} else if (!options.isError) {				options.InvalidFields.splice(errindex, 1);			}			return options.isError;		},		 /********************		  * _getErrorMessage		  *		  * @param form		  * @param field		  * @param rule		  * @param rules		  * @param i		  * @param options		  * @param originalValidationMethod		  * @return {*}		  * @private		  */		 _getErrorMessage:function (form, field, rule, rules, i, options, originalValidationMethod) {			 // If we are using the custon validation type, build the index for the rule.			 // Otherwise if we are doing a function call, make the call and return the object			 // that is passed back.			 var beforeChangeRule = rule;			 if (rule == "custom") {				 var custom_validation_type_index = jQuery.inArray(rule, rules)+ 1;				 var custom_validation_type = rules[custom_validation_type_index];				 rule = "custom[" + custom_validation_type + "]";			 }			 var element_classes = (field.attr("data-validation-engine")) ? field.attr("data-validation-engine") : field.attr("class");			 var element_classes_array = element_classes.split(" ");			 // Call the original validation method. If we are dealing with dates, also pass the form			 var errorMsg;			 if (rule == "future" || rule == "past"  || rule == "maxCheckbox" || rule == "minCheckbox") {				 errorMsg = originalValidationMethod(form, field, rules, i, options);			 } else {				 errorMsg = originalValidationMethod(field, rules, i, options);			 }			 // If the original validation method returned an error and we have a custom error message,			 // return the custom message instead. Otherwise return the original error message.			 if (errorMsg != undefined) {				 var custom_message = methods._getCustomErrorMessage($(field), element_classes_array, beforeChangeRule, options);				 if (custom_message) return custom_message;			 }			 return errorMsg;		 },		 _getCustomErrorMessage:function (field, classes, rule, options) {			var custom_message = false;			var validityProp = methods._validityProp[rule];			if (validityProp != undefined) {				custom_message = field.attr("data-errormessage-"+validityProp);				if (custom_message != undefined) 					return custom_message;			}			custom_message = field.attr("data-errormessage");			if (custom_message != undefined) 				return custom_message;			var id = '#' + field.attr("id");			// If we have custom messages for the element's id, get the message for the rule from the id.			// Otherwise, if we have custom messages for the element's classes, use the first class message we find instead.			if (typeof options.custom_error_messages[id] != "undefined" &&				typeof options.custom_error_messages[id][rule] != "undefined" ) {				        custom_message = options.custom_error_messages[id][rule]['message'];			} else if (classes.length > 0) {				for (var i = 0; i < classes.length && classes.length > 0; i++) {					 var element_class = "." + classes[i];					if (typeof options.custom_error_messages[element_class] != "undefined" &&						typeof options.custom_error_messages[element_class][rule] != "undefined") {							custom_message = options.custom_error_messages[element_class][rule]['message'];							break;					}				}			}			if (!custom_message &&				typeof options.custom_error_messages[rule] != "undefined" &&				typeof options.custom_error_messages[rule]['message'] != "undefined"){					 custom_message = options.custom_error_messages[rule]['message'];			 }			 return custom_message;		 },		 _validityProp: {			 "required": "value-missing",			 "custom": "custom-error",			 "groupRequired": "value-missing",			 "ajax": "custom-error",			 "minSize": "range-underflow",			 "maxSize": "range-overflow",			 "min": "range-underflow",			 "max": "range-overflow",			 "past": "type-mismatch",			 "future": "type-mismatch",			 "dateRange": "type-mismatch",			 "dateTimeRange": "type-mismatch",			 "maxCheckbox": "range-overflow",			 "minCheckbox": "range-underflow",			 "equals": "pattern-mismatch",			 "funcCall": "custom-error",			 "creditCard": "pattern-mismatch",			 "condRequired": "value-missing"		 },		/**		* Required validation		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		*            user options		* @return an error string if validation failed		*/		_required: function(field, rules, i, options) {			switch (field.prop("type")) {				case "text":				case "password":				case "textarea":				case "file":				case "select-one":				case "select-multiple":				default:					if (! $.trim(field.val()) || field.val() == field.attr("data-validation-placeholder") || field.val() == field.attr("placeholder"))						return options.allrules[rules[i]].alertText;					break;				case "radio":				case "checkbox":									var form = field.closest("form");					var name = field.attr("name");					if (form.find("input[name='" + name + "']:checked").size() == 0) 					{										if (form.find("input[name='" + name + "']").size() == 1)						{							return options.allrules[rules[i]].alertTextCheckboxe;						}						else						{														return options.allrules[rules[i]].alertTextCheckboxMultiple;						}					}					break;			}		},		/**		* Validate that 1 from the group field is required		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		*            user options		* @return an error string if validation failed		*/		_groupRequired: function(field, rules, i, options) {			var classGroup = "["+options.validateAttribute+"*=" +rules[i + 1] +"]";			var isValid = false;			// Check all fields from the group			field.closest("form").find(classGroup).each(function(){				if(!methods._required($(this), rules, i, options)){					isValid = true;					return false;				}			}); 			if(!isValid) {        return options.allrules[rules[i]].alertText;      }		},		/**		* Validate rules		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		*            user options		* @return an error string if validation failed		*/		_custom: function(field, rules, i, options) {			var customRule = rules[i + 1];			var rule = options.allrules[customRule];			var fn;			if(!rule) {				alert("jqv:custom rule not found - "+customRule);				return;			}						if(rule["regex"]) {				 var ex=rule.regex;					if(!ex) {						alert("jqv:custom regex not found - "+customRule);						return;					}					var pattern = new RegExp(ex);					if (!pattern.test(field.val())) return options.allrules[customRule].alertText;								} else if(rule["func"]) {				fn = rule["func"]; 				 				if (typeof(fn) !== "function") {					alert("jqv:custom parameter 'function' is no function - "+customRule);						return;				}				 				if (!fn(field, rules, i, options))					return options.allrules[customRule].alertText;			} else {				alert("jqv:custom type not allowed "+customRule);					return;			}		},		/**		* Validate custom function outside of the engine scope		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		*            user options		* @return an error string if validation failed		*/		_funcCall: function(field, rules, i, options) {			var functionName = rules[i + 1];			var fn;			if(functionName.indexOf('.') >-1)			{				var namespaces = functionName.split('.');				var scope = window;				while(namespaces.length)				{					scope = scope[namespaces.shift()];				}				fn = scope;			}			else				fn = window[functionName] || options.customFunctions[functionName];			if (typeof(fn) == 'function')				return fn(field, rules, i, options);		},		/**		* Field match		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		*            user options		* @return an error string if validation failed		*/		_equals: function(field, rules, i, options) {			var equalsField = rules[i + 1];			if (field.val() != $("#" + equalsField).val())				return options.allrules.equals.alertText;		},		/**		* Check the maximum size (in characters)		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		*            user options		* @return an error string if validation failed		*/		_maxSize: function(field, rules, i, options) {			var max = rules[i + 1];			var len = field.val().length;			if (len > max) {				var rule = options.allrules.maxSize;				//return rule.alertText + max + rule.alertText2;				return rule.alertText + rule.alertText2;			}		},		/**		* Check the minimum size (in characters)		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		*            user options		* @return an error string if validation failed		*/		_minSize: function(field, rules, i, options) {			var min = rules[i + 1];			var len = field.val().length;			if (len < min) {				var rule = options.allrules.minSize;				//return rule.alertText + min + rule.alertText2;				return rule.alertText + rule.alertText2;			}		},		/**		* Check number minimum value		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		*            user options		* @return an error string if validation failed		*/		_min: function(field, rules, i, options) {			var min = parseFloat(rules[i + 1]);			var len = parseFloat(field.val());			if (len < min) {				var rule = options.allrules.min;				if (rule.alertText2) return rule.alertText + min + rule.alertText2;				return rule.alertText + min;			}		},		/**		* Check number maximum value		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		*            user options		* @return an error string if validation failed		*/		_max: function(field, rules, i, options) {			var max = parseFloat(rules[i + 1]);			var len = parseFloat(field.val());			if (len >max ) {				var rule = options.allrules.max;				if (rule.alertText2) return rule.alertText + max + rule.alertText2;				//orefalo: to review, also do the translations				return rule.alertText + max;			}		},		/**		* Checks date is in the past		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		*            user options		* @return an error string if validation failed		*/		_past: function(form, field, rules, i, options) {			var p=rules[i + 1];			var fieldAlt = $(form.find("input[name='" + p.replace(/^#+/, '') + "']"));			var pdate;			if (p.toLowerCase() == "now") {				pdate = new Date();			} else if (undefined != fieldAlt.val()) {				if (fieldAlt.is(":disabled"))					return;				pdate = methods._parseDate(fieldAlt.val());			} else {				pdate = methods._parseDate(p);			}			var vdate = methods._parseDate(field.val());			if (vdate > pdate ) {				var rule = options.allrules.past;				if (rule.alertText2) return rule.alertText + methods._dateToString(pdate) + rule.alertText2;				return rule.alertText + methods._dateToString(pdate);			}		},		/**		* Checks date is in the future		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		*            user options		* @return an error string if validation failed		*/		_future: function(form, field, rules, i, options) {			var p=rules[i + 1];			var fieldAlt = $(form.find("input[name='" + p.replace(/^#+/, '') + "']"));			var pdate;			if (p.toLowerCase() == "now") {				pdate = new Date();			} else if (undefined != fieldAlt.val()) {				if (fieldAlt.is(":disabled"))					return;				pdate = methods._parseDate(fieldAlt.val());			} else {				pdate = methods._parseDate(p);			}			var vdate = methods._parseDate(field.val());			if (vdate < pdate ) {				var rule = options.allrules.future;				if (rule.alertText2)					return rule.alertText + methods._dateToString(pdate) + rule.alertText2;				return rule.alertText + methods._dateToString(pdate);			}		},		/**		* Checks if valid date		*		* @param {string} date string		* @return a bool based on determination of valid date		*/		_isDate: function (value) {			var dateRegEx = new RegExp(/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(?:(?:0?[1-9]|1[0-2])(\/|-)(?:0?[1-9]|1\d|2[0-8]))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(0?2(\/|-)29)(\/|-)(?:(?:0[48]00|[13579][26]00|[2468][048]00)|(?:\d\d)?(?:0[48]|[2468][048]|[13579][26]))$/);			return dateRegEx.test(value);		},		/**		* Checks if valid date time		*		* @param {string} date string		* @return a bool based on determination of valid date time		*/		_isDateTime: function (value){			var dateTimeRegEx = new RegExp(/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1}$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^((1[012]|0?[1-9]){1}\/(0?[1-9]|[12][0-9]|3[01]){1}\/\d{2,4}\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1})$/);			return dateTimeRegEx.test(value);		},		//Checks if the start date is before the end date		//returns true if end is later than start		_dateCompare: function (start, end) {			return (new Date(start.toString()) < new Date(end.toString()));		},		/**		* Checks date range		*		* @param {jqObject} first field name		* @param {jqObject} second field name		* @return an error string if validation failed		*/		_dateRange: function (field, rules, i, options) {			//are not both populated			if ((!options.firstOfGroup[0].value && options.secondOfGroup[0].value) || (options.firstOfGroup[0].value && !options.secondOfGroup[0].value)) {				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;			}			//are not both dates			if (!methods._isDate(options.firstOfGroup[0].value) || !methods._isDate(options.secondOfGroup[0].value)) {				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;			}			//are both dates but range is off			if (!methods._dateCompare(options.firstOfGroup[0].value, options.secondOfGroup[0].value)) {				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;			}		},		/**		* Checks date time range		*		* @param {jqObject} first field name		* @param {jqObject} second field name		* @return an error string if validation failed		*/		_dateTimeRange: function (field, rules, i, options) {			//are not both populated			if ((!options.firstOfGroup[0].value && options.secondOfGroup[0].value) || (options.firstOfGroup[0].value && !options.secondOfGroup[0].value)) {				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;			}			//are not both dates			if (!methods._isDateTime(options.firstOfGroup[0].value) || !methods._isDateTime(options.secondOfGroup[0].value)) {				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;			}			//are both dates but range is off			if (!methods._dateCompare(options.firstOfGroup[0].value, options.secondOfGroup[0].value)) {				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;			}		},		/**		* Max number of checkbox selected		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		*            user options		* @return an error string if validation failed		*/		_maxCheckbox: function(form, field, rules, i, options) {			var nbCheck = rules[i + 1];			var groupname = field.attr("name");			var groupSize = form.find("input[name='" + groupname + "']:checked").size();			if (groupSize > nbCheck) {				options.showArrow = false;				if (options.allrules.maxCheckbox.alertText2)					 return options.allrules.maxCheckbox.alertText + " " + nbCheck + " " + options.allrules.maxCheckbox.alertText2;				return options.allrules.maxCheckbox.alertText;			}		},		/**		* Min number of checkbox selected		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		*            user options		* @return an error string if validation failed		*/		_minCheckbox: function(form, field, rules, i, options) {			var nbCheck = rules[i + 1];			var groupname = field.attr("name");			var groupSize = form.find("input[name='" + groupname + "']:checked").size();			if (groupSize < nbCheck) {				options.showArrow = false;				return options.allrules.minCheckbox.alertText + " " + nbCheck + " " + options.allrules.minCheckbox.alertText2;			}		},		/**		* Checks that it is a valid credit card number according to the		* Luhn checksum algorithm.		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		*            user options		* @return an error string if validation failed		*/		_creditCard: function(field, rules, i, options) {			//spaces and dashes may be valid characters, but must be stripped to calculate the checksum.			var valid = false, cardNumber = field.val().replace(/ +/g, '').replace(/-+/g, '');			var numDigits = cardNumber.length;			if (numDigits >= 14 && numDigits <= 16 && parseInt(cardNumber) > 0) {				var sum = 0, i = numDigits - 1, pos = 1, digit, luhn = new String();				do {					digit = parseInt(cardNumber.charAt(i));					luhn += (pos++ % 2 == 0) ? digit * 2 : digit;				} while (--i >= 0)				for (i = 0; i < luhn.length; i++) {					sum += parseInt(luhn.charAt(i));				}				valid = sum % 10 == 0;			}			if (!valid) return options.allrules.creditCard.alertText;		},		/**		* Ajax field validation		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		*            user options		* @return nothing! the ajax validator handles the prompts itself		*/		 _ajax: function(field, rules, i, options) {			 var errorSelector = rules[i + 1];			 var rule = options.allrules[errorSelector];			 var extraData = rule.extraData;			 var extraDataDynamic = rule.extraDataDynamic;			 var data = {				"fieldId" : field.attr("id"),				"fieldValue" : field.val()			 };			 if (typeof extraData === "object") {				$.extend(data, extraData);			 } else if (typeof extraData === "string") {				var tempData = extraData.split("&");				for(var i = 0; i < tempData.length; i++) {					var values = tempData[i].split("=");					if (values[0] && values[0]) {						data[values[0]] = values[1];					}				}			 }			 if (extraDataDynamic) {				 var tmpData = [];				 var domIds = String(extraDataDynamic).split(",");				 for (var i = 0; i < domIds.length; i++) {					 var id = domIds[i];					 if ($(id).length) {						 var inputValue = field.closest("form").find(id).val();						 var keyValue = id.replace('#', '') + '=' + escape(inputValue);						 data[id.replace('#', '')] = inputValue;					 }				 }			 }			 			 // If a field change event triggered this we want to clear the cache for this ID			 if (options.eventTrigger == "field") {				delete(options.ajaxValidCache[field.attr("id")]);			 }			 // If there is an error or if the the field is already validated, do not re-execute AJAX			 if (!options.isError && !methods._checkAjaxFieldStatus(field.attr("id"), options)) {				 $.ajax({					 type: options.ajaxFormValidationMethod,					 url: rule.url,					 cache: false,					 dataType: "json",					 data: data,					 field: field,					 rule: rule,					 methods: methods,					 options: options,					 beforeSend: function() {},					 error: function(data, transport) {						 methods._ajaxError(data, transport);					 },					 success: function(json) {						 // asynchronously called on success, data is the json answer from the server						 var errorFieldId = json[0];						 //var errorField = $($("#" + errorFieldId)[0]);						 var errorField = $($("input[id='" + errorFieldId +"']")[0]);						 // make sure we found the element						 if (errorField.length == 1) {							 var status = json[1];							 // read the optional msg from the server							 var msg = json[2];							 if (!status) {								 // Houston we got a problem - display an red prompt								 options.ajaxValidCache[errorFieldId] = false;								 options.isError = true;								 // resolve the msg prompt								 if(msg) {									 if (options.allrules[msg]) {										 var txt = options.allrules[msg].alertText;										 if (txt) {											msg = txt;                     }									 }								 }								 else									msg = rule.alertText;								 methods._showPrompt(errorField, msg, "", true, options);							 } else {								 options.ajaxValidCache[errorFieldId] = true;								 // resolves the msg prompt								 if(msg) {									 if (options.allrules[msg]) {										 var txt = options.allrules[msg].alertTextOk;										 if (txt) {											msg = txt;                     }									 }								 }								 else								 msg = rule.alertTextOk;								 // see if we should display a green prompt								 if (msg)									methods._showPrompt(errorField, msg, "pass", true, options);								 else									methods._closePrompt(errorField);																 // If a submit form triggered this, we want to re-submit the form								 if (options.eventTrigger == "submit")									field.closest("form").submit();							 }						 }						 errorField.trigger("jqv.field.result", [errorField, options.isError, msg]);					 }				 });				 				 return rule.alertTextLoad;			 }		 },		/**		* Common method to handle ajax errors		*		* @param {Object} data		* @param {Object} transport		*/		_ajaxError: function(data, transport) {			if(data.status == 0 && transport == null)				alert("The page is not served from a server! ajax call failed");			else if(typeof console != "undefined")				console.log("Ajax error: " + data.status + " " + transport);		},		/**		* date -> string		*		* @param {Object} date		*/		_dateToString: function(date) {			return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate();		},		/**		* Parses an ISO date		* @param {String} d		*/		_parseDate: function(d) {			var dateParts = d.split("-");			if(dateParts==d)				dateParts = d.split("/");			return new Date(dateParts[0], (dateParts[1] - 1) ,dateParts[2]);		},		/**		* Builds or updates a prompt with the given information		*		* @param {jqObject} field		* @param {String} promptText html text to display type		* @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)		* @param {boolean} ajaxed - use to mark fields than being validated with ajax		* @param {Map} options user options		*/		 _showPrompt: function(field, promptText, type, ajaxed, options, ajaxform) {			 var prompt = methods._getPrompt(field);			 // The ajax submit errors are not see has an error in the form,			 // When the form errors are returned, the engine see 2 bubbles, but those are ebing closed by the engine at the same time			 // Because no error was found befor submitting			 if(ajaxform) prompt = false;			 			 if(options.promptType == 'diy' && (field.attr('type') == 'text' || field.attr('type') == 'password' || field.attr('type') == 'checkbox'))			{				// create the prompt				var prompt = $('<div>');				prompt.addClass(methods._getClassName(field.attr("id")) + "formError");				// add a class name to identify the parent form of the prompt				prompt.addClass("parentForm"+methods._getClassName(field.parents('form').attr("id")));				prompt.addClass("error-text");				prompt.html(promptText);				field.parent().find('.error-text').remove();				if(field.parent().attr('style') == 'font-size:16px;')				{					if(field.parent().parent().next().attr('class') != 'error-text')					{						field.parent().parent().after(prompt);					}				}				else if(field.next().length)				{					field.next().after(prompt);				}				else				{					field.after(prompt);				}								switch (type) {					case "pass":						prompt.addClass("greenPopup");						break;					case "load":						prompt.addClass("blackPopup");						break;					default:						/* it has error  */						//alert("unknown popup type:"+type);				}				if (ajaxed)				{					prompt.addClass("ajaxed");				}								if(type == 'pass')				{					prompt.hide();				}								return;			}			 if (prompt)				methods._updatePrompt(field, prompt, promptText, type, ajaxed, options);			 else				methods._buildPrompt(field, promptText, type, ajaxed, options);		 },		/**		* Builds and shades a prompt for the given field.		*		* @param {jqObject} field		* @param {String} promptText html text to display type		* @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)		* @param {boolean} ajaxed - use to mark fields than being validated with ajax		* @param {Map} options user options		*/		_buildPrompt: function(field, promptText, type, ajaxed, options) {						// create the prompt			var prompt = $('<div>');			prompt.addClass(methods._getClassName(field.attr("id")) + "formError");			// add a class name to identify the parent form of the prompt			prompt.addClass("parentForm"+methods._getClassName(field.parents('form').attr("id")));			prompt.addClass("formError");			switch (type) {				case "pass":					prompt.addClass("greenPopup");					break;				case "load":					prompt.addClass("blackPopup");					break;				default:					/* it has error  */					//alert("unknown popup type:"+type);			}			if (ajaxed)				prompt.addClass("ajaxed");			// create the prompt content			var promptContent = $('<div>').addClass("formErrorContent").html(promptText).appendTo(prompt);			// create the css arrow pointing at the field			// note that there is no triangle on max-checkbox and radio			if (options.showArrow) {				var arrow = $('<div>').addClass("formErrorArrow");				//prompt positioning adjustment support. Usage: positionType:Xshift,Yshift (for ex.: bottomLeft:+20 or bottomLeft:-20,+10)				var positionType=field.data("promptPosition") || options.promptPosition;				if (typeof(positionType)=='string') 				{					var pos=positionType.indexOf(":");					if(pos!=-1)						positionType=positionType.substring(0,pos);				}				switch (positionType) {					case "bottomLeft":					case "bottomRight":						prompt.find(".formErrorContent").before(arrow);						arrow.addClass("formErrorArrowBottom").html('<div class="line1"><!-- --></div><div class="line2"><!-- --></div><div class="line3"><!-- --></div><div class="line4"><!-- --></div><div class="line5"><!-- --></div><div class="line6"><!-- --></div><div class="line7"><!-- --></div><div class="line8"><!-- --></div><div class="line9"><!-- --></div><div class="line10"><!-- --></div>');						break;					case "topLeft":					case "topRight":						arrow.html('<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>');						prompt.append(arrow);						break;				}			}			// Modify z-indexes  for jquery ui			if (field.closest('.ui-dialog').length)				prompt.addClass('formErrorInsideDialog');			prompt.css({				"opacity": 0,				'position':'absolute'			});			field.before(prompt);						var pos = methods._calculatePosition(field, prompt, options);			prompt.css({				"top": pos.callerTopPosition,				"left": pos.callerleftPosition,				"marginTop": pos.marginTopSize,				"opacity": 0			}).data("callerField", field);			if (options.autoHidePrompt) {				setTimeout(function(){					prompt.animate({						"opacity": 0					},function(){						prompt.closest('.formErrorOuter').remove();						prompt.remove();					});				}, options.autoHideDelay);			} 			return prompt.animate({				"opacity": 0.87			});		},		/**		* Updates the prompt text field - the field for which the prompt		* @param {jqObject} field		* @param {String} promptText html text to display type		* @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)		* @param {boolean} ajaxed - use to mark fields than being validated with ajax		* @param {Map} options user options		*/		_updatePrompt: function(field, prompt, promptText, type, ajaxed, options, noAnimation) {			if (prompt) {				if (typeof type !== "undefined") {					if (type == "pass")						prompt.addClass("greenPopup");					else						prompt.removeClass("greenPopup");					if (type == "load")						prompt.addClass("blackPopup");					else						prompt.removeClass("blackPopup");				}				if (ajaxed)					prompt.addClass("ajaxed");				else					prompt.removeClass("ajaxed");				prompt.find(".formErrorContent").html(promptText);				var pos = methods._calculatePosition(field, prompt, options);				var css = {"top": pos.callerTopPosition,				"left": pos.callerleftPosition,				"marginTop": pos.marginTopSize};				if (noAnimation)					prompt.css(css);				else					prompt.animate(css);			}		},		/**		* Closes the prompt associated with the given field		*		* @param {jqObject}		*            field		*/		 _closePrompt: function(field) {			 var prompt = methods._getPrompt(field);			 if (prompt)				 prompt.fadeTo("fast", 0, function() {					 prompt.parent('.formErrorOuter').remove();					 prompt.remove();				 });		 },		 closePrompt: function(field) {			 return methods._closePrompt(field);		 },		/**		* Returns the error prompt matching the field if any		*		* @param {jqObject}		*            field		* @return undefined or the error prompt (jqObject)		*/		_getPrompt: function(field) {				var formId = $(field).closest('form').attr('id');			var className = methods._getClassName(field.attr("id")) + "formError";				var match = $("." + methods._escapeExpression(className) + '.parentForm' + formId)[0];			if (match)			return $(match);		},		/**		  * Returns the escapade classname		  *		  * @param {selector}		  *            className		  */		  _escapeExpression: function (selector) {			  return selector.replace(/([#;&,\.\+\*\~':"\!\^$\[\]\(\)=>\|])/g, "\\$1");		  },		/**		 * returns true if we are in a RTLed document		 *		 * @param {jqObject} field		 */		isRTL: function(field)		{			var $document = $(document);			var $body = $('body');			var rtl =				(field && field.hasClass('rtl')) ||				(field && (field.attr('dir') || '').toLowerCase()==='rtl') ||				$document.hasClass('rtl') ||				($document.attr('dir') || '').toLowerCase()==='rtl' ||				$body.hasClass('rtl') ||				($body.attr('dir') || '').toLowerCase()==='rtl';			return Boolean(rtl);		},		/**		* Calculates prompt position		*		* @param {jqObject}		*            field		* @param {jqObject}		*            the prompt		* @param {Map}		*            options		* @return positions		*/		_calculatePosition: function (field, promptElmt, options) {			var promptTopPosition, promptleftPosition, marginTopSize;			var fieldWidth 	= field.width();			var fieldLeft 	= field.position().left; 			var fieldTop 	=  field.position().top;			var fieldHeight 	=  field.height();				var promptHeight = promptElmt.height();			// is the form contained in an overflown container?			promptTopPosition = promptleftPosition = 0;			// compensation for the arrow			marginTopSize = -promptHeight;					//prompt positioning adjustment support			//now you can adjust prompt position			//usage: positionType:Xshift,Yshift			//for example:			//   bottomLeft:+20 means bottomLeft position shifted by 20 pixels right horizontally			//   topRight:20, -15 means topRight position shifted by 20 pixels to right and 15 pixels to top			//You can use +pixels, - pixels. If no sign is provided than + is default.			var positionType=field.data("promptPosition") || options.promptPosition;			var shift1="";			var shift2="";			var shiftX=0;			var shiftY=0;			if (typeof(positionType)=='string') {				//do we have any position adjustments ?				if (positionType.indexOf(":")!=-1) {					shift1=positionType.substring(positionType.indexOf(":")+1);					positionType=positionType.substring(0,positionType.indexOf(":"));					//if any advanced positioning will be needed (percents or something else) - parser should be added here					//for now we use simple parseInt()					//do we have second parameter?					if (shift1.indexOf(",") !=-1) {						shift2=shift1.substring(shift1.indexOf(",") +1);						shift1=shift1.substring(0,shift1.indexOf(","));						shiftY=parseInt(shift2);						if (isNaN(shiftY)) shiftY=0;					};					shiftX=parseInt(shift1);					if (isNaN(shift1)) shift1=0;				};			};						switch (positionType) {				default:				case "topRight":					promptleftPosition +=  fieldLeft + fieldWidth - 30;					promptTopPosition +=  fieldTop;					break;				case "topLeft":					promptTopPosition +=  fieldTop;					promptleftPosition += fieldLeft; 					break;				case "centerRight":					promptTopPosition = fieldTop+4;					marginTopSize = 0;					promptleftPosition= fieldLeft + field.outerWidth(true)+5;					break;				case "centerLeft":					promptleftPosition = fieldLeft - (promptElmt.width() + 2);					promptTopPosition = fieldTop+4;					marginTopSize = 0;										break;				case "bottomLeft":					promptTopPosition = fieldTop + field.height() + 5;					marginTopSize = 0;					promptleftPosition = fieldLeft;					break;				case "bottomRight":					promptleftPosition = fieldLeft + fieldWidth - 30;					promptTopPosition =  fieldTop +  field.height() + 5;					marginTopSize = 0;			};					//apply adjusments if any			promptleftPosition += shiftX;			promptTopPosition  += shiftY;			return {				"callerTopPosition": promptTopPosition + "px",				"callerleftPosition": promptleftPosition + "px",				"marginTopSize": marginTopSize + "px"			};		},		/**		* Saves the user options and variables in the form.data		*		* @param {jqObject}		*            form - the form where the user option should be saved		* @param {Map}		*            options - the user options		* @return the user options (extended from the defaults)		*/		 _saveOptions: function(form, options) {			 // is there a language localisation ?			 if ($.validationEngineLanguage)			 var allRules = $.validationEngineLanguage.allRules;			 else			 $.error("jQuery.validationEngine rules are not loaded, plz add localization files to the page");			 // --- Internals DO NOT TOUCH or OVERLOAD ---			 // validation rules and i18			 $.validationEngine.defaults.allrules = allRules;			 var userOptions = $.extend(true,{},$.validationEngine.defaults,options);			 form.data('jqv', userOptions);			 return userOptions;		 },		 /**		 * Removes forbidden characters from class name		 * @param {String} className		 */		 _getClassName: function(className) {			 if(className)				 return className.replace(/:/g, "_").replace(/\./g, "_");                 },		/**		* Conditionally required field		*		* @param {jqObject} field		* @param {Array[String]} rules		* @param {int} i rules index		* @param {Map}		* user options		* @return an error string if validation failed		*/		_condRequired: function(field, rules, i, options) {			var idx, dependingField;			for(idx = (i + 1); idx < rules.length; idx++) {				dependingField = jQuery("#" + rules[idx]).first();				/* Use _required for determining wether dependingField has a value.				 * There is logic there for handling all field types, and default value; so we won't replicate that here				 */				if (dependingField.length && methods._required(dependingField, ["required"], 0, options) == undefined) {					/* We now know any of the depending fields has a value,					 * so we can validate this field as per normal required code					 */					return methods._required(field, ["required"], 0, options);				}			}		}        };	 /**	 * Plugin entry point.	 * You may pass an action as a parameter or a list of options.	 * if none, the init and attach methods are being called.	 * Remember: if you pass options, the attached method is NOT called automatically	 *	 * @param {String}	 *            method (optional) action	 */	 $.fn.validationEngine = function(method) {		 var form = $(this);		 if(!form[0]) return form;  // stop here if the form does not exist		 if (typeof(method) == 'string' && method.charAt(0) != '_' && methods[method]) {			 // make sure init is called once			 if(method != "showPrompt" && method != "hide" && method != "hideAll")			 methods.init.apply(form);			 return methods[method].apply(form, Array.prototype.slice.call(arguments, 1));		 } else if (typeof method == 'object' || !method) {			 // default constructor with or without arguments			 methods.init.apply(form, arguments);			 return methods.attach.apply(form);		 } else {			 $.error('Method ' + method + ' does not exist in jQuery.validationEngine');		 }	};	// LEAK GLOBAL OPTIONS	$.validationEngine= {fieldIdCounter: 0,defaults:{		// Name of the event triggering field validation		validationEventTrigger: "blur",		// Automatically scroll viewport to the first error		scroll: true,		// Focus on the first input		focusFirstField:true,		// Opening box position, possible locations are: topLeft,		// topRight, bottomLeft, centerRight, bottomRight		promptPosition: "topRight",		promptType:'',		bindMethod:"bind",		// internal, automatically set to true when it parse a _ajax rule		inlineAjax: false,		// if set to true, the form data is sent asynchronously via ajax to the form.action url (get)		ajaxFormValidation: false,		// The url to send the submit ajax validation (default to action)		ajaxFormValidationURL: false,		// HTTP method used for ajax validation		ajaxFormValidationMethod: 'get',		// Ajax form validation callback method: boolean onComplete(form, status, errors, options)		// retuns false if the form.submit event needs to be canceled.		onAjaxFormComplete: $.noop,		// called right before the ajax call, may return false to cancel		onBeforeAjaxFormValidation: $.noop,		// Stops form from submitting and execute function assiciated with it		onValidationComplete: false,		// Used when you have a form fields too close and the errors messages are on top of other disturbing viewing messages		doNotShowAllErrosOnSubmit: false,		// Object where you store custom messages to override the default error messages		custom_error_messages:{},		// true if you want to vind the input fields		binded: true,		// set to true, when the prompt arrow needs to be displayed		showArrow: true,		// did one of the validation fail ? kept global to stop further ajax validations		isError: false,		// Caches field validation status, typically only bad status are created.		// the array is used during ajax form validation to detect issues early and prevent an expensive submit		ajaxValidCache: {},		// Auto update prompt position after window resize		autoPositionUpdate: false,		InvalidFields: [],		onSuccess: false,		onFailure: false,		// Auto-hide prompt		autoHidePrompt: false,		// Delay before auto-hide		autoHideDelay: 10000,		// Fade out duration while hiding the validations		fadeDuration: 0.3,    // Use Prettify select library    prettySelect: false,    // Custom ID uses prefix    usePrefix: "",    // Custom ID uses suffix    useSuffix: "",    // Only show one message per error prompt    showOneMessage: false	}};	$(function(){$.validationEngine.defaults.promptPosition = methods.isRTL()?'topLeft':"topRight"});})(jQuery);
 |