dqs-jquery-form-validator-rails 2.2.164 → 2.2.165

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -14
  3. data/app/assets/javascripts/brazil.dev.js +6 -6
  4. data/app/assets/javascripts/brazil.js +3 -4
  5. data/app/assets/javascripts/date.dev.js +2 -2
  6. data/app/assets/javascripts/date.js +2 -3
  7. data/app/assets/javascripts/file.dev.js +30 -32
  8. data/app/assets/javascripts/file.js +3 -4
  9. data/app/assets/javascripts/html5.dev.js +9 -14
  10. data/app/assets/javascripts/html5.js +3 -4
  11. data/app/assets/javascripts/jquery.form-validator.js +1784 -0
  12. data/app/assets/javascripts/jquery.form-validator.min.js +3 -4
  13. data/app/assets/javascripts/jsconf.dev.js +8 -21
  14. data/app/assets/javascripts/jsconf.js +3 -4
  15. data/app/assets/javascripts/lang/de.dev.js +43 -45
  16. data/app/assets/javascripts/lang/de.js +3 -4
  17. data/app/assets/javascripts/lang/es.dev.js +40 -39
  18. data/app/assets/javascripts/lang/es.js +3 -4
  19. data/app/assets/javascripts/lang/fr.dev.js +43 -42
  20. data/app/assets/javascripts/lang/fr.js +3 -4
  21. data/app/assets/javascripts/lang/pt.dev.js +2 -3
  22. data/app/assets/javascripts/lang/pt.js +3 -4
  23. data/app/assets/javascripts/lang/sv.dev.js +2 -3
  24. data/app/assets/javascripts/lang/sv.js +3 -4
  25. data/app/assets/javascripts/location.dev.js +1 -1
  26. data/app/assets/javascripts/location.js +2 -3
  27. data/app/assets/javascripts/sanitize.dev.js +30 -39
  28. data/app/assets/javascripts/sanitize.js +3 -4
  29. data/app/assets/javascripts/security.dev.js +34 -51
  30. data/app/assets/javascripts/security.js +3 -4
  31. data/app/assets/javascripts/sweden.dev.js +13 -16
  32. data/app/assets/javascripts/sweden.js +3 -4
  33. data/app/assets/javascripts/toggleDisabled.dev.js +5 -6
  34. data/app/assets/javascripts/toggleDisabled.js +3 -4
  35. data/app/assets/javascripts/uk.dev.js +13 -13
  36. data/app/assets/javascripts/uk.js +3 -4
  37. data/lib/dqs/jquery/form/validator/rails/version.rb +1 -1
  38. metadata +2 -17
  39. data/app/assets/javascripts/lang/cz.dev.js +0 -65
  40. data/app/assets/javascripts/lang/cz.js +0 -9
  41. data/app/assets/javascripts/lang/it.dev.js +0 -62
  42. data/app/assets/javascripts/lang/it.js +0 -9
  43. data/app/assets/javascripts/lang/pl.dev.js +0 -65
  44. data/app/assets/javascripts/lang/pl.js +0 -9
  45. data/app/assets/javascripts/lang/ro.dev.js +0 -65
  46. data/app/assets/javascripts/lang/ro.js +0 -9
  47. data/app/assets/javascripts/lang/ru.dev.js +0 -66
  48. data/app/assets/javascripts/lang/ru.js +0 -9
  49. data/app/assets/javascripts/src/core-validators.js +0 -343
  50. data/app/assets/javascripts/src/dialogs.js +0 -123
  51. data/app/assets/javascripts/src/jquery-plugins.js +0 -452
  52. data/app/assets/javascripts/src/module-loader.js +0 -150
  53. data/app/assets/javascripts/src/setup.js +0 -168
  54. data/app/assets/javascripts/src/utils.js +0 -840
