bootstrap-validator-rails 0.5.1 → 0.5.2

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 (27) hide show
  1. checksums.yaml +4 -4
  2. data/lib/bootstrap-validator-rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/bootstrapValidator.js +1297 -325
  4. data/vendor/assets/javascripts/bootstrapValidator.min.js +5 -4
  5. data/vendor/assets/javascripts/language/ar_MA.js +16 -1
  6. data/vendor/assets/javascripts/language/be_NL.js +89 -74
  7. data/vendor/assets/javascripts/language/bg_BG.js +81 -66
  8. data/vendor/assets/javascripts/language/cs_CZ.js +35 -20
  9. data/vendor/assets/javascripts/language/da_DK.js +94 -79
  10. data/vendor/assets/javascripts/language/de_DE.js +106 -91
  11. data/vendor/assets/javascripts/language/en_US.js +86 -71
  12. data/vendor/assets/javascripts/language/es_CL.js +89 -74
  13. data/vendor/assets/javascripts/language/es_ES.js +89 -74
  14. data/vendor/assets/javascripts/language/fr_FR.js +96 -81
  15. data/vendor/assets/javascripts/language/gr_EL.js +93 -78
  16. data/vendor/assets/javascripts/language/hu_HU.js +17 -2
  17. data/vendor/assets/javascripts/language/it_IT.js +53 -38
  18. data/vendor/assets/javascripts/language/nl_NL.js +99 -84
  19. data/vendor/assets/javascripts/language/pl_PL.js +88 -73
  20. data/vendor/assets/javascripts/language/pt_BR.js +80 -65
  21. data/vendor/assets/javascripts/language/tr_TR.js +93 -78
  22. data/vendor/assets/javascripts/language/vi_VN.js +35 -20
  23. data/vendor/assets/javascripts/language/zh_CN.js +100 -85
  24. data/vendor/assets/javascripts/language/zh_TW.js +81 -66
  25. data/vendor/assets/stylesheets/bootstrapValidator.css +9 -0
  26. data/vendor/assets/stylesheets/bootstrapValidator.min.css +2 -2
  27. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 993cafc397ed0f6251ab9e179ae990fdf959b23d
4
- data.tar.gz: fba1ab25acc15ed0de59376b08cb6e951a9368e3
3
+ metadata.gz: 38c37b4ddad28ac35bf3bb88f14ce65384010f42
4
+ data.tar.gz: 333b2c34b2eec6756a853637ed149f2c742a9587
5
5
  SHA512:
6
- metadata.gz: a4443faf6e9e915226f57ba38f9dba8daa324a9db901482d668e01f6651e9ca24d639342c1118d5b2be0d6eef84d2372f7f0e9ee0c0ff1d1d7de48de41254d86
7
- data.tar.gz: 0e51a2bc522d55015c07c83dfaba355b933776b79d12716b94c7601e0d025d5a8c9b9185db9406c32e3f854716dd53e10f8443f38764d1825c5bc9f84591c3a3
6
+ metadata.gz: b55f2222d42ae011c4bbaf8adfc388aa48c59001054ca918f5e6ff4155e892a02813d8f1815646b5748c3bfe2774520bea8c38f3126c2323495be27b4c4cb52b
7
+ data.tar.gz: 6414b5f3cca5ede7d41e76cf73653ef2e9c028950c88fedaf3d83fe504e2d5e714c03fe51176d4da599f314111ef5e887e0a8fabaaaf1d3831d210dd343d79a3
@@ -1,6 +1,6 @@
1
1
  module BootstrapValidatorRails
2
2
  module Rails
3
- VERSION = "0.5.1"
4
- BOOTSTRAP_VALIDATOR_VERSION = "0.5.1"
3
+ VERSION = "0.5.2"
4
+ BOOTSTRAP_VALIDATOR_VERSION = "0.5.2"
5
5
  end
6
6
  end
