PageSourceSearch

https://s1.iotexpo.com.cn/js/jquery.validationEngine.js?7DBD72E6D199A4E4

js iotexpo.com.cn collected 2026-10-04 15:04:18 UTC 84,002 bytes, 2,328 lines download raw bytes

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

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.