jQuery-Validation-Engine-rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+