@@ -2,11 +2,15 @@
2
2
  * BootstrapValidator (http://bootstrapvalidator.com)
3
3
  * The best jQuery plugin to validate form fields. Designed to use with Bootstrap 3
4
4
  *
5
- * @version v0.5.1, built on 2014-08-22 4:55:09 PM
5
+ * @version v0.5.2, built on 2014-09-25 4:01:07 PM
6
6
  * @author https://twitter.com/nghuuphuoc
7
7
  * @copyright (c) 2013 - 2014 Nguyen Huu Phuoc
8
8
  * @license MIT
9
9
  */
10
+ if (typeof jQuery === 'undefined') {
11
+ throw new Error('BootstrapValidator\'s JavaScript requires jQuery');
12
+ }
13
+
10
14
  (function($) {
11
15
  var BootstrapValidator = function(form, options) {
12
16
  this.$form = $(form);
@@ -54,22 +58,7 @@
54
58
  _init: function() {
55
59
  var that = this,
56
60
  options = {
57
- excluded: this.$form.attr('data-bv-excluded'),
58
- trigger: this.$form.attr('data-bv-trigger'),
59
- message: this.$form.attr('data-bv-message'),
60
61
  container: this.$form.attr('data-bv-container'),
61
- group: this.$form.attr('data-bv-group'),
62
- submitButtons: this.$form.attr('data-bv-submitbuttons'),
63
- threshold: this.$form.attr('data-bv-threshold'),
64
- live: this.$form.attr('data-bv-live'),
65
- onSuccess: this.$form.attr('data-bv-onsuccess'),
66
- onError: this.$form.attr('data-bv-onerror'),
67
- fields: {},
68
- feedbackIcons: {
69
- valid: this.$form.attr('data-bv-feedbackicons-valid'),
70
- invalid: this.$form.attr('data-bv-feedbackicons-invalid'),
71
- validating: this.$form.attr('data-bv-feedbackicons-validating')
72
- },
73
62
  events: {
74
63
  formInit: this.$form.attr('data-bv-events-form-init'),
75
64
  formError: this.$form.attr('data-bv-events-form-error'),
@@ -82,7 +71,23 @@
82
71
  fieldStatus: this.$form.attr('data-bv-events-field-status'),
83
72
  validatorError: this.$form.attr('data-bv-events-validator-error'),
84
73
  validatorSuccess: this.$form.attr('data-bv-events-validator-success')
85
- }
74
+ },
75
+ excluded: this.$form.attr('data-bv-excluded'),
76
+ feedbackIcons: {
77
+ valid: this.$form.attr('data-bv-feedbackicons-valid'),
78
+ invalid: this.$form.attr('data-bv-feedbackicons-invalid'),
79
+ validating: this.$form.attr('data-bv-feedbackicons-validating')
80
+ },
81
+ group: this.$form.attr('data-bv-group'),
82
+ live: this.$form.attr('data-bv-live'),
83
+ message: this.$form.attr('data-bv-message'),
84
+ onError: this.$form.attr('data-bv-onerror'),
85
+ onSuccess: this.$form.attr('data-bv-onsuccess'),
86
+ submitButtons: this.$form.attr('data-bv-submitbuttons'),
87
+ threshold: this.$form.attr('data-bv-threshold'),
88
+ trigger: this.$form.attr('data-bv-trigger'),
89
+ verbose: this.$form.attr('data-bv-verbose'),
90
+ fields: {}
86
91
  };
87
92
 
88
93
  this.$form
@@ -124,11 +129,17 @@
124
129
 
125
130
  this.$form
126
131
  .on('click.bv', '[type="submit"]', function(e) {
127
- // Don't perform validation when clicking on the submit button/input
128
- // which aren't defined by the 'submitButtons' option
129
- var $button = $(e.target).eq(0);
130
- if (that.options.submitButtons && !$button.is(that.options.submitButtons) && !$button.is(that.$hiddenButton)) {
131
- that.$form.off('submit.bv').submit();
132
+ // #746: Check if the button click handler returns false
133
+ if (!e.isDefaultPrevented()) {
134
+ var $target = $(e.target),
135
+ // The button might contain HTML tag
136
+ $button = $target.is('[type="submit"]') ? $target.eq(0) : $target.parent('[type="submit"]').eq(0);
137
+
138
+ // Don't perform validation when clicking on the submit button/input
139
+ // which aren't defined by the 'submitButtons' option
140
+ if (that.options.submitButtons && !$button.is(that.options.submitButtons) && !$button.is(that.$hiddenButton)) {
141
+ that.$form.off('submit.bv').submit();
142
+ }
132
143
  }
133
144
  });
134
145
 
@@ -199,17 +210,18 @@
199
210
  }
200
211
 
201
212
  var opts = {
213
+ container: $field.attr('data-bv-container'),
202
214
  excluded: $field.attr('data-bv-excluded'),
203
215
  feedbackIcons: $field.attr('data-bv-feedbackicons'),
204
- trigger: $field.attr('data-bv-trigger'),
205
- message: $field.attr('data-bv-message'),
206
- container: $field.attr('data-bv-container'),
207
216
  group: $field.attr('data-bv-group'),
208
- selector: $field.attr('data-bv-selector'),
209
- threshold: $field.attr('data-bv-threshold'),
217
+ message: $field.attr('data-bv-message'),
218
+ onError: $field.attr('data-bv-onerror'),
210
219
  onStatus: $field.attr('data-bv-onstatus'),
211
220
  onSuccess: $field.attr('data-bv-onsuccess'),
212
- onError: $field.attr('data-bv-onerror'),
221
+ selector: $field.attr('data-bv-selector'),
222
+ threshold: $field.attr('data-bv-threshold'),
223
+ trigger: $field.attr('data-bv-trigger'),
224
+ verbose: $field.attr('data-bv-verbose'),
213
225
  validators: validators
214
226
  },
215
227
  emptyOptions = $.isEmptyObject(opts), // Check if the field options are set using HTML attributes
@@ -243,15 +255,15 @@
243
255
  break;
244
256
  }
245
257
 
246
- if (this.options.fields[field] === null || this.options.fields[field].validators === null) {
258
+ // We don't need to validate non-existing fields
259
+ if (fields.length === 0) {
247
260
  return;
248
261
  }
249
262
 
250
- // We don't need to validate non-existing fields
251
- if (fields.length === 0) {
252
- delete this.options.fields[field];
263
+ if (this.options.fields[field] === null || this.options.fields[field].validators === null) {
253
264
  return;
254
265
  }
266
+
255
267
  var validatorName;
256
268
  for (validatorName in this.options.fields[field].validators) {
257
269
  if (!$.fn.bootstrapValidator.validators[validatorName]) {
@@ -277,7 +289,7 @@
277
289
  group = this.options.fields[field].group || this.options.group,
278
290
  $parent = $field.parents(group),
279
291
  // Allow user to indicate where the error messages are shown
280
- container = this.options.fields[field].container || this.options.container,
292
+ container = ('function' === typeof (this.options.fields[field].container || this.options.container)) ? (this.options.fields[field].container || this.options.container).call(this, $field, this) : (this.options.fields[field].container || this.options.container),
281
293
  $message = (container && container !== 'tooltip' && container !== 'popover') ? $(container) : this._getMessageContainer($field, group);
282
294
 
283
295
  if (container && container !== 'tooltip' && container !== 'popover') {
@@ -292,7 +304,7 @@
292
304
  $field.off(events).on(events, function() {
293
305
  that.updateStatus($(this), that.STATUS_NOT_VALIDATED);
294
306
  });
295
-
307
+
296
308
  // Create help block elements for showing the error messages
297
309
  $field.data('bv.messages', $message);
298
310
  for (validatorName in this.options.fields[field].validators) {
@@ -309,16 +321,9 @@
309
321
  .appendTo($message);
310
322
  }
311
323
 
312
- // Prepare the validator events
313
- if (this.options.fields[field].validators[validatorName].onSuccess) {
314
- $field.on(this.options.events.validatorSuccess, function(e, data) {
315
- $.fn.bootstrapValidator.helpers.call(that.options.fields[field].validators[validatorName].onSuccess, [e, data]);
316
- });
317
- }
318
- if (this.options.fields[field].validators[validatorName].onError) {
319
- $field.on(this.options.events.validatorError, function(e, data) {
320
- $.fn.bootstrapValidator.helpers.call(that.options.fields[field].validators[validatorName].onError, [e, data]);
321
- });
324
+ // Init the validator
325
+ if ('function' === typeof $.fn.bootstrapValidator.validators[validatorName].init) {
326
+ $.fn.bootstrapValidator.validators[validatorName].init(this, $field, this.options.fields[field].validators[validatorName]);
322
327
  }
323
328
  }
324
329
 
@@ -329,7 +334,9 @@
329
334
  && this.options.feedbackIcons.validating && this.options.feedbackIcons.invalid && this.options.feedbackIcons.valid
330
335
  && (!updateAll || i === total - 1))
331
336
  {
332
- $parent.removeClass('has-success').removeClass('has-error').addClass('has-feedback');
337
+ // $parent.removeClass('has-success').removeClass('has-error').addClass('has-feedback');
338
+ // Keep error messages which are populated from back-end
339
+ $parent.addClass('has-feedback');
333
340
  var $icon = $('<i/>')
334
341
  .css('display', 'none')
335
342
  .addClass('form-control-feedback')
@@ -350,34 +357,80 @@
350
357
  // The feedback icon does not render correctly if there is no label
351
358
  // https://github.com/twbs/bootstrap/issues/12873
352
359
  if ($parent.find('label').length === 0) {
353
- $icon.css('top', 0);
360
+ $icon.addClass('bv-no-label');
354
361
  }
355
362
  // Fix feedback icons in input-group
356
363
  if ($parent.find('.input-group').length !== 0) {
357
- $icon.css({
358
- 'top': 0,
359
- 'z-index': 100
360
- }).insertAfter($parent.find('.input-group').eq(0));
364
+ $icon.addClass('bv-icon-input-group')
365
+ .insertAfter($parent.find('.input-group').eq(0));
366
+ }
367
+
368
+ if (container) {
369
+ $field
370
+ // Show tooltip/popover message when field gets focus
371
+ .off('focus.bv')
372
+ .on('focus.bv', function() {
373
+ switch (container) {
374
+ case 'tooltip':
375
+ $icon.tooltip('show');
376
+ break;
377
+ case 'popover':
378
+ $icon.popover('show');
379
+ break;
380
+ default:
381
+ break;
382
+ }
383
+ })
384
+ // and hide them when losing focus
385
+ .off('blur.bv')
386
+ .on('blur.bv', function() {
387
+ switch (container) {
388
+ case 'tooltip':
389
+ $icon.tooltip('hide');
390
+ break;
391
+ case 'popover':
392
+ $icon.popover('hide');
393
+ break;
394
+ default:
395
+ break;
396
+ }
397
+ });
361
398
  }
362
399
  }
363
400
  }
364
401
 
365
402
  // Prepare the events
366
- if (this.options.fields[field].onSuccess) {
367
- fields.on(this.options.events.fieldSuccess, function(e, data) {
368
- $.fn.bootstrapValidator.helpers.call(that.options.fields[field].onSuccess, [e, data]);
369
- });
370
- }
371
- if (this.options.fields[field].onError) {
372
- fields.on(this.options.events.fieldError, function(e, data) {
373
- $.fn.bootstrapValidator.helpers.call(that.options.fields[field].onError, [e, data]);
374
- });
375
- }
376
- if (this.options.fields[field].onStatus) {
377
- fields.on(this.options.events.fieldStatus, function(e, data) {
378
- $.fn.bootstrapValidator.helpers.call(that.options.fields[field].onStatus, [e, data]);
403
+ fields
404
+ .on(this.options.events.fieldSuccess, function(e, data) {
405
+ var onSuccess = that.getOptions(data.field, null, 'onSuccess');
406
+ if (onSuccess) {
407
+ $.fn.bootstrapValidator.helpers.call(onSuccess, [e, data]);
408
+ }
409
+ })
410
+ .on(this.options.events.fieldError, function(e, data) {
411
+ var onError = that.getOptions(data.field, null, 'onError');
412
+ if (onError) {
413
+ $.fn.bootstrapValidator.helpers.call(onError, [e, data]);
414
+ }
415
+ })
416
+ .on(this.options.events.fieldStatus, function(e, data) {
417
+ var onStatus = that.getOptions(data.field, null, 'onStatus');
418
+ if (onStatus) {
419
+ $.fn.bootstrapValidator.helpers.call(onStatus, [e, data]);
420
+ }
421
+ })
422
+ .on(this.options.events.validatorError, function(e, data) {
423
+ var onError = that.getOptions(data.field, data.validator, 'onError');
424
+ if (onError) {
425
+ $.fn.bootstrapValidator.helpers.call(onError, [e, data]);
426
+ }
427
+ })
428
+ .on(this.options.events.validatorSuccess, function(e, data) {
429
+ var onSuccess = that.getOptions(data.field, data.validator, 'onSuccess');
430
+ if (onSuccess) {
431
+ $.fn.bootstrapValidator.helpers.call(onSuccess, [e, data]);
432
+ }
379
433
  });
380
- }
381
434
 
382
435
  // Set live mode
383
436
  events = $.map(trigger, function(item) {
@@ -624,7 +677,8 @@
624
677
  bv: this,
625
678
  field: field,
626
679
  element: $field,
627
- validator: validatorName
680
+ validator: validatorName,
681
+ result: $field.data('bv.response.' + validatorName)
628
682
  };
629
683
 
630
684
  // Trigger an event after given validator completes
@@ -693,6 +747,37 @@
693
747
  return this._cacheFields[field];
694
748
  },
695
749
 
750
+ /**
751
+ * Get the field options
752
+ *
753
+ * @param {String|jQuery} [field] The field name or field element. If it is not set, the method returns the form options
754
+ * @param {String} [validator] The name of validator. It null, the method returns form options
755
+ * @param {String} [option] The option name
756
+ * @return {String|Object}
757
+ */
758
+ getOptions: function(field, validator, option) {
759
+ if (!field) {
760
+ return this.options;
761
+ }
762
+ if ('object' === typeof field) {
763
+ field = field.attr('data-bv-field');
764
+ }
765
+ if (!this.options.fields[field]) {
766
+ return null;
767
+ }
768
+
769
+ var options = this.options.fields[field];
770
+ if (!validator) {
771
+ return option ? options[option] : options;
772
+ }
773
+ if (!options.validators || !options.validators[validator]) {
774
+ return null;
775
+ }
776
+
777
+ return option ? options.validators[validator][option] : options.validators[validator];
778
+ },
779
+
780
+
696
781
  /**
697
782
  * Disable/enable submit buttons
698
783
  *
@@ -750,7 +835,7 @@
750
835
  break;
751
836
  }
752
837
 
753
- if (this.options.fields[field] && this.options.fields[field].enabled === false) {
838
+ if (fields.length === 0 || (this.options.fields[field] && this.options.fields[field].enabled === false)) {
754
839
  return this;
755
840
  }
756
841
 
@@ -759,6 +844,7 @@
759
844
  total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length,
760
845
  updateAll = ('radio' === type || 'checkbox' === type),
761
846
  validators = this.options.fields[field].validators,
847
+ verbose = this.options.fields[field].verbose === 'true' || this.options.fields[field].verbose === true || this.options.verbose === 'true' || this.options.verbose === true,
762
848
  validatorName,
763
849
  validateResult;
764
850
 
@@ -768,16 +854,23 @@
768
854
  continue;
769
855
  }
770
856
 
857
+ var stop = false;
771
858
  for (validatorName in validators) {
772
859
  if ($field.data('bv.dfs.' + validatorName)) {
773
860
  $field.data('bv.dfs.' + validatorName).reject();
774
861
  }
862
+ if (stop) {
863
+ break;
864
+ }
775
865
 
776
866
  // Don't validate field if it is already done
777
867
  var result = $field.data('bv.result.' + validatorName);
778
- if (result === this.STATUS_VALID || result === this.STATUS_INVALID || validators[validatorName].enabled === false) {
868
+ if (result === this.STATUS_VALID || result === this.STATUS_INVALID) {
779
869
  this._onFieldValidated($field, validatorName);
780
870
  continue;
871
+ } else if (validators[validatorName].enabled === false) {
872
+ this.updateStatus(updateAll ? field : $field, this.STATUS_VALID, validatorName);
873
+ continue;
781
874
  }
782
875
 
783
876
  $field.data('bv.result.' + validatorName, this.STATUS_VALIDATING);
@@ -788,29 +881,39 @@
788
881
  this.updateStatus(updateAll ? field : $field, this.STATUS_VALIDATING, validatorName);
789
882
  $field.data('bv.dfs.' + validatorName, validateResult);
790
883
 
791
- validateResult.done(function($f, v, isValid, message) {
884
+ validateResult.done(function($f, v, response) {
792
885
  // v is validator name
793
- $f.removeData('bv.dfs.' + v);
794
- if (message) {
795
- that.updateMessage($f, v, message);
886
+ $f.removeData('bv.dfs.' + v).data('bv.response.' + v, response);
887
+ if (response.message) {
888
+ that.updateMessage($f, v, response.message);
796
889
  }
797
890
 
798
- that.updateStatus(updateAll ? $f.attr('data-bv-field') : $f, isValid ? that.STATUS_VALID : that.STATUS_INVALID, v);
891
+ that.updateStatus(updateAll ? $f.attr('data-bv-field') : $f, response.valid ? that.STATUS_VALID : that.STATUS_INVALID, v);
799
892
 
800
- if (isValid && that._submitIfValid === true) {
893
+ if (response.valid && that._submitIfValid === true) {
801
894
  // If a remote validator returns true and the form is ready to submit, then do it
802
895
  that._submit();
896
+ } else if (!response.valid && !verbose) {
897
+ stop = true;
803
898
  }
804
899
  });
805
900
  }
806
901
  // ... or object { valid: true/false, message: 'dynamic message' }
807
902
  else if ('object' === typeof validateResult && validateResult.valid !== undefined && validateResult.message !== undefined) {
903
+ $field.data('bv.response.' + validatorName, validateResult);
808
904
  this.updateMessage(updateAll ? field : $field, validatorName, validateResult.message);
809
905
  this.updateStatus(updateAll ? field : $field, validateResult.valid ? this.STATUS_VALID : this.STATUS_INVALID, validatorName);
906
+ if (!validateResult.valid && !verbose) {
907
+ break;
908
+ }
810
909
  }
811
910
  // ... or a boolean value
812
911
  else if ('boolean' === typeof validateResult) {
912
+ $field.data('bv.response.' + validatorName, validateResult);
813
913
  this.updateStatus(updateAll ? field : $field, validateResult ? this.STATUS_VALID : this.STATUS_INVALID, validatorName);
914
+ if (!validateResult && !verbose) {
915
+ break;
916
+ }
814
917
  }
815
918
  }
816
919
  }
@@ -888,7 +991,7 @@
888
991
  $allErrors = $message.find('.help-block[data-bv-validator][data-bv-for="' + field + '"]'),
889
992
  $errors = validatorName ? $allErrors.filter('[data-bv-validator="' + validatorName + '"]') : $allErrors,
890
993
  $icon = $parent.find('.form-control-feedback[data-bv-icon-for="' + field + '"]'),
891
- container = this.options.fields[field].container || this.options.container,
994
+ container = ('function' === typeof (this.options.fields[field].container || this.options.container)) ? (this.options.fields[field].container || this.options.container).call(this, $field, this) : (this.options.fields[field].container || this.options.container),
892
995
  isValidField = null;
893
996
 
894
997
  // Update status
@@ -976,22 +1079,24 @@
976
1079
  case ($icon && 'tooltip' === container):
977
1080
  (isValidField === false)
978
1081
  ? $icon.css('cursor', 'pointer').tooltip('destroy').tooltip({
1082
+ container: 'body',
979
1083
  html: true,
980
1084
  placement: 'top',
981
1085
  title: $allErrors.filter('[data-bv-result="' + that.STATUS_INVALID + '"]').eq(0).html()
982
1086
  })
983
- : $icon.css('cursor', '').tooltip('destroy');
1087
+ : $icon.tooltip('hide');
984
1088
  break;
985
1089
  // ... or popover
986
1090
  case ($icon && 'popover' === container):
987
1091
  (isValidField === false)
988
1092
  ? $icon.css('cursor', 'pointer').popover('destroy').popover({
1093
+ container: 'body',
989
1094
  content: $allErrors.filter('[data-bv-result="' + that.STATUS_INVALID + '"]').eq(0).html(),
990
1095
  html: true,
991
1096
  placement: 'top',
992
1097
  trigger: 'hover click'
993
1098
  })
994
- : $icon.css('cursor', '').popover('destroy');
1099
+ : $icon.popover('hide');
995
1100
  break;
996
1101
  default:
997
1102
  (status === this.STATUS_INVALID) ? $errors.show() : $errors.hide();
@@ -1100,15 +1205,9 @@
1100
1205
  var $f = map[field];
1101
1206
  if ($f.data('bv.messages')
1102
1207
  .find('.help-block[data-bv-validator][data-bv-for="' + field + '"]')
1103
- .filter(function() {
1104
- var v = $(this).attr('data-bv-validator'),
1105
- f = $(this).attr('data-bv-for');
1106
- return (that.options.fields[f].validators[v].enabled !== false
1107
- && $f.data('bv.result.' + v) && $f.data('bv.result.' + v) !== that.STATUS_VALID);
1108
- })
1109
- .length !== 0)
1208
+ .filter('[data-bv-result="' + this.STATUS_INVALID +'"]')
1209
+ .length > 0)
1110
1210
  {
1111
- // The field is not valid
1112
1211
  return false;
1113
1212
  }
1114
1213
  }
@@ -1205,36 +1304,6 @@
1205
1304
  return messages;
1206
1305
  },
1207
1306
 
1208
- /**
1209
- * Get the field options
1210
- *
1211
- * @param {String|jQuery} [field] The field name or field element. If it is not set, the method returns the form options
1212
- * @param {String} [validator] The name of validator. It null, the method returns form options
1213
- * @param {String} [option] The option name
1214
- * @return {String|Object}
1215
- */
1216
- getOptions: function(field, validator, option) {
1217
- if (!field) {
1218
- return this.options;
1219
- }
1220
- if ('object' === typeof field) {
1221
- field = field.attr('data-bv-field');
1222
- }
1223
- if (!this.options.fields[field]) {
1224
- return null;
1225
- }
1226
-
1227
- var options = this.options.fields[field];
1228
- if (!validator) {
1229
- return options;
1230
- }
1231
- if (!options.validators || !options.validators[validator]) {
1232
- return null;
1233
- }
1234
-
1235
- return option ? options.validators[validator][option] : options.validators[validator];
1236
- },
1237
-
1238
1307
  /**
1239
1308
  * Update the option of a specific validator
1240
1309
  *
@@ -1519,10 +1588,9 @@
1519
1588
  * It will remove all error messages, feedback icons and turn off the events
1520
1589
  */
1521
1590
  destroy: function() {
1522
- var field, fields, $field, validator, $icon, container, group;
1591
+ var field, fields, $field, validator, $icon, group;
1523
1592
  for (field in this.options.fields) {
1524
1593
  fields = this.getFieldElements(field);
1525
- container = this.options.fields[field].container || this.options.container,
1526
1594
  group = this.options.fields[field].group || this.options.group;
1527
1595
  for (var i = 0; i < fields.length; i++) {
1528
1596
  $field = fields.eq(i);
@@ -1543,6 +1611,7 @@
1543
1611
  // Remove feedback icons, tooltip/popover container
1544
1612
  $icon = $field.parents(group).find('i[data-bv-icon-for="' + field + '"]');
1545
1613
  if ($icon) {
1614
+ var container = ('function' === typeof (this.options.fields[field].container || this.options.container)) ? (this.options.fields[field].container || this.options.container).call(this, $field, this) : (this.options.fields[field].container || this.options.container);
1546
1615
  switch (container) {
1547
1616
  case 'tooltip':
1548
1617
  $icon.tooltip('destroy').remove();
@@ -1560,7 +1629,14 @@
1560
1629
  if ($field.data('bv.dfs.' + validator)) {
1561
1630
  $field.data('bv.dfs.' + validator).reject();
1562
1631
  }
1563
- $field.removeData('bv.result.' + validator).removeData('bv.dfs.' + validator);
1632
+ $field.removeData('bv.result.' + validator)
1633
+ .removeData('bv.response.' + validator)
1634
+ .removeData('bv.dfs.' + validator);
1635
+
1636
+ // Destroy the validator
1637
+ if ('function' === typeof $.fn.bootstrapValidator.validators[validator].destroy) {
1638
+ $.fn.bootstrapValidator.validators[validator].destroy(this, $field, this.options.fields[field].validators[validator]);
1639
+ }
1564
1640
  }
1565
1641
  }
1566
1642
  }
@@ -1698,7 +1774,15 @@
1698
1774
  fieldStatus: 'status.field.bv',
1699
1775
  validatorError: 'error.validator.bv',
1700
1776
  validatorSuccess: 'success.validator.bv'
1701
- }
1777
+ },
1778
+
1779
+ // Whether to be verbose when validating a field or not.
1780
+ // Possible values:
1781
+ // - true: when a field has multiple validators, all of them will be checked, and respectively - if errors occur in
1782
+ // multiple validators, all of them will be displayed to the user
1783
+ // - false: when a field has multiple validators, validation for this field will be terminated upon the first encountered error.
1784
+ // Thus, only the very first error message related to this field will be displayed to the user
1785
+ verbose: true
1702
1786
  };
1703
1787
 
1704
1788
  // Available validators
@@ -1959,6 +2043,35 @@
1959
2043
  }
1960
2044
  };
1961
2045
  }(window.jQuery));
2046
+ ;(function($) {
2047
+ $.fn.bootstrapValidator.validators.blank = {
2048
+ /**
2049
+ * Placeholder validator that can be used to display a custom validation message
2050
+ * returned from the server
2051
+ * Example:
2052
+ *
2053
+ * (1) a "blank" validator is applied to an input field.
2054
+ * (2) data is entered via the UI that is unable to be validated client-side.
2055
+ * (3) server returns a 400 with JSON data that contains the field that failed
2056
+ * validation and an associated message.
2057
+ * (4) ajax 400 call handler does the following:
2058
+ *
2059
+ * bv.updateMessage(field, 'blank', errorMessage);
2060
+ * bv.updateStatus(field, 'INVALID');
2061
+ *
2062
+ * @see https://github.com/nghuuphuoc/bootstrapvalidator/issues/542
2063
+ * @see https://github.com/nghuuphuoc/bootstrapvalidator/pull/666
2064
+ * @param {BootstrapValidator} validator The validator plugin instance
2065
+ * @param {jQuery} $field Field element
2066
+ * @param {Object} options Can consist of the following keys:
2067
+ * - message: The invalid message
2068
+ * @returns {Boolean}
2069
+ */
2070
+ validate: function(validator, $field, options) {
2071
+ return true;
2072
+ }
2073
+ };
2074
+ }(window.jQuery));
1962
2075
  ;(function($) {
1963
2076
  $.fn.bootstrapValidator.i18n.callback = $.extend($.fn.bootstrapValidator.i18n.callback || {}, {
1964
2077
  'default': 'Please enter a valid value'
@@ -1983,19 +2096,20 @@
1983
2096
  * // $field is the field element
1984
2097
  * }
1985
2098
  * - message: The invalid message
1986
- * @returns {Boolean|Deferred}
2099
+ * @returns {Deferred}
1987
2100
  */
1988
2101
  validate: function(validator, $field, options) {
1989
- var value = $field.val();
2102
+ var value = $field.val(),
2103
+ dfd = new $.Deferred(),
2104
+ result = { valid: true };
1990
2105
 
1991
2106
  if (options.callback) {
1992
- var dfd = new $.Deferred(),
1993
- response = $.fn.bootstrapValidator.helpers.call(options.callback, [value, validator, $field]);
1994
- dfd.resolve($field, 'callback', 'boolean' === typeof response ? response : response.valid, 'object' === typeof response && response.message ? response.message : null);
1995
- return dfd;
2107
+ var response = $.fn.bootstrapValidator.helpers.call(options.callback, [value, validator, $field]);
2108
+ result = ('boolean' === typeof response) ? { valid: response } : response;
1996
2109
  }
1997
2110
 
1998
- return true;
2111
+ dfd.resolve($field, 'callback', result);
2112
+ return dfd;
1999
2113
  }
2000
2114
  };
2001
2115
  }(window.jQuery));
@@ -2500,17 +2614,24 @@
2500
2614
  return true;
2501
2615
  }
2502
2616
 
2503
- var compareWith = validator.getFieldElements(options.field);
2504
- if (compareWith === null || compareWith.length === 0) {
2505
- return true;
2506
- }
2617
+ var fields = options.field.split(','),
2618
+ isValid = true;
2507
2619
 
2508
- if (value !== compareWith.val()) {
2509
- validator.updateStatus(options.field, validator.STATUS_VALID, 'different');
2510
- return true;
2511
- } else {
2512
- return false;
2620
+ for (var i = 0; i < fields.length; i++) {
2621
+ var compareWith = validator.getFieldElements(fields[i]);
2622
+ if (compareWith == null || compareWith.length === 0) {
2623
+ continue;
2624
+ }
2625
+
2626
+ var compareValue = compareWith.val();
2627
+ if (value === compareValue) {
2628
+ isValid = false;
2629
+ } else if (compareValue !== '') {
2630
+ validator.updateStatus(compareWith, validator.STATUS_VALID, 'different');
2631
+ }
2513
2632
  }
2633
+
2634
+ return isValid;
2514
2635
  }
2515
2636
  };
2516
2637
  }(window.jQuery));