@@ -0,0 +1,1784 @@
1
+ /**
2
+ * jQuery Form Validator
3
+ * ------------------------------------------
4
+ * Created by Victor Jonsson <http://www.victorjonsson.se>
5
+ *
6
+ * @website http://formvalidator.net/
7
+ * @license MIT
8
+ * @version 2.2.81
9
+ */
10
+ (function ($) {
11
+
12
+ 'use strict';
13
+
14
+ var $window = $(window),
15
+ _getInputParentContainer = function ($elem) {
16
+ if ($elem.valAttr('error-msg-container')) {
17
+ return $($elem.valAttr('error-msg-container'));
18
+ } else {
19
+ var $parent = $elem.parent();
20
+ if ( !$parent.hasClass('form-group') && !$parent.closest('form').hasClass('form-horizontal') ) {
21
+ var $formGroup = $parent.closest('.form-group');
22
+ if ($formGroup.length) {
23
+ return $formGroup.eq(0);
24
+ }
25
+ }
26
+ return $parent;
27
+ }
28
+ },
29
+ _applyErrorStyle = function ($elem, conf) {
30
+ $elem
31
+ .addClass(conf.errorElementClass)
32
+ .removeClass('valid');
33
+
34
+ _getInputParentContainer($elem)
35
+ .addClass(conf.inputParentClassOnError)
36
+ .removeClass(conf.inputParentClassOnSuccess);
37
+
38
+ if (conf.borderColorOnError !== '') {
39
+ $elem.css('border-color', conf.borderColorOnError);
40
+ }
41
+ },
42
+ _removeErrorStyle = function ($elem, conf) {
43
+ $elem.each(function () {
44
+ var $this = $(this);
45
+
46
+ _setInlineErrorMessage($this, '', conf, conf.errorMessagePosition);
47
+
48
+ $this
49
+ .removeClass('valid')
50
+ .removeClass(conf.errorElementClass)
51
+ .css('border-color', '');
52
+
53
+ _getInputParentContainer($this)
54
+ .removeClass(conf.inputParentClassOnError)
55
+ .removeClass(conf.inputParentClassOnSuccess)
56
+ .find('.' + conf.errorMessageClass) // remove inline span holding error message
57
+ .remove();
58
+ });
59
+ },
60
+ _setInlineErrorMessage = function ($input, mess, conf, $messageContainer) {
61
+ var custom = document.getElementById($input.attr('name') + '_err_msg'),
62
+ setErrorMessage = function($elem) {
63
+ $window.trigger('validationErrorDisplay', [$input, $elem])
64
+ $elem.html(mess);
65
+ };
66
+
67
+ if (custom) {
68
+ setErrorMessage($(custom));
69
+ }
70
+ else if (typeof $messageContainer == 'object') {
71
+ var $found = false;
72
+ $messageContainer.find('.' + conf.errorMessageClass).each(function () {
73
+ if (this.inputReferer == $input[0]) {
74
+ $found = $(this);
75
+ return false;
76
+ }
77
+ });
78
+ if ($found) {
79
+ if (!mess) {
80
+ $found.remove();
81
+ } else {
82
+ setErrorMessage($found);
83
+ }
84
+ } else {
85
+ var $mess = $('<div class="' + conf.errorMessageClass + '"></div>');
86
+ setErrorMessage($mess);
87
+ $mess[0].inputReferer = $input[0];
88
+ $messageContainer.prepend($mess);
89
+ }
90
+ }
91
+ else {
92
+
93
+ var $parent = _getInputParentContainer($input),
94
+ $mess = $parent.find('.' + conf.errorMessageClass + '.help-block');
95
+
96
+ if ($mess.length == 0) {
97
+ $mess = $('<span></span>').addClass('help-block').addClass(conf.errorMessageClass);
98
+ $mess.appendTo($parent);
99
+ }
100
+
101
+ setErrorMessage($mess);
102
+ }
103
+ },
104
+ _templateMessage = function ($form, title, errorMessages, conf) {
105
+ var messages = conf.errorMessageTemplate.messages.replace(/\{errorTitle\}/g, title),
106
+ fields = [],
107
+ container;
108
+
109
+ $.each(errorMessages, function (i, msg) {
110
+ fields.push(conf.errorMessageTemplate.field.replace(/\{msg\}/g, msg));
111
+ });
112
+
113
+ messages = messages.replace(/\{fields\}/g, fields.join(''));
114
+ container = conf.errorMessageTemplate.container.replace(/\{errorMessageClass\}/g, conf.errorMessageClass);
115
+ container = container.replace(/\{messages\}/g, messages);
116
+ $form.children().eq(0).before(container);
117
+ };
118
+
119
+
120
+ /**
121
+ * Assigns validateInputOnBlur function to elements blur event
122
+ *
123
+ * @param {Object} language Optional, will override $.formUtils.LANG
124
+ * @param {Object} conf Optional, will override the default settings
125
+ * @return {jQuery}
126
+ */
127
+ $.fn.validateOnBlur = function (language, conf) {
128
+ this.find('*[data-validation]')
129
+ .bind('blur.validation', function () {
130
+ $(this).validateInputOnBlur(language, conf, true, 'blur');
131
+ });
132
+ if (conf.validateCheckboxRadioOnClick) {
133
+ // bind click event to validate on click for radio & checkboxes for nice UX
134
+ this.find('input[type=checkbox][data-validation],input[type=radio][data-validation]')
135
+ .bind('click.validation', function () {
136
+ $(this).validateInputOnBlur(language, conf, true, 'click');
137
+ });
138
+ }
139
+
140
+ return this;
141
+ };
142
+
143
+ /*
144
+ * Assigns validateInputOnBlur function to elements custom event
145
+ * @param {Object} language Optional, will override $.formUtils.LANG
146
+ * @param {Object} settings Optional, will override the default settings
147
+ * * @return {jQuery}
148
+ */
149
+ $.fn.validateOnEvent = function (language, settings) {
150
+ this.find('*[data-validation-event]')
151
+ .each(function () {
152
+ var $el = $(this),
153
+ etype = $el.valAttr("event");
154
+ if (etype) {
155
+ $el
156
+ .unbind(etype + ".validation")
157
+ .bind(etype + ".validation", function () {
158
+ $(this).validateInputOnBlur(language, settings, true, etype);
159
+ });
160
+ }
161
+ });
162
+ return this;
163
+ };
164
+
165
+ /**
166
+ * fade in help message when input gains focus
167
+ * fade out when input loses focus
168
+ * <input data-help="The info that I want to display for the user when input is focused" ... />
169
+ *
170
+ * @param {String} attrName - Optional, default is data-help
171
+ * @return {jQuery}
172
+ */
173
+ $.fn.showHelpOnFocus = function (attrName) {
174
+ if (!attrName) {
175
+ attrName = 'data-validation-help';
176
+ }
177
+
178
+ // Remove previously added event listeners
179
+ this.find('.has-help-txt')
180
+ .valAttr('has-keyup-event', false)
181
+ .removeClass('has-help-txt');
182
+
183
+ // Add help text listeners
184
+ this.find('textarea,input').each(function () {
185
+ var $elem = $(this),
186
+ className = 'jquery_form_help_' + ($elem.attr('name') || '').replace(/(:|\.|\[|\])/g, ""),
187
+ help = $elem.attr(attrName);
188
+
189
+ if (help) {
190
+ $elem
191
+ .addClass('has-help-txt')
192
+ .unbind('focus.help')
193
+ .bind('focus.help', function () {
194
+ var $help = $elem.parent().find('.' + className);
195
+ if ($help.length == 0) {
196
+ $help = $('<span />')
197
+ .addClass(className)
198
+ .addClass('help')
199
+ .addClass('help-block') // twitter bs
200
+ .text(help)
201
+ .hide();
202
+
203
+ $elem.after($help);
204
+ }
205
+ $help.fadeIn();
206
+ })
207
+ .unbind('blur.help')
208
+ .bind('blur.help', function () {
209
+ $(this)
210
+ .parent()
211
+ .find('.' + className)
212
+ .fadeOut('slow');
213
+ });
214
+ }
215
+ });
216
+
217
+ return this;
218
+ };
219
+
220
+ /**
221
+ * @param {Function} cb
222
+ * @param {Object} [conf]
223
+ * @param {Object} [lang]
224
+ */
225
+ $.fn.validate = function(cb, conf, lang) {
226
+ var language = $.extend({}, $.formUtils.LANG, lang || {});
227
+ this.each(function() {
228
+ var $elem = $(this),
229
+ formDefaultConfig = $elem.closest('form').get(0).validationConfig || {};
230
+
231
+ $elem.one('validation', function(evt, isValid) {
232
+ if( typeof cb == 'function' )
233
+ cb(isValid, this, evt);
234
+ });
235
+
236
+ $elem.validateInputOnBlur(
237
+ language,
238
+ $.extend({}, formDefaultConfig, conf || {}),
239
+ true
240
+ );
241
+ });
242
+ };
243
+
244
+ /**
245
+ * Tells whether or not validation of this input will have to postpone the form submit ()
246
+ * @returns {Boolean}
247
+ */
248
+ $.fn.willPostponeValidation = function() {
249
+ return (this.valAttr('suggestion-nr') ||
250
+ this.valAttr('postpone') ||
251
+ this.hasClass('hasDatepicker'))
252
+ && !window.postponedValidation;
253
+ };
254
+
255
+ /**
256
+ * Validate single input when it loses focus
257
+ * shows error message in a span element
258
+ * that is appended to the parent element
259
+ *
260
+ * @param {Object} [language] Optional, will override $.formUtils.LANG
261
+ * @param {Object} [conf] Optional, will override the default settings
262
+ * @param {Boolean} attachKeyupEvent Optional
263
+ * @param {String} eventType
264
+ * @return {jQuery}
265
+ */
266
+ $.fn.validateInputOnBlur = function (language, conf, attachKeyupEvent, eventType) {
267
+
268
+ $.formUtils.eventType = eventType;
269
+
270
+ if ( this.willPostponeValidation() ) {
271
+ // This validation has to be postponed
272
+ var _self = this,
273
+ postponeTime = this.valAttr('postpone') || 200;
274
+
275
+ window.postponedValidation = function () {
276
+ _self.validateInputOnBlur(language, conf, attachKeyupEvent, eventType);
277
+ window.postponedValidation = false;
278
+ };
279
+
280
+ setTimeout(function () {
281
+ if (window.postponedValidation) {
282
+ window.postponedValidation();
283
+ }
284
+ }, postponeTime);
285
+
286
+ return this;
287
+ }
288
+
289
+ language = $.extend({}, $.formUtils.LANG, language || {});
290
+ _removeErrorStyle(this, conf);
291
+ var $elem = this,
292
+ $form = $elem.closest("form"),
293
+ validationRule = $elem.attr(conf.validationRuleAttribute),
294
+ result = $.formUtils.validateInput(
295
+ $elem,
296
+ language,
297
+ conf,
298
+ $form,
299
+ eventType
300
+ );
301
+
302
+ if ( result.isValid ) {
303
+ if( result.shouldChangeDisplay ) {
304
+ $elem.addClass('valid');
305
+ _getInputParentContainer($elem)
306
+ .addClass(conf.inputParentClassOnSuccess);
307
+ }
308
+ }
309
+ else if (!result.isValid) {
310
+
311
+ _applyErrorStyle($elem, conf);
312
+ _setInlineErrorMessage($elem, result.errorMsg, conf, conf.errorMessagePosition);
313
+
314
+ if (attachKeyupEvent) {
315
+ $elem
316
+ .unbind('keyup.validation')
317
+ .bind('keyup.validation', function () {
318
+ $(this).validateInputOnBlur(language, conf, false, 'keyup');
319
+ });
320
+ }
321
+ }
322
+
323
+ return this;
324
+ };
325
+
326
+ /**
327
+ * Short hand for fetching/adding/removing element attributes
328
+ * prefixed with 'data-validation-'
329
+ *
330
+ * @param {String} name
331
+ * @param {String|Boolean} [val]
332
+ * @return string|undefined
333
+ * @protected
334
+ */
335
+ $.fn.valAttr = function (name, val) {
336
+ if (val === undefined) {
337
+ return this.attr('data-validation-' + name);
338
+ } else if (val === false || val === null) {
339
+ return this.removeAttr('data-validation-' + name);
340
+ } else {
341
+ if (name.length > 0) name = '-' + name;
342
+ return this.attr('data-validation' + name, val);
343
+ }
344
+ };
345
+
346
+ /**
347
+ * Function that validates all inputs in active form
348
+ *
349
+ * @param {Object} [language]
350
+ * @param {Object} [conf]
351
+ * @param {Boolean} [displayError] Defaults to true
352
+ */
353
+ $.fn.isValid = function (language, conf, displayError) {
354
+
355
+ if ($.formUtils.isLoadingModules) {
356
+ var $self = this;
357
+ setTimeout(function () {
358
+ $self.isValid(language, conf, displayError);
359
+ }, 200);
360
+ return null;
361
+ }
362
+
363
+ conf = $.extend({}, $.formUtils.defaultConfig(), conf || {});
364
+ language = $.extend({}, $.formUtils.LANG, language || {});
365
+ displayError = displayError !== false;
366
+
367
+ if ($.formUtils.errorDisplayPreventedWhenHalted) {
368
+ // isValid() was called programmatically with argument displayError set
369
+ // to false when the validation was halted by any of the validators
370
+ delete $.formUtils.errorDisplayPreventedWhenHalted
371
+ displayError = false;
372
+ }
373
+
374
+ $.formUtils.isValidatingEntireForm = true;
375
+ $.formUtils.haltValidation = false;
376
+
377
+ /**
378
+ * Adds message to error message stack if not already in the message stack
379
+ *
380
+ * @param {String} mess
381
+ * @para {jQuery} $elem
382
+ */
383
+ var addErrorMessage = function (mess, $elem) {
384
+ if ($.inArray(mess, errorMessages) < 0) {
385
+ errorMessages.push(mess);
386
+ }
387
+ errorInputs.push($elem);
388
+ $elem.attr('current-error', mess);
389
+ if (displayError)
390
+ _applyErrorStyle($elem, conf);
391
+ },
392
+
393
+ /** Holds inputs (of type checkox or radio) already validated, to prevent recheck of mulitple checkboxes & radios */
394
+ checkedInputs = [],
395
+
396
+ /** Error messages for this validation */
397
+ errorMessages = [],
398
+
399
+ /** Input elements which value was not valid */
400
+ errorInputs = [],
401
+
402
+ /** Form instance */
403
+ $form = this,
404
+
405
+ /**
406
+ * Tells whether or not to validate element with this name and of this type
407
+ *
408
+ * @param {String} name
409
+ * @param {String} type
410
+ * @return {Boolean}
411
+ */
412
+ ignoreInput = function (name, type) {
413
+ if (type === 'submit' || type === 'button' || type == 'reset') {
414
+ return true;
415
+ }
416
+ return $.inArray(name, conf.ignore || []) > -1;
417
+ };
418
+
419
+ // Reset style and remove error class
420
+ if (displayError) {
421
+ $form.find('.' + conf.errorMessageClass + '.alert').remove();
422
+ _removeErrorStyle($form.find('.' + conf.errorElementClass + ',.valid'), conf);
423
+ }
424
+
425
+ // Validate element values
426
+ $form.find('input,textarea,select').filter(':not([type="submit"],[type="button"])').each(function () {
427
+ var $elem = $(this),
428
+ elementType = $elem.attr('type'),
429
+ isCheckboxOrRadioBtn = elementType == 'radio' || elementType == 'checkbox',
430
+ elementName = $elem.attr('name');
431
+
432
+ if (!ignoreInput(elementName, elementType) && (!isCheckboxOrRadioBtn || $.inArray(elementName, checkedInputs) < 0)) {
433
+
434
+ if (isCheckboxOrRadioBtn)
435
+ checkedInputs.push(elementName);
436
+
437
+ var result = $.formUtils.validateInput(
438
+ $elem,
439
+ language,
440
+ conf,
441
+ $form,
442
+ 'submit'
443
+ );
444
+
445
+ if( result.shouldChangeDisplay ) {
446
+ if ( !result.isValid ) {
447
+ addErrorMessage(result.errorMsg, $elem);
448
+ } else if( result.isValid ) {
449
+ $elem
450
+ .valAttr('current-error', false)
451
+ .addClass('valid');
452
+
453
+ _getInputParentContainer($elem)
454
+ .addClass(conf.inputParentClassOnSuccess);
455
+ }
456
+ }
457
+ }
458
+ });
459
+
460
+ // Run validation callback
461
+ if (typeof conf.onValidate == 'function') {
462
+ var errors = conf.onValidate($form);
463
+ if ($.isArray(errors)) {
464
+ $.each(errors, function (i, err) {
465
+ addErrorMessage(err.message, err.element);
466
+ });
467
+ }
468
+ else if (errors && errors.element && errors.message) {
469
+ addErrorMessage(errors.message, errors.element);
470
+ }
471
+ }
472
+
473
+ // Reset form validation flag
474
+ $.formUtils.isValidatingEntireForm = false;
475
+
476
+ // Validation failed
477
+ if (!$.formUtils.haltValidation && errorInputs.length > 0) {
478
+
479
+ if (displayError) {
480
+ // display all error messages in top of form
481
+ if (conf.errorMessagePosition === 'top') {
482
+ _templateMessage($form, language.errorTitle, errorMessages, conf);
483
+ }
484
+ // Customize display message
485
+ else if (conf.errorMessagePosition === 'custom') {
486
+ if (typeof conf.errorMessageCustom === 'function') {
487
+ conf.errorMessageCustom($form, language.errorTitle, errorMessages, conf);
488
+ }
489
+ }
490
+ // Display error message below input field or in defined container
491
+ else {
492
+ $.each(errorInputs, function (i, $input) {
493
+ _setInlineErrorMessage($input, $input.attr('current-error'), conf, conf.errorMessagePosition);
494
+ });
495
+ }
496
+
497
+ if (conf.scrollToTopOnError) {
498
+ $window.scrollTop($form.offset().top - 20);
499
+ }
500
+ }
501
+
502
+ return false;
503
+ }
504
+
505
+ if (!displayError && $.formUtils.haltValidation) {
506
+ $.formUtils.errorDisplayPreventedWhenHalted = true;
507
+ }
508
+
509
+ return !$.formUtils.haltValidation;
510
+ };
511
+
512
+ /**
513
+ * @deprecated
514
+ * @param language
515
+ * @param conf
516
+ */
517
+ $.fn.validateForm = function (language, conf) {
518
+ if (window.console && typeof window.console.warn == 'function') {
519
+ window.console.warn('Use of deprecated function $.validateForm, use $.isValid instead');
520
+ }
521
+ return this.isValid(language, conf, true);
522
+ }
523
+
524
+ /**
525
+ * Plugin for displaying input length restriction
526
+ */
527
+ $.fn.restrictLength = function (maxLengthElement) {
528
+ new $.formUtils.lengthRestriction(this, maxLengthElement);
529
+ return this;
530
+ };
531
+
532
+ /**
533
+ * Add suggestion dropdown to inputs having data-suggestions with a comma
534
+ * separated string with suggestions
535
+ * @param {Array} [settings]
536
+ * @returns {jQuery}
537
+ */
538
+ $.fn.addSuggestions = function (settings) {
539
+ var sugs = false;
540
+ this.find('input').each(function () {
541
+ var $field = $(this);
542
+
543
+ sugs = $.split($field.attr('data-suggestions'));
544
+
545
+ if (sugs.length > 0 && !$field.hasClass('has-suggestions')) {
546
+ $.formUtils.suggest($field, sugs, settings);
547
+ $field.addClass('has-suggestions');
548
+ }
549
+ });
550
+ return this;
551
+ };
552
+
553
+ /**
554
+ * A bit smarter split function
555
+ * delimiter can be space, comma, dash or pipe
556
+ * @param {String} val
557
+ * @param {Function|String} [callback]
558
+ * @returns {Array|void}
559
+ */
560
+ $.split = function (val, callback) {
561
+ if (typeof callback != 'function') {
562
+ // return array
563
+ if (!val)
564
+ return [];
565
+ var values = [];
566
+ $.each(val.split(callback ? callback : /[,|\-\s]\s*/g),
567
+ function (i, str) {
568
+ str = $.trim(str);
569
+ if (str.length)
570
+ values.push(str);
571
+ }
572
+ );
573
+ return values;
574
+ } else if (val) {
575
+ // exec callback func on each
576
+ $.each(val.split(/[,|\-\s]\s*/g),
577
+ function (i, str) {
578
+ str = $.trim(str);
579
+ if (str.length)
580
+ return callback(str, i);
581
+ }
582
+ );
583
+ }
584
+ };
585
+
586
+ /**
587
+ * Short hand function that makes the validation setup require less code
588
+ * @param conf
589
+ */
590
+ $.validate = function (conf) {
591
+
592
+ var defaultConf = $.extend($.formUtils.defaultConfig(), {
593
+ form: 'form',
594
+ /*
595
+ * Enable custom event for validation
596
+ */
597
+ validateOnEvent: false,
598
+ validateOnBlur: true,
599
+ validateCheckboxRadioOnClick: true,
600
+ showHelpOnFocus: true,
601
+ addSuggestions: true,
602
+ modules: '',
603
+ onModulesLoaded: null,
604
+ language: false,
605
+ onSuccess: false,
606
+ onError: false,
607
+ onElementValidate: false,
608
+ });
609
+
610
+ conf = $.extend(defaultConf, conf || {});
611
+
612
+ if( conf.lang && conf.lang != 'en' ) {
613
+ var langModule = 'lang/'+conf.lang+'.js';
614
+ conf.modules += conf.modules.length ? ','+langModule : langModule;
615
+ }
616
+
617
+ // Add validation to forms
618
+ $(conf.form).each(function (i, form) {
619
+
620
+ // Make a reference to the config for this form
621
+ form.validationConfig = conf;
622
+
623
+ // Trigger jQuery event that we're about to setup va
624
+ var $form = $(form);
625
+ $window.trigger('formValidationSetup', [$form, conf]);
626
+
627
+ // Remove classes and event handlers that might have been
628
+ // added by a previous call to $.validate
629
+ $form.find('.has-help-txt')
630
+ .unbind('focus.validation')
631
+ .unbind('blur.validation');
632
+
633
+ $form
634
+ .removeClass('has-validation-callback')
635
+ .unbind('submit.validation')
636
+ .unbind('reset.validation')
637
+ .find('input[data-validation],textarea[data-validation]')
638
+ .unbind('blur.validation');
639
+
640
+ // Validate when submitted
641
+ $form.bind('submit.validation', function () {
642
+
643
+ var $form = $(this);
644
+
645
+ if ($.formUtils.haltValidation) {
646
+ // pressing several times on submit button while validation is halted
647
+ return false;
648
+ }
649
+
650
+ if ($.formUtils.isLoadingModules) {
651
+ setTimeout(function () {
652
+ $form.trigger('submit.validation');
653
+ }, 200);
654
+ return false;
655
+ }
656
+
657
+ var valid = $form.isValid(conf.language, conf);
658
+
659
+ if ($.formUtils.haltValidation) {
660
+ // Validation got halted by one of the validators
661
+ return false;
662
+ } else {
663
+ if (valid && typeof conf.onSuccess == 'function') {
664
+ var callbackResponse = conf.onSuccess($form);
665
+ if (callbackResponse === false) {
666
+ return false;
667
+ }
668
+ } else if (!valid && typeof conf.onError == 'function') {
669
+ conf.onError($form);
670
+ return false;
671
+ } else {
672
+ return valid;
673
+ }
674
+ }
675
+ })
676
+ .bind('reset.validation', function () {
677
+ // remove messages
678
+ $(this).find('.' + conf.errorMessageClass + '.alert').remove();
679
+ _removeErrorStyle($(this).find('.' + conf.errorElementClass + ',.valid'), conf);
680
+ })
681
+ .addClass('has-validation-callback');
682
+
683
+ if (conf.showHelpOnFocus) {
684
+ $form.showHelpOnFocus();
685
+ }
686
+ if (conf.addSuggestions) {
687
+ $form.addSuggestions();
688
+ }
689
+ if (conf.validateOnBlur) {
690
+ $form.validateOnBlur(conf.language, conf);
691
+ $form.bind('html5ValidationAttrsFound', function () {
692
+ $form.validateOnBlur(conf.language, conf);
693
+ })
694
+ }
695
+ if (conf.validateOnEvent) {
696
+ $form.validateOnEvent(conf.language, conf);
697
+ }
698
+ });
699
+
700
+ if (conf.modules != '') {
701
+ $.formUtils.loadModules(conf.modules, false, function() {
702
+ if (typeof conf.onModulesLoaded == 'function') {
703
+ conf.onModulesLoaded();
704
+ }
705
+ $window.trigger('validatorsLoaded', [typeof conf.form == 'string' ? $(conf.form) : conf.form, conf]);
706
+ });
707
+ }
708
+ };
709
+
710
+ /**
711
+ * Object containing utility methods for this plugin
712
+ */
713
+ $.formUtils = {
714
+
715
+ /**
716
+ * Default config for $(...).isValid();
717
+ */
718
+ defaultConfig: function () {
719
+ return {
720
+ ignore: [], // Names of inputs not to be validated even though node attribute containing the validation rules tells us to
721
+ errorElementClass: 'error', // Class that will be put on elements which value is invalid
722
+ borderColorOnError: '#b94a48', // Border color of elements which value is invalid, empty string to not change border color
723
+ errorMessageClass: 'form-error', // class name of div containing error messages when validation fails
724
+ validationRuleAttribute: 'data-validation', // name of the attribute holding the validation rules
725
+ validationErrorMsgAttribute: 'data-validation-error-msg', // define custom err msg inline with element
726
+ errorMessagePosition: 'element', // Can be either "top" or "element" or "custom"
727
+ errorMessageTemplate: {
728
+ container: '<div class="{errorMessageClass} alert alert-danger">{messages}</div>',
729
+ messages: '<strong>{errorTitle}</strong><ul>{fields}</ul>',
730
+ field: '<li>{msg}</li>'
731
+ },
732
+ errorMessageCustom: _templateMessage,
733
+ scrollToTopOnError: true,
734
+ dateFormat: 'yyyy-mm-dd',
735
+ addValidClassOnAll: false, // whether or not to apply class="valid" even if the input wasn't validated
736
+ decimalSeparator: '.',
737
+ inputParentClassOnError: 'has-error', // twitter-bootstrap default class name
738
+ inputParentClassOnSuccess: 'has-success', // twitter-bootstrap default class name
739
+ validateHiddenInputs: false, // whether or not hidden inputs should be validated
740
+ }
741
+ },
742
+
743
+ /**
744
+ * Available validators
745
+ */
746
+ validators: {},
747
+
748
+ /**
749
+ * Events triggered by form validator
750
+ */
751
+ _events: {load: [], valid: [], invalid: []},
752
+
753
+ /**
754
+ * Setting this property to true during validation will
755
+ * stop further validation from taking place and form will
756
+ * not be sent
757
+ */
758
+ haltValidation: false,
759
+
760
+ /**
761
+ * This variable will be true $.fn.isValid() is called
762
+ * and false when $.fn.validateOnBlur is called
763
+ */
764
+ isValidatingEntireForm: false,
765
+
766
+ /**
767
+ * Function for adding a validator
768
+ * @param {Object} validator
769
+ */
770
+ addValidator: function (validator) {
771
+ // prefix with "validate_" for backward compatibility reasons
772
+ var name = validator.name.indexOf('validate_') === 0 ? validator.name : 'validate_' + validator.name;
773
+ if (validator.validateOnKeyUp === undefined)
774
+ validator.validateOnKeyUp = true;
775
+ this.validators[name] = validator;
776
+ },
777
+
778
+ /**
779
+ * @var {Boolean}
780
+ */
781
+ isLoadingModules: false,
782
+
783
+ /**
784
+ * @var {Object}
785
+ */
786
+ loadedModules: {},
787
+
788
+ /**
789
+ * @example
790
+ * $.formUtils.loadModules('date, security.dev');
791
+ *
792
+ * Will load the scripts date.js and security.dev.js from the
793
+ * directory where this script resides. If you want to load
794
+ * the modules from another directory you can use the
795
+ * path argument.
796
+ *
797
+ * The script will be cached by the browser unless the module
798
+ * name ends with .dev
799
+ *
800
+ * @param {String} modules - Comma separated string with module file names (no directory nor file extension)
801
+ * @param {String} [path] - Optional, path where the module files is located if their not in the same directory as the core modules
802
+ * @param {Boolean|function} [fireEvent] - Optional, whether or not to fire event 'load' when modules finished loading
803
+ */
804
+ loadModules: function (modules, path, fireEvent) {
805
+
806
+ if (fireEvent === undefined)
807
+ fireEvent = true;
808
+
809
+ if ($.formUtils.isLoadingModules) {
810
+ setTimeout(function () {
811
+ $.formUtils.loadModules(modules, path, fireEvent);
812
+ });
813
+ return;
814
+ }
815
+
816
+ var hasLoadedAnyModule = false,
817
+ loadModuleScripts = function (modules, path) {
818
+
819
+ var moduleList = $.split(modules),
820
+ numModules = moduleList.length,
821
+ moduleLoadedCallback = function () {
822
+ numModules--;
823
+ if (numModules == 0) {
824
+ $.formUtils.isLoadingModules = false;
825
+ if (fireEvent && hasLoadedAnyModule) {
826
+ if( typeof fireEvent == 'function' ) {
827
+ fireEvent();
828
+ } else {
829
+ $window.trigger('validatorsLoaded');
830
+ }
831
+ }
832
+ }
833
+ };
834
+
835
+
836
+ if (numModules > 0) {
837
+ $.formUtils.isLoadingModules = true;
838
+ }
839
+
840
+ var cacheSuffix = '?_=' + ( new Date().getTime() ),
841
+ appendToElement = document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0];
842
+
843
+ $.each(moduleList, function (i, modName) {
844
+ modName = $.trim(modName);
845
+ if (modName.length == 0) {
846
+ moduleLoadedCallback();
847
+ }
848
+ else {
849
+ var scriptUrl = path + modName + (modName.slice(-3) == '.js' ? '' : '.js'),
850
+ script = document.createElement('SCRIPT');
851
+
852
+ if (scriptUrl in $.formUtils.loadedModules) {
853
+ // already loaded
854
+ moduleLoadedCallback();
855
+ }
856
+ else {
857
+
858
+ // Remember that this script is loaded
859
+ $.formUtils.loadedModules[scriptUrl] = 1;
860
+ hasLoadedAnyModule = true;
861
+
862
+ // Load the script
863
+ script.type = 'text/javascript';
864
+ script.onload = moduleLoadedCallback;
865
+ script.src = scriptUrl + ( scriptUrl.slice(-7) == '.dev.js' ? cacheSuffix : '' );
866
+ script.onerror = function() {
867
+ if( 'console' in window && window.console.log ) {
868
+ window.console.log('Unable to load form validation module '+scriptUrl);
869
+ }
870
+ };
871
+ script.onreadystatechange = function () {
872
+ // IE 7 fix
873
+ if (this.readyState == 'complete' || this.readyState == 'loaded') {
874
+ moduleLoadedCallback();
875
+ // Handle memory leak in IE
876
+ this.onload = null;
877
+ this.onreadystatechange = null;
878
+ }
879
+ };
880
+ appendToElement.appendChild(script);
881
+ }
882
+ }
883
+ });
884
+ };
885
+
886
+ if (path) {
887
+ loadModuleScripts(modules, path);
888
+ } else {
889
+ var findScriptPathAndLoadModules = function () {
890
+ var foundPath = false;
891
+ $('script[src*="form-validator"]').each(function () {
892
+ foundPath = this.src.substr(0, this.src.lastIndexOf('/')) + '/';
893
+ if (foundPath == '/')
894
+ foundPath = '';
895
+ return false;
896
+ });
897
+
898
+ if (foundPath !== false) {
899
+ loadModuleScripts(modules, foundPath);
900
+ return true;
901
+ }
902
+ return false;
903
+ };
904
+
905
+ if (!findScriptPathAndLoadModules()) {
906
+ $(findScriptPathAndLoadModules);
907
+ }
908
+ }
909
+ },
910
+
911
+ /**
912
+ * Validate the value of given element according to the validation rules
913
+ * found in the attribute data-validation. Will return an object representing
914
+ * a validation result, having the props shouldChangeDisplay, isValid and errorMsg
915
+ * @param {jQuery} $elem
916
+ * @param {Object} language ($.formUtils.LANG)
917
+ * @param {Object} conf
918
+ * @param {jQuery} $form
919
+ * @param {String} [eventContext]
920
+ * @return {Object}
921
+ */
922
+ validateInput: function ($elem, language, conf, $form, eventContext) {
923
+
924
+ $elem.trigger('beforeValidation');
925
+ conf = conf || $.formUtils.defaultConfig();
926
+ language = language || $.formUtils.LANG;
927
+
928
+ var value = $elem.val() || '',
929
+ result = {isValid: true, shouldChangeDisplay:true, errorMsg:''},
930
+ optional = $elem.valAttr('optional'),
931
+
932
+ // test if a checkbox forces this element to be validated
933
+ validationDependsOnCheckedInput = false,
934
+ validationDependentInputIsChecked = false,
935
+ validateIfCheckedElement = false,
936
+
937
+ // get value of this element's attribute "... if-checked"
938
+ validateIfCheckedElementName = $elem.valAttr('if-checked');
939
+
940
+ if ($elem.attr('disabled') || (!$elem.is(':visible') && !conf.validateHiddenInputs)) {
941
+ result.shouldChangeDisplay = false;
942
+ return result;
943
+ }
944
+
945
+ // make sure we can proceed
946
+ if (validateIfCheckedElementName != null) {
947
+
948
+ // Set the boolean telling us that the validation depends
949
+ // on another input being checked
950
+ validationDependsOnCheckedInput = true;
951
+
952
+ // select the checkbox type element in this form
953
+ validateIfCheckedElement = $form.find('input[name="' + validateIfCheckedElementName + '"]');
954
+
955
+ // test if it's property "checked" is checked
956
+ if (validateIfCheckedElement.prop('checked')) {
957
+ // set value for validation checkpoint
958
+ validationDependentInputIsChecked = true;
959
+ }
960
+ }
961
+
962
+ // validation checkpoint
963
+ // if empty AND optional attribute is present
964
+ // OR depending on a checkbox being checked AND checkbox is checked, return true
965
+ var isInvalidNumberInput = !value && $elem[0].type == 'number';
966
+ if ((!value && optional === 'true' && !isInvalidNumberInput) || (validationDependsOnCheckedInput && !validationDependentInputIsChecked)) {
967
+ result.shouldChangeDisplay = conf.addValidClassOnAll;
968
+ return result;
969
+ }
970
+
971
+ var validationRules = $elem.attr(conf.validationRuleAttribute),
972
+
973
+ // see if form element has inline err msg attribute
974
+ validationErrorMsg = true;
975
+
976
+ if (!validationRules) {
977
+ result.shouldChangeDisplay = conf.addValidClassOnAll;
978
+ return result;
979
+ }
980
+
981
+ $.split(validationRules, function (rule) {
982
+ if (rule.indexOf('validate_') !== 0) {
983
+ rule = 'validate_' + rule;
984
+ }
985
+
986
+ var validator = $.formUtils.validators[rule];
987
+
988
+ if (validator && typeof validator['validatorFunction'] == 'function') {
989
+
990
+ // special change of element for checkbox_group rule
991
+ if (rule == 'validate_checkbox_group') {
992
+ // set element to first in group, so error msg attr doesn't need to be set on all elements in group
993
+ $elem = $form.find("[name='" + $elem.attr('name') + "']:eq(0)");
994
+ }
995
+
996
+ var isValid = null;
997
+ if (eventContext != 'keyup' || validator.validateOnKeyUp) {
998
+ isValid = validator.validatorFunction(value, $elem, conf, language, $form);
999
+ }
1000
+
1001
+ if (!isValid) {
1002
+ validationErrorMsg = null;
1003
+ if (isValid !== null) {
1004
+ validationErrorMsg = $elem.attr(conf.validationErrorMsgAttribute + '-' + rule.replace('validate_', ''));
1005
+ if (!validationErrorMsg) {
1006
+ validationErrorMsg = $elem.attr(conf.validationErrorMsgAttribute);
1007
+ if (!validationErrorMsg) {
1008
+ validationErrorMsg = language[validator.errorMessageKey];
1009
+ if (!validationErrorMsg)
1010
+ validationErrorMsg = validator.errorMessage;
1011
+ }
1012
+ }
1013
+ }
1014
+ return false; // break iteration
1015
+ }
1016
+
1017
+ } else {
1018
+ throw new Error('Using undefined validator "' + rule + '"');
1019
+ }
1020
+
1021
+ }, ' ');
1022
+
1023
+ if (typeof validationErrorMsg == 'string') {
1024
+ $elem.trigger('validation', false);
1025
+ result.errorMsg = validationErrorMsg;
1026
+ result.isValid = false;
1027
+ result.shouldChangeDisplay = true;
1028
+ } else if (validationErrorMsg === null) {
1029
+ result.shouldChangeDisplay = conf.addValidClassOnAll;
1030
+ } else {
1031
+ $elem.trigger('validation', true);
1032
+ result.shouldChangeDisplay = true;
1033
+ }
1034
+
1035
+ // Run element validation callback
1036
+ if (typeof conf.onElementValidate == 'function' && validationErrorMsg !== null) {
1037
+ conf.onElementValidate(result.isValid, $elem, $form, validationErrorMsg);
1038
+ }
1039
+
1040
+ return result;
1041
+ },
1042
+
1043
+ /**
1044
+ * Is it a correct date according to given dateFormat. Will return false if not, otherwise
1045
+ * an array 0=>year 1=>month 2=>day
1046
+ *
1047
+ * @param {String} val
1048
+ * @param {String} dateFormat
1049
+ * @return {Array}|{Boolean}
1050
+ */
1051
+ parseDate: function (val, dateFormat) {
1052
+ var divider = dateFormat.replace(/[a-zA-Z]/gi, '').substring(0, 1),
1053
+ regexp = '^',
1054
+ formatParts = dateFormat.split(divider || null),
1055
+ matches, day, month, year;
1056
+
1057
+ $.each(formatParts, function (i, part) {
1058
+ regexp += (i > 0 ? '\\' + divider : '') + '(\\d{' + part.length + '})';
1059
+ });
1060
+
1061
+ regexp += '$';
1062
+
1063
+ matches = val.match(new RegExp(regexp));
1064
+ if (matches === null) {
1065
+ return false;
1066
+ }
1067
+
1068
+ var findDateUnit = function (unit, formatParts, matches) {
1069
+ for (var i = 0; i < formatParts.length; i++) {
1070
+ if (formatParts[i].substring(0, 1) === unit) {
1071
+ return $.formUtils.parseDateInt(matches[i + 1]);
1072
+ }
1073
+ }
1074
+ return -1;
1075
+ };
1076
+
1077
+ month = findDateUnit('m', formatParts, matches);
1078
+ day = findDateUnit('d', formatParts, matches);
1079
+ year = findDateUnit('y', formatParts, matches);
1080
+
1081
+ if ((month === 2 && day > 28 && (year % 4 !== 0 || year % 100 === 0 && year % 400 !== 0))
1082
+ || (month === 2 && day > 29 && (year % 4 === 0 || year % 100 !== 0 && year % 400 === 0))
1083
+ || month > 12 || month === 0) {
1084
+ return false;
1085
+ }
1086
+ if ((this.isShortMonth(month) && day > 30) || (!this.isShortMonth(month) && day > 31) || day === 0) {
1087
+ return false;
1088
+ }
1089
+
1090
+ return [year, month, day];
1091
+ },
1092
+
1093
+ /**
1094
+ * skum fix. är talet 05 eller lägre ger parseInt rätt int annars får man 0 när man kör parseInt?
1095
+ *
1096
+ * @param {String} val
1097
+ * @param {Number}
1098
+ */
1099
+ parseDateInt: function (val) {
1100
+ if (val.indexOf('0') === 0) {
1101
+ val = val.replace('0', '');
1102
+ }
1103
+ return parseInt(val, 10);
1104
+ },
1105
+
1106
+ /**
1107
+ * Has month only 30 days?
1108
+ *
1109
+ * @param {Number} m
1110
+ * @return {Boolean}
1111
+ */
1112
+ isShortMonth: function (m) {
1113
+ return (m % 2 === 0 && m < 7) || (m % 2 !== 0 && m > 7);
1114
+ },
1115
+
1116
+ /**
1117
+ * Restrict input length
1118
+ *
1119
+ * @param {jQuery} $inputElement Jquery Html object
1120
+ * @param {jQuery} $maxLengthElement jQuery Html Object
1121
+ * @return void
1122
+ */
1123
+ lengthRestriction: function ($inputElement, $maxLengthElement) {
1124
+ // read maxChars from counter display initial text value
1125
+ var maxChars = parseInt($maxLengthElement.text(), 10),
1126
+ charsLeft = 0,
1127
+
1128
+ // internal function does the counting and sets display value
1129
+ countCharacters = function () {
1130
+ var numChars = $inputElement.val().length;
1131
+ if (numChars > maxChars) {
1132
+ // get current scroll bar position
1133
+ var currScrollTopPos = $inputElement.scrollTop();
1134
+ // trim value to max length
1135
+ $inputElement.val($inputElement.val().substring(0, maxChars));
1136
+ $inputElement.scrollTop(currScrollTopPos);
1137
+ }
1138
+ charsLeft = maxChars - numChars;
1139
+ if (charsLeft < 0)
1140
+ charsLeft = 0;
1141
+
1142
+ // set counter text
1143
+ $maxLengthElement.text(charsLeft);
1144
+ };
1145
+
1146
+ // bind events to this element
1147
+ // setTimeout is needed, cut or paste fires before val is available
1148
+ $($inputElement).bind('keydown keyup keypress focus blur', countCharacters)
1149
+ .bind('cut paste', function () {
1150
+ setTimeout(countCharacters, 100);
1151
+ });
1152
+
1153
+ // count chars on pageload, if there are prefilled input-values
1154
+ $(document).bind("ready", countCharacters);
1155
+ },
1156
+
1157
+ /**
1158
+ * Test numeric against allowed range
1159
+ *
1160
+ * @param $value int
1161
+ * @param $rangeAllowed str; (1-2, min1, max2, 10)
1162
+ * @return array
1163
+ */
1164
+ numericRangeCheck: function (value, rangeAllowed) {
1165
+ // split by dash
1166
+ var range = $.split(rangeAllowed),
1167
+ // min or max
1168
+ minmax = parseInt(rangeAllowed.substr(3), 10);
1169
+
1170
+ if( range.length == 1 && rangeAllowed.indexOf('min') == -1 && rangeAllowed.indexOf('max') == -1 ) {
1171
+ range = [rangeAllowed, rangeAllowed]; // only a number, checking agains an exact number of characters
1172
+ }
1173
+
1174
+ // range ?
1175
+ if (range.length == 2 && (value < parseInt(range[0], 10) || value > parseInt(range[1], 10) )) {
1176
+ return [ "out", range[0], range[1] ];
1177
+ } // value is out of range
1178
+ else if (rangeAllowed.indexOf('min') === 0 && (value < minmax )) // min
1179
+ {
1180
+ return ["min", minmax];
1181
+ } // value is below min
1182
+ else if (rangeAllowed.indexOf('max') === 0 && (value > minmax )) // max
1183
+ {
1184
+ return ["max", minmax];
1185
+ } // value is above max
1186
+ // since no other returns executed, value is in allowed range
1187
+ return [ "ok" ];
1188
+ },
1189
+
1190
+
1191
+ _numSuggestionElements: 0,
1192
+ _selectedSuggestion: null,
1193
+ _previousTypedVal: null,
1194
+
1195
+ /**
1196
+ * Utility function that can be used to create plugins that gives
1197
+ * suggestions when inputs is typed into
1198
+ * @param {jQuery} $elem
1199
+ * @param {Array} suggestions
1200
+ * @param {Object} settings - Optional
1201
+ * @return {jQuery}
1202
+ */
1203
+ suggest: function ($elem, suggestions, settings) {
1204
+ var conf = {
1205
+ css: {
1206
+ maxHeight: '150px',
1207
+ background: '#FFF',
1208
+ lineHeight: '150%',
1209
+ textDecoration: 'underline',
1210
+ overflowX: 'hidden',
1211
+ overflowY: 'auto',
1212
+ border: '#CCC solid 1px',
1213
+ borderTop: 'none',
1214
+ cursor: 'pointer'
1215
+ },
1216
+ activeSuggestionCSS: {
1217
+ background: '#E9E9E9'
1218
+ }
1219
+ },
1220
+ setSuggsetionPosition = function ($suggestionContainer, $input) {
1221
+ var offset = $input.offset();
1222
+ $suggestionContainer.css({
1223
+ width: $input.outerWidth(),
1224
+ left: offset.left + 'px',
1225
+ top: (offset.top + $input.outerHeight()) + 'px'
1226
+ });
1227
+ };
1228
+
1229
+ if (settings)
1230
+ $.extend(conf, settings);
1231
+
1232
+ conf.css['position'] = 'absolute';
1233
+ conf.css['z-index'] = 9999;
1234
+ $elem.attr('autocomplete', 'off');
1235
+
1236
+ if (this._numSuggestionElements === 0) {
1237
+ // Re-position suggestion container if window size changes
1238
+ $window.bind('resize', function () {
1239
+ $('.jquery-form-suggestions').each(function () {
1240
+ var $container = $(this),
1241
+ suggestID = $container.attr('data-suggest-container');
1242
+ setSuggsetionPosition($container, $('.suggestions-' + suggestID).eq(0));
1243
+ });
1244
+ });
1245
+ }
1246
+
1247
+ this._numSuggestionElements++;
1248
+
1249
+ var onSelectSuggestion = function ($el) {
1250
+ var suggestionId = $el.valAttr('suggestion-nr');
1251
+ $.formUtils._selectedSuggestion = null;
1252
+ $.formUtils._previousTypedVal = null;
1253
+ $('.jquery-form-suggestion-' + suggestionId).fadeOut('fast');
1254
+ };
1255
+
1256
+ $elem
1257
+ .data('suggestions', suggestions)
1258
+ .valAttr('suggestion-nr', this._numSuggestionElements)
1259
+ .unbind('focus.suggest')
1260
+ .bind('focus.suggest', function () {
1261
+ $(this).trigger('keyup');
1262
+ $.formUtils._selectedSuggestion = null;
1263
+ })
1264
+ .unbind('keyup.suggest')
1265
+ .bind('keyup.suggest', function () {
1266
+ var $input = $(this),
1267
+ foundSuggestions = [],
1268
+ val = $.trim($input.val()).toLocaleLowerCase();
1269
+
1270
+ if (val == $.formUtils._previousTypedVal) {
1271
+ return;
1272
+ }
1273
+ else {
1274
+ $.formUtils._previousTypedVal = val;
1275
+ }
1276
+
1277
+ var hasTypedSuggestion = false,
1278
+ suggestionId = $input.valAttr('suggestion-nr'),
1279
+ $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
1280
+
1281
+ $suggestionContainer.scrollTop(0);
1282
+
1283
+ // Find the right suggestions
1284
+ if (val != '') {
1285
+ var findPartial = val.length > 2;
1286
+ $.each($input.data('suggestions'), function (i, suggestion) {
1287
+ var lowerCaseVal = suggestion.toLocaleLowerCase();
1288
+ if (lowerCaseVal == val) {
1289
+ foundSuggestions.push('<strong>' + suggestion + '</strong>');
1290
+ hasTypedSuggestion = true;
1291
+ return false;
1292
+ } else if (lowerCaseVal.indexOf(val) === 0 || (findPartial && lowerCaseVal.indexOf(val) > -1)) {
1293
+ foundSuggestions.push(suggestion.replace(new RegExp(val, 'gi'), '<strong>$&</strong>'));
1294
+ }
1295
+ });
1296
+ }
1297
+
1298
+ // Hide suggestion container
1299
+ if (hasTypedSuggestion || (foundSuggestions.length == 0 && $suggestionContainer.length > 0)) {
1300
+ $suggestionContainer.hide();
1301
+ }
1302
+
1303
+ // Create suggestion container if not already exists
1304
+ else if (foundSuggestions.length > 0 && $suggestionContainer.length == 0) {
1305
+ $suggestionContainer = $('<div></div>').css(conf.css).appendTo('body');
1306
+ $elem.addClass('suggestions-' + suggestionId);
1307
+ $suggestionContainer
1308
+ .attr('data-suggest-container', suggestionId)
1309
+ .addClass('jquery-form-suggestions')
1310
+ .addClass('jquery-form-suggestion-' + suggestionId);
1311
+ }
1312
+
1313
+ // Show hidden container
1314
+ else if (foundSuggestions.length > 0 && !$suggestionContainer.is(':visible')) {
1315
+ $suggestionContainer.show();
1316
+ }
1317
+
1318
+ // add suggestions
1319
+ if (foundSuggestions.length > 0 && val.length != foundSuggestions[0].length) {
1320
+
1321
+ // put container in place every time, just in case
1322
+ setSuggsetionPosition($suggestionContainer, $input);
1323
+
1324
+ // Add suggestions HTML to container
1325
+ $suggestionContainer.html('');
1326
+ $.each(foundSuggestions, function (i, text) {
1327
+ $('<div></div>')
1328
+ .append(text)
1329
+ .css({
1330
+ overflow: 'hidden',
1331
+ textOverflow: 'ellipsis',
1332
+ whiteSpace: 'nowrap',
1333
+ padding: '5px'
1334
+ })
1335
+ .addClass('form-suggest-element')
1336
+ .appendTo($suggestionContainer)
1337
+ .click(function () {
1338
+ $input.focus();
1339
+ $input.val($(this).text());
1340
+ onSelectSuggestion($input);
1341
+ });
1342
+ });
1343
+ }
1344
+ })
1345
+ .unbind('keydown.validation')
1346
+ .bind('keydown.validation', function (e) {
1347
+ var code = (e.keyCode ? e.keyCode : e.which),
1348
+ suggestionId,
1349
+ $suggestionContainer,
1350
+ $input = $(this);
1351
+
1352
+ if (code == 13 && $.formUtils._selectedSuggestion !== null) {
1353
+ suggestionId = $input.valAttr('suggestion-nr');
1354
+ $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
1355
+ if ($suggestionContainer.length > 0) {
1356
+ var newText = $suggestionContainer.find('div').eq($.formUtils._selectedSuggestion).text();
1357
+ $input.val(newText);
1358
+ onSelectSuggestion($input);
1359
+ e.preventDefault();
1360
+ }
1361
+ }
1362
+ else {
1363
+ suggestionId = $input.valAttr('suggestion-nr');
1364
+ $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
1365
+ var $suggestions = $suggestionContainer.children();
1366
+ if ($suggestions.length > 0 && $.inArray(code, [38, 40]) > -1) {
1367
+ if (code == 38) { // key up
1368
+ if ($.formUtils._selectedSuggestion === null)
1369
+ $.formUtils._selectedSuggestion = $suggestions.length - 1;
1370
+ else
1371
+ $.formUtils._selectedSuggestion--;
1372
+ if ($.formUtils._selectedSuggestion < 0)
1373
+ $.formUtils._selectedSuggestion = $suggestions.length - 1;
1374
+ }
1375
+ else if (code == 40) { // key down
1376
+ if ($.formUtils._selectedSuggestion === null)
1377
+ $.formUtils._selectedSuggestion = 0;
1378
+ else
1379
+ $.formUtils._selectedSuggestion++;
1380
+ if ($.formUtils._selectedSuggestion > ($suggestions.length - 1))
1381
+ $.formUtils._selectedSuggestion = 0;
1382
+
1383
+ }
1384
+
1385
+ // Scroll in suggestion window
1386
+ var containerInnerHeight = $suggestionContainer.innerHeight(),
1387
+ containerScrollTop = $suggestionContainer.scrollTop(),
1388
+ suggestionHeight = $suggestionContainer.children().eq(0).outerHeight(),
1389
+ activeSuggestionPosY = suggestionHeight * ($.formUtils._selectedSuggestion);
1390
+
1391
+ if (activeSuggestionPosY < containerScrollTop || activeSuggestionPosY > (containerScrollTop + containerInnerHeight)) {
1392
+ $suggestionContainer.scrollTop(activeSuggestionPosY);
1393
+ }
1394
+
1395
+ $suggestions
1396
+ .removeClass('active-suggestion')
1397
+ .css('background', 'none')
1398
+ .eq($.formUtils._selectedSuggestion)
1399
+ .addClass('active-suggestion')
1400
+ .css(conf.activeSuggestionCSS);
1401
+
1402
+ e.preventDefault();
1403
+ return false;
1404
+ }
1405
+ }
1406
+ })
1407
+ .unbind('blur.suggest')
1408
+ .bind('blur.suggest', function () {
1409
+ onSelectSuggestion($(this));
1410
+ });
1411
+
1412
+ return $elem;
1413
+ },
1414
+
1415
+ /**
1416
+ * Error dialogs
1417
+ *
1418
+ * @var {Object}
1419
+ */
1420
+ LANG: {
1421
+ errorTitle: 'Form submission failed!',
1422
+ requiredFields: 'You have not answered all required fields',
1423
+ badTime: 'You have not given a correct time',
1424
+ badEmail: 'You have not given a correct e-mail address',
1425
+ badTelephone: 'You have not given a correct phone number',
1426
+ badSecurityAnswer: 'You have not given a correct answer to the security question',
1427
+ badDate: 'You have not given a correct date',
1428
+ lengthBadStart: 'The input value must be between ',
1429
+ lengthBadEnd: ' characters',
1430
+ lengthTooLongStart: 'The input value is longer than ',
1431
+ lengthTooShortStart: 'The input value is shorter than ',
1432
+ notConfirmed: 'Input values could not be confirmed',
1433
+ badDomain: 'Incorrect domain value',
1434
+ badUrl: 'The input value is not a correct URL',
1435
+ badCustomVal: 'The input value is incorrect',
1436
+ andSpaces: ' and spaces ',
1437
+ badInt: 'The input value was not a correct number',
1438
+ badSecurityNumber: 'Your social security number was incorrect',
1439
+ badUKVatAnswer: 'Incorrect UK VAT Number',
1440
+ badStrength: 'The password isn\'t strong enough',
1441
+ badNumberOfSelectedOptionsStart: 'You have to choose at least ',
1442
+ badNumberOfSelectedOptionsEnd: ' answers',
1443
+ badAlphaNumeric: 'The input value can only contain alphanumeric characters ',
1444
+ badAlphaNumericExtra: ' and ',
1445
+ wrongFileSize: 'The file you are trying to upload is too large (max %s)',
1446
+ wrongFileType: 'Only files of type %s is allowed',
1447
+ groupCheckedRangeStart: 'Please choose between ',
1448
+ groupCheckedTooFewStart: 'Please choose at least ',
1449
+ groupCheckedTooManyStart: 'Please choose a maximum of ',
1450
+ groupCheckedEnd: ' item(s)',
1451
+ badCreditCard: 'The credit card number is not correct',
1452
+ badCVV: 'The CVV number was not correct',
1453
+ wrongFileDim : 'Incorrect image dimensions,',
1454
+ imageTooTall : 'the image can not be taller than',
1455
+ imageTooWide : 'the image can not be wider than',
1456
+ imageTooSmall : 'the image was too small',
1457
+ min : 'min',
1458
+ max : 'max',
1459
+ imageRatioNotAccepted : 'Image ratio is not be accepted',
1460
+ badBrazilTelephoneAnswer: 'The phone number entered is invalid',
1461
+ badBrazilCEPAnswer: 'The CEP entered is invalid',
1462
+ badBrazilCPFAnswer: 'The CPF entered is invalid'
1463
+ }
1464
+ };
1465
+
1466
+
1467
+ /* * * * * * * * * * * * * * * * * * * * * *
1468
+ CORE VALIDATORS
1469
+ * * * * * * * * * * * * * * * * * * * * */
1470
+
1471
+
1472
+ /*
1473
+ * Validate email
1474
+ */
1475
+ $.formUtils.addValidator({
1476
+ name: 'email',
1477
+ validatorFunction: function (email) {
1478
+
1479
+ var emailParts = email.toLowerCase().split('@'),
1480
+ localPart = emailParts[0],
1481
+ domain = emailParts[1];
1482
+
1483
+ if (localPart && domain) {
1484
+
1485
+ if( localPart.indexOf('"') == 0 ) {
1486
+ var len = localPart.length;
1487
+ localPart = localPart.replace(/\"/g, '');
1488
+ if( localPart.length != (len-2) ) {
1489
+ return false; // It was not allowed to have more than two apostrophes
1490
+ }
1491
+ }
1492
+
1493
+ return $.formUtils.validators.validate_domain.validatorFunction(emailParts[1]) &&
1494
+ localPart.indexOf('.') != 0 &&
1495
+ localPart.substring(localPart.length-1, localPart.length) != '.' &&
1496
+ localPart.indexOf('..') == -1 &&
1497
+ !(/[^\w\+\.\-\#\-\_\~\!\$\&\'\(\)\*\+\,\;\=\:]/.test(localPart));
1498
+ }
1499
+
1500
+ return false;
1501
+ },
1502
+ errorMessage: '',
1503
+ errorMessageKey: 'badEmail'
1504
+ });
1505
+
1506
+ /*
1507
+ * Validate domain name
1508
+ */
1509
+ $.formUtils.addValidator({
1510
+ name: 'domain',
1511
+ validatorFunction: function (val) {
1512
+ return val.length > 0 &&
1513
+ val.length <= 253 && // Including sub domains
1514
+ !(/[^a-zA-Z0-9]/.test(val.slice(-2))) && !(/[^a-zA-Z0-9]/.test(val.substr(0, 1))) && !(/[^a-zA-Z0-9\.\-]/.test(val)) &&
1515
+ val.split('..').length == 1 &&
1516
+ val.split('.').length > 1;
1517
+ },
1518
+ errorMessage: '',
1519
+ errorMessageKey: 'badDomain'
1520
+ });
1521
+
1522
+ /*
1523
+ * Validate required
1524
+ */
1525
+ $.formUtils.addValidator({
1526
+ name: 'required',
1527
+ validatorFunction: function (val, $el, config, language, $form) {
1528
+ switch ($el.attr('type')) {
1529
+ case 'checkbox':
1530
+ return $el.is(':checked');
1531
+ case 'radio':
1532
+ return $form.find('input[name="' + $el.attr('name') + '"]').filter(':checked').length > 0;
1533
+ default:
1534
+ return $.trim(val) !== '';
1535
+ }
1536
+ },
1537
+ errorMessage: '',
1538
+ errorMessageKey: 'requiredFields'
1539
+ });
1540
+
1541
+ /*
1542
+ * Validate length range
1543
+ */
1544
+ $.formUtils.addValidator({
1545
+ name: 'length',
1546
+ validatorFunction: function (val, $el, conf, lang) {
1547
+ var lengthAllowed = $el.valAttr('length'),
1548
+ type = $el.attr('type');
1549
+
1550
+ if (lengthAllowed == undefined) {
1551
+ alert('Please add attribute "data-validation-length" to ' + $el[0].nodeName + ' named ' + $el.attr('name'));
1552
+ return true;
1553
+ }
1554
+
1555
+ // check if length is above min, below max or within range.
1556
+ var len = type == 'file' && $el.get(0).files !== undefined ? $el.get(0).files.length : val.length,
1557
+ lengthCheckResults = $.formUtils.numericRangeCheck(len, lengthAllowed),
1558
+ checkResult;
1559
+
1560
+ switch (lengthCheckResults[0]) { // outside of allowed range
1561
+ case "out":
1562
+ this.errorMessage = lang.lengthBadStart + lengthAllowed + lang.lengthBadEnd;
1563
+ checkResult = false;
1564
+ break;
1565
+ // too short
1566
+ case "min":
1567
+ this.errorMessage = lang.lengthTooShortStart + lengthCheckResults[1] + lang.lengthBadEnd;
1568
+ checkResult = false;
1569
+ break;
1570
+ // too long
1571
+ case "max":
1572
+ this.errorMessage = lang.lengthTooLongStart + lengthCheckResults[1] + lang.lengthBadEnd;
1573
+ checkResult = false;
1574
+ break;
1575
+ // ok
1576
+ default:
1577
+ checkResult = true;
1578
+ }
1579
+
1580
+ return checkResult;
1581
+ },
1582
+ errorMessage: '',
1583
+ errorMessageKey: ''
1584
+ });
1585
+
1586
+ /*
1587
+ * Validate url
1588
+ */
1589
+ $.formUtils.addValidator({
1590
+ name: 'url',
1591
+ validatorFunction: function (url) {
1592
+ // written by Scott Gonzalez: http://projects.scottsplayground.com/iri/
1593
+ // - Victor Jonsson added support for arrays in the url ?arg[]=sdfsdf
1594
+ // - General improvements made by Stéphane Moureau <https://github.com/TraderStf>
1595
+ var urlFilter = /^(https?|ftp):\/\/((((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])(\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])(\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/(((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|\[|\]|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#(((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;
1596
+ if (urlFilter.test(url)) {
1597
+ var domain = url.split('://')[1],
1598
+ domainSlashPos = domain.indexOf('/');
1599
+
1600
+ if (domainSlashPos > -1)
1601
+ domain = domain.substr(0, domainSlashPos);
1602
+
1603
+ return $.formUtils.validators.validate_domain.validatorFunction(domain); // todo: add support for IP-addresses
1604
+ }
1605
+ return false;
1606
+ },
1607
+ errorMessage: '',
1608
+ errorMessageKey: 'badUrl'
1609
+ });
1610
+
1611
+ /*
1612
+ * Validate number (floating or integer)
1613
+ */
1614
+ $.formUtils.addValidator({
1615
+ name: 'number',
1616
+ validatorFunction: function (val, $el, conf) {
1617
+ if (val !== '') {
1618
+ var allowing = $el.valAttr('allowing') || '',
1619
+ decimalSeparator = $el.valAttr('decimal-separator') || conf.decimalSeparator,
1620
+ allowsRange = false,
1621
+ begin, end,
1622
+ steps = $el.valAttr('step') || '',
1623
+ allowsSteps = false;
1624
+
1625
+ if (allowing.indexOf('number') == -1)
1626
+ allowing += ',number';
1627
+
1628
+ if (allowing.indexOf('negative') == -1 && val.indexOf('-') === 0) {
1629
+ return false;
1630
+ }
1631
+
1632
+ if (allowing.indexOf('range') > -1) {
1633
+ begin = parseFloat(allowing.substring(allowing.indexOf("[") + 1, allowing.indexOf(";")));
1634
+ end = parseFloat(allowing.substring(allowing.indexOf(";") + 1, allowing.indexOf("]")));
1635
+ allowsRange = true;
1636
+ }
1637
+
1638
+ if (steps != "")
1639
+ allowsSteps = true;
1640
+
1641
+ if (decimalSeparator == ',') {
1642
+ if (val.indexOf('.') > -1) {
1643
+ return false;
1644
+ }
1645
+ // Fix for checking range with floats using ,
1646
+ val = val.replace(',', '.');
1647
+ }
1648
+
1649
+ if (allowing.indexOf('number') > -1 && val.replace(/[0-9-]/g, '') === '' && (!allowsRange || (val >= begin && val <= end)) && (!allowsSteps || (val % steps == 0))) {
1650
+ return true;
1651
+ }
1652
+ if (allowing.indexOf('float') > -1 && val.match(new RegExp('^([0-9-]+)\\.([0-9]+)$')) !== null && (!allowsRange || (val >= begin && val <= end)) && (!allowsSteps || (val % steps == 0))) {
1653
+ return true;
1654
+ }
1655
+ }
1656
+ return false;
1657
+ },
1658
+ errorMessage: '',
1659
+ errorMessageKey: 'badInt'
1660
+ });
1661
+
1662
+ /*
1663
+ * Validate alpha numeric
1664
+ */
1665
+ $.formUtils.addValidator({
1666
+ name: 'alphanumeric',
1667
+ validatorFunction: function (val, $el, conf, language) {
1668
+ var patternStart = '^([a-zA-Z0-9',
1669
+ patternEnd = ']+)$',
1670
+ additionalChars = $el.valAttr('allowing'),
1671
+ pattern = '';
1672
+
1673
+ if (additionalChars) {
1674
+ pattern = patternStart + additionalChars + patternEnd;
1675
+ var extra = additionalChars.replace(/\\/g, '');
1676
+ if (extra.indexOf(' ') > -1) {
1677
+ extra = extra.replace(' ', '');
1678
+ extra += language.andSpaces || $.formUtils.LANG.andSpaces;
1679
+ }
1680
+ this.errorMessage = language.badAlphaNumeric + language.badAlphaNumericExtra + extra;
1681
+ } else {
1682
+ pattern = patternStart + patternEnd;
1683
+ this.errorMessage = language.badAlphaNumeric;
1684
+ }
1685
+
1686
+ return new RegExp(pattern).test(val);
1687
+ },
1688
+ errorMessage: '',
1689
+ errorMessageKey: ''
1690
+ });
1691
+
1692
+ /*
1693
+ * Validate against regexp
1694
+ */
1695
+ $.formUtils.addValidator({
1696
+ name: 'custom',
1697
+ validatorFunction: function (val, $el, conf) {
1698
+ var regexp = new RegExp($el.valAttr('regexp'));
1699
+ return regexp.test(val);
1700
+ },
1701
+ errorMessage: '',
1702
+ errorMessageKey: 'badCustomVal'
1703
+ });
1704
+
1705
+ /*
1706
+ * Validate date
1707
+ */
1708
+ $.formUtils.addValidator({
1709
+ name: 'date',
1710
+ validatorFunction: function (date, $el, conf) {
1711
+ var dateFormat = $el.valAttr('format') || conf.dateFormat || 'yyyy-mm-dd';
1712
+ return $.formUtils.parseDate(date, dateFormat) !== false;
1713
+ },
1714
+ errorMessage: '',
1715
+ errorMessageKey: 'badDate'
1716
+ });
1717
+
1718
+
1719
+ /*
1720
+ * Validate group of checkboxes, validate qty required is checked
1721
+ * written by Steve Wasiura : http://stevewasiura.waztech.com
1722
+ * element attrs
1723
+ * data-validation="checkbox_group"
1724
+ * data-validation-qty="1-2" // min 1 max 2
1725
+ * data-validation-error-msg="chose min 1, max of 2 checkboxes"
1726
+ */
1727
+ $.formUtils.addValidator({
1728
+ name: 'checkbox_group',
1729
+ validatorFunction: function (val, $el, conf, lang, $form) {
1730
+ // preset return var
1731
+ var isValid = true,
1732
+ // get name of element. since it is a checkbox group, all checkboxes will have same name
1733
+ elname = $el.attr('name'),
1734
+ // get checkboxes and count the checked ones
1735
+ $checkBoxes = $("input[type=checkbox][name^='" + elname + "']", $form),
1736
+ checkedCount = $checkBoxes.filter(':checked').length,
1737
+ // get el attr that specs qty required / allowed
1738
+ qtyAllowed = $el.valAttr('qty');
1739
+
1740
+ if (qtyAllowed == undefined) {
1741
+ var elementType = $el.get(0).nodeName;
1742
+ alert('Attribute "data-validation-qty" is missing from ' + elementType + ' named ' + $el.attr('name'));
1743
+ }
1744
+
1745
+ // call Utility function to check if count is above min, below max, within range etc.
1746
+ var qtyCheckResults = $.formUtils.numericRangeCheck(checkedCount, qtyAllowed);
1747
+
1748
+ // results will be array, [0]=result str, [1]=qty int
1749
+ switch (qtyCheckResults[0]) {
1750
+ // outside allowed range
1751
+ case "out":
1752
+ this.errorMessage = lang.groupCheckedRangeStart + qtyAllowed + lang.groupCheckedEnd;
1753
+ isValid = false;
1754
+ break;
1755
+ // below min qty
1756
+ case "min":
1757
+ this.errorMessage = lang.groupCheckedTooFewStart + qtyCheckResults[1] + lang.groupCheckedEnd;
1758
+ isValid = false;
1759
+ break;
1760
+ // above max qty
1761
+ case "max":
1762
+ this.errorMessage = lang.groupCheckedTooManyStart + qtyCheckResults[1] + lang.groupCheckedEnd;
1763
+ isValid = false;
1764
+ break;
1765
+ // ok
1766
+ default:
1767
+ isValid = true;
1768
+ }
1769
+
1770
+ if( !isValid ) {
1771
+ var _triggerOnBlur = function() {
1772
+ $checkBoxes.unbind('click', _triggerOnBlur);
1773
+ $checkBoxes.filter('*[data-validation]').validateInputOnBlur(lang, conf, false, 'blur');
1774
+ };
1775
+ $checkBoxes.bind('click', _triggerOnBlur);
1776
+ }
1777
+
1778
+ return isValid;
1779
+ }
1780
+ // errorMessage : '', // set above in switch statement
1781
+ // errorMessageKey: '' // not used
1782
+ });
1783
+
1784
+ })(jQuery);