jQuery-Validation-Engine-rails 0.0.1

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