@@ -2584,6 +2705,12 @@
2584
2705
  });
2585
2706
 
2586
2707
  $.fn.bootstrapValidator.validators.emailAddress = {
2708
+ html5Attributes: {
2709
+ message: 'message',
2710
+ multiple: 'multiple',
2711
+ separator: 'separator'
2712
+ },
2713
+
2587
2714
  enableByHtml5: function($field) {
2588
2715
  return ('email' === $field.attr('type'));
2589
2716
  },
@@ -2594,6 +2721,8 @@
2594
2721
  * @param {BootstrapValidator} validator Validate plugin instance
2595
2722
  * @param {jQuery} $field Field element
2596
2723
  * @param {Object} [options]
2724
+ * - multiple: Allow multiple email addresses, separated by a comma or semicolon; default is false.
2725
+ * - separator: Regex for character or characters expected as separator between addresses; default is comma /[,;]/, i.e. comma or semicolon.
2597
2726
  * @returns {Boolean}
2598
2727
  */
2599
2728
  validate: function(validator, $field, options) {
@@ -2604,8 +2733,56 @@
2604
2733
 
2605
2734
  // Email address regular expression
2606
2735
  // http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
2607
- var emailRegExp = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
2608
- return emailRegExp.test(value);
2736
+ var emailRegExp = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
2737
+ allowMultiple = options.multiple === true || options.multiple === 'true';
2738
+
2739
+ if (allowMultiple) {
2740
+ var separator = options.separator || /[,;]/,
2741
+ addresses = this._splitEmailAddresses(value, separator);
2742
+
2743
+ for (var i = 0; i < addresses.length; i++) {
2744
+ if (!emailRegExp.test(addresses[i])) {
2745
+ return false;
2746
+ }
2747
+ }
2748
+
2749
+ return true;
2750
+ } else {
2751
+ return emailRegExp.test(value);
2752
+ }
2753
+ },
2754
+
2755
+ _splitEmailAddresses: function(emailAddresses, separator) {
2756
+ var quotedFragments = emailAddresses.split(/"/),
2757
+ quotedFragmentCount = quotedFragments.length,
2758
+ emailAddressArray = [],
2759
+ nextEmailAddress = '';
2760
+
2761
+ for (var i = 0; i < quotedFragmentCount; i++) {
2762
+ if (i % 2 === 0) {
2763
+ var splitEmailAddressFragments = quotedFragments[i].split(separator),
2764
+ splitEmailAddressFragmentCount = splitEmailAddressFragments.length;
2765
+
2766
+ if (splitEmailAddressFragmentCount === 1) {
2767
+ nextEmailAddress += splitEmailAddressFragments[0];
2768
+ } else {
2769
+ emailAddressArray.push(nextEmailAddress + splitEmailAddressFragments[0]);
2770
+
2771
+ for (var j = 1; j < splitEmailAddressFragmentCount - 1; j++) {
2772
+ emailAddressArray.push(splitEmailAddressFragments[j]);
2773
+ }
2774
+ nextEmailAddress = splitEmailAddressFragments[splitEmailAddressFragmentCount - 1];
2775
+ }
2776
+ } else {
2777
+ nextEmailAddress += '"' + quotedFragments[i];
2778
+ if (i < quotedFragmentCount - 1) {
2779
+ nextEmailAddress += '"';
2780
+ }
2781
+ }
2782
+ }
2783
+
2784
+ emailAddressArray.push(nextEmailAddress);
2785
+ return emailAddressArray;
2609
2786
  }
2610
2787
  };
2611
2788
  }(window.jQuery));
@@ -2618,6 +2795,7 @@
2618
2795
  html5Attributes: {
2619
2796
  extension: 'extension',
2620
2797
  maxsize: 'maxSize',
2798
+ minsize: 'minSize',
2621
2799
  message: 'message',
2622
2800
  type: 'type'
2623
2801
  },
@@ -2630,6 +2808,7 @@
2630
2808
  * @param {Object} options Can consist of the following keys:
2631
2809
  * - extension: The allowed extensions, separated by a comma
2632
2810
  * - maxSize: The maximum size in bytes
2811
+ * - minSize: the minimum size in bytes
2633
2812
  * - message: The invalid message
2634
2813
  * - type: The allowed MIME type, separated by a comma
2635
2814
  * @returns {Boolean}
@@ -2650,7 +2829,12 @@
2650
2829
  var files = $field.get(0).files,
2651
2830
  total = files.length;
