PageSourceSearch

https://www.wensotti.com/scripts/validationEngine/jquery.validationEngine.js

js wensotti.com collected 2026-10-04 23:11:15 UTC 72,979 bytes, 2,079 lines download raw bytes

1/*
2 * Inline Form Validation Engine 2.6.2, jQuery plugin
3 *
4 * Copyright(c) 2010, Cedric Dugas
5 * http://www.position-absolute.com
6 *
7 * 2.0 Rewrite by Olivier Refalo
8 * http://www.crionics.com
9 *
10 * Form validation engine allowing custom regex rules to be added.
11 * Licensed under the MIT License
12 */
13 (function($) {
14
15	"use strict";
16
17	var methods = {
18
19		/**
20		* Kind of the constructor, called before any action
21		* @param {Map} user options
22		*/
23		init: function(options) {
24			var form = this;
25			if (!form.data('jqv') || form.data('jqv') == null ) {
26				options = methods._saveOptions(form, options);
27				// bind all formError elements to close on click
28				$(document).on("click", ".formError", function() {
29					$(this).fadeOut(150, function() {
30						// remove prompt once invisible
31						$(this).parent('.formErrorOuter').remove();
32						$(this).remove();
33					});
34				});
35			}
36			return this;
37		 },
38		/**
39		* Attachs jQuery.validationEngine to form.submit and field.blur events
40		* Takes an optional params: a list of options
41		* ie. jQuery("#formID1").validationEngine('attach', {promptPosition : "centerRight"});
42		*/
43		attach: function(userOptions) {
44
45			var form = this;
46			var options;
47
48			if(userOptions)
49				options = methods._saveOptions(form, userOptions);
50			else
51				options = form.data('jqv');
52
53			options.validateAttribute = (form.find("[data-validation-engine*=validate]").length) ? "data-validation-engine" : "class";
54			if (options.binded) {
55
56				// delegate fields
57				form.on(options.validationEventTrigger, "["+options.validateAttribute+"*=validate]:not([type=checkbox]):not([type=radio]):not(.datepicker)", methods._onFieldEvent);
58				form.on("click", "["+options.validateAttribute+"*=validate][type=checkbox],["+options.validateAttribute+"*=validate][type=radio]", methods._onFieldEvent);
59				form.on(options.validationEventTrigger,"["+options.validateAttribute+"*=validate][class*=datepicker]", {"delay": 300}, methods._onFieldEvent);
60			}
61			if (options.autoPositionUpdate) {
62				$(window).bind("resize", {
63					"noAnimation": true,
64					"formElem": form
65				}, methods.updatePromptsPosition);
66			}
67			form.on("click","a[data-validation-engine-skip], a[class*='validate-skip'], button[data-validation-engine-skip], button[class*='validate-skip'], input[data-validation-engine-skip], input[class*='validate-skip']", methods._submitButtonClick);
68			form.removeData('jqv_submitButton');
69
70			// bind form.submit
71			form.on("submit", methods._onSubmitEvent);
72			return this;
73		},
74		/**
75		* Unregisters any bindings that may point to jQuery.validaitonEngine
76		*/
77		detach: function() {
78
79			var form = this;
80			var options = form.data('jqv');
81
82			// unbind fields
83			form.find("["+options.validateAttribute+"*=validate]").not("[type=checkbox]").off(options.validationEventTrigger, methods._onFieldEvent);
84			form.find("["+options.validateAttribute+"*=validate][type=checkbox],[class*=validate][type=radio]").off("click", methods._onFieldEvent);
85
86			// unbind form.submit
87			form.off("submit", methods._onSubmitEvent);
88			form.removeData('jqv');
89            
90			form.off("click", "a[data-validation-engine-skip], a[class*='validate-skip'], button[data-validation-engine-skip], button[class*='validate-skip'], input[data-validation-engine-skip], input[class*='validate-skip']", methods._submitButtonClick);
91			form.removeData('jqv_submitButton');
92
93			if (options.autoPositionUpdate)
94				$(window).off("resize", methods.updatePromptsPosition);
95
96			return this;
97		},
98		/**
99		* Validates either a form or a list of fields, shows prompts accordingly.
100		* Note: There is no ajax form validation with this method, only field ajax validation are evaluated
101		*
102		* @return true if the form validates, false if it fails
103		*/
104		validate: function() {
105			var element = $(this);
106			var valid = null;
107
108			if (element.is("form") || element.hasClass("validationEngineContainer")) {
109				if (element.hasClass('validating')) {
110					// form is already validating.
111					// Should abort old validation and start new one. I don't know how to implement it.
112					return false;
113				} else {				
114					element.addClass('validating');
115					var options = element.data('jqv');
116					var valid = methods._validateFields(this);
117
118					// If the form doesn't validate, clear the 'validating' class before the user has a chance to submit again
119					setTimeout(function(){
120						element.removeClass('validating');
121					}, 100);
122					if (valid && options.onSuccess) {
123						options.onSuccess();
124					} else if (!valid && options.onFailure) {
125						options.onFailure();
126					}
127				}
128			} else if (element.is('form') || element.hasClass('validationEngineContainer')) {
129				element.removeClass('validating');
130			} else {
131				// field validation
132				var form = element.closest('form, .validationEngineContainer'),
133					options = (form.data('jqv')) ? form.data('jqv') : $.validationEngine.defaults,
134					valid = methods._validateField(element, options);
135
136				if (valid && options.onFieldSuccess)
137					options.onFieldSuccess();
138				else if (options.onFieldFailure && options.InvalidFields.length > 0) {
139					options.onFieldFailure();
140				}
141			}
142			if(options.onValidationComplete) {
143				// !! ensures that an undefined return is interpreted as return false but allows a onValidationComplete() to possibly return true and have form continue processing
144				return !!options.onValidationComplete(form, valid);
145			}
146			return valid;
147		},
148		/**
149		*  Redraw prompts position, useful when you change the DOM state when validating
150		*/
151		updatePromptsPosition: function(event) {
152
153			if (event && this == window) {
154				var form = event.data.formElem;
155				var noAnimation = event.data.noAnimation;
156			}
157			else
158				var form = $(this.closest('form, .validationEngineContainer'));
159
160			var options = form.data('jqv');
161			// No option, take default one
162			form.find('['+options.validateAttribute+'*=validate]').not(":disabled").each(function(){
163				var field = $(this);
164				if (options.prettySelect && field.is(":hidden"))
165				  field = form.find("#" + options.usePrefix + field.attr('id') + options.useSuffix);
166				var prompt = methods._getPrompt(field);
167				var promptText = $(prompt).find(".formErrorContent").html();
168
169				if(prompt)
170					methods._updatePrompt(field, $(prompt), promptText, undefined, false, options, noAnimation);
171			});
172			return this;
173		},
174		/**
175		* Displays a prompt on a element.
176		* Note that the element needs an id!
177		*
178		* @param {String} promptText html text to display type
179		* @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
180		* @param {String} possible values topLeft, topRight, bottomLeft, centerRight, bottomRight
181		*/
182		showPrompt: function(promptText, type, promptPosition, showArrow) {
183			var form = this.closest('form, .validationEngineContainer');
184			var options = form.data('jqv');
185			// No option, take default one
186			if(!options)
187				options = methods._saveOptions(this, options);
188			if(promptPosition)
189				options.promptPosition=promptPosition;
190			options.showArrow = showArrow==true;
191
192			methods._showPrompt(this, promptText, type, false, options);
193			return this;
194		},
195		/**
196		* Closes form error prompts, CAN be invidual
197		*/
198		hide: function() {
199			 var form = $(this).closest('form, .validationEngineContainer');
200			 var options = form.data('jqv');
201			 var fadeDuration = (options && options.fadeDuration) ? options.fadeDuration : 0.3;
202			 var closingtag;
203			 
204			 if($(this).is("form") || $(this).hasClass("validationEngineContainer")) {
205				 closingtag = "parentForm"+methods._getClassName($(this).attr("id"));
206			 } else {
207				 closingtag = methods._getClassName($(this).attr("id")) +"formError";
208			 }
209			 $('.'+closingtag).fadeTo(fadeDuration, 0.3, function() {
210				 $(this).parent('.formErrorOuter').remove();
211				 $(this).remove();
212			 });
213			 return this;
214		 },
215		 /**
216		 * Closes all error prompts on the page
217		 */
218		 hideAll: function() {
219
220			 var form = this;
221			 var options = form.data('jqv');
222			 var duration = options ? options.fadeDuration:300;
223			 $('.formError').fadeTo(duration, 300, function() {
224				 $(this).parent('.formErrorOuter').remove();
225				 $(this).remove();
226			 });
227			 return this;
228		 },
229		/**
230		* Typically called when user exists a field using tab or a mouse click, triggers a field
231		* validation
232		*/
233		_onFieldEvent: function(event) {
234			var field = $(this);
235			var form = field.closest('form, .validationEngineContainer');
236			var options = form.data('jqv');
237			options.eventTrigger = "field";
238			// validate the current field
239			window.setTimeout(function() {
240				methods._validateField(field, options);
241				if (options.InvalidFields.length == 0 && options.onFieldSuccess) {
242					options.onFieldSuccess();
243				} else if (options.InvalidFields.length > 0 && options.onFieldFailure) {
244					options.onFieldFailure();
245				}
246			}, (event.data) ? event.data.delay : 0);
247
248		},
249		/**
250		* Called when the form is submited, shows prompts accordingly
251		*
252		* @param {jqObject}
253		*            form
254		* @return false if form submission needs to be cancelled
255		*/
256		_onSubmitEvent: function() {
257			var form = $(this);
258			var options = form.data('jqv');
259			
260			//check if it is trigger from skipped button
261			if (form.data("jqv_submitButton")){
262				var submitButton = $("#" + form.data("jqv_submitButton"));
263				if (submitButton){
264					if (submitButton.length > 0){
265						if (submitButton.hasClass("validate-skip") || submitButton.attr("data-validation-engine-skip") == "true")
266							return true;
267					}
268				}
269			}
270
271			options.eventTrigger = "submit";
272
273			// validate each field 
274			// (- skip field ajax validation, not necessary IF we will perform an ajax form validation)
275			var r=methods._validateFields(form);
276
277			if (r && options.ajaxFormValidation) {
278				methods._validateFormWithAjax(form, options);
279				// cancel form auto-submission - process with async call onAjaxFormComplete
280				return false;
281			}
282
283			if(options.onValidationComplete) {
284				// !! ensures that an undefined return is interpreted as return false but allows a onValidationComplete() to possibly return true and have form continue processing
285				return !!options.onValidationComplete(form, r);
286			}
287			return r;
288		},
289		/**
290		* Return true if the ajax field validations passed so far
291		* @param {Object} options
292		* @return true, is all ajax validation passed so far (remember ajax is async)
293		*/
294		_checkAjaxStatus: function(options) {
295			var status = true;
296			$.each(options.ajaxValidCache, function(key, value) {
297				if (!value) {
298					status = false;
299					// break the each
300					return false;
301				}
302			});
303			return status;
304		},
305		
306		/**
307		* Return true if the ajax field is validated
308		* @param {String} fieldid
309		* @param {Object} options
310		* @return true, if validation passed, false if false or doesn't exist
311		*/
312		_checkAjaxFieldStatus: function(fieldid, options) {
313			return options.ajaxValidCache[fieldid] == true;
314		},
315		/**
316		* Validates form fields, shows prompts accordingly
317		*
318		* @param {jqObject}
319		*            form
320		* @param {skipAjaxFieldValidation}
321		*            boolean - when set to true, ajax field validation is skipped, typically used when the submit button is clicked
322		*
323		* @return true if form is valid, false if not, undefined if ajax form validation is done
324		*/
325		_validateFields: function(form) {
326			var options = form.data('jqv');
327
328			// this variable is set to true if an error is found
329			var errorFound = false;
330
331			// Trigger hook, start validation
332			form.trigger("jqv.form.validating");
333			// first, evaluate status of non ajax fields
334			var first_err=null;
335			form.find('['+options.validateAttribute+'*=validate]').not(":disabled").each( function() {
336				var field = $(this);
337				var names = [];
338				if ($.inArray(field.attr('name'), names) < 0) {
339					errorFound |= methods._validateField(field, options);
340					if (errorFound && first_err==null)
341						if (field.is(":hidden") && options.prettySelect)
342							first_err = field = form.find("#" + options.usePrefix + methods._jqSelector(field.attr('id')) + options.useSuffix);
343						else {
344
345							//Check if we need to adjust what element to show the prompt on
346							//and and such scroll to instead
347							if(field.data('jqv-prompt-at') instanceof jQuery ){
348								field = field.data('jqv-prompt-at');
349							} else if(field.data('jqv-prompt-at')) {
350								field = $(field.data('jqv-prompt-at'));
351							}
352							first_err=field;
353						}
354					if (options.doNotShowAllErrosOnSubmit)
355						return false;
356					names.push(field.attr('name'));
357
358					//if option set, stop checking validation rules after one error is found
359					if(options.showOneMessage == true && errorFound){
360						return false;
361					}
362				}
363			});
364
365			// second, check to see if all ajax calls completed ok
366			// errorFound |= !methods._checkAjaxStatus(options);
367
368			// third, check status and scroll the container accordingly
369			form.trigger("jqv.form.result", [errorFound]);
370
371			if (errorFound) {
372				if (options.scroll) {
373					var destination=first_err.offset().top;
374					var fixleft = first_err.offset().left;
375
376					//prompt positioning adjustment support. Usage: positionType:Xshift,Yshift (for ex.: bottomLeft:+20 or bottomLeft:-20,+10)
377					var positionType=options.promptPosition;
378					if (typeof(positionType)=='string' && positionType.indexOf(":")!=-1)
379						positionType=positionType.substring(0,positionType.indexOf(":"));
380
381					if (positionType!="bottomRight" && positionType!="bottomLeft") {
382						var prompt_err= methods._getPrompt(first_err);
383						if (prompt_err) {
384							destination=prompt_err.offset().top;
385						}
386					}
387					
388					// Offset the amount the page scrolls by an amount in px to accomodate fixed elements at top of page
389					if (options.scrollOffset) {
390						destination -= options.scrollOffset;
391					}
392
393					// get the position of the first error, there should be at least one, no need to check this
394					//var destination = form.find(".formError:not('.greenPopup'):first").offset().top;
395					if (options.isOverflown) {
396						var overflowDIV = $(options.overflownDIV);
397						if(!overflowDIV.length) return false;
398						var scrollContainerScroll = overflowDIV.scrollTop();
399						var scrollContainerPos = -parseInt(overflowDIV.offset().top);
400
401						destination += scrollContainerScroll + scrollContainerPos - 5;
402						var scrollContainer = $(options.overflownDIV + ":not(:animated)");
403
404						scrollContainer.animate({ scrollTop: destination }, 1100, function(){
405							if(options.focusFirstField) first_err.focus();
406						});
407
408					} else {
409						$("html, body").animate({
410							scrollTop: destination
411						}, 1100, function(){
412							if(options.focusFirstField) first_err.focus();
413						});
414						$("html, body").animate({scrollLeft: fixleft},1100)
415					}
416
417				} else if(options.focusFirstField)
418					first_err.focus();
419				return false;
420			}
421			return true;
422		},
423		/**
424		* This method is called to perform an ajax form validation.
425		* During this process all the (field, value) pairs are sent to the server which returns a list of invalid fields or true
426		*
427		* @param {jqObject} form
428		* @param {Map} options
429		*/
430		_validateFormWithAjax: function(form, options) {
431
432			var data = form.serialize();
433									var type = (options.ajaxFormValidationMethod) ? options.ajaxFormValidationMethod : "GET";
434			var url = (options.ajaxFormValidationURL) ? options.ajaxFormValidationURL : form.attr("action");
435									var dataType = (options.dataType) ? options.dataType : "json";
436			$.ajax({
437				type: type,
438				url: url,
439				cache: false,
440				dataType: dataType,
441				data: data,
442				form: form,
443				methods: methods,
444				options: options,
445				beforeSend: function() {
446					return options.onBeforeAjaxFormValidation(form, options);
447				},
448				error: function(data, transport) {
449					if (options.onFailure) {
450						options.onFailure(data, transport);
451					} else {
452						methods._ajaxError(data, transport);
453					}
454				},
455				success: function(json) {
456					if ((dataType == "json") && (json !== true)) {
457						// getting to this case doesn't necessary means that the form is invalid
458						// the server may return green or closing prompt actions
459						// this flag helps figuring it out
460						var errorInForm=false;
461						for (var i = 0; i < json.length; i++) {
462							var value = json[i];
463
464							var errorFieldId = value[0];
465							var errorField = $($("#" + errorFieldId)[0]);
466
467							// make sure we found the element
468							if (errorField.length == 1) {
469
470								// promptText or selector
471								var msg = value[2];
472								// if the field is valid
473								if (value[1] == true) {
474
475									if (msg == ""  || !msg){
476										// if for some reason, status==true and error="", just close the prompt
477										methods._closePrompt(errorField);
478									} else {
479										// the field is valid, but we are displaying a green prompt
480										if (options.allrules[msg]) {
481											var txt = options.allrules[msg].alertTextOk;
482											if (txt)
483												msg = txt;
484										}
485										if (options.showPrompts) methods._showPrompt(errorField, msg, "pass", false, options, true);
486									}
487								} else {
488									// the field is invalid, show the red error prompt
489									errorInForm|=true;
490									if (options.allrules[msg]) {
491										var txt = options.allrules[msg].alertText;
492										if (txt)
493											msg = txt;
494									}
495									if(options.showPrompts) methods._showPrompt(errorField, msg, "", false, options, true);
496								}
497							}
498						}
499						options.onAjaxFormComplete(!errorInForm, form, json, options);
500					} else
501						options.onAjaxFormComplete(true, form, json, options);
502
503				}
504			});
505
506		},
507		/**
508		* Validates field, shows prompts accordingly
509		*
510		* @param {jqObject}
511		*            field
512		* @param {Array[String]}
513		*            field's validation rules
514		* @param {Map}
515		*            user options
516		* @return false if field is valid (It is inversed for *fields*, it return false on validate and true on errors.)
517		*/
518		_validateField: function(field, options, skipAjaxValidation) {
519			if (!field.attr("id")) {
520				field.attr("id", "form-validation-field-" + $.validationEngine.fieldIdCounter);
521				++$.validationEngine.fieldIdCounter;
522			}
523
524           if (!options.validateNonVisibleFields && (field.is(":hidden") && !options.prettySelect || field.parent().is(":hidden")))
525				return false;
526
527			var rulesParsing = field.attr(options.validateAttribute);
528			var getRules = /validate\[(.*)\]/.exec(rulesParsing);
529
530			if (!getRules)
531				return false;
532			var str = getRules[1];
533			var rules = str.split(/\[|,|\]/);
534
535			// true if we ran the ajax validation, tells the logic to stop messing with prompts
536			var isAjaxValidator = false;
537			var fieldName = field.attr("name");
538			var promptText = "";
539			var promptType = "";
540			var required = false;
541			var limitErrors = false;
542			options.isError = false;
543			options.showArrow = true;
544			
545			// If the programmer wants to limit the amount of error messages per field,
546			if (options.maxErrorsPerField > 0) {
547				limitErrors = true;
548			}
549
550			var form = $(field.closest("form, .validationEngineContainer"));
551			// Fix for adding spaces in the rules
552			for (var i = 0; i < rules.length; i++) {
553				rules[i] = rules[i].replace(" ", "");
554				// Remove any parsing errors
555				if (rules[i] === '') {
556					delete rules[i];
557				}
558			}
559
560			for (var i = 0, field_errors = 0; i < rules.length; i++) {
561				
562				// If we are limiting errors, and have hit the max, break
563				if (limitErrors && field_errors >= options.maxErrorsPerField) {
564					// If we haven't hit a required yet, check to see if there is one in the validation rules for this
565					// field and that it's index is greater or equal to our current index
566					if (!required) {
567						var have_required = $.inArray('required', rules);
568						required = (have_required != -1 &&  have_required >= i);
569					}
570					break;
571				}
572				
573				
574				var errorMsg = undefined;
575				switch (rules[i]) {
576
577					case "required":
578						required = true;
579						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._required);
580						break;
581					case "custom":
582						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._custom);
583						break;
584					case "groupRequired":
585						// Check is its the first of group, if not, reload validation with first field
586						// AND continue normal validation on present field
587						var classGroup = "["+options.validateAttribute+"*=" +rules[i + 1] +"]";
588						var firstOfGroup = form.find(classGroup).eq(0);
589						if(firstOfGroup[0] != field[0]){
590
591							methods._validateField(firstOfGroup, options, skipAjaxValidation); 
592							options.showArrow = true;
593
594						}
595						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._groupRequired);
596						if(errorMsg)  required = true;
597						options.showArrow = false;
598						break;
599					case "ajax":
600						// AJAX defaults to returning it's loading message
601						errorMsg = methods._ajax(field, rules, i, options);
602						if (errorMsg) {
603							promptType = "load";
604						}
605						break;
606					case "minSize":
607						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._minSize);
608						break;
609					case "maxSize":
610						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._maxSize);
611						break;
612					case "min":
613						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._min);
614						break;
615					case "max":
616						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._max);
617						break;
618					case "past":
619						errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._past);
620						break;
621					case "future":
622						errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._future);
623						break;
624					case "dateRange":
625						var classGroup = "["+options.validateAttribute+"*=" + rules[i + 1] + "]";
626						options.firstOfGroup = form.find(classGroup).eq(0);
627						options.secondOfGroup = form.find(classGroup).eq(1);
628
629						//if one entry out of the pair has value then proceed to run through validation
630						if (options.firstOfGroup[0].value || options.secondOfGroup[0].value) {
631							errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._dateRange);
632						}
633						if (errorMsg) required = true;
634						options.showArrow = false;
635						break;
636
637					case "dateTimeRange":
638						var classGroup = "["+options.validateAttribute+"*=" + rules[i + 1] + "]";
639						options.firstOfGroup = form.find(classGroup).eq(0);
640						options.secondOfGroup = form.find(classGroup).eq(1);
641
642						//if one entry out of the pair has value then proceed to run through validation
643						if (options.firstOfGroup[0].value || options.secondOfGroup[0].value) {
644							errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._dateTimeRange);
645						}
646						if (errorMsg) required = true;
647						options.showArrow = false;
648						break;
649					case "maxCheckbox":
650						field = $(form.find("input[name='" + fieldName + "']"));
651						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._maxCheckbox);
652						break;
653					case "minCheckbox":
654						field = $(form.find("input[name='" + fieldName + "']"));
655						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._minCheckbox);
656						break;
657					case "equals":
658						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._equals);
659						break;
660					case "funcCall":
661						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._funcCall);
662						break;
663					case "creditCard":
664						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._creditCard);
665						break;
666					case "condRequired":
667						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._c
667ondRequired);
668						if (errorMsg !== undefined) {
669							required = true;
670						}
671						break;
672
673					default:
674				}
675				
676				var end_validation = false;
677				
678				// If we were passed back an message object, check what the status was to determine what to do
679				if (typeof errorMsg == "object") {
680					switch (errorMsg.status) {
681						case "_break":
682							end_validation = true;
683							break;
684						// If we have an error message, set errorMsg to the error message
685						case "_error":
686							errorMsg = errorMsg.message;
687							break;
688						// If we want to throw an error, but not show a prompt, return early with true
689						case "_error_no_prompt":
690							return true;
691							break;
692						// Anything else we continue on
693						default:
694							break;
695					}
696				}
697				
698				// If it has been specified that validation should end now, break
699				if (end_validation) {
700					break;
701				}
702				
703				// If we have a string, that means that we have an error, so add it to the error message.
704				if (typeof errorMsg == 'string') {
705					promptText += errorMsg + "<br/>";
706					options.isError = true;
707					field_errors++;
708				}	
709			}
710			// If the rules required is not added, an empty field is not validated
711			//the 3rd condition is added so that even empty password fields should be equal
712			//otherwise if one is filled and another left empty, the "equal" condition would fail
713			//which does not make any sense
714			if(!required && !(field.val()) && field.val().length < 1 && rules.indexOf("equals") < 0) options.isError = false;
715
716			// Hack for radio/checkbox group button, the validation go into the
717			// first radio/checkbox of the group
718			var fieldType = field.prop("type");
719			var positionType=field.data("promptPosition") || options.promptPosition;
720
721			if ((fieldType == "radio" || fieldType == "checkbox") && form.find("input[name='" + fieldName + "']").size() > 1) {
722				if(positionType === 'inline') {
723					field = $(form.find("input[name='" + fieldName + "'][type!=hidden]:last"));
724				} else {
725				field = $(form.find("input[name='" + fieldName + "'][type!=hidden]:first"));
726				}
727				options.showArrow = false;
728			}
729
730			if(field.is(":hidden") && options.prettySelect) {
731				field = form.find("#" + options.usePrefix + methods._jqSelector(field.attr('id')) + options.useSuffix);
732			}
733
734			if (options.isError && options.showPrompts){
735				methods._showPrompt(field, promptText, promptType, false, options);
736			}else{
737				if (!isAjaxValidator) methods._closePrompt(field);
738			}
739
740			if (!isAjaxValidator) {
741				field.trigger("jqv.field.result", [field, options.isError, promptText]);
742			}
743
744			/* Record error */
745			var errindex = $.inArray(field[0], options.InvalidFields);
746			if (errindex == -1) {
747				if (options.isError)
748				options.InvalidFields.push(field[0]);
749			} else if (!options.isError) {
750				options.InvalidFields.splice(errindex, 1);
751			}
752				
753			methods._handleStatusCssClasses(field, options);
754	
755			/* run callback function for each field */
756			if (options.isError && options.onFieldFailure)
757				options.onFieldFailure(field);
758
759			if (!options.isError && options.onFieldSuccess)
760				options.onFieldSuccess(field);
761
762			return options.isError;
763		},
764		/**
765		* Handling css classes of fields indicating result of validation 
766		*
767		* @param {jqObject}
768		*            field
769		* @param {Array[String]}
770		*            field's validation rules            
771		* @private
772		*/
773		_handleStatusCssClasses: function(field, options) {
774			/* remove all classes */
775			if(options.addSuccessCssClassToField)
776				field.removeClass(options.addSuccessCssClassToField);
777			
778			if(options.addFailureCssClassToField)
779				field.removeClass(options.addFailureCssClassToField);
780			
781			/* Add classes */
782			if (options.addSuccessCssClassToField && !options.isError)
783				field.addClass(options.addSuccessCssClassToField);
784			
785			if (options.addFailureCssClassToField && options.isError)
786				field.addClass(options.addFailureCssClassToField);		
787		},
788		
789		 /********************
790		  * _getErrorMessage
791		  *
792		  * @param form
793		  * @param field
794		  * @param rule
795		  * @param rules
796		  * @param i
797		  * @param options
798		  * @param originalValidationMethod
799		  * @return {*}
800		  * @private
801		  */
802		 _getErrorMessage:function (form, field, rule, rules, i, options, originalValidationMethod) {
803			 // If we are using the custon validation type, build the index for the rule.
804			 // Otherwise if we are doing a function call, make the call and return the object
805			 // that is passed back.
806	 		 var rule_index = jQuery.inArray(rule, rules);
807			 if (rule === "custom" || rule === "funcCall") {
808				 var custom_validation_type = rules[rule_index + 1];
809				 rule = rule + "[" + custom_validation_type + "]";
810				 // Delete the rule from the rules array so that it doesn't try to call the
811			    // same rule over again
812			    delete(rules[rule_index]);
813			 }
814			 // Change the rule to the composite rule, if it was different from the original
815			 var alteredRule = rule;
816
817
818			 var element_classes = (field.attr("data-validation-engine")) ? field.attr("data-validation-engine") : field.attr("class");
819			 var element_classes_array = element_classes.split(" ");
820
821			 // Call the original validation method. If we are dealing with dates or checkboxes, also pass the form
822			 var errorMsg;
823			 if (rule == "future" || rule == "past"  || rule == "maxCheckbox" || rule == "minCheckbox") {
824				 errorMsg = originalValidationMethod(form, field, rules, i, options);
825			 } else {
826				 errorMsg = originalValidationMethod(field, rules, i, options);
827			 }
828
829			 // If the original validation method returned an error and we have a custom error message,
830			 // return the custom message instead. Otherwise return the original error message.
831			 if (errorMsg != undefined) {
832				 var custom_message = methods._getCustomErrorMessage($(field), element_classes_array, alteredRule, options);
833				 if (custom_message) errorMsg = custom_message;
834			 }
835			 return errorMsg;
836
837		 },
838		 _getCustomErrorMessage:function (field, classes, rule, options) {
839			var custom_message = false;
840			var validityProp = /^custom\[.*\]$/.test(rule) ? methods._validityProp["custom"] : methods._validityProp[rule];
841			 // If there is a validityProp for this rule, check to see if the field has an attribute for it
842			if (validityProp != undefined) {
843				custom_message = field.attr("data-errormessage-"+validityProp);
844				// If there was an error message for it, return the message
845				if (custom_message != undefined) 
846					return custom_message;
847			}
848			custom_message = field.attr("data-errormessage");
849			 // If there is an inline custom error message, return it
850			if (custom_message != undefined) 
851				return custom_message;
852			var id = '#' + field.attr("id");
853			// If we have custom messages for the element's id, get the message for the rule from the id.
854			// Otherwise, if we have custom messages for the element's classes, use the first class message we find instead.
855			if (typeof options.custom_error_messages[id] != "undefined" &&
856				typeof options.custom_error_messages[id][rule] != "undefined" ) {
857						  custom_message = options.custom_error_messages[id][rule]['message'];
858			} else if (classes.length > 0) {
859				for (var i = 0; i < classes.length && classes.length > 0; i++) {
860					 var element_class = "." + classes[i];
861					if (typeof options.custom_error_messages[element_class] != "undefined" &&
862						typeof options.custom_error_messages[element_class][rule] != "undefined") {
863							custom_message = options.custom_error_messages[element_class][rule]['message'];
864							break;
865					}
866				}
867			}
868			if (!custom_message &&
869				typeof options.custom_error_messages[rule] != "undefined" &&
870				typeof options.custom_error_messages[rule]['message'] != "undefined"){
871					 custom_message = options.custom_error_messages[rule]['message'];
872			 }
873			 return custom_message;
874		 },
875		 _validityProp: {
876			 "required": "value-missing",
877			 "custom": "custom-error",
878			 "groupRequired": "value-missing",
879			 "ajax": "custom-error",
880			 "minSize": "range-underflow",
881			 "maxSize": "range-overflow",
882			 "min": "range-underflow",
883			 "max": "range-overflow",
884			 "past": "type-mismatch",
885			 "future": "type-mismatch",
886			 "dateRange": "type-mismatch",
887			 "dateTimeRange": "type-mismatch",
888			 "maxCheckbox": "range-overflow",
889			 "minCheckbox": "range-underflow",
890			 "equals": "pattern-mismatch",
891			 "funcCall": "custom-error",
892			 "creditCard": "pattern-mismatch",
893			 "condRequired": "value-missing"
894		 },
895		/**
896		* Required validation
897		*
898		* @param {jqObject} field
899		* @param {Array[String]} rules
900		* @param {int} i rules index
901		* @param {Map}
902		*            user options
903		* @param {bool} condRequired flag when method is used for internal purpose in condRequired check
904		* @return an error string if validation failed
905		*/
906		_required: function(field, rules, i, options, condRequired) {
907			switch (field.prop("type")) {
908				case "text":
909				case "password":
910				case "textarea":
911				case "file":
912				case "select-one":
913				case "select-multiple":
914				default:
915					var field_val      = $.trim( field.val()                               );
916					var dv_placeholder = $.trim( field.attr("data-validation-placeholder") );
917					var placeholder    = $.trim( field.attr("placeholder")                 );
918					if (
919						   ( !field_val                                    )
920						|| ( dv_placeholder && field_val == dv_placeholder )
921						|| ( placeholder    && field_val == placeholder    )
922					) {
923						return options.allrules[rules[i]].alertText;
924					}
925					break;
926				case "radio":
927				case "checkbox":
928					// new validation style to only check dependent field
929					if (condRequired) {
930						if (!field.attr('checked')) {
931							return options.allrules[rules[i]].alertTextCheckboxMultiple;
932						}
933						break;
934					}
935					// old validation style
936					var form = field.closest("form, .validationEngineContainer");
937					var name = field.attr("name");
938					if (form.find("input[name='" + name + "']:checked").size() == 0) {
939						if (form.find("input[name='" + name + "']:visible").size() == 1)
940							return options.allrules[rules[i]].alertTextCheckboxe;
941						else
942							return options.allrules[rules[i]].alertTextCheckboxMultiple;
943					}
944					break;
945			}
946		},
947		/**
948		* Validate that 1 from the group field is required
949		*
950		* @param {jqObject} field
951		* @param {Array[String]} rules
952		* @param {int} i rules index
953		* @param {Map}
954		*            user options
955		* @return an error string if validation failed
956		*/
957		_groupRequired: function(field, rules, i, options) {
958			var classGroup = "["+options.validateAttribute+"*=" +rules[i + 1] +"]";
959			var isValid = false;
960			// Check all fields from the group
961			field.closest("form, .validationEngineContainer").find(classGroup).each(function(){
962				if(!methods._required($(this), rules, i, options)){
963					isValid = true;
964					return false;
965				}
966			}); 
967
968			if(!isValid) {
969		  return options.allrules[rules[i]].alertText;
970		}
971		},
972		/**
973		* Validate rules
974		*
975		* @param {jqObject} field
976		* @param {Array[String]} rules
977		* @param {int} i rules index
978		* @param {Map}
979		*            user options
980		* @return an error string if validation failed
981		*/
982		_custom: function(field, rules, i, options) {
983			var customRule = rules[i + 1];
984			var rule = options.allrules[customRule];
985			var fn;
986			if(!rule) {
987				alert("jqv:custom rule not found - "+customRule);
988				return;
989			}
990			
991			if(rule["regex"]) {
992				 var ex=rule.regex;
993					if(!ex) {
994						alert("jqv:custom regex not found - "+customRule);
995						return;
996					}
997					var pattern = new RegExp(ex);
998
999					if (!pattern.test(field.val())) return options.allrules[customRule].alertText;
1000					
1001			} else if(rule["func"]) {
1002				fn = rule["func"]; 
1003				 
1004				if (typeof(fn) !== "function") {
1005					alert("jqv:custom parameter 'function' is no function - "+customRule);
1006						return;
1007				}
1008				 
1009				if (!fn(field, rules, i, options))
1010					return options.allrules[customRule].alertText;
1011			} else {
1012				alert("jqv:custom type not allowed "+customRule);
1013					return;
1014			}
1015		},
1016		/**
1017		* Validate custom function outside of the engine scope
1018		*
1019		* @param {jqObject} field
1020		* @param {Array[String]} rules
1021		* @param {int} i rules index
1022		* @param {Map}
1023		*            user options
1024		* @return an error string if validation failed
1025		*/
1026		_funcCall: function(field, rules, i, options) {
1027			var functionName = rules[i + 1];
1028			var fn;
1029			if(functionName.indexOf('.') >-1)
1030			{
1031				var namespaces = functionName.split('.');
1032				var scope = window;
1033				while(namespaces.length)
1034				{
1035					scope = scope[namespaces.shift()];
1036				}
1037				fn = scope;
1038			}
1039			else
1040				fn = window[functionName] || options.customFunctions[functionName];
1041			if (typeof(fn) == 'function')
1042				return fn(field, rules, i, options);
1043
1044		},
1045		/**
1046		* Field match
1047		*
1048		* @param {jqObject} field
1049		* @param {Array[String]} rules
1050		* @param {int} i rules index
1051		* @param {Map}
1052		*            user options
1053		* @return an error string if validation failed
1054		*/
1055		_equals: function(field, rules, i, options) {
1056			var equalsField = rules[i + 1];
1057
1058			if (field.val() != $("#" + equalsField).val())
1059				return options.allrules.equals.alertText;
1060		},
1061		/**
1062		* Check the maximum size (in characters)
1063		*
1064		* @param {jqObject} field
1065		* @param {Array[String]} rules
1066		* @param {int} i rules index
1067		* @param {Map}
1068		*            user options
1069		* @return an error string if validation failed
1070		*/
1071		_maxSize: function(field, rules, i, options) {
1072			var max = rules[i + 1];
1073			var len = field.val().length;
1074
1075			if (len > max) {
1076				var rule = options.allrules.maxSize;
1077				return rule.alertText + max + rule.alertText2;
1078			}
1079		},
1080		/**
1081		* Check the minimum size (in characters)
1082		*
1083		* @param {jqObject} field
1084		* @param {Array[String]} rules
1085		* @param {int} i rules index
1086		* @param {Map}
1087		*            user options
1088		* @return an error string if validation failed
1089		*/
1090		_minSize: function(field, rules, i, options) {
1091			var min = rules[i + 1];
1092			var len = field.val().length;
1093
1094			if (len < min) {
1095				var rule = options.allrules.minSize;
1096				return rule.alertText + min + rule.alertText2;
1097			}
1098		},
1099		/**
1100		* Check number minimum value
1101		*
1102		* @param {jqObject} field
1103		* @param {Array[String]} rules
1104		* @param {int} i rules index
1105		* @param {Map}
1106		*            user options
1107		* @return an error string if validation failed
1108		*/
1109		_min: function(field, rules, i, options) {
1110			var min = parseFloat(rules[i + 1]);
1111			var len = parseFloat(field.val());
1112
1113			if (len < min) {
1114				var rule = options.allrules.min;
1115				if (rule.alertText2) return rule.alertText + min + rule.alertText2;
1116				return rule.alertText + min;
1117			}
1118		},
1119		/**
1120		* Check number maximum value
1121		*
1122		* @param {jqObject} field
1123		* @param {Array[String]} rules
1124		* @param {int} i rules index
1125		* @param {Map}
1126		*            user options
1127		* @return an error string if validation failed
1128		*/
1129		_max: function(field, rules, i, options) {
1130			var max = parseFloat(rules[i + 1]);
1131			var len = parseFloat(field.val());
1132
1133			if (len >max ) {
1134				var rule = options.allrules.max;
1135				if (rule.alertText2) return rule.alertText + max + rule.alertText2;
1136				//orefalo: to review, also do the translations
1137				return rule.alertText + max;
1138			}
1139		},
1140		/**
1141		* Checks date is in the past
1142		*
1143		* @param {jqObject} field
1144		* @param {Array[String]} rules
1145		* @param {int} i rules index
1146		* @param {Map}
1147		*            user options
1148		* @return an error string if validation failed
1149		*/
1150		_past: function(form, field, rules, i, options) {
1151
1152			var p=rules[i + 1];
1153			var fieldAlt = $(form.find("*[name='" + p.replace(/^#+/, '') + "']"));
1154			var pdate;
1155
1156			if (p.toLowerCase() == "now") {
1157				pdate = new Date();
1158			} else if (undefined != fieldAlt.val()) {
1159				if (fieldAlt.is(":disabled"))
1160					return;
1161				pdate = methods._parseDate(fieldAlt.val());
1162			} else {
1163				pdate = methods._parseDate(p);
1164			}
1165			var vdate = methods._parseDate(field.val());
1166
1167			if (vdate > pdate ) {
1168				var rule = options.allrules.past;
1169				if (rule.alertText2) return rule.alertText + methods._dateToString(pdate) + rule.alertText2;
1170				return rule.alertText + methods._dateToString(pdate);
1171			}
1172		},
1173		/**
1174		* Checks date is in the future
1175		*
1176		* @param {jqObject} field
1177		* @param {Array[String]} rules
1178		* @param {int} i rules index
1179		* @param {Map}
1180		*            user options
1181		* @return an error string if validation failed
1182		*/
1183		_future: function(form, field, rules, i, options) {
1184
1185			var p=rules[i + 1];
1186			var fieldAlt = $(form.find("*[name='" + p.replace(/^#+/, '') + "']"));
1187			var pdate;
1188
1189			if (p.toLowerCase() == "now") {
1190				pdate = new Date();
1191			} else if (undefined != fieldAlt.val()) {
1192				if (fieldAlt.is(":disabled"))
1193					return;
1194				pdate = methods._parseDate(fieldAlt.val());
1195			} else {
1196				pdate = methods._parseDate(p);
1197			}
1198			var vdate = methods._parseDate(field.val());
1199
1200			if (vdate < pdate ) {
1201				var rule = options.allrules.future;
1202				if (rule.alertText2)
1203					return rule.alertText + methods._dateToString(pdate) + rule.alertText2;
1204				return rule.alertText + methods._dateToString(pdate);
1205			}
1206		},
1207		/**
1208		* Checks if valid date
1209		*
1210		* @param {string} date string
1211		* @return a bool based on determination of valid date
1212		*/
1213		_isDate: function (value) {
1214			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]))$/);
1215			return dateRegEx.test(value);
1216		},
1217		/**
1218		* Checks if valid date time
1219		*
1220		* @param {string} date string
1221		* @return a bool based on determination of valid date time
1222		*/
1223		_isDateTime: function (value){
1224			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})$/);
1225			return dateTimeRegEx.test(value);
1226		},
1227		//Checks if the start date is before the end date
1228		//returns true if end is later than start
1229		_dateCompare: function (start, end) {
1230			return (new Date(start.toString()) < new Date(end.toString()));
1231		},
1232		/**
1233		* Checks date range
1234		*
1235		* @param {jqObject} first field name
1236		* @param {jqObject} second field name
1237		* @return an error string if validation failed
1238		*/
1239		_dateRange: function (field, rules, i, options) {
1240			//are not both populated
1241			if ((!options.firstOfGroup[0].value && options.secondOfGroup[0].value) || (options.firstOfGroup[0].value && !options.secondOfGroup[0].value)) {
1242				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
1243			}
1244
1245			//are not both dates
1246			if (!methods._isDate(options.firstOfGroup[0].value) || !methods._isDate(options.secondOfGroup[0].value)) {
1247				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
1248			}
1249
1250			//are both dates but range is off
1251			if (!methods._dateCompare(options.firstOfGroup[0].value, options.secondOfGroup[0].value)) {
1252				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
1253			}
1254		},
1255		/**
1256		* Checks date time range
1257		*
1258		* @param {jqObject} first field name
1259		* @param {jqObject} second field name
1260		* @return an error string if validation failed
1261		*/
1262		_dateTimeRange: function (field, rules, i, options) {
1263			//are not both populated
1264			if ((!options.firstOfGroup[0].value && options.secondOfGroup[0].value) || (options.firstOfGroup[0].value && !options.secondOfGroup[0].value)) {
1265				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
1266			}
1267			//are not both dates
1268			if (!methods._isDateTime(options.firstOfGroup[0].value) || !methods._isDateTime(options.secondOfGroup[0].value)) {
1269				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
1270			}
1271			//are both dates but range is off
1272			if (!methods._dateCompare(options.firstOfGroup[0].value, options.secondOfGroup[0].value)) {
1273				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
1274			}
1275		},
1276		/**
1277		* Max number of checkbox selected
1278		*
1279		* @param {jqObject} field
1280		* @param {Array[String]} rules
1281		* @param {int} i rules index
1282		* @param {Map}
1283		*            user options
1284		* @return an error string if validation failed
1285		*/
1286		_maxCheckbox: function(form, field, rules, i, options) {
1287
1288			var nbCheck = rules[i + 1];
1289			var groupname = field.attr("name");
1290			var groupSize = form.find("input[name='" + groupname + "']:checked").size();
1291			if (groupSize > nbCheck) {
1292				options.showArrow = false;
1293				if (options.allrules.maxCheckbox.alertText2)
1294					 return options.allrules.maxCheckbox.alertText + " " + nbCheck + " " + options.allrules.maxCheckbox.alertText2;
1295				return options.allrules.maxCheckbox.alertText;
1296			}
1297		},
1298		/**
1299		* Min number of checkbox selected
1300		*
1301		* @param {jqObject} field
1302		* @param {Array[String]} rules
1303		* @param {int} i rules index
1304		* @param {Map}
1305		*            user options
1306		* @return an error string if validation failed
1307		*/
1308		_minCheckbox: function(form, field, rules, i, options) {
1309
1310			var nbCheck = rules[i + 1];
1311			var groupname = field.attr("name");
1312			var groupSize = form.find("input[name='" + groupname + "']:checked").size();
1313			if (groupSize < nbCheck) {
1314				options.showArrow = false;
1315				return options.allrules.minCheckbox.alertText + " " + nbCheck + " " + options.allrules.minCheckbox.alertText2;
1316			}
1317		},
1318		/**
1319		* Checks that it is a valid credit card number according to the
1320		* Luhn checksum algorithm.
1321		*
1322		* @param {jqObject} field
1323		* @param {Array[String]} rules
1324		* @param {int} i rules index
1325		* @param {Map}
1326		*            user options
1327		* @return an error string if validation failed
1328		*/
1329		_creditCard: function(field, rules, i, options) {
1330			//spaces and dashes may be valid characters, but must be stripped to calculate the checksum.
1331			var valid = false, cardNumber = field.val().replace(/ +/g, '').replace(/-+/g, '');
1332
1333			var numDigits = cardNumber.length;
1334			if (numDigits >= 14 && numDigits <= 16 && parseInt(cardNumber) > 0) {
1335
1336				var sum = 0, i = numDigits - 1, pos = 1, digit, luhn = new String();
1337				do {
1338					digit = parseInt(cardNumber.charAt(i));
1339					luhn += (pos++ % 2 == 0) ? digit * 2 : digit;
1340				} while (--i >= 0)
1341
1342				for (i = 0; i < luhn.length; i++) {
1343					sum += parseInt(luhn.charAt(i));
1344				}
1345				valid = sum % 10 == 0;
1346			}
1347			if (!valid) return options.allrules.creditCard.alertText;
1348		},
1349		/**
1350		* Ajax field validation
1351		*
1352		* @param {jqObject} field
1353		* @param {Array[String]} rules
1354		* @param {int} i rules index
1355		* @param {Map}
1356		*            user options
1357		* @return nothing! the ajax validator handles the prompts itself
1358		*/
1359		 _ajax: function(field, rules, i, options) {
1360
1361			 var errorSelector = rules[i + 1];
1362			 var rule = options.allrules[errorSelector];
1363			 var extraData = rule.extraData;
1364			 var extraDataDynamic = rule.extraDataDynamic;
1365			 var data = {
1366				"fieldId" : field.attr("id"),
1367				"fieldValue" : field.val()
1368			 };
1369
1370			 if (typeof extraData === "object") {
1371				$.extend(data, extraData);
1372			 } else if (typeof extraData === "string") {
1373				var tempData = extraData.split("&");
1374				for(var i = 0; i < tempData.length; i++) {
1375					var values = tempData[i].split("=");
1376					if (values[0] && values[0]) {
1377						data[values[0]] = values[1];
1378					}
1379				}
1380			 }
1381
1382			 if (extraDataDynamic) {
1383				 var tmpData = [];
1384				 var domIds = String(extraDataDynamic).split(",");
1385				 for (var i = 0; i < domIds.length; i++) {
1386					 var id = domIds[i];
1387					 if ($(id).length) {
1388						 var inputValue = field.closest("form, .validationEngineContainer").find(id).val();
1389						 var keyValue = id.replace('#', '') + '=' + escape(inputValue);
1390						 data[id.replace('#', '')] = inputValue;
1391					 }
1392				 }
1393			 }
1394			 
1395			 // If a field change event triggered this we want to clear the cache for this ID
1396			 if (options.eventTrigger == "field") {
1397				delete(options.ajaxValidCache[field.attr("id")]);
1398			 }
1399
1400			 // If there is an error or if the the field is already validated, do not re-execute AJAX
1401			 if (!options.isError && !methods._checkAjaxFieldStatus(field.attr("id"), options)) {
1402				 $.ajax({
1403					 type: options.ajaxFormValidationMethod,
1404					 url: rule.url,
1405					 cache: false,
1406					 dataType: "json",
1407					 data: data,
1408					 field: field,
1409					 rule: rule,
1410					 methods: methods,
1411					 options: options,
1412					 beforeSend: function() {},
1413					 error: function(data, transport) {
1414						if (options.onFailure) {
1415							options.onFailure(data, transport);
1416						} else {
1417							methods._ajaxError(data, transport);
1418						}
1419					 },
1420					 success: function(json) {
1421
1422						 // asynchronously called on success, data is the json answer from the server
1423						 var errorFieldId = json[0];
1424						 //var errorField = $($("#" + errorFieldId)[0]);
1425						 var errorField = $("#"+ errorFieldId).eq(0);
1426
1427						 // make sure we found the element
1428						 if (errorField.length == 1) {
1429							 var status = json[1];
1430							 // read the optional msg from the server
1431							 var msg = json[2];
1432							 if (!status) {
1433								 // Houston we got a problem - display an red prompt
1434								 options.ajaxValidCache[errorFieldId] = false;
1435								 options.isError = true;
1436
1437								 // resolve the msg prompt
1438								 if(msg) {
1439									 if (options.allrules[msg]) {
1440										 var txt = options.allrules[msg].alertText;
1441										 if (txt) {
1442											msg = txt;
1443							}
1444									 }
1445								 }
1446								 else
1447									msg = rule.alertText;
1448
1449								 if (options.showPrompts) methods._showPrompt(errorField, msg, "", true, options);
1450							 } else {
1451								 options.ajaxValidCache[errorFieldId] = true;
1452
1453								 // resolves the msg prompt
1454								 if(msg) {
1455									 if (options.allrules[msg]) {
1456										 var txt = options.allrules[msg].alertTextOk;
1457										 if (txt) {
1458											msg = txt;
1459							}
1460									 }
1461								 }
1462								 else
1463								 msg = rule.alertTextOk;
1464
1465								 if (options.showPrompts) {
1466									 // see if we should display a green prompt
1467									 if (msg)
1468										methods._showPrompt(errorField, msg, "pass", true, options);
1469									 else
1470										methods._closePrompt(errorField);
1471								}
1472								
1473								 // If a submit form triggered this, we want to re-submit the form
1474								 if (options.eventTrigger == "submit")
1475									field.closest("form").submit();
1476							 }
1477						 }
1478						 errorField.trigger("jqv.field.result", [errorField, options.isError, msg]);
1479					 }
1480				 });
1481				 
1482				 return rule.alertTextLoad;
1483			 }
1484		 },
1485		/**
1486		* Common method to handle ajax errors
1487		*
1488		* @param {Object} data
1489		* @param {Object} transport
1490		*/
1491		_ajaxError: function(data, transport) {
1492			if(data.status == 0 && transport == null)
1493				alert("The page is not served from a server! ajax call failed");
1494			else if(typeof console != "undefined")
1495				console.log("Ajax error: " + data.status + " " + transport);
1496		},
1497		/**
1498		* date -> string
1499		*
1500		* @param {Object} date
1501		*/
1502		_dateToString: function(date) {
1503			return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate();
1504		},
1505		/**
1506		* Parses an ISO date
1507		* @param {String} d
1508		*/
1509		_parseDate: function(d) {
1510
1511			var dateParts = d.split("-");
1512			if(dateParts==d)
1513				dateParts = d.split("/");
1514			if(dateParts==d) {
1515				dateParts = d.split(".");
1516				return new Date(dateParts[2], (dateParts[1] - 1), dateParts[0]);
1517			}
1518			return new Date(dateParts[0], (dateParts[1] - 1) ,dateParts[2]);
1519		},
1520		/**
1521		* Builds or updates a prompt with the given information
1522		*
1523		* @param {jqObject} field
1524		* @param {String} promptText html text to display type
1525		* @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
1526		* @param {boolean} ajaxed - use to mark fields than being validated with ajax
1527		* @param {Map} options user options
1528		*/
1529		 _showPrompt: function(field, promptText, type, ajaxed, options, ajaxform) {
1530		 	//Check if we need to adjust what element to show the prompt on
1531			if(field.data('jqv-prompt-at') instanceof jQuery ){
1532				field = field.data('jqv-prompt-at');
1533			} else if(field.data('jqv-prompt-at')) {
1534				field = $(field.data('jqv-prompt-at'));
1535			}
1536
1537			 var prompt = methods._getPrompt(field);
1538			 // The ajax submit errors are not see has an error in the form,
1539			 // When the form errors are returned, the engine see 2 bubbles, but those are ebing closed by the engine at the same time
1540			 // Because no error was found befor submitting
1541			 if(ajaxform) prompt = false;
1542			 // Check that there is indded text
1543			 if($.trim(promptText)){ 
1544				 if (prompt)
1545					methods._updatePrompt(field, prompt, promptText, type, ajaxed, options);
1546				 else
1547					methods._buildPrompt(field, promptText, type, ajaxed, options);
1548			}
1549		 },
1550		/**
1551		* Builds and shades a prompt for the given field.
1552		*
1553		* @param {jqObject} field
1554		* @param {String} promptText html text to display type
1555		* @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
1556		* @param {boolean} ajaxed - use to mark fields than being validated with ajax
1557		* @param {Map} options user options
1558		*/
1559		_buildPrompt: function(field, promptText, type, ajaxed, options) {
1560
1561			// create the prompt
1562			var prompt = $('<div>');
1563			prompt.addClass(methods._getClassName(field.attr("id")) + "formError");
1564			// add a class name to identify the parent form of the prompt
1565			prompt.addClass("parentForm"+methods._getClassName(field.closest('form, .validationEngineContainer').attr("id")));
1566			prompt.addClass("formError");
1567
1568			switch (type) {
1569				case "pass":
1570					prompt.addClass("greenPopup");
1571					break;
1572				case "load":
1573					prompt.addClass("blackPopup");
1574					break;
1575				default:
1576					/* it has error  */
1577					//alert("unknown popup type:"+type);
1578			}
1579			if (ajaxed)
1580				prompt.addClass("ajaxed");
1581
1582			// create the prompt content
1583			var promptContent = $('<div>').addClass("formErrorContent").html(promptText).appendTo(prompt);
1584
1585			// determine position type
1586			var positionType=field.data("promptPosition") || options.promptPosition;
1587
1588			// create the css arrow pointing at the field
1589			// note that there is no triangle on max-checkbox and radio
1590			if (options.showArrow) {
1591				var arrow = $('<div>').addClass("formErrorArrow");
1592
1593				//prompt positioning adjustment support. Usage: positionType:Xshift,Yshift (for ex.: bottomLeft:+20 or bottomLeft:-20,+10)
1594				if (typeof(positionType)=='string') 
1595				{
1596					var pos=positionType.indexOf(":");
1597					if(pos!=-1)
1598						positionType=positionType.substring(0,pos);
1599				}
1600
1601				switch (positionType) {
1602					case "bottomLeft":
1603					case "bottomRight":
1604						prompt.find(".formErrorContent").before(arrow);
1605						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>');
1606						break;
1607					case "topLeft":
1608					case "topRight":
1609						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>');
1610						prompt.append(arrow);
1611						break;
1612				}
1613			}
1614			// Add custom prompt class
1615			if (options.addPromptClass)
1616				prompt.addClass(options.addPromptClass);
1617
1618            // Add custom prompt class defined in element
1619            var requiredOverride = field.attr('data-required-class');
1620            if(requiredOverride !== undefined) {
1621                prompt.addClass(requiredOverride);
1622            } else {
1623                if(options.prettySelect) {
1624                    if($('#' + field.attr('id')).next().is('select')) {
1625                        var prettyOverrideClass = $('#' + field.attr('id').substr(options.usePrefix.length).substring(options.useSuffix.length)).attr('data-required-class');
1626                        if(prettyOverrideClass !== undefined) {
1627                            prompt.addClass(prettyOverrideClass);
1628                        }
1629                    }
1630                }
1631            }
1632
1633			prompt.css({
1634				"opacity": 0
1635			});
1636			if(positionType === 'inline') {
1637				prompt.addClass("inline");
1638				if(typeof field.attr('data-prompt-target') !== 'undefined' && $('#'+field.attr('data-prompt-target')).length > 0) {
1639					prompt.appendTo($('#'+field.attr('data-prompt-target')));
1640				} else {
1641					field.after(prompt);
1642				}
1643			} else {
1644				field.before(prompt);				
1645			}
1646			
1647			var pos = methods._calculatePosition(field, prompt, options);
1648			prompt.css({
1649				'position': positionType === 'inline' ? 'relative' : 'absolute',
1650				"top": pos.callerTopPosition,
1651				"left": pos.callerleftPosition,
1652				"marginTop": pos.marginTopSize,
1653				"opacity": 0
1654			}).data("callerField", field);
1655			
1656
1657			if (options.autoHidePrompt) {
1658				setTimeout(function(){
1659					prompt.animate({
1660						"opacity": 0
1661					},function(){
1662						prompt.closest('.formErrorOuter').remove();
1663						prompt.remove();
1664					});
1665				}, options.autoHideDelay);
1666			} 
1667			return prompt.animate({
1668				"opacity": 0.87
1669			});
1670		},
1671		/**
1672		* Updates the prompt text field - the field for which the prompt
1673		* @param {jqObject} field
1674		* @param {String} promptText html text to display type
1675		* @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
1676		* @param {boolean} ajaxed - use to mark fields than being validated with ajax
1677		* @param {Map} options user options
1678		*/
1679		_updatePrompt: function(field, prompt, promptText, type, ajaxed, options, noAnimation) {
1680
1681			if (prompt) {
1682				if (typeof type !== "undefined") {
1683					if (type == "pass")
1684						prompt.addClass("greenPopup");
1685					else
1686						prompt.removeClass("greenPopup");
1687
1688					if (type == "load")
1689						prompt.addClass("blackPopup");
1690					else
1691						prompt.removeClass("blackPopup");
1692				}
1693				if (ajaxed)
1694					prompt.addClass("ajaxed");
1695				else
1696					prompt.removeClass("ajaxed");
1697
1698				prompt.find(".formErrorContent").html(promptText);
1699
1700				var pos = methods._calculatePosition(field, prompt, options);
1701				var css = {"top": pos.callerTopPosition,
1702				"left": pos.callerleftPosition,
1703				"marginTop": pos.marginTopSize};
1704
1705				if (noAnimation)
1706					prompt.css(css);
1707				else
1708					prompt.animate(css);
1709			}
1710		},
1711		/**
1712		* Closes the prompt associated with the given field
1713		*
1714		* @param {jqObject}
1715		*            field
1716		*/
1717		 _closePrompt: function(field) {
1718			 var prompt = methods._getPrompt(field);
1719			 if (prompt)
1720				 prompt.fadeTo("fast", 0, function() {
1721					 prompt.parent('.formErrorOuter').remove();
1722					 prompt.remove();
1723				 });
1724		 },
1725		 closePrompt: function(field) {
1726			 return methods._closePrompt(field);
1727		 },
1728		/**
1729		* Returns the error prompt matching the field if any
1730		*
1731		* @param {jqObject}
1732		*            field
1733		* @return undefined or the error prompt (jqObject)
1734		*/
1735		_getPrompt: function(field) {
1736				var formId = $(field).closest('form, .validationEngineContainer').attr('id');
1737			var className = methods._getClassName(field.attr("id")) + "formError";
1738				var match = $("." + methods._escapeExpression(className) + '.parentForm' + methods._getClassName(formId))[0];
1739			if (match)
1740			return $(match);
1741		},
1742		/**
1743		  * Returns the escapade classname
1744		  *
1745		  * @param {selector}
1746		  *            className
1747		  */
1748		  _escapeExpression: function (selector) {
1749			  return selector.replace(/([#;&,\.\+\*\~':"\!\^$\[\]\(\)=>\|])/g, "\\$1");
1750		  },
1751		/**
1752		 * returns true if we are in a RTLed document
1753		 *
1754		 * @param {jqObject} field
1755		 */
1756		isRTL: function(field)
1757		{
1758			var $document = $(document);
1759			var $body = $('body');
1760			var rtl =
1761				(field && field.hasClass('rtl')) ||
1762				(field && (field.attr('dir') || '').toLowerCase()==='rtl') ||
1763				$document.hasClass('rtl') ||
1764				($document.attr('dir') || '').toLowerCase()==='rtl' ||
1765				$body.hasClass('rtl') ||
1766				($body.attr('dir') || '').toLowerCase()==='rtl';
1767			return Boolean(rtl);
1768		},
1769		/**
1770		* Calculates prompt position
1771		*
1772		* @param {jqObject}
1773		*            field
1774		* @param {jqObject}
1775		*            the prompt
1776		* @param {Map}
1777		*            options
1778		* @return positions
1779		*/
1780		_calculatePosition: function (field, promptElmt, options) {
1781
1782			var promptTopPosition, promptleftPosition, marginTopSize;
1783			var fieldWidth 	= field.width();
1784			var fieldLeft 	= field.position().left; 
1785			var fieldTop 	=  field.position().top;
1786			var fieldHeight 	=  field.height();	
1787			var promptHeight = promptElmt.height();
1788
1789
1790			// is the form contained in an overflown container?
1791			promptTopPosition = promptleftPosition = 0;
1792			// compensation for the arrow
1793			marginTopSize = -promptHeight;
1794		
1795
1796			//prompt positioning adjustment support
1797			//now you can adjust prompt position
1798			//usage: positionType:Xshift,Yshift
1799			//for example:
1800			//   bottomLeft:+20 means bottomLeft position shifted by 20 pixels right horizontally
1801			//   topRight:20, -15 means topRight position shifted by 20 pixels to right and 15 pixels to top
1802			//You can use +pixels, - pixels. If no sign is provided than + is default.
1803			var positionType=field.data("promptPosition") || options.promptPosition;
1804			var shift1="";
1805			var shift2="";
1806			var shiftX=0;
1807			var shiftY=0;
1808			if (typeof(positionType)=='string') {
1809				//do we have any position adjustments ?
1810				if (positionType.indexOf(":")!=-1) {
1811					shift1=positionType.substring(positionType.indexOf(":")+1);
1812					positionType=positionType.substring(0,positionType.indexOf(":"));
1813
1814					//if any advanced positioning will be needed (percents or something else) - parser should be added here
1815					//for now we use simple parseInt()
1816
1817					//do we have second parameter?
1818					if (shift1.indexOf(",") !=-1) {
1819						shift2=shift1.substring(shift1.indexOf(",") +1);
1820						shift1=shift1.substring(0,shift1.indexOf(","));
1821						shiftY=parseInt(shift2);
1822						if (isNaN(shiftY)) shiftY=0;
1823					};
1824
1825					shiftX=parseInt(shift1);
1826					if (isNaN(shift1)) shift1=0;
1827
1828				};
1829			};
1830
1831			
1832			switch (positionType) {
1833				default:
1834				case "topRight":
1835					promptleftPosition +=  fieldLeft + fieldWidth - 30;
1836					promptTopPosition +=  fieldTop;
1837					break;
1838
1839				case "topLeft":
1840					promptTopPosition +=  fieldTop;
1841					promptleftPosition += fieldLeft; 
1842					break;
1843
1844				case "centerRight":
1845					promptTopPosition = fieldTop+4;
1846					marginTopSize = 0;
1847					promptleftPosition= fieldLeft + field.outerWidth(true)+5;
1848					break;
1849				case "centerLeft":
1850					promptleftPosition = fieldLeft - (promptElmt.width() + 2);
1851					promptTopPosition = fieldTop+4;
1852					marginTopSize = 0;
1853					
1854					break;
1855
1856				case "bottomLeft":
1857					promptTopPosition = fieldTop + field.height() + 5;
1858					marginTopSize = 0;
1859					promptleftPosition = fieldLeft;
1860					break;
1861				case "bottomRight":
1862					promptleftPosition = fieldLeft + fieldWidth - 30;
1863					promptTopPosition =  fieldTop +  field.height() + 5;
1864					marginTopSize = 0;
1865					break;
1866				case "inline":
1867					promptleftPosition = 0;
1868					promptTopPosition = 0;
1869					marginTopSize = 0;
1870			};
1871
1872		
1873
1874			//apply adjusments if any
1875			promptleftPosition += shiftX;
1876			promptTopPosition  += shiftY;
1877
1878			return {
1879				"callerTopPosition": promptTopPosition + "px",
1880				"callerleftPosition": promptleftPosition + "px",
1881				"marginTopSize": marginTopSize + "px"
1882			};
1883		},
1884		/**
1885		* Saves the user options and variables in the form.data
1886		*
1887		* @param {jqObject}
1888		*            form - the form where the user option should be saved
1889		* @param {Map}
1890		*            options - the user options
1891		* @return the user options (extended from the defaults)
1892		*/
1893		 _saveOptions: function(form, options) {
1894
1895			 // is there a language localisation ?
1896			 if ($.validationEngineLanguage)
1897			 var allRules = $.validationEngineLanguage.allRules;
1898			 else
1899			 $.error("jQuery.validationEngine rules are not loaded, plz add localization files to the page");
1900			 // --- Internals DO NOT TOUCH or OVERLOAD ---
1901			 // validation rules and i18
1902			 $.validationEngine.defaults.allrules = allRules;
1903
1904			 var userOptions = $.extend(true,{},$.validationEngine.defaults,options);
1905
1906			 form.data('jqv', userOptions);
1907			 return userOptions;
1908		 },
1909
1910		 /**
1911		 * Removes forbidden characters from class name
1912		 * @param {String} className
1913		 */
1914		 _getClassName: function(className) {
1915			 if(className)
1916				 return className.replace(/:/g, "_").replace(/\./g, "_");
1917					  },
1918		/**
1919		 * Escape special character for jQuery selector
1920		 * http://totaldev.com/content/escaping-characters-get-valid-jquery-id
1921		 * @param {String} selector
1922		 */
1923		 _jqSelector: function(str){
1924			return str.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1');
1925		},
1926		/**
1927		* Conditionally required field
1928		*
1929		* @param {jqObject} field
1930		* @param {Array[String]} rules
1931		* @param {int} i rules index
1932		* @param {Map}
1933		* user options
1934		* @return an error string if validation failed
1935		*/
1936		_condRequired: function(field, rules, i, options) {
1937			var idx, dependingField;
1938
1939			for(idx = (i + 1); idx < rules.length; idx++) {
1940				dependingField = jQuery("#" + rules[idx]).first();
1941
1942				/* Use _required for determining wether dependingField has a value.
1943				 * There is logic there for handling all field types, and default value; so we won't replicate that here
1944				 * Indicate this special use by setting the last parameter to true so we only validate the dependingField on chackboxes and radio buttons (#462)
1945				 */
1946				if (dependingField.length && methods._required(dependingField, ["required"], 0, options, true) == undefined) {
1947					/* We now know any of the depending fields has a value,
1948					 * so we can validate this field as per normal required code
1949					 */
1950					return methods._required(field, ["required"], 0, options);
1951				}
1952			}
1953		},
1954
1955	    _submitButtonClick: function(event) {
1956	        var button = $(this);
1957	        var form = button.closest('form, .validationEngineContainer');
1958	        form.data("jqv_submitButton", button.attr("id"));
1959	    }
1960		  };
1961
1962	 /**
1963	 * Plugin entry point.
1964	 * You may pass an action as a parameter or a list of options.
1965	 * if none, the init and attach methods are being called.
1966	 * Remember: if you pass options, the attached method is NOT called automatically
1967	 *
1968	 * @param {String}
1969	 *            method (optional) action
1970	 */
1971	 $.fn.validationEngine = function(method) {
1972
1973		 var form = $(this);
1974		 if(!form[0]) return form;  // stop here if the form does not exist
1975
1976		 if (typeof(method) == 'string' && method.charAt(0) != '_' && methods[method]) {
1977
1978			 // make sure init is called once
1979			 if(method != "showPrompt" && method != "hide" && method != "hideAll")
1980			 methods.init.apply(form);
1981
1982			 return methods[method].apply(form, Array.prototype.slice.call(arguments, 1));
1983		 } else if (typeof method == 'object' || !method) {
1984
1985			 // default constructor with or without arguments
1986			 methods.init.apply(form, arguments);
1987			 return methods.attach.apply(form);
1988		 } else {
1989			 $.error('Method ' + method + ' does not exist in jQuery.validationEngine');
1990		 }
1991	};
1992
1993
1994
1995	// LEAK GLOBAL OPTIONS
1996	$.validationEngine= {fieldIdCounter: 0,defaults:{
1997
1998		// Name of the event triggering field validation
1999		validationEventTrigger: "blur",
2000		// Automatically scroll viewport to the first error
2001		scroll: true,
2002		// Focus on the first input
2003		focusFirstField:true,
2004		// Show prompts, set to false to disable prompts
2005		showPrompts: true,
2006       // Should we attempt to validate non-visible input fields contained in the form? (Useful in cases of tabbed containers, e.g. jQuery-UI tabs)
2007       validateNonVisibleFields: false,
2008		// Opening box position, possible locations are: topLeft,
2009		// topRight, bottomLeft, centerRight, bottomRight, inline
2010		// inline gets inserted after the validated field or into an element specified in data-prompt-target
2011		promptPosition: "topLeft",
2012		bindMethod:"internal",
2013		// internal, automatically set to true when it parse a _ajax rule
2014		inlineAjax: false,
2015		// if set to true, the form data is sent asynchronously via ajax to the form.action url (get)
2016		ajaxFormValidation: false,
2017		// The url to send the submit ajax validation (default to action)
2018		ajaxFormValidationURL: false,
2019		// HTTP method used for ajax validation
2020		ajaxFormValidationMethod: 'get',
2021		// Ajax form validation callback method: boolean onComplete(form, status, errors, options)
2022		// retuns false if the form.submit event needs to be canceled.
2023		onAjaxFormComplete: $.noop,
2024		// called right before the ajax call, may return false to cancel
2025		onBeforeAjaxFormValidation: $.noop,
2026		// Stops form from submitting and execute function assiciated with it
2027		onValidationComplete: false,
2028
2029		// Used when you have a form fields too close and the errors messages are on top of other disturbing viewing messages
2030		doNotShowAllErrosOnSubmit: false,
2031		// Object where you store custom messages to override the default error messages
2032		custom_error_messages:{},
2033		// true if you want to vind the input fields
2034		binded: true,
2035		// set to true, when the prompt arrow needs to be displayed
2036		showArrow: true,
2037		// did one of the validation fail ? kept global to stop further ajax validations
2038		isError: false,
2039		// Limit how many displayed errors a field can have
2040		maxErrorsPerField: false,
2041		
2042		// Caches field validation status, typically only bad status are created.
2043		// the array is used during ajax form validation to detect issues early and prevent an expensive submit
2044		ajaxValidCache: {},
2045		// Auto update prompt position after window resize
2046		autoPositionUpdate: false,
2047
2048		InvalidFields: [],
2049		onFieldSuccess: false,
2050		onFieldFailure: false,
2051		onSuccess: false,
2052		onFailure: false,
2053		validateAttribute: "class",
2054		addSuccessCssClassToField: "",
2055		addFailureCssClassToField: "",
2056		
2057		// Auto-hide prompt
2058		autoHidePrompt: true,
2059		// Delay before auto-hide
2060		autoHideDelay: 3000,
2061		// Fade out duration while hiding the validations
2062		fadeDuration: 0.3,
2063		 // Use Prettify select library
2064		 prettySelect: false,
2065		 // Add css class on prompt
2066		 addPromptClass : "",
2067		 // Custom ID uses prefix
2068		 usePrefix: "",
2069		 // Custom ID uses suffix
2070		 useSuffix: "",
2071		 // Only show one message per error prompt
2072		 showOneMessage: false,
2073		 
2074		 scrollOffset : 200
2075	}};
2076	//$(function(){$.validationEngine.defaults.promptPosition = methods.isRTL()?'topLeft':"topRight"});
2077})(jQuery);
2078
2079

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.