bootstrap-validator-rails 0.5.1 → 0.5.2

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