2652
2831
  for (var i = 0; i < total; i++) {
2653
- // Check file size
2832
+ // Check the minSize
2833
+ if (options.minSize && files[i].size < parseInt(options.minSize, 10)) {
2834
+ return false;
2835
+ }
2836
+
2837
+ // Check the maxSize
2654
2838
  if (options.maxSize && files[i].size > parseInt(options.maxSize, 10)) {
2655
2839
  return false;
2656
2840
  }
@@ -2861,7 +3045,7 @@
2861
3045
  CZ: 'Czech Republic',
2862
3046
  DE: 'Germany',
2863
3047
  DK: 'Denmark',
2864
- DO: 'Dominican Republic',
3048
+ DO: 'Dominica',
2865
3049
  DZ: 'Algeria',
2866
3050
  EE: 'Estonia',
2867
3051
  ES: 'Spain',
@@ -2903,7 +3087,7 @@
2903
3087
  NO: 'Norway',
2904
3088
  PK: 'Pakistan',
2905
3089
  PL: 'Poland',
2906
- PS: 'Palestinian',
3090
+ PS: 'Palestine',
2907
3091
  PT: 'Portugal',
2908
3092
  QA: 'Qatar',
2909
3093
  RO: 'Romania',
@@ -3082,33 +3266,35 @@
3082
3266
  $.fn.bootstrapValidator.i18n.id = $.extend($.fn.bootstrapValidator.i18n.id || {}, {
3083
3267
  'default': 'Please enter a valid identification number',
3084
3268
  countryNotSupported: 'The country code %s is not supported',
3085
- country: 'Please enter a valid %s identification number',
3269
+ country: 'Please enter a valid identification number in %s',
3086
3270
  countries: {
3087
3271
  BA: 'Bosnia and Herzegovina',
3088
- BG: 'Bulgarian',
3089
- BR: 'Brazilian',
3090
- CH: 'Swiss',
3091
- CL: 'Chilean',
3092
- CZ: 'Czech',
3093
- DK: 'Danish',
3094
- EE: 'Estonian',
3095
- ES: 'Spanish',
3096
- FI: 'Finnish',
3097
- HR: 'Croatian',
3098
- IE: 'Irish',
3272
+ BG: 'Bulgaria',
3273
+ BR: 'Brazil',
3274
+ CH: 'Switzerland',
3275
+ CL: 'Chile',
3276
+ CN: 'China',
3277
+ CZ: 'Czech Republic',
3278
+ DK: 'Denmark',
3279
+ EE: 'Estonia',
3280
+ ES: 'Spain',
3281
+ FI: 'Finland',
3282
+ HR: 'Croatia',
3283
+ IE: 'Ireland',
3099
3284
  IS: 'Iceland',
3100
- LT: 'Lithuanian',
3101
- LV: 'Latvian',
3285
+ LT: 'Lithuania',
3286
+ LV: 'Latvia',
3102
3287
  ME: 'Montenegro',
3103
- MK: 'Macedonian',
3104
- NL: 'Dutch',
3105
- RO: 'Romanian',
3106
- RS: 'Serbian',
3107
- SE: 'Swedish',
3108
- SI: 'Slovenian',
3109
- SK: 'Slovak',
3288
+ MK: 'Macedonia',
3289
+ NL: 'Netherlands',
3290
+ RO: 'Romania',
3291
+ RS: 'Serbia',
3292
+ SE: 'Sweden',
3293
+ SI: 'Slovenia',
3294
+ SK: 'Slovakia',
3110
3295
  SM: 'San Marino',
3111
- ZA: 'South African'
3296
+ TH: 'Thailand',
3297
+ ZA: 'South Africa'
3112
3298
  }
3113
3299
  });
3114
3300
 
@@ -3120,8 +3306,8 @@
3120
3306
 
3121
3307
  // Supported country codes
3122
3308
  COUNTRY_CODES: [
3123
- 'BA', 'BG', 'BR', 'CH', 'CL', 'CZ', 'DK', 'EE', 'ES', 'FI', 'HR', 'IE', 'IS', 'LT', 'LV', 'ME', 'MK', 'NL',
3124
- 'RO', 'RS', 'SE', 'SI', 'SK', 'SM', 'ZA'
3309
+ 'BA', 'BG', 'BR', 'CH', 'CL', 'CN', 'CZ', 'DK', 'EE', 'ES', 'FI', 'HR', 'IE', 'IS', 'LT', 'LV', 'ME', 'MK', 'NL',
3310
+ 'RO', 'RS', 'SE', 'SI', 'SK', 'SM', 'TH', 'ZA'
3125
3311
  ],
3126
3312
 
3127
3313
  /**
@@ -3394,6 +3580,542 @@
3394
3580
  return sum + '' === value.charAt(8).toUpperCase();
3395
3581
  },
3396
3582
 
3583
+ /**
3584
+ * Validate Chinese citizen identification number
3585
+ *
3586
+ * Rules:
3587
+ * - For current 18-digit system (since 1st Oct 1999, defined by GB11643—1999 national standard):
3588
+ * - Digit 0-5: Must be a valid administrative division code of China PR.
3589
+ * - Digit 6-13: Must be a valid YYYYMMDD date of birth. A future date is tolerated.
3590
+ * - Digit 14-16: Order code, any integer.
3591
+ * - Digit 17: An ISO 7064:1983, MOD 11-2 checksum.
3592
+ * Both upper/lower case of X are tolerated.
3593
+ * - For deprecated 15-digit system:
3594
+ * - Digit 0-5: Must be a valid administrative division code of China PR.
3595
+ * - Digit 6-11: Must be a valid YYMMDD date of birth, indicating the year of 19XX.
3596
+ * - Digit 12-14: Order code, any integer.
3597
+ * Lists of valid administrative division codes of China PR can be seen here:
3598
+ * <http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/>
3599
+ * Published and maintained by National Bureau of Statistics of China PR.
3600
+ * NOTE: Current and deprecated codes MUST BOTH be considered valid.
3601
+ * Many Chinese citizens born in once existed administrative divisions!
3602
+ *
3603
+ * @see http://en.wikipedia.org/wiki/Resident_Identity_Card#Identity_card_number
3604
+ * @param {String} value The ID
3605
+ * @returns {Boolean}
3606
+ */
3607
+ _cn: function(value) {
3608
+ // Basic format check (18 or 15 digits, considering X in checksum)
3609
+ value = value.trim();
3610
+ if (!/^\d{15}$/.test(value) && !/^\d{17}[\dXx]{1}$/.test(value)) {
3611
+ return false;
3612
+ }
3613
+
3614
+ // Check China PR Administrative division code
3615
+ var adminDivisionCodes = {
3616
+ 11: {
3617
+ 0: [0],
3618
+ 1: [[0, 9], [11, 17]],
3619
+ 2: [0, 28, 29]
3620
+ },
3621
+ 12: {
3622
+ 0: [0],
3623
+ 1: [[0, 16]],
3624
+ 2: [0, 21, 23, 25]
3625
+ },
3626
+ 13: {
3627
+ 0: [0],
3628
+ 1: [[0, 5], 7, 8, 21, [23, 33], [81, 85]],
3629
+ 2: [[0, 5], [7, 9], [23, 25], 27, 29, 30, 81, 83],
3630
+ 3: [[0, 4], [21, 24]],
3631
+ 4: [[0, 4], 6, 21, [23, 35], 81],
3632
+ 5: [[0, 3], [21, 35], 81, 82],
3633
+ 6: [[0, 4], [21, 38], [81, 84]],
3634
+ 7: [[0, 3], 5, 6, [21, 33]],
3635
+ 8: [[0, 4], [21, 28]],
3636
+ 9: [[0, 3], [21, 30], [81, 84]],
3637
+ 10: [[0, 3], [22, 26], 28, 81, 82],
3638
+ 11: [[0, 2], [21, 28], 81, 82]
3639
+ },
3640
+ 14: {
3641
+ 0: [0],
3642
+ 1: [0, 1, [5, 10], [21, 23], 81],
3643
+ 2: [[0, 3], 11, 12, [21, 27]],
3644
+ 3: [[0, 3], 11, 21, 22],
3645
+ 4: [[0, 2], 11, 21, [23, 31], 81],
3646
+ 5: [[0, 2], 21, 22, 24, 25, 81],
3647
+ 6: [[0, 3], [21, 24]],
3648
+ 7: [[0, 2], [21, 29], 81],
3649
+ 8: [[0, 2], [21, 30], 81, 82],
3650
+ 9: [[0, 2], [21, 32], 81],
3651
+ 10: [[0, 2], [21, 34], 81, 82],
3652
+ 11: [[0, 2], [21, 30], 81, 82],
3653
+ 23: [[0, 3], 22, 23, [25, 30], 32, 33]
3654
+ },
3655
+ 15: {
3656
+ 0: [0],
3657
+ 1: [[0, 5], [21, 25]],
3658
+ 2: [[0, 7], [21, 23]],
3659
+ 3: [[0, 4]],
3660
+ 4: [[0, 4], [21, 26], [28, 30]],
3661
+ 5: [[0, 2], [21, 26], 81],
3662
+ 6: [[0, 2], [21, 27]],
3663
+ 7: [[0, 3], [21, 27], [81, 85]],
3664
+ 8: [[0, 2], [21, 26]],
3665
+ 9: [[0, 2], [21, 29], 81],
3666
+ 22: [[0, 2], [21, 24]],
3667
+ 25: [[0, 2], [22, 31]],
3668
+ 26: [[0, 2], [24, 27], [29, 32], 34],
3669
+ 28: [0, 1, [22, 27]],
3670
+ 29: [0, [21, 23]]
3671
+ },
3672
+ 21: {
3673
+ 0: [0],
3674
+ 1: [[0, 6], [11, 14], [22, 24], 81],
3675
+ 2: [[0, 4], [11, 13], 24, [81, 83]],
3676
+ 3: [[0, 4], 11, 21, 23, 81],
3677
+ 4: [[0, 4], 11, [21, 23]],
3678
+ 5: [[0, 5], 21, 22],
3679
+ 6: [[0, 4], 24, 81, 82],
3680
+ 7: [[0, 3], 11, 26, 27, 81, 82],
3681
+ 8: [[0, 4], 11, 81, 82],
3682
+ 9: [[0, 5], 11, 21, 22],
3683
+ 10: [[0, 5], 11, 21, 81],
3684
+ 11: [[0, 3], 21, 22],
3685
+ 12: [[0, 2], 4, 21, 23, 24, 81, 82],
3686
+ 13: [[0, 3], 21, 22, 24, 81, 82],
3687
+ 14: [[0, 4], 21, 22, 81]
3688
+ },
3689
+ 22: {
3690
+ 0: [0],
3691
+ 1: [[0, 6], 12, 22, [81, 83]],
3692
+ 2: [[0, 4], 11, 21, [81, 84]],
3693
+ 3: [[0, 3], 22, 23, 81, 82],
3694
+ 4: [[0, 3], 21, 22],
3695
+ 5: [[0, 3], 21, 23, 24, 81, 82],
3696
+ 6: [[0, 2], 4, 5, [21, 23], 25, 81],
3697
+ 7: [[0, 2], [21, 24], 81],
3698
+ 8: [[0, 2], 21, 22, 81, 82],
3699
+ 24: [[0, 6], 24, 26]
3700
+ },
3701
+ 23: {
3702
+ 0: [0],
3703
+ 1: [[0, 12], 21, [23, 29], [81, 84]],
3704
+ 2: [[0, 8], 21, [23, 25], 27, [29, 31], 81],
3705
+ 3: [[0, 7], 21, 81, 82],
3706
+ 4: [[0, 7], 21, 22],
3707
+ 5: [[0, 3], 5, 6, [21, 24]],
3708
+ 6: [[0, 6], [21, 24]],
3709
+ 7: [[0, 16], 22, 81],
3710
+ 8: [[0, 5], 11, 22, 26, 28, 33, 81, 82],
3711
+ 9: [[0, 4], 21],
3712
+ 10: [[0, 5], 24, 25, 81, [83, 85]],
3713
+ 11: [[0, 2], 21, 23, 24, 81, 82],
3714
+ 12: [[0, 2], [21, 26], [81, 83]],
3715
+ 27: [[0, 4], [21, 23]]
3716
+ },
3717
+ 31: {
3718
+ 0: [0],
3719
+ 1: [0, 1, [3, 10], [12, 20]],
3720
+ 2: [0, 30]
3721
+ },
3722
+ 32: {
3723
+ 0: [0],
3724
+ 1: [[0, 7], 11, [13, 18], 24, 25],
3725
+ 2: [[0, 6], 11, 81, 82],
3726
+ 3: [[0, 5], 11, 12, [21, 24], 81, 82],
3727
+ 4: [[0, 2], 4, 5, 11, 12, 81, 82],
3728
+ 5: [[0, 9], [81, 85]],
3729
+ 6: [[0, 2], 11, 12, 21, 23, [81, 84]],
3730
+ 7: [0, 1, 3, 5, 6, [21, 24]],
3731
+ 8: [[0, 4], 11, 26, [29, 31]],
3732
+ 9: [[0, 3], [21, 25], 28, 81, 82],
3733
+ 10: [[0, 3], 11, 12, 23, 81, 84, 88],
3734
+ 11: [[0, 2], 11, 12, [81, 83]],
3735
+ 12: [[0, 4], [81, 84]],
3736
+ 13: [[0, 2], 11, [21, 24]]
3737
+ },
3738
+ 33: {
3739
+ 0: [0],
3740
+ 1: [[0, 6], [8, 10], 22, 27, 82, 83, 85],
3741
+ 2: [0, 1, [3, 6], 11, 12, 25, 26, [81, 83]],
3742
+ 3: [[0, 4], 22, 24, [26, 29], 81, 82],
3743
+ 4: [[0, 2], 11, 21, 24, [81, 83]],
3744
+ 5: [[0, 3], [21, 23]],
3745
+ 6: [[0, 2], 21, 24, [81, 83]],
3746
+ 7: [[0, 3], 23, 26, 27, [81, 84]],
3747
+ 8: [[0, 3], 22, 24, 25, 81],
3748
+ 9: [[0, 3], 21, 22],
3749
+ 10: [[0, 4], [21, 24], 81, 82],
3750
+ 11: [[0, 2], [21, 27], 81]
3751
+ },
3752
+ 34: {
3753
+ 0: [0],
3754
+ 1: [[0, 4], 11, [21, 24], 81],
3755
+ 2: [[0, 4], 7, 8, [21, 23], 25],
3756
+ 3: [[0, 4], 11, [21, 23]],
3757
+ 4: [[0, 6], 21],
3758
+ 5: [[0, 4], 6, [21, 23]],
3759
+ 6: [[0, 4], 21],
3760
+ 7: [[0, 3], 11, 21],
3761
+ 8: [[0, 3], 11, [22, 28], 81],
3762
+ 10: [[0, 4], [21, 24]],
3763
+ 11: [[0, 3], 22, [24, 26], 81, 82],
3764
+ 12: [[0, 4], 21, 22, 25, 26, 82],
3765
+ 13: [[0, 2], [21, 24]],
3766
+ 14: [[0, 2], [21, 24]],
3767
+ 15: [[0, 3], [21, 25]],
3768
+ 16: [[0, 2], [21, 23]],
3769
+ 17: [[0, 2], [21, 23]],
3770
+ 18: [[0, 2], [21, 25], 81]
3771
+ },
3772
+ 35: {
3773
+ 0: [0],
3774
+ 1: [[0, 5], 11, [21, 25], 28, 81, 82],
3775
+ 2: [[0, 6], [11, 13]],
3776
+ 3: [[0, 5], 22],
3777
+ 4: [[0, 3], 21, [23, 30], 81],
3778
+ 5: [[0, 5], 21, [24, 27], [81, 83]],
3779
+ 6: [[0, 3], [22, 29], 81],
3780
+ 7: [[0, 2], [21, 25], [81, 84]],
3781
+ 8: [[0, 2], [21, 25], 81],
3782
+ 9: [[0, 2], [21, 26], 81, 82]
3783
+ },
3784
+ 36: {
3785
+ 0: [0],
3786
+ 1: [[0, 5], 11, [21, 24]],
3787
+ 2: [[0, 3], 22, 81],
3788
+ 3: [[0, 2], 13, [21, 23]],
3789
+ 4: [[0, 3], 21, [23, 30], 81, 82],
3790
+ 5: [[0, 2], 21],
3791
+ 6: [[0, 2], 22, 81],
3792
+ 7: [[0, 2], [21, 35], 81, 82],
3793
+ 8: [[0, 3], [21, 30], 81],
3794
+ 9: [[0, 2], [21, 26], [81, 83]],
3795
+ 10: [[0, 2], [21, 30]],
3796
+ 11: [[0, 2], [21, 30], 81]
3797
+ },
3798
+ 37: {
3799
+ 0: [0],
3800
+ 1: [[0, 5], 12, 13, [24, 26], 81],
3801
+ 2: [[0, 3], 5, [11, 14], [81, 85]],
3802
+ 3: [[0, 6], [21, 23]],
3803
+ 4: [[0, 6], 81],
3804
+ 5: [[0, 3], [21, 23]],
3805
+ 6: [[0, 2], [11, 13], 34, [81, 87]],
3806
+ 7: [[0, 5], 24, 25, [81, 86]],
3807
+ 8: [[0, 2], 11, [26, 32], [81, 83]],
3808
+ 9: [[0, 3], 11, 21, 23, 82, 83],
3809
+ 10: [[0, 2], [81, 83]],
3810
+ 11: [[0, 3], 21, 22],
3811
+ 12: [[0, 3]],
3812
+ 13: [[0, 2], 11, 12, [21, 29]],
3813
+ 14: [[0, 2], [21, 28], 81, 82],
3814
+ 15: [[0, 2], [21, 26], 81],
3815
+ 16: [[0, 2], [21, 26]],
3816
+ 17: [[0, 2], [21, 28]]
3817
+ },
3818
+ 41: {
3819
+ 0: [0],
3820
+ 1: [[0, 6], 8, 22, [81, 85]],
3821
+ 2: [[0, 5], 11, [21, 25]],
3822
+ 3: [[0, 7], 11, [22, 29], 81],
3823
+ 4: [[0, 4], 11, [21, 23], 25, 81, 82],
3824
+ 5: [[0, 3], 5, 6, 22, 23, 26, 27, 81],
3825
+ 6: [[0, 3], 11, 21, 22],
3826
+ 7: [[0, 4], 11, 21, [24, 28], 81, 82],
3827
+ 8: [[0, 4], 11, [21, 23], 25, [81, 83]],
3828
+ 9: [[0, 2], 22, 23, [26, 28]],
3829
+ 10: [[0, 2], [23, 25], 81, 82],
3830
+ 11: [[0, 4], [21, 23]],
3831
+ 12: [[0, 2], 21, 22, 24, 81, 82],
3832
+ 13: [[0, 3], [21, 30], 81],
3833
+ 14: [[0, 3], [21, 26], 81],
3834
+ 15: [[0, 3], [21, 28]],
3835
+ 16: [[0, 2], [21, 28], 81],
3836
+ 17: [[0, 2], [21, 29]],
3837
+ 90: [0, 1]
3838
+ },
3839
+ 42: {
3840
+ 0: [0],
3841
+ 1: [[0, 7], [11, 17]],
3842
+ 2: [[0, 5], 22, 81],
3843
+ 3: [[0, 3], [21, 25], 81],
3844
+ 5: [[0, 6], [25, 29], [81, 83]],
3845
+ 6: [[0, 2], 6, 7, [24, 26], [82, 84]],
3846
+ 7: [[0, 4]],
3847
+ 8: [[0, 2], 4, 21, 22, 81],
3848
+ 9: [[0, 2], [21, 23], 81, 82, 84],
3849
+ 10: [[0, 3], [22, 24], 81, 83, 87],
3850
+ 11: [[0, 2], [21, 27], 81, 82],
3851
+ 12: [[0, 2], [21, 24], 81],
3852
+ 13: [[0, 3], 21, 81],
3853
+ 28: [[0, 2], 22, 23, [25, 28]],
3854
+ 90: [0, [4, 6], 21]
3855
+ },
3856
+ 43: {
3857
+ 0: [0],
3858
+ 1: [[0, 5], 11, 12, 21, 22, 24, 81],
3859
+ 2: [[0, 4], 11, 21, [23, 25], 81],
3860
+ 3: [[0, 2], 4, 21, 81, 82],
3861
+ 4: [0, 1, [5, 8], 12, [21, 24], 26, 81, 82],
3862
+ 5: [[0, 3], 11, [21, 25], [27, 29], 81],
3863
+ 6: [[0, 3], 11, 21, 23, 24, 26, 81, 82],
3864
+ 7: [[0, 3], [21, 26], 81],
3865
+ 8: [[0, 2], 11, 21, 22],
3866
+ 9: [[0, 3], [21, 23], 81],
3867
+ 10: [[0, 3], [21, 28], 81],
3868
+ 11: [[0, 3], [21, 29]],
3869
+ 12: [[0, 2], [21, 30], 81],
3870
+ 13: [[0, 2], 21, 22, 81, 82],
3871
+ 31: [0, 1, [22, 27], 30]
3872
+ },
3873
+ 44: {
3874
+ 0: [0],
3875
+ 1: [[0, 7], [11, 16], 83, 84],
3876
+ 2: [[0, 5], 21, 22, 24, 29, 32, 33, 81, 82],
3877
+ 3: [0, 1, [3, 8]],
3878
+ 4: [[0, 4]],
3879
+ 5: [0, 1, [6, 15], 23, 82, 83],
3880
+ 6: [0, 1, [4, 8]],
3881
+ 7: [0, 1, [3, 5], 81, [83, 85]],
3882
+ 8: [[0, 4], 11, 23, 25, [81, 83]],
3883
+ 9: [[0, 3], 23, [81, 83]],
3884
+ 12: [[0, 3], [23, 26], 83, 84],
3885
+ 13: [[0, 3], [22, 24], 81],
3886
+ 14: [[0, 2], [21, 24], 26, 27, 81],
3887
+ 15: [[0, 2], 21, 23, 81],
3888
+ 16: [[0, 2], [21, 25]],
3889
+ 17: [[0, 2], 21, 23, 81],
3890
+ 18: [[0, 3], 21, 23, [25, 27], 81, 82],
3891
+ 19: [0],
3892
+ 20: [0],
3893
+ 51: [[0, 3], 21, 22],
3894
+ 52: [[0, 3], 21, 22, 24, 81],
3895
+ 53: [[0, 2], [21, 23], 81]
3896
+ },
3897
+ 45: {
3898
+ 0: [0],
3899
+ 1: [[0, 9], [21, 27]],
3900
+ 2: [[0, 5], [21, 26]],
3901
+ 3: [[0, 5], 11, 12, [21, 32]],
3902
+ 4: [0, 1, [3, 6], 11, [21, 23], 81],
3903
+ 5: [[0, 3], 12, 21],
3904
+ 6: [[0, 3], 21, 81],
3905
+ 7: [[0, 3], 21, 22],
3906
+ 8: [[0, 4], 21, 81],
3907
+ 9: [[0, 3], [21, 24], 81],
3908
+ 10: [[0, 2], [21, 31]],
3909
+ 11: [[0, 2], [21, 23]],
3910
+ 12: [[0, 2], [21, 29], 81],
3911
+ 13: [[0, 2], [21, 24], 81],
3912
+ 14: [[0, 2], [21, 25], 81]
3913
+ },
3914
+ 46: {
3915
+ 0: [0],
3916
+ 1: [0, 1, [5, 8]],
3917
+ 2: [0, 1],
3918
+ 3: [0, [21, 23]],
3919
+ 90: [[0, 3], [5, 7], [21, 39]]
3920
+ },
3921
+ 50: {
3922
+ 0: [0],
3923
+ 1: [[0, 19]],
3924
+ 2: [0, [22, 38], [40, 43]],
3925
+ 3: [0, [81, 84]]
3926
+ },
3927
+ 51: {
3928
+ 0: [0],
3929
+ 1: [0, 1, [4, 8], [12, 15], [21, 24], 29, 31, 32, [81, 84]],
3930
+ 3: [[0, 4], 11, 21, 22],
3931
+ 4: [[0, 3], 11, 21, 22],
3932
+ 5: [[0, 4], 21, 22, 24, 25],
3933
+ 6: [0, 1, 3, 23, 26, [81, 83]],
3934
+ 7: [0, 1, 3, 4, [22, 27], 81],
3935
+ 8: [[0, 2], 11, 12, [21, 24]],
3936
+ 9: [[0, 4], [21, 23]],
3937
+ 10: [[0, 2], 11, 24, 25, 28],
3938
+ 11: [[0, 2], [11, 13], 23, 24, 26, 29, 32, 33, 81],
3939
+ 13: [[0, 4], [21, 25], 81],
3940
+ 14: [[0, 2], [21, 25]],
3941
+ 15: [[0, 3], [21, 29]],
3942
+ 16: [[0, 3], [21, 23], 81],
3943
+ 17: [[0, 3], [21, 25], 81],
3944
+ 18: [[0, 3], [21, 27]],
3945
+ 19: [[0, 3], [21, 23]],
3946
+ 20: [[0, 2], 21, 22, 81],
3947
+ 32: [0, [21, 33]],
3948
+ 33: [0, [21, 38]],
3949
+ 34: [0, 1, [22, 37]]
3950
+ },
3951
+ 52: {
3952
+ 0: [0],
3953
+ 1: [[0, 3], [11, 15], [21, 23], 81],
3954
+ 2: [0, 1, 3, 21, 22],
3955
+ 3: [[0, 3], [21, 30], 81, 82],
3956
+ 4: [[0, 2], [21, 25]],
3957
+ 5: [[0, 2], [21, 27]],
3958
+ 6: [[0, 3], [21, 28]],
3959
+ 22: [0, 1, [22, 30]],
3960
+ 23: [0, 1, [22, 28]],
3961
+ 24: [0, 1, [22, 28]],
3962
+ 26: [0, 1, [22, 36]],
3963
+ 27: [[0, 2], 22, 23, [25, 32]]
3964
+ },
3965
+ 53: {
3966
+ 0: [0],
3967
+ 1: [[0, 3], [11, 14], 21, 22, [24, 29], 81],
3968
+ 3: [[0, 2], [21, 26], 28, 81],
3969
+ 4: [[0, 2], [21, 28]],
3970
+ 5: [[0, 2], [21, 24]],
3971
+ 6: [[0, 2], [21, 30]],
3972
+ 7: [[0, 2], [21, 24]],
3973
+ 8: [[0, 2], [21, 29]],
3974
+ 9: [[0, 2], [21, 27]],
3975
+ 23: [0, 1, [22, 29], 31],
3976
+ 25: [[0, 4], [22, 32]],
3977
+ 26: [0, 1, [21, 28]],
3978
+ 27: [0, 1, [22, 30]], 28: [0, 1, 22, 23],
3979
+ 29: [0, 1, [22, 32]],
3980
+ 31: [0, 2, 3, [22, 24]],
3981
+ 34: [0, [21, 23]],
3982
+ 33: [0, 21, [23, 25]],
3983
+ 35: [0, [21, 28]]
3984
+ },
3985
+ 54: {
3986
+ 0: [0],
3987
+ 1: [[0, 2], [21, 27]],
3988
+ 21: [0, [21, 29], 32, 33],
3989
+ 22: [0, [21, 29], [31, 33]],
3990
+ 23: [0, 1, [22, 38]],
3991
+ 24: [0, [21, 31]],
3992
+ 25: [0, [21, 27]],
3993
+ 26: [0, [21, 27]]
3994
+ },
3995
+ 61: {
3996
+ 0: [0],
3997
+ 1: [[0, 4], [11, 16], 22, [24, 26]],
3998
+ 2: [[0, 4], 22],
3999
+ 3: [[0, 4], [21, 24], [26, 31]],
4000
+ 4: [[0, 4], [22, 31], 81],
4001
+ 5: [[0, 2], [21, 28], 81, 82],
4002
+ 6: [[0, 2], [21, 32]],
4003
+ 7: [[0, 2], [21, 30]],
4004
+ 8: [[0, 2], [21, 31]],
4005
+ 9: [[0, 2], [21, 29]],
4006
+ 10: [[0, 2], [21, 26]]
4007
+ },
4008
+ 62: {
4009
+ 0: [0],
4010
+ 1: [[0, 5], 11, [21, 23]],
4011
+ 2: [0, 1],
4012
+ 3: [[0, 2], 21],
4013
+ 4: [[0, 3], [21, 23]],
4014
+ 5: [[0, 3], [21, 25]],
4015
+ 6: [[0, 2], [21, 23]],
4016
+ 7: [[0, 2], [21, 25]],
4017
+ 8: [[0, 2], [21, 26]],
4018
+ 9: [[0, 2], [21, 24], 81, 82],
4019
+ 10: [[0, 2], [21, 27]],
4020
+ 11: [[0, 2], [21, 26]],
4021
+ 12: [[0, 2], [21, 28]],
4022
+ 24: [0, 21, [24, 29]],
4023
+ 26: [0, 21, [23, 30]],
4024
+ 29: [0, 1, [21, 27]],
4025
+ 30: [0, 1, [21, 27]]
4026
+ },
4027
+ 63: {
4028
+ 0: [0],
4029
+ 1: [[0, 5], [21, 23]],
4030
+ 2: [0, 2, [21, 25]],
4031
+ 21: [0, [21, 23], [26, 28]],
4032
+ 22: [0, [21, 24]],
4033
+ 23: [0, [21, 24]],
4034
+ 25: [0, [21, 25]],
4035
+ 26: [0, [21, 26]],
4036
+ 27: [0, 1, [21, 26]],
4037
+ 28: [[0, 2], [21, 23]]
4038
+ },
4039
+ 64: {
4040
+ 0: [0],
4041
+ 1: [0, 1, [4, 6], 21, 22, 81],
4042
+ 2: [[0, 3], 5, [21, 23]],
4043
+ 3: [[0, 3], [21, 24], 81],
4044
+ 4: [[0, 2], [21, 25]],
4045
+ 5: [[0, 2], 21, 22]
4046
+ },
4047
+ 65: {
4048
+ 0: [0],
4049
+ 1: [[0, 9], 21],
4050
+ 2: [[0, 5]],
4051
+ 21: [0, 1, 22, 23],
4052
+ 22: [0, 1, 22, 23],
4053
+ 23: [[0, 3], [23, 25], 27, 28],
4054
+ 28: [0, 1, [22, 29]],
4055
+ 29: [0, 1, [22, 29]],
4056
+ 30: [0, 1, [22, 24]], 31: [0, 1, [21, 31]],
4057
+ 32: [0, 1, [21, 27]],
4058
+ 40: [0, 2, 3, [21, 28]],
4059
+ 42: [[0, 2], 21, [23, 26]],
4060
+ 43: [0, 1, [21, 26]],
4061
+ 90: [[0, 4]], 27: [[0, 2], 22, 23]
4062
+ },
4063
+ 71: { 0: [0] },
4064
+ 81: { 0: [0] },
4065
+ 82: { 0: [0] }
4066
+ };
4067
+
4068
+ var provincial = parseInt(value.substr(0, 2), 10),
4069
+ prefectural = parseInt(value.substr(2, 2), 10),
4070
+ county = parseInt(value.substr(4, 2), 10);
4071
+
4072
+ if (!adminDivisionCodes[provincial] || !adminDivisionCodes[provincial][prefectural]) {
4073
+ return false;
4074
+ }
4075
+ var inRange = false,
4076
+ rangeDef = adminDivisionCodes[provincial][prefectural];
4077
+ for (var i = 0; i < rangeDef.length; i++) {
4078
+ if (($.isArray(rangeDef[i]) && rangeDef[i][0] <= county && county <= rangeDef[i][1])
4079
+ || (!$.isArray(rangeDef[i]) && county === rangeDef[i]))
4080
+ {
4081
+ inRange = true;
4082
+ break;
4083
+ }
4084
+ }
4085
+
4086
+ if (!inRange) {
4087
+ return false;
4088
+ }
4089
+
4090
+ // Check date of birth
4091
+ var dob;
4092
+ if (value.length === 18) {
4093
+ dob = value.substr(6, 8);
4094
+ } else /* length == 15 */ {
4095
+ dob = '19' + value.substr(6, 6);
4096
+ }
4097
+ var year = parseInt(dob.substr(0, 4), 10),
4098
+ month = parseInt(dob.substr(4, 2), 10),
4099
+ day = parseInt(dob.substr(6, 2), 10);
4100
+ if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
4101
+ return false;
4102
+ }
4103
+
4104
+ // Check checksum (18-digit system only)
4105
+ if (value.length === 18) {
4106
+ var sum = 0,
4107
+ weight = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
4108
+ for (i = 0; i < 17; i++) {
4109
+ sum += parseInt(value.charAt(i), 10) * weight[i];
4110
+ }
4111
+ sum = (12 - (sum % 11)) % 11;
4112
+ var checksum = (value.charAt(17).toUpperCase() !== 'X') ? parseInt(value.charAt(17), 10) : 10;
4113
+ return checksum === sum;
4114
+ }
4115
+
4116
+ return true;
4117
+ },
4118
+
3397
4119
  /**
3398
4120
  * Validate Czech national identification number (RC)
3399
4121
  * Examples:
@@ -3864,6 +4586,29 @@
3864
4586
  return /^\d{5}$/.test(value);
3865
4587
  },
3866
4588
 
4589
+ /**
4590
+ * Validate Thailand citizen number
4591
+ * Examples:
4592
+ * - Valid: 7145620509547, 3688699975685, 2368719339716
4593
+ * - Invalid: 1100800092310
4594
+ *
4595
+ * @see http://en.wikipedia.org/wiki/National_identification_number#Thailand
4596
+ * @param {String} value The ID
4597
+ * @returns {Boolean}
4598
+ */
4599
+ _th: function(value) {
4600
+ if (value.length !== 13) {
4601
+ return false;
4602
+ }
4603
+
4604
+ var sum = 0;
4605
+ for (var i = 0; i < 12; i++) {
4606
+ sum += parseInt(value.charAt(i), 10) * (13 - i);
4607
+ }
4608
+
4609
+ return (11 - sum % 11) % 10 === parseInt(value.charAt(12), 10);
4610
+ },
4611
+
3867
4612
  /**
3868
4613
  * Validate South African ID
3869
4614
  * Example:
@@ -4105,7 +4850,7 @@
4105
4850
  case (options.ipv4 && options.ipv6):
4106
4851
  /* falls through */
