|
1 | 1 | /*! |
2 | | - * Validator v0.10.2 for Bootstrap 3, by @1000hz |
| 2 | + * Validator v0.11.0 for Bootstrap 3, by @1000hz |
3 | 3 | * Copyright 2016 Cina Saffary |
4 | 4 | * Licensed under http://opensource.org/licenses/MIT |
5 | 5 | * |
|
15 | 15 | function getValue($el) { |
16 | 16 | return $el.is('[type="checkbox"]') ? $el.prop('checked') : |
17 | 17 | $el.is('[type="radio"]') ? !!$('[name="' + $el.attr('name') + '"]:checked').length : |
18 | | - $.trim($el.val()) |
| 18 | + $el.val() |
19 | 19 | } |
20 | 20 |
|
21 | 21 | var Validator = function (element, options) { |
22 | | - this.options = options |
23 | | - this.$element = $(element) |
24 | | - this.$inputs = this.$element.find(Validator.INPUT_SELECTOR) |
25 | | - this.$btn = $('button[type="submit"], input[type="submit"]') |
26 | | - .filter('[form="' + this.$element.attr('id') + '"]') |
27 | | - .add(this.$element.find('input[type="submit"], button[type="submit"]')) |
| 22 | + this.options = options |
| 23 | + this.validators = $.extend({}, Validator.VALIDATORS, options.custom) |
| 24 | + this.$element = $(element) |
| 25 | + this.$btn = $('button[type="submit"], input[type="submit"]') |
| 26 | + .filter('[form="' + this.$element.attr('id') + '"]') |
| 27 | + .add(this.$element.find('input[type="submit"], button[type="submit"]')) |
28 | 28 |
|
29 | | - options.errors = $.extend({}, Validator.DEFAULTS.errors, options.errors) |
| 29 | + this.update() |
30 | 30 |
|
31 | | - for (var custom in options.custom) { |
32 | | - if (!options.errors[custom]) throw new Error('Missing default error message for custom validator: ' + custom) |
33 | | - } |
34 | | - |
35 | | - $.extend(Validator.VALIDATORS, options.custom) |
36 | | - |
37 | | - this.$element.attr('novalidate', true) // disable automatic native validation |
38 | | - this.toggleSubmit() |
39 | | - |
40 | | - this.$element.on('input.bs.validator change.bs.validator focusout.bs.validator', Validator.INPUT_SELECTOR, $.proxy(this.onInput, this)) |
| 31 | + this.$element.on('input.bs.validator change.bs.validator focusout.bs.validator', $.proxy(this.onInput, this)) |
41 | 32 | this.$element.on('submit.bs.validator', $.proxy(this.onSubmit, this)) |
42 | 33 |
|
43 | 34 | this.$element.find('[data-match]').each(function () { |
|
48 | 39 | getValue($this) && $this.trigger('input.bs.validator') |
49 | 40 | }) |
50 | 41 | }) |
| 42 | + |
| 43 | + this.$inputs.filter(function () { return getValue($(this)) }).trigger('focusout') |
| 44 | + |
| 45 | + this.$element.attr('novalidate', true) // disable automatic native validation |
| 46 | + this.toggleSubmit() |
51 | 47 | } |
52 | 48 |
|
53 | | - Validator.INPUT_SELECTOR = ':input:not([type="submit"], button):enabled:visible' |
| 49 | + Validator.VERSION = '0.11.0' |
| 50 | + |
| 51 | + Validator.INPUT_SELECTOR = ':input:not([type="hidden"], [type="submit"], button)' |
54 | 52 |
|
55 | 53 | Validator.FOCUS_OFFSET = 20 |
56 | 54 |
|
|
73 | 71 | Validator.VALIDATORS = { |
74 | 72 | 'native': function ($el) { |
75 | 73 | var el = $el[0] |
76 | | - return el.checkValidity ? el.checkValidity() : true |
| 74 | + if (el.checkValidity) { |
| 75 | + return !el.checkValidity() && !el.validity.valid && (el.validationMessage || "error!") |
| 76 | + } |
77 | 77 | }, |
78 | 78 | 'match': function ($el) { |
79 | 79 | var target = $el.data('match') |
80 | | - return !$el.val() || $el.val() === $(target).val() |
| 80 | + return $el.val() !== $(target).val() && Validator.DEFAULTS.errors.match |
81 | 81 | }, |
82 | 82 | 'minlength': function ($el) { |
83 | 83 | var minlength = $el.data('minlength') |
84 | | - return !$el.val() || $el.val().length >= minlength |
| 84 | + return $el.val().length < minlength && Validator.DEFAULTS.errors.minlength |
85 | 85 | } |
86 | 86 | } |
87 | 87 |
|
| 88 | + Validator.prototype.update = function () { |
| 89 | + this.$inputs = this.$element.find(Validator.INPUT_SELECTOR) |
| 90 | + .add(this.$element.find('[data-validate="true"]')) |
| 91 | + .not(this.$element.find('[data-validate="false"]')) |
| 92 | + |
| 93 | + return this |
| 94 | + } |
| 95 | + |
88 | 96 | Validator.prototype.onInput = function (e) { |
89 | 97 | var self = this |
90 | 98 | var $el = $(e.target) |
91 | 99 | var deferErrors = e.type !== 'focusout' |
| 100 | + |
| 101 | + if (!this.$inputs.is($el)) return |
| 102 | + |
92 | 103 | this.validateInput($el, deferErrors).done(function () { |
93 | 104 | self.toggleSubmit() |
94 | 105 | }) |
95 | 106 | } |
96 | 107 |
|
97 | 108 | Validator.prototype.validateInput = function ($el, deferErrors) { |
98 | 109 | var value = getValue($el) |
99 | | - var prevValue = $el.data('bs.validator.previous') |
100 | 110 | var prevErrors = $el.data('bs.validator.errors') |
101 | 111 | var errors |
102 | 112 |
|
103 | | - if (prevValue === value) return $.Deferred().resolve() |
104 | | - else $el.data('bs.validator.previous', value) |
105 | | - |
106 | 113 | if ($el.is('[type="radio"]')) $el = this.$element.find('input[name="' + $el.attr('name') + '"]') |
107 | 114 |
|
108 | 115 | var e = $.Event('validate.bs.validator', {relatedTarget: $el[0]}) |
|
136 | 143 | Validator.prototype.runValidators = function ($el) { |
137 | 144 | var errors = [] |
138 | 145 | var deferred = $.Deferred() |
139 | | - var options = this.options |
140 | 146 |
|
141 | 147 | $el.data('bs.validator.deferred') && $el.data('bs.validator.deferred').reject() |
142 | 148 | $el.data('bs.validator.deferred', deferred) |
143 | 149 |
|
144 | | - function getErrorMessage(key) { |
| 150 | + function getValidatorSpecificError(key) { |
145 | 151 | return $el.data(key + '-error') |
146 | | - || $el.data('error') |
147 | | - || key == 'native' && $el[0].validationMessage |
148 | | - || options.errors[key] |
149 | 152 | } |
150 | 153 |
|
151 | | - $.each(Validator.VALIDATORS, $.proxy(function (key, validator) { |
| 154 | + function getValidityStateError() { |
| 155 | + var validity = $el[0].validity |
| 156 | + return validity.typeMismatch ? $el.data('type-error') |
| 157 | + : validity.patternMismatch ? $el.data('pattern-error') |
| 158 | + : validity.stepMismatch ? $el.data('step-error') |
| 159 | + : validity.rangeOverflow ? $el.data('max-error') |
| 160 | + : validity.rangeUnderflow ? $el.data('min-error') |
| 161 | + : validity.valueMissing ? $el.data('required-error') |
| 162 | + : null |
| 163 | + } |
| 164 | + |
| 165 | + function getGenericError() { |
| 166 | + return $el.data('error') |
| 167 | + } |
| 168 | + |
| 169 | + function getErrorMessage(key) { |
| 170 | + return getValidatorSpecificError(key) |
| 171 | + || getValidityStateError() |
| 172 | + || getGenericError() |
| 173 | + } |
| 174 | + |
| 175 | + $.each(this.validators, $.proxy(function (key, validator) { |
| 176 | + var error = null |
152 | 177 | if ((getValue($el) || $el.attr('required')) && |
153 | 178 | ($el.data(key) || key == 'native') && |
154 | | - !validator.call(this, $el)) { |
155 | | - var error = getErrorMessage(key) |
| 179 | + (error = validator.call(this, $el))) { |
| 180 | + error = getErrorMessage(key) || error |
156 | 181 | !~errors.indexOf(error) && errors.push(error) |
157 | 182 | } |
158 | 183 | }, this)) |
|
189 | 214 | var $input = $(".has-error:first :input") |
190 | 215 | if ($input.length === 0) return |
191 | 216 |
|
192 | | - $(document.body).animate({scrollTop: $input.offset().top - Validator.FOCUS_OFFSET}, 250) |
| 217 | + $('html, body').animate({scrollTop: $input.offset().top - Validator.FOCUS_OFFSET}, 250) |
193 | 218 | $input.focus() |
194 | 219 | } |
195 | 220 |
|
|
241 | 266 |
|
242 | 267 | Validator.prototype.isIncomplete = function () { |
243 | 268 | function fieldIncomplete() { |
244 | | - return !getValue($(this)) |
| 269 | + var value = getValue($(this)) |
| 270 | + return !(typeof value == "string" ? $.trim(value) : value) |
245 | 271 | } |
246 | 272 |
|
247 | 273 | return !!this.$inputs.filter('[required]').filter(fieldIncomplete).length |
|
274 | 300 |
|
275 | 301 | this.$inputs |
276 | 302 | .off('.bs.validator') |
277 | | - .removeData(['bs.validator.errors', 'bs.validator.deferred', 'bs.validator.previous']) |
| 303 | + .removeData(['bs.validator.errors', 'bs.validator.deferred']) |
278 | 304 | .each(function () { |
279 | 305 | var $this = $(this) |
280 | 306 | var timeout = $this.data('bs.validator.timeout') |
|
0 commit comments