4107
4852
  default:
4108
- valid = ipv4Regex.test(value) && ipv6Regex.test(value);
4853
+ valid = ipv4Regex.test(value) || ipv6Regex.test(value);
4109
4854
  message = options.message || $.fn.bootstrapValidator.i18n.ip['default'];
4110
4855
  break;
4111
4856
  }
@@ -4566,6 +5311,10 @@
4566
5311
  .length > 0;
4567
5312
  }
4568
5313
 
5314
+ if ('number' === type && $field.get(0).validity && $field.get(0).validity.badInput === true) {
5315
+ return true;
5316
+ }
5317
+
4569
5318
  return $.trim($field.val()) !== '';
4570
5319
  }
4571
5320
  };
@@ -4620,12 +5369,20 @@
4620
5369
  country: 'Please enter a valid phone number in %s',
4621
5370
  countries: {
4622
5371
  BR: 'Brazil',
5372
+ CN: 'China',
5373
+ CZ: 'Czech Republic',
5374
+ DK: 'Denmark',
4623
5375
  ES: 'Spain',
4624
5376
  FR: 'France',
4625
5377
  GB: 'United Kingdom',
4626
5378
  MA: 'Morocco',
4627
5379
  PK: 'Pakistan',
4628
- US: 'USA'
5380
+ RO: 'Romania',
5381
+ RU: 'Russia',
5382
+ SK: 'Slovakia',
5383
+ TH: 'Thailand',
5384
+ US: 'USA',
5385
+ VE: 'Venezuela'
4629
5386
  }
4630
5387
  });
4631
5388
 
@@ -4636,7 +5393,7 @@
4636
5393
  },
4637
5394
 
4638
5395
  // The supported countries
4639
- COUNTRY_CODES: ['BR', 'ES', 'FR', 'GB', 'MA', 'PK', 'US'],
5396
+ COUNTRY_CODES: ['BR', 'CN', 'CZ', 'DK', 'ES', 'FR', 'GB', 'MA', 'PK', 'RO', 'RU', 'SK', 'TH', 'US', 'VE'],
4640
5397
 
4641
5398
  /**
4642
5399
  * Return true if the input value contains a valid phone number for the country
@@ -4681,6 +5438,26 @@
4681
5438
  isValid = (/^(([\d]{4}[-.\s]{1}[\d]{2,3}[-.\s]{1}[\d]{2}[-.\s]{1}[\d]{2})|([\d]{4}[-.\s]{1}[\d]{3}[-.\s]{1}[\d]{4})|((\(?\+?[0-9]{2}\)?\s?)?(\(?\d{2}\)?\s?)?\d{4,5}[-.\s]?\d{4}))$/).test(value);
4682
5439
  break;
4683
5440
 
5441
+ case 'CN':
5442
+ // http://regexr.com/39dq4
5443
+ value = $.trim(value);
5444
+ isValid = (/^((00|\+)?(86(?:-| )))?((\d{11})|(\d{3}[- ]{1}\d{4}[- ]{1}\d{4})|((\d{2,4}[- ]){1}(\d{7,8}|(\d{3,4}[- ]{1}\d{4}))([- ]{1}\d{1,4})?))$/).test(value);
5445
+ break;
5446
+
5447
+ case 'CZ':
5448
+ // Test: http://regexr.com/39hhl
5449
+ isValid = /^(((00)([- ]?)|\+)(420)([- ]?))?((\d{3})([- ]?)){2}(\d{3})$/.test(value);
5450
+ break;
5451
+
5452
+ case 'DK':
5453
+ // Mathing DK phone numbers with country code in 1 of 3 formats and an
5454
+ // 8 digit phone number not starting with a 0 or 1. Can have 1 space
5455
+ // between each character except inside the country code.
5456
+ // Test: http://regex101.com/r/sS8fO4/1
5457
+ value = $.trim(value);
5458
+ isValid = (/^(\+45|0045|\(45\))?\s?[2-9](\s?\d){7}$/).test(value);
5459
+ break;
5460
+
4684
5461
  case 'ES':
4685
5462
  // http://regex101.com/r/rB9mA9/1
4686
5463
  value = $.trim(value);
@@ -4706,13 +5483,40 @@
4706
5483
  value = $.trim(value);
4707
5484
  isValid = (/^(?:(?:(?:\+|00)212[\s]?(?:[\s]?\(0\)[\s]?)?)|0){1}(?:5[\s.-]?[2-3]|6[\s.-]?[13-9]){1}[0-9]{1}(?:[\s.-]?\d{2}){3}$/).test(value);
4708
5485
  break;
4709
-
5486
+
4710
5487
  case 'PK':
4711
5488
  // http://regex101.com/r/yH8aV9/2
4712
5489
  value = $.trim(value);
4713
5490
  isValid = (/^0?3[0-9]{2}[0-9]{7}$/).test(value);
4714
5491
  break;
4715
-
5492
+
5493
+ case 'RO':
5494
+ // All mobile network and land line
5495
+ // http://regexr.com/39fv1
5496
+ isValid = (/^(\+4|)?(07[0-8]{1}[0-9]{1}|02[0-9]{2}|03[0-9]{2}){1}?(\s|\.|\-)?([0-9]{3}(\s|\.|\-|)){2}$/g).test(value);
5497
+ break;
5498
+
5499
+ case 'RU':
5500
+ // http://regex101.com/r/gW7yT5/5
5501
+ isValid = (/^((8|\+7|007)[\-\.\/ ]?)?([\(\/\.]?\d{3}[\)\/\.]?[\-\.\/ ]?)?[\d\-\.\/ ]{7,10}$/g).test(value);
5502
+ break;
5503
+
5504
+ case 'SK':
5505
+ // Test: http://regexr.com/39hhl
5506
+ isValid = /^(((00)([- ]?)|\+)(420)([- ]?))?((\d{3})([- ]?)){2}(\d{3})$/.test(value);
5507
+ break;
5508
+
5509
+ case 'TH':
5510
+ // http://regex101.com/r/vM5mZ4/2
5511
+ isValid = (/^0\(?([6|8-9]{2})*-([0-9]{3})*-([0-9]{4})$/).test(value);
5512
+ break;
5513
+
5514
+ case 'VE':
5515
+ // http://regex101.com/r/eM2yY0/6
5516
+ value = $.trim(value);
5517
+ isValid = (/^0(?:2(?:12|4[0-9]|5[1-9]|6[0-9]|7[0-8]|8[1-35-8]|9[1-5]|3[45789])|4(?:1[246]|2[46]))\d{7}$/).test(value);
5518
+ break;
5519
+
4716
5520
  case 'US':
4717
5521
  /* falls through */
4718
5522
  default:
@@ -4784,7 +5588,18 @@
4784
5588
  message: 'message',
4785
5589
  name: 'name',
4786
5590
  type: 'type',
4787
- url: 'url'
5591
+ url: 'url',
5592
+ delay: 'delay'
5593
+ },
5594
+
5595
+ /**
5596
+ * Destroy the timer when destroying the bootstrapValidator (using validator.destroy() method)
5597
+ */
5598
+ destroy: function(validator, $field, options) {
5599
+ if ($field.data('bv.remote.timer')) {
5600
+ clearTimeout($field.data('bv.remote.timer'));
5601
+ $field.removeData('bv.remote.timer');
5602
+ }
4788
5603
  },
4789
5604
 
4790
5605
  /**
@@ -4799,21 +5614,24 @@
4799
5614
  * {
4800
5615
  * <fieldName>: <fieldValue>
4801
5616
  * }
5617
+ * - delay
4802
5618
  * - name {String} [optional]: Override the field name for the request.
4803
5619
  * - message: The invalid message
4804
5620
  * - headers: Additional headers
4805
- * @returns {Boolean|Deferred}
5621
+ * @returns {Deferred}
4806
5622
  */
4807
5623
  validate: function(validator, $field, options) {
4808
- var value = $field.val();
5624
+ var value = $field.val(),
5625
+ dfd = new $.Deferred();
4809
5626
  if (value === '') {
4810
- return true;
5627
+ dfd.resolve($field, 'remote', { valid: true });
5628
+ return dfd;
4811
5629
  }
4812
5630
 
4813
5631
  var name = $field.attr('data-bv-field'),
4814
5632
  data = options.data || {},
4815
5633
  url = options.url,
4816
- type = options.type || 'POST',
5634
+ type = options.type || 'GET',
4817
5635
  headers = options.headers || {};
4818
5636
 
4819
5637
  // Support dynamic data
@@ -4827,24 +5645,38 @@
4827
5645
  }
4828
5646
 
4829
5647
  data[options.name || name] = value;
5648
+ function runCallback() {
5649
+ var xhr = $.ajax({
5650
+ type: type,
5651
+ headers: headers,
5652
+ url: url,
5653
+ dataType: 'json',
5654
+ data: data
5655
+ });
5656
+ xhr.then(function(response) {
5657
+ response.valid = response.valid === true || response.valid === 'true';
5658
+ dfd.resolve($field, 'remote', response);
5659
+ });
4830
5660
 
4831
- var dfd = new $.Deferred();
4832
- var xhr = $.ajax({
4833
- type: type,
4834
- headers: headers,
4835
- url: url,
4836
- dataType: 'json',
4837
- data: data
4838
- });
4839
- xhr.then(function(response) {
4840
- dfd.resolve($field, 'remote', response.valid === true || response.valid === 'true', response.message ? response.message : null);
4841
- });
5661
+ dfd.fail(function() {
5662
+ xhr.abort();
5663
+ });
4842
5664
 
4843
- dfd.fail(function() {
4844
- xhr.abort();
4845
- });
5665
+ return dfd;
5666
+ }
5667
+
5668
+ if (options.delay) {
5669
+ // Since the form might have multiple fields with the same name
5670
+ // I have to attach the timer to the field element
5671
+ if ($field.data('bv.remote.timer')) {
5672
+ clearTimeout($field.data('bv.remote.timer'));
5673
+ }
4846
5674
 
4847
- return dfd;
5675
+ $field.data('bv.remote.timer', setTimeout(runCallback, options.delay));
5676
+ return dfd;
5677
+ } else {
5678
+ return runCallback();
5679
+ }
4848
5680
  }
4849
5681
  };
4850
5682
  }(window.jQuery));
@@ -5108,14 +5940,17 @@
5108
5940
  },
5109
5941
 
5110
5942
  enableByHtml5: function($field) {
5111
- var maxLength = $field.attr('maxlength');
5943
+ var options = {},
5944
+ maxLength = $field.attr('maxlength'),
5945
+ minLength = $field.attr('minlength');
5112
5946
  if (maxLength) {
5113
- return {
5114
- max: parseInt(maxLength, 10)
5115
- };
5947
+ options.max = parseInt(maxLength, 10);
5948
+ }
5949
+ if (minLength) {
5950
+ options.min = parseInt(minLength, 10);
5116
5951
  }
5117
5952
 
5118
- return false;
5953
+ return $.isEmptyObject(options) ? false : options;
5119
5954
  },
5120
5955
 
5121
5956
  /**
@@ -5181,7 +6016,8 @@
5181
6016
  $.fn.bootstrapValidator.validators.uri = {
5182
6017
  html5Attributes: {
5183
6018
  message: 'message',
5184
- allowlocal: 'allowLocal'
6019
+ allowlocal: 'allowLocal',
6020
+ protocol: 'protocol'
5185
6021
  },
5186
6022
 
5187
6023
  enableByHtml5: function($field) {
@@ -5196,6 +6032,7 @@
5196
6032
  * @param {Object} options
5197
6033
  * - message: The error message
5198
6034
  * - allowLocal: Allow the private and local network IP. Default to false
6035
+ * - protocol: The protocols, separated by a comma. Default to "http, https, ftp"
5199
6036
  * @returns {Boolean}
5200
6037
  */
5201
6038
  validate: function(validator, $field, options) {
@@ -5233,11 +6070,14 @@
5233
6070
  // - Added exclusion of private, reserved and/or local networks ranges
5234
6071
  // unless `allowLocal` is true
5235
6072
  //
6073
+ // - Added possibility of choosing a custom protocol
6074
+ //
5236
6075
  var allowLocal = options.allowLocal === true || options.allowLocal === 'true',
6076
+ protocol = (options.protocol || 'http, https, ftp').split(',').join('|').replace(/\s/g, ''),
5237
6077
  urlExp = new RegExp(
5238
6078
  "^" +
5239
6079
  // protocol identifier
5240
- "(?:(?:https?|ftp)://)" +
6080
+ "(?:(?:" + protocol + ")://)" +
5241
6081
  // user:pass authentication
5242
6082
  "(?:\\S+(?::\\S*)?@)?" +
5243
6083
  "(?:" +
@@ -5271,7 +6111,7 @@
5271
6111
  // resource path
5272
6112
  "(?:/[^\\s]*)?" +
5273
6113
  "$", "i"
5274
- );
6114
+ );
5275
6115
 
5276
6116
  return urlExp.test(value);
5277
6117
  }
@@ -5327,44 +6167,45 @@
5327
6167
  $.fn.bootstrapValidator.i18n.vat = $.extend($.fn.bootstrapValidator.i18n.vat || {}, {
5328
6168
  'default': 'Please enter a valid VAT number',
5329
6169
  countryNotSupported: 'The country code %s is not supported',
5330
- country: 'Please enter a valid %s VAT number',
6170
+ country: 'Please enter a valid VAT number in %s',
5331
6171
  countries: {
5332
- AT: 'Austrian',
5333
- BE: 'Belgian',
5334
- BG: 'Bulgarian',
5335
- BR: 'Brazilian',
5336
- CH: 'Swiss',
5337
- CY: 'Cypriot',
5338
- CZ: 'Czech',
5339
- DE: 'German',
5340
- DK: 'Danish',
5341
- EE: 'Estonian',
5342
- ES: 'Spanish',
5343
- FI: 'Finnish',
5344
- FR: 'French',
6172
+ AT: 'Austria',
6173
+ BE: 'Belgium',
6174
+ BG: 'Bulgaria',
6175
+ BR: 'Brazil',
6176
+ CH: 'Switzerland',
6177
+ CY: 'Cyprus',
6178
+ CZ: 'Czech Republic',
6179
+ DE: 'Germany',
6180
+ DK: 'Denmark',
6181
+ EE: 'Estonia',
6182
+ ES: 'Spain',
6183
+ FI: 'Finland',
6184
+ FR: 'France',
5345
6185
  GB: 'United Kingdom',
5346
6186
  GR: 'Greek',
5347
6187
  EL: 'Greek',
5348
- HU: 'Hungarian',
5349
- HR: 'Croatian',
5350
- IE: 'Irish',
6188
+ HU: 'Hungary',
6189
+ HR: 'Croatia',
6190
+ IE: 'Ireland',
5351
6191
  IS: 'Iceland',
5352
- IT: 'Italian',
5353
- LT: 'Lithuanian',
6192
+ IT: 'Italy',
6193
+ LT: 'Lithuania',
5354
6194
  LU: 'Luxembourg',
5355
- LV: 'Latvian',
5356
- MT: 'Maltese',
5357
- NL: 'Dutch',
5358
- NO: 'Norwegian',
5359
- PL: 'Polish',
5360
- PT: 'Portuguese',
5361
- RO: 'Romanian',
5362
- RU: 'Russian',
5363
- RS: 'Serbian',
5364
- SE: 'Swedish',
5365
- SI: 'Slovenian',
5366
- SK: 'Slovak',
5367
- ZA: 'South African'
6195
+ LV: 'Latvia',
6196
+ MT: 'Malta',
6197
+ NL: 'Netherlands',
6198
+ NO: 'Norway',
6199
+ PL: 'Poland',
6200
+ PT: 'Portugal',
6201
+ RO: 'Romania',
6202
+ RU: 'Russia',
6203
+ RS: 'Serbia',
6204
+ SE: 'Sweden',
6205
+ SI: 'Slovenia',
6206
+ SK: 'Slovakia',
6207
+ VE: 'Venezuela',
6208
+ ZA: 'South Africa'
5368
6209
  }
5369
6210
  });
5370
6211
 
@@ -5377,7 +6218,8 @@
5377
6218
  // Supported country codes
5378
6219
  COUNTRY_CODES: [
5379
6220
  'AT', 'BE', 'BG', 'BR', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'EL', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU',
5380
- 'IE', 'IS', 'IT', 'LT', 'LU', 'LV', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'RU', 'RS', 'SE', 'SK', 'SI', 'ZA'
6221
+ 'IE', 'IS', 'IT', 'LT', 'LU', 'LV', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'RU', 'RS', 'SE', 'SK', 'SI', 'VE',
6222
+ 'ZA'
5381
6223
  ],
5382
6224
 
5383
6225
  /**
@@ -5436,15 +6278,17 @@
5436
6278
  * @returns {Boolean}
5437
6279
  */
5438
6280
  _at: function(value) {
5439
- if (!/^ATU[0-9]{8}$/.test(value)) {
6281
+ if (/^ATU[0-9]{8}$/.test(value)) {
6282
+ value = value.substr(2);
6283
+ }
6284
+ if (!/^U[0-9]{8}$/.test(value)) {
5440
6285
  return false;
5441
6286
  }
5442
6287
 
5443
- value = value.substr(3);
6288
+ value = value.substr(1);
5444
6289
  var sum = 0,
5445
6290
  weight = [1, 2, 1, 2, 1, 2, 1],
5446
6291
  temp = 0;
5447
-
5448
6292
  for (var i = 0; i < 7; i++) {
5449
6293
  temp = parseInt(value.charAt(i), 10) * weight[i];
5450
6294
  if (temp > 9) {
@@ -5471,15 +6315,16 @@
5471
6315
  * @returns {Boolean}
5472
6316
  */
5473
6317
  _be: function(value) {
5474
- if (!/^BE[0]{0,1}[0-9]{9}$/.test(value)) {
6318
+ if (/^BE[0]{0,1}[0-9]{9}$/.test(value)) {
6319
+ value = value.substr(2);
6320
+ }
6321
+ if (!/^[0]{0,1}[0-9]{9}$/.test(value)) {
5475
6322
  return false;
5476
6323
  }
5477
6324
 
5478
- value = value.substr(2);
5479
6325
  if (value.length === 9) {
5480
6326
  value = '0' + value;
5481
6327
  }
5482
-
5483
6328
  if (value.substr(1, 1) === '0') {
5484
6329
  return false;
5485
6330
  }
@@ -5501,11 +6346,13 @@
5501
6346
  * @returns {Boolean}
5502
6347
  */
5503
6348
  _bg: function(value) {
5504
- if (!/^BG[0-9]{9,10}$/.test(value)) {
6349
+ if (/^BG[0-9]{9,10}$/.test(value)) {
6350
+ value = value.substr(2);
6351
+ }
6352
+ if (!/^[0-9]{9,10}$/.test(value)) {
5505
6353
  return false;
5506
6354
  }
5507
6355
 
5508
- value = value.substr(2);
5509
6356
  var sum = 0, i = 0;
5510
6357
 
5511
6358
  // Legal entities
@@ -5648,11 +6495,14 @@
5648
6495
  * @returns {Boolean}
5649
6496
  */
5650
6497
  _ch: function(value) {
5651
- if (!/^CHE[0-9]{9}(MWST)?$/.test(value)) {
6498
+ if (/^CHE[0-9]{9}(MWST)?$/.test(value)) {
6499
+ value = value.substr(2);
6500
+ }
6501
+ if (!/^E[0-9]{9}(MWST)?$/.test(value)) {
5652
6502
  return false;
5653
6503
  }
5654
6504
 
5655
- value = value.substr(3);
6505
+ value = value.substr(1);
5656
6506
  var sum = 0,
5657
6507
  weight = [5, 4, 3, 2, 7, 6, 5, 4];
5658
6508
  for (var i = 0; i < 8; i++) {
@@ -5680,12 +6530,13 @@
5680
6530
  * @returns {Boolean}
5681
6531
  */
5682
6532
  _cy: function(value) {
5683
- if (!/^CY[0-5|9]{1}[0-9]{7}[A-Z]{1}$/.test(value)) {
6533
+ if (/^CY[0-5|9]{1}[0-9]{7}[A-Z]{1}$/.test(value)) {
6534
+ value = value.substr(2);
6535
+ }
6536
+ if (!/^[0-5|9]{1}[0-9]{7}[A-Z]{1}$/.test(value)) {
5684
6537
  return false;
5685
6538
  }
5686
6539
 
5687
- value = value.substr(2);
5688
-
5689
6540
  // Do not allow to start with "12"
5690
6541
  if (value.substr(0, 2) === '12') {
5691
6542
  return false;
@@ -5724,12 +6575,13 @@
5724
6575
  * @returns {Boolean}
5725
6576
  */
5726
6577
  _cz: function(value) {
5727
- if (!/^CZ[0-9]{8,10}$/.test(value)) {
6578
+ if (/^CZ[0-9]{8,10}$/.test(value)) {
6579
+ value = value.substr(2);
6580
+ }
6581
+ if (!/^[0-9]{8,10}$/.test(value)) {
5728
6582
  return false;
5729
6583
  }
5730
6584
 
5731
- value = value.substr(2);
5732
-
5733
6585
  var sum = 0,
5734
6586
  i = 0;
5735
6587
  if (value.length === 8) {
@@ -5811,11 +6663,13 @@
5811
6663
  * @returns {Boolean}
5812
6664
  */
5813
6665
  _de: function(value) {
5814
- if (!/^DE[0-9]{9}$/.test(value)) {
6666
+ if (/^DE[0-9]{9}$/.test(value)) {
6667
+ value = value.substr(2);
6668
+ }
6669
+ if (!/^[0-9]{9}$/.test(value)) {
5815
6670
  return false;
5816
6671
  }
5817
6672
 
5818
- value = value.substr(2);
5819
6673
  return $.fn.bootstrapValidator.helpers.mod11And10(value);
5820
6674
  },
5821
6675
 
@@ -5829,11 +6683,13 @@
5829
6683
  * @returns {Boolean}
5830
6684
  */
5831
6685
  _dk: function(value) {
5832
- if (!/^DK[0-9]{8}$/.test(value)) {
6686
+ if (/^DK[0-9]{8}$/.test(value)) {
6687
+ value = value.substr(2);
6688
+ }
6689
+ if (!/^[0-9]{8}$/.test(value)) {
5833
6690
  return false;
5834
6691
  }
5835
6692
 
5836
- value = value.substr(2);
5837
6693
  var sum = 0,
5838
6694
  weight = [2, 7, 6, 5, 4, 3, 2, 1];
5839
6695
  for (var i = 0; i < 8; i++) {
@@ -5853,14 +6709,15 @@
5853
6709
  * @returns {Boolean}
5854
6710
  */
5855
6711
  _ee: function(value) {
5856
- if (!/^EE[0-9]{9}$/.test(value)) {
6712
+ if (/^EE[0-9]{9}$/.test(value)) {
6713
+ value = value.substr(2);
6714
+ }
6715
+ if (!/^[0-9]{9}$/.test(value)) {
5857
6716
  return false;
5858
6717
  }
5859
6718
 
5860
- value = value.substr(2);
5861
6719
  var sum = 0,
5862
6720
  weight = [3, 7, 1, 3, 7, 1, 3, 7, 1];
5863
-
5864
6721
  for (var i = 0; i < 9; i++) {
5865
6722
  sum += parseInt(value.charAt(i), 10) * weight[i];
5866
6723
  }
@@ -5883,11 +6740,13 @@
5883
6740
  * @returns {Boolean}
5884
6741
  */
5885
6742
  _es: function(value) {
5886
- if (!/^ES[0-9A-Z][0-9]{7}[0-9A-Z]$/.test(value)) {
6743
+ if (/^ES[0-9A-Z][0-9]{7}[0-9A-Z]$/.test(value)) {
6744
+ value = value.substr(2);
6745
+ }
6746
+ if (!/^[0-9A-Z][0-9]{7}[0-9A-Z]$/.test(value)) {
5887
6747
  return false;
5888
6748
  }
5889
6749
 
5890
- value = value.substr(2);
5891
6750
  var dni = function(value) {
5892
6751
  var check = parseInt(value.substr(0, 8), 10);
5893
6752
  check = 'TRWAGMYFPDXBNJZSQVHLCKE'[check % 23];
@@ -5947,14 +6806,15 @@
5947
6806
  * @returns {Boolean}
5948
6807
  */
5949
6808
  _fi: function(value) {
5950
- if (!/^FI[0-9]{8}$/.test(value)) {
6809
+ if (/^FI[0-9]{8}$/.test(value)) {
6810
+ value = value.substr(2);
6811
+ }
6812
+ if (!/^[0-9]{8}$/.test(value)) {
5951
6813
  return false;
5952
6814
  }
5953
6815
 
5954
- value = value.substr(2);
5955
6816
  var sum = 0,
5956
6817
  weight = [7, 9, 10, 5, 8, 4, 2, 1];
5957
-
5958
6818
  for (var i = 0; i < 8; i++) {
5959
6819
  sum += parseInt(value.charAt(i), 10) * weight[i];
5960
6820
  }
@@ -5974,12 +6834,13 @@
5974
6834
  * @returns {Boolean}
5975
6835
  */
5976
6836
  _fr: function(value) {
5977
- if (!/^FR[0-9A-Z]{2}[0-9]{9}$/.test(value)) {
6837
+ if (/^FR[0-9A-Z]{2}[0-9]{9}$/.test(value)) {
6838
+ value = value.substr(2);
6839
+ }
6840
+ if (!/^[0-9A-Z]{2}[0-9]{9}$/.test(value)) {
5978
6841
  return false;
5979
6842
  }
5980
6843
 
5981
- value = value.substr(2);
5982
-
5983
6844
  if (!$.fn.bootstrapValidator.helpers.luhn(value.substr(2))) {
5984
6845
  return false;
5985
6846
  }
@@ -6011,16 +6872,23 @@
6011
6872
  * @returns {Boolean}
6012
6873
  */
6013
6874
  _gb: function(value) {
6014
- if (!/^GB[0-9]{9}$/.test(value) /* Standard */
6015
- && !/^GB[0-9]{12}$/.test(value) /* Branches */
6016
- && !/^GBGD[0-9]{3}$/.test(value) /* Government department */
6017
- && !/^GBHA[0-9]{3}$/.test(value) /* Health authority */
6018
- && !/^GB(GD|HA)8888[0-9]{5}$/.test(value))
6875
+ if (/^GB[0-9]{9}$/.test(value) /* Standard */
6876
+ || /^GB[0-9]{12}$/.test(value) /* Branches */
6877
+ || /^GBGD[0-9]{3}$/.test(value) /* Government department */
6878
+ || /^GBHA[0-9]{3}$/.test(value) /* Health authority */
6879
+ || /^GB(GD|HA)8888[0-9]{5}$/.test(value))
6880
+ {
6881
+ value = value.substr(2);
6882
+ }
6883
+ if (!/^[0-9]{9}$/.test(value)
6884
+ && !/^[0-9]{12}$/.test(value)
6885
+ && !/^GD[0-9]{3}$/.test(value)
6886
+ && !/^HA[0-9]{3}$/.test(value)
6887
+ && !/^(GD|HA)8888[0-9]{5}$/.test(value))
6019
6888
  {
6020
6889
  return false;
6021
6890
  }
6022
6891
 
6023
- value = value.substr(2);
6024
6892
  var length = value.length;
6025
6893
  if (length === 5) {
6026
6894
  var firstTwo = value.substr(0, 2),
@@ -6061,11 +6929,13 @@
6061
6929
  * @returns {Boolean}
6062
6930
  */
6063
6931
  _gr: function(value) {
6064
- if (!/^GR[0-9]{9}$/.test(value)) {
6932
+ if (/^(GR|EL)[0-9]{9}$/.test(value)) {
6933
+ value = value.substr(2);
6934
+ }
6935
+ if (!/^[0-9]{9}$/.test(value)) {
6065
6936
  return false;
6066
6937
  }
6067
6938
 
6068
- value = value.substr(2);
6069
6939
  if (value.length === 8) {
6070
6940
  value = '0' + value;
6071
6941
  }
@@ -6082,11 +6952,6 @@
6082
6952
 
6083
6953
  // EL is traditionally prefix of Greek VAT numbers
6084
6954
  _el: function(value) {
6085
- if (!/^EL[0-9]{9}$/.test(value)) {
6086
- return false;
6087
- }
6088
-
6089
- value = 'GR' + value.substr(2);
6090
6955
  return this._gr(value);
6091
6956
  },
6092
6957
 
@@ -6100,11 +6965,13 @@
6100
6965
  * @returns {Boolean}
6101
6966
  */
6102
6967
  _hu: function(value) {
6103
- if (!/^HU[0-9]{8}$/.test(value)) {
6968
+ if (/^HU[0-9]{8}$/.test(value)) {
6969
+ value = value.substr(2);
6970
+ }
6971
+ if (!/^[0-9]{8}$/.test(value)) {
6104
6972
  return false;
6105
6973
  }
6106
6974
 
6107
- value = value.substr(2);
6108
6975
  var sum = 0,
6109
6976
  weight = [9, 7, 3, 1, 9, 7, 3, 1];
6110
6977
 
@@ -6125,11 +6992,13 @@
6125
6992
  * @returns {Boolean}
6126
6993
  */
6127
6994
  _hr: function(value) {
6128
- if (!/^HR[0-9]{11}$/.test(value)) {
6995
+ if (/^HR[0-9]{11}$/.test(value)) {
6996
+ value = value.substr(2);
6997
+ }
6998
+ if (!/^[0-9]{11}$/.test(value)) {
6129
6999
  return false;
6130
7000
  }
6131
7001
 
6132
- value = value.substr(2);
6133
7002
  return $.fn.bootstrapValidator.helpers.mod11And10(value);
6134
7003
  },
6135
7004
 
@@ -6143,11 +7012,13 @@
6143
7012
  * @returns {Boolean}
6144
7013
  */
6145
7014
  _ie: function(value) {
6146
- if (!/^IE[0-9]{1}[0-9A-Z\*\+]{1}[0-9]{5}[A-Z]{1,2}$/.test(value)) {
7015
+ if (/^IE[0-9]{1}[0-9A-Z\*\+]{1}[0-9]{5}[A-Z]{1,2}$/.test(value)) {
7016
+ value = value.substr(2);
7017
+ }
7018
+ if (!/^[0-9]{1}[0-9A-Z\*\+]{1}[0-9]{5}[A-Z]{1,2}$/.test(value)) {
6147
7019
  return false;
6148
7020
  }
6149
7021
 
6150
- value = value.substr(2);
6151
7022
  var getCheckDigit = function(value) {
6152
7023
  while (value.length < 7) {
6153
7024
  value = '0' + value;
@@ -6183,7 +7054,10 @@
6183
7054
  * @returns {Boolean}
6184
7055
  */
6185
7056
  _is: function(value) {
6186
- return /^IS\d{5,6}$/.test(value);
7057
+ if (/^IS[0-9]{5,6}$/.test(value)) {
7058
+ value = value.substr(2);
7059
+ }
7060
+ return /^[0-9]{5,6}$/.test(value);
6187
7061
  },
6188
7062
 
6189
7063
  /**
@@ -6200,11 +7074,13 @@
6200
7074
  * @returns {Boolean}
6201
7075
  */
6202
7076
  _it: function(value) {
6203
- if (!/^IT[0-9]{11}$/.test(value)) {
7077
+ if (/^IT[0-9]{11}$/.test(value)) {
7078
+ value = value.substr(2);
7079
+ }
7080
+ if (!/^[0-9]{11}$/.test(value)) {
6204
7081
  return false;
6205
7082
  }
6206
7083
 
6207
- value = value.substr(2);
6208
7084
  if (parseInt(value.substr(0, 7), 10) === 0) {
6209
7085
  return false;
6210
7086
  }
@@ -6231,11 +7107,13 @@
6231
7107
  * @returns {Boolean}
6232
7108
  */
6233
7109
  _lt: function(value) {
6234
- if (!/^LT([0-9]{7}1[0-9]{1}|[0-9]{10}1[0-9]{1})$/.test(value)) {
7110
+ if (/^LT([0-9]{7}1[0-9]{1}|[0-9]{10}1[0-9]{1})$/.test(value)) {
7111
+ value = value.substr(2);
7112
+ }
7113
+ if (!/^([0-9]{7}1[0-9]{1}|[0-9]{10}1[0-9]{1})$/.test(value)) {
6235
7114
  return false;
6236
7115
  }
6237
7116
 
6238
- value = value.substr(2);
6239
7117
  var length = value.length,
6240
7118
  sum = 0,
6241
7119
  i;
@@ -6263,11 +7141,13 @@
6263
7141
  * @returns {Boolean}
6264
7142
  */
6265
7143
  _lu: function(value) {
6266
- if (!/^LU[0-9]{8}$/.test(value)) {
7144
+ if (/^LU[0-9]{8}$/.test(value)) {
7145
+ value = value.substr(2);
7146
+ }
7147
+ if (!/^[0-9]{8}$/.test(value)) {
6267
7148
  return false;
6268
7149
  }
6269
7150
 
6270
- value = value.substr(2);
6271
7151
  return ((parseInt(value.substr(0, 6), 10) % 89) + '' === value.substr(6, 2));
6272
7152
  },
6273
7153
 
@@ -6281,11 +7161,13 @@
6281
7161
  * @returns {Boolean}
6282
7162
  */
6283
7163
  _lv: function(value) {
6284
- if (!/^LV[0-9]{11}$/.test(value)) {
7164
+ if (/^LV[0-9]{11}$/.test(value)) {
7165
+ value = value.substr(2);
7166
+ }
7167
+ if (!/^[0-9]{11}$/.test(value)) {
6285
7168
  return false;
6286
7169
  }
6287
7170
 
6288
- value = value.substr(2);
6289
7171
  var first = parseInt(value.charAt(0), 10),
6290
7172
  sum = 0,
6291
7173
  weight = [],
@@ -6332,11 +7214,13 @@
6332
7214
  * @returns {Boolean}
6333
7215
  */
6334
7216
  _mt: function(value) {
6335
- if (!/^MT[0-9]{8}$/.test(value)) {
7217
+ if (/^MT[0-9]{8}$/.test(value)) {
7218
+ value = value.substr(2);
7219
+ }
7220
+ if (!/^[0-9]{8}$/.test(value)) {
6336
7221
  return false;
6337
7222
  }
6338
7223
 
6339
- value = value.substr(2);
6340
7224
  var sum = 0,
6341
7225
  weight = [3, 4, 6, 7, 8, 9, 10, 1];
6342
7226
 
@@ -6357,10 +7241,13 @@
6357
7241
  * @returns {Boolean}
6358
7242
  */
6359
7243
  _nl: function(value) {
6360
- if (!/^NL[0-9]{9}B[0-9]{2}$/.test(value)) {
7244
+ if (/^NL[0-9]{9}B[0-9]{2}$/.test(value)) {
7245
+ value = value.substr(2);
7246
+ }
7247
+ if (!/^[0-9]{9}B[0-9]{2}$/.test(value)) {
6361
7248
  return false;
6362
7249
  }
6363
- value = value.substr(2);
7250
+
6364
7251
  var sum = 0,
6365
7252
  weight = [9, 8, 7, 6, 5, 4, 3, 2];
6366
7253
  for (var i = 0; i < 8; i++) {
@@ -6382,10 +7269,13 @@
6382
7269
  * @returns {Boolean}
6383
7270
  */
6384
7271
  _no: function(value) {
6385
- if (!/^NO[0-9]{9}$/.test(value)) {
7272
+ if (/^NO[0-9]{9}$/.test(value)) {
7273
+ value = value.substr(2);
7274
+ }
7275
+ if (!/^[0-9]{9}$/.test(value)) {
6386
7276
  return false;
6387
7277
  }
6388
- value = value.substr(2);
7278
+
6389
7279
  var sum = 0,
6390
7280
  weight = [3, 2, 7, 6, 5, 4, 3, 2];
6391
7281
  for (var i = 0; i < 8; i++) {
@@ -6409,11 +7299,13 @@
6409
7299
  * @returns {Boolean}
6410
7300
  */
6411
7301
  _pl: function(value) {
6412
- if (!/^PL[0-9]{10}$/.test(value)) {
7302
+ if (/^PL[0-9]{10}$/.test(value)) {
7303
+ value = value.substr(2);
7304
+ }
7305
+ if (!/^[0-9]{10}$/.test(value)) {
6413
7306
  return false;
6414
7307
  }
6415
7308
 
6416
- value = value.substr(2);
6417
7309
  var sum = 0,
6418
7310
  weight = [6, 5, 7, 2, 3, 4, 5, 6, 7, -1];
6419
7311
 
@@ -6434,11 +7326,13 @@
6434
7326
  * @returns {Boolean}
6435
7327
  */
6436
7328
  _pt: function(value) {
6437
- if (!/^PT[0-9]{9}$/.test(value)) {
7329
+ if (/^PT[0-9]{9}$/.test(value)) {
7330
+ value = value.substr(2);
7331
+ }
7332
+ if (!/^[0-9]{9}$/.test(value)) {
6438
7333
  return false;
6439
7334
  }
6440
7335
 
6441
- value = value.substr(2);
6442
7336
  var sum = 0,
6443
7337
  weight = [9, 8, 7, 6, 5, 4, 3, 2];
6444
7338
 
@@ -6462,10 +7356,12 @@
6462
7356
  * @returns {Boolean}
6463
7357
  */
6464
7358
  _ro: function(value) {
6465
- if (!/^RO[1-9][0-9]{1,9}$/.test(value)) {
7359
+ if (/^RO[1-9][0-9]{1,9}$/.test(value)) {
7360
+ value = value.substr(2);
7361
+ }
7362
+ if (!/^[1-9][0-9]{1,9}$/.test(value)) {
6466
7363
  return false;
6467
7364
  }
6468
- value = value.substr(2);
6469
7365
 
6470
7366
  var length = value.length,
6471
7367
  weight = [7, 5, 3, 2, 1, 7, 5, 3, 2].slice(10 - length),
@@ -6485,11 +7381,13 @@
6485
7381
  * @returns {Boolean}
6486
7382
  */
6487
7383
  _ru: function(value) {
6488
- if (!/^RU([0-9]{9}|[0-9]{12})$/.test(value)) {
7384
+ if (/^RU([0-9]{10}|[0-9]{12})$/.test(value)) {
7385
+ value = value.substr(2);
7386
+ }
7387
+ if (!/^([0-9]{10}|[0-9]{12})$/.test(value)) {
6489
7388
  return false;
6490
7389
  }
6491
7390
 
6492
- value = value.substr(2);
6493
7391
  var i = 0;
6494
7392
  if (value.length === 10) {
6495
7393
  var sum = 0,
@@ -6535,11 +7433,13 @@
6535
7433
  * @returns {Boolean}
6536
7434
  */
6537
7435
  _rs: function(value) {
6538
- if (!/^RS[0-9]{9}$/.test(value)) {
7436
+ if (/^RS[0-9]{9}$/.test(value)) {
7437
+ value = value.substr(2);
7438
+ }
7439
+ if (!/^[0-9]{9}$/.test(value)) {
6539
7440
  return false;
6540
7441
  }
6541
7442
 
6542
- value = value.substr(2);
6543
7443
  var sum = 10,
6544
7444
  temp = 0;
6545
7445
  for (var i = 0; i < 8; i++) {
@@ -6563,11 +7463,14 @@
6563
7463
  * @returns {Boolean}
6564
7464
  */
6565
7465
  _se: function(value) {
6566
- if (!/^SE[0-9]{10}01$/.test(value)) {
7466
+ if (/^SE[0-9]{10}01$/.test(value)) {
7467
+ value = value.substr(2);
7468
+ }
7469
+ if (!/^[0-9]{10}01$/.test(value)) {
6567
7470
  return false;
6568
7471
  }
6569
7472
 
6570
- value = value.substr(2, 10);
7473
+ value = value.substr(0, 10);
6571
7474
  return $.fn.bootstrapValidator.helpers.luhn(value);
6572
7475
  },
6573
7476
 
@@ -6581,11 +7484,13 @@
6581
7484
  * @returns {Boolean}
6582
7485
  */
6583
7486
  _si: function(value) {
6584
- if (!/^SI[0-9]{8}$/.test(value)) {
7487
+ if (/^SI[0-9]{8}$/.test(value)) {
7488
+ value = value.substr(2);
7489
+ }
7490
+ if (!/^[0-9]{8}$/.test(value)) {
6585
7491
  return false;
6586
7492
  }
6587
7493
 
6588
- value = value.substr(2);
6589
7494
  var sum = 0,
6590
7495
  weight = [8, 7, 6, 5, 4, 3, 2];
6591
7496
 
@@ -6609,11 +7514,52 @@
6609
7514
  * @returns {Boolean}
6610
7515
  */
6611
7516
  _sk: function(value) {
6612
- if (!/^SK[1-9][0-9][(2-4)|(6-9)][0-9]{7}$/.test(value)) {
7517
+ if (/^SK[1-9][0-9][(2-4)|(6-9)][0-9]{7}$/.test(value)) {
7518
+ value = value.substr(2);
7519
+ }
7520
+ if (!/^[1-9][0-9][(2-4)|(6-9)][0-9]{7}$/.test(value)) {
6613
7521
  return false;
6614
7522
  }
6615
7523
 
6616
- return (parseInt(value.substr(2), 10) % 11 === 0);
7524
+ return (parseInt(value, 10) % 11 === 0);
7525
+ },
7526
+
7527
+ /**
7528
+ * Validate Venezuelan VAT number (RIF)
7529
+ * Examples:
7530
+ * - Valid: VEJ309272292, VEV242818101, VEJ000126518, VEJ000458324, J309272292, V242818101, J000126518, J000458324
7531
+ * - Invalid: VEJ309272293, VEV242818100, J000126519, J000458323
7532
+ *
7533
+ * @param {String} value VAT number
7534
+ * @returns {Boolean}
7535
+ */
7536
+ _ve: function(value) {
7537
+ if (/^VE[VEJPG][0-9]{9}$/.test(value)) {
7538
+ value = value.substr(2);
7539
+ }
7540
+ if (!/^[VEJPG][0-9]{9}$/.test(value)) {
7541
+ return false;
7542
+ }
7543
+
7544
+ var types = {
7545
+ 'V': 4,
7546
+ 'E': 8,
7547
+ 'J': 12,
7548
+ 'P': 16,
7549
+ 'G': 20
7550
+ },
7551
+ sum = types[value.charAt(0)],
7552
+ weight = [3, 2, 7, 6, 5, 4, 3, 2];
7553
+
7554
+ for (var i = 0; i < 8; i++) {
7555
+ sum += parseInt(value.charAt(i + 1), 10) * weight[i];
7556
+ }
7557
+
7558
+ sum = 11 - sum % 11;
7559
+ if (sum === 11 || sum === 10) {
7560
+ sum = 0;
7561
+ }
7562
+ return (sum + '' === value.substr(9, 1));
6617
7563
  },
6618
7564
 
6619
7565
  /**
@@ -6626,7 +7572,11 @@
6626
7572
  * @returns {Boolean}
6627
7573
  */
6628
7574
  _za: function(value) {
6629
- return /^ZA4\d{9}$/.test(value);
7575
+ if (/^ZA4[0-9]{9}$/.test(value)) {
7576
+ value = value.substr(2);
7577
+ }
7578
+
7579
+ return /^4[0-9]{9}$/.test(value);
6630
7580
  }
6631
7581
  };
6632
7582
  }(window.jQuery));
@@ -6681,20 +7631,24 @@
6681
7631
  }(window.jQuery));
6682
7632
  ;(function($) {
6683
7633
  $.fn.bootstrapValidator.i18n.zipCode = $.extend($.fn.bootstrapValidator.i18n.zipCode || {}, {
6684
- 'default': 'Please enter a valid zip code',
7634
+ 'default': 'Please enter a valid postal code',
6685
7635
  countryNotSupported: 'The country code %s is not supported',
6686
- country: 'Please enter a valid %s',
7636
+ country: 'Please enter a valid postal code in %s',
6687
7637
  countries: {
6688
- BR: 'Brazilian postal code',
6689
- CA: 'Canadian postal code',
6690
- DK: 'Danish postal code',
6691
- GB: 'United Kingdom postal code',
6692
- IT: 'Italian postal code',
6693
- MA: 'Moroccan postal code',
6694
- NL: 'Dutch postal code',
6695
- SE: 'Swiss postal code',
6696
- SG: 'Singapore postal code',
6697
- US: 'US zip code'
7638
+ BR: 'Brazil',
7639
+ CA: 'Canada',
7640
+ CZ: 'Czech Republic',
7641
+ DK: 'Denmark',
7642
+ GB: 'United Kingdom',
7643
+ IT: 'Italy',
7644
+ MA: 'Morocco',
7645
+ NL: 'Netherlands',
7646
+ RO: 'Romania',
7647
+ RU: 'Russia',
7648
+ SE: 'Sweden',
7649
+ SG: 'Singapore',
7650
+ SK: 'Slovakia',
7651
+ US: 'USA'
6698
7652
  }
6699
7653
  });
6700
7654
 
@@ -6704,7 +7658,7 @@
6704
7658
  country: 'country'
6705
7659
  },
6706
7660
 
6707
- COUNTRY_CODES: ['BR', 'CA', 'DK', 'GB', 'IT', 'MA', 'NL', 'SE', 'SG', 'US'],
7661
+ COUNTRY_CODES: ['BR', 'CA', 'CZ', 'DK', 'GB', 'IT', 'MA', 'NL', 'RO', 'RU', 'SE', 'SG', 'SK', 'US'],
6708
7662
 
6709
7663
  /**
6710
7664
  * Return true if and only if the input value is a valid country zip code
@@ -6756,6 +7710,11 @@
6756
7710
  isValid = /^(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|X|Y){1}[0-9]{1}(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|W|X|Y|Z){1}\s?[0-9]{1}(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|W|X|Y|Z){1}[0-9]{1}$/i.test(value);
6757
7711
  break;
6758
7712
 
7713
+ case 'CZ':
7714
+ // Test: http://regexr.com/39hhr
7715
+ isValid = /^(\d{3})([ ]?)(\d{2})$/.test(value);
7716
+ break;
7717
+
6759
7718
  case 'DK':
6760
7719
  isValid = /^(DK(-|\s)?)?\d{4}$/i.test(value);
6761
7720
  break;
@@ -6778,6 +7737,14 @@
6778
7737
  case 'NL':
6779
7738
  isValid = /^[1-9][0-9]{3} ?(?!sa|sd|ss)[a-z]{2}$/i.test(value);
6780
7739
  break;
7740
+
7741
+ case 'RO':
7742
+ isValid = /^(0[1-8]{1}|[1-9]{1}[0-5]{1})?[0-9]{4}$/i.test(value);
7743
+ break;
7744
+
7745
+ case 'RU':
7746
+ isValid = /^[0-9]{6}$/i.test(value);
7747
+ break;
6781
7748
 
6782
7749
  case 'SE':
6783
7750
  isValid = /^(S-)?\d{3}\s?\d{2}$/i.test(value);
@@ -6786,7 +7753,12 @@
6786
7753
  case 'SG':
6787
7754
  isValid = /^([0][1-9]|[1-6][0-9]|[7]([0-3]|[5-9])|[8][0-2])(\d{4})$/i.test(value);
6788
7755
  break;
6789
-
7756
+
7757
+ case 'SK':
7758
+ // Test: http://regexr.com/39hhr
7759
+ isValid = /^(\d{3})([ ]?)(\d{2})$/.test(value);
7760
+ break;
7761
+
6790
7762
  case 'US':
6791
7763
  /* falls through */
6792
7764
  default: