bootstrap_validator_rails 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +32 -0
- data/lib/bootstrap_validator_rails/engine.rb +4 -0
- data/lib/bootstrap_validator_rails/version.rb +3 -0
- data/lib/bootstrap_validator_rails.rb +42 -0
- data/lib/tasks/bootstrap_validator_rails_tasks.rake +4 -0
- data/test/bootstrap_validator_rails_test.rb +13 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/post.rb +3 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config/application.rb +23 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +82 -0
- data/test/dummy/config/environments/test.rb +39 -0
- data/test/dummy/config/initializers/assets.rb +8 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +56 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20140723124112_create_posts.rb +7 -0
- data/test/dummy/db/schema.rb +20 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/ENV=test.log +0 -0
- data/test/dummy/log/development.log +22 -0
- data/test/dummy/log/test.log +781 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/test_helper.rb +15 -0
- data/vendor/assets/javascripts/bootstrapValidator.js +1803 -0
- data/vendor/assets/javascripts/language/de_DE.js +326 -0
- data/vendor/assets/javascripts/language/en_US.js +327 -0
- data/vendor/assets/javascripts/language/es_CL.js +326 -0
- data/vendor/assets/javascripts/language/hu_HU.js +326 -0
- data/vendor/assets/javascripts/language/vi_VN.js +322 -0
- data/vendor/assets/javascripts/language/zh_CN.js +326 -0
- data/vendor/assets/javascripts/language/zh_TW.js +326 -0
- data/vendor/assets/javascripts/validator/base64.js +25 -0
- data/vendor/assets/javascripts/validator/between.js +66 -0
- data/vendor/assets/javascripts/validator/callback.js +40 -0
- data/vendor/assets/javascripts/validator/choice.js +68 -0
- data/vendor/assets/javascripts/validator/creditCard.js +103 -0
- data/vendor/assets/javascripts/validator/cusip.js +55 -0
- data/vendor/assets/javascripts/validator/cvv.js +116 -0
- data/vendor/assets/javascripts/validator/date.js +118 -0
- data/vendor/assets/javascripts/validator/different.js +41 -0
- data/vendor/assets/javascripts/validator/digits.js +24 -0
- data/vendor/assets/javascripts/validator/ean.js +40 -0
- data/vendor/assets/javascripts/validator/emailAddress.js +31 -0
- data/vendor/assets/javascripts/validator/file.js +69 -0
- data/vendor/assets/javascripts/validator/greaterThan.js +61 -0
- data/vendor/assets/javascripts/validator/grid.js +37 -0
- data/vendor/assets/javascripts/validator/hex.js +25 -0
- data/vendor/assets/javascripts/validator/hexColor.js +28 -0
- data/vendor/assets/javascripts/validator/iban.js +246 -0
- data/vendor/assets/javascripts/validator/id.js +815 -0
- data/vendor/assets/javascripts/validator/identical.js +40 -0
- data/vendor/assets/javascripts/validator/imei.js +44 -0
- data/vendor/assets/javascripts/validator/integer.js +28 -0
- data/vendor/assets/javascripts/validator/ip.js +48 -0
- data/vendor/assets/javascripts/validator/isbn.js +86 -0
- data/vendor/assets/javascripts/validator/isin.js +59 -0
- data/vendor/assets/javascripts/validator/ismn.js +59 -0
- data/vendor/assets/javascripts/validator/issn.js +46 -0
- data/vendor/assets/javascripts/validator/lessThan.js +61 -0
- data/vendor/assets/javascripts/validator/mac.js +25 -0
- data/vendor/assets/javascripts/validator/notEmpty.js +32 -0
- data/vendor/assets/javascripts/validator/numeric.js +39 -0
- data/vendor/assets/javascripts/validator/phone.js +84 -0
- data/vendor/assets/javascripts/validator/regexp.js +42 -0
- data/vendor/assets/javascripts/validator/remote.js +70 -0
- data/vendor/assets/javascripts/validator/rtn.js +38 -0
- data/vendor/assets/javascripts/validator/sedol.js +40 -0
- data/vendor/assets/javascripts/validator/siren.js +28 -0
- data/vendor/assets/javascripts/validator/siret.js +38 -0
- data/vendor/assets/javascripts/validator/step.js +64 -0
- data/vendor/assets/javascripts/validator/stringCase.js +36 -0
- data/vendor/assets/javascripts/validator/stringLength.js +81 -0
- data/vendor/assets/javascripts/validator/uri.js +101 -0
- data/vendor/assets/javascripts/validator/uuid.js +46 -0
- data/vendor/assets/javascripts/validator/vat.js +1220 -0
- data/vendor/assets/javascripts/validator/vin.js +49 -0
- data/vendor/assets/javascripts/validator/zipCode.js +162 -0
- data/vendor/assets/stylesheets/bootstrapValidator.css +21 -0
- metadata +233 -0
|
@@ -0,0 +1,1803 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BootstrapValidator (http://bootstrapvalidator.com)
|
|
3
|
+
* The best jQuery plugin to validate form fields. Designed to use with Bootstrap 3
|
|
4
|
+
*
|
|
5
|
+
* @author http://twitter.com/nghuuphuoc
|
|
6
|
+
* @copyright (c) 2013 - 2014 Nguyen Huu Phuoc
|
|
7
|
+
* @license MIT
|
|
8
|
+
*/
|
|
9
|
+
(function($) {
|
|
10
|
+
var BootstrapValidator = function(form, options) {
|
|
11
|
+
this.$form = $(form);
|
|
12
|
+
this.options = $.extend({}, $.fn.bootstrapValidator.DEFAULT_OPTIONS, options);
|
|
13
|
+
|
|
14
|
+
this.$invalidFields = $([]); // Array of invalid fields
|
|
15
|
+
this.$submitButton = null; // The submit button which is clicked to submit form
|
|
16
|
+
|
|
17
|
+
// Validating status
|
|
18
|
+
this.STATUS_NOT_VALIDATED = 'NOT_VALIDATED';
|
|
19
|
+
this.STATUS_VALIDATING = 'VALIDATING';
|
|
20
|
+
this.STATUS_INVALID = 'INVALID';
|
|
21
|
+
this.STATUS_VALID = 'VALID';
|
|
22
|
+
|
|
23
|
+
// Determine the event that is fired when user change the field value
|
|
24
|
+
// Most modern browsers supports input event except IE 7, 8.
|
|
25
|
+
// IE 9 supports input event but the event is still not fired if I press the backspace key.
|
|
26
|
+
// Get IE version
|
|
27
|
+
// https://gist.github.com/padolsey/527683/#comment-7595
|
|
28
|
+
var ieVersion = (function() {
|
|
29
|
+
var v = 3, div = document.createElement('div'), a = div.all || [];
|
|
30
|
+
while (div.innerHTML = '<!--[if gt IE '+(++v)+']><br><![endif]-->', a[0]) {}
|
|
31
|
+
return v > 4 ? v : !v;
|
|
32
|
+
}());
|
|
33
|
+
|
|
34
|
+
var el = document.createElement('div');
|
|
35
|
+
this._changeEvent = (ieVersion === 9 || !('oninput' in el)) ? 'keyup' : 'input';
|
|
36
|
+
|
|
37
|
+
// The flag to indicate that the form is ready to submit when a remote/callback validator returns
|
|
38
|
+
this._submitIfValid = null;
|
|
39
|
+
|
|
40
|
+
// Field elements
|
|
41
|
+
this._cacheFields = {};
|
|
42
|
+
|
|
43
|
+
this._init();
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
BootstrapValidator.prototype = {
|
|
47
|
+
constructor: BootstrapValidator,
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Init form
|
|
51
|
+
*/
|
|
52
|
+
_init: function() {
|
|
53
|
+
var that = this,
|
|
54
|
+
options = {
|
|
55
|
+
excluded: this.$form.attr('data-bv-excluded'),
|
|
56
|
+
trigger: this.$form.attr('data-bv-trigger'),
|
|
57
|
+
message: this.$form.attr('data-bv-message'),
|
|
58
|
+
container: this.$form.attr('data-bv-container'),
|
|
59
|
+
group: this.$form.attr('data-bv-group'),
|
|
60
|
+
submitButtons: this.$form.attr('data-bv-submitbuttons'),
|
|
61
|
+
threshold: this.$form.attr('data-bv-threshold'),
|
|
62
|
+
live: this.$form.attr('data-bv-live'),
|
|
63
|
+
onSuccess: this.$form.attr('data-bv-onsuccess'),
|
|
64
|
+
onError: this.$form.attr('data-bv-onerror'),
|
|
65
|
+
fields: {},
|
|
66
|
+
feedbackIcons: {
|
|
67
|
+
valid: this.$form.attr('data-bv-feedbackicons-valid'),
|
|
68
|
+
invalid: this.$form.attr('data-bv-feedbackicons-invalid'),
|
|
69
|
+
validating: this.$form.attr('data-bv-feedbackicons-validating')
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
this.$form
|
|
74
|
+
// Disable client side validation in HTML 5
|
|
75
|
+
.attr('novalidate', 'novalidate')
|
|
76
|
+
.addClass(this.options.elementClass)
|
|
77
|
+
// Disable the default submission first
|
|
78
|
+
.on('submit.bv', function(e) {
|
|
79
|
+
e.preventDefault();
|
|
80
|
+
that.validate();
|
|
81
|
+
})
|
|
82
|
+
.on('click.bv', this.options.submitButtons, function() {
|
|
83
|
+
that.$submitButton = $(this);
|
|
84
|
+
// The user just click the submit button
|
|
85
|
+
that._submitIfValid = true;
|
|
86
|
+
})
|
|
87
|
+
// Find all fields which have either "name" or "data-bv-field" attribute
|
|
88
|
+
.find('[name], [data-bv-field]')
|
|
89
|
+
.each(function() {
|
|
90
|
+
var $field = $(this),
|
|
91
|
+
field = $field.attr('name') || $field.attr('data-bv-field'),
|
|
92
|
+
opts = that._parseOptions($field);
|
|
93
|
+
if (opts) {
|
|
94
|
+
$field.attr('data-bv-field', field);
|
|
95
|
+
options.fields[field] = $.extend({}, opts, options.fields[field]);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
this.options = $.extend(true, this.options, options);
|
|
100
|
+
for (var field in this.options.fields) {
|
|
101
|
+
this._initField(field);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.$form.trigger($.Event('init.form.bv'), {
|
|
105
|
+
bv: this,
|
|
106
|
+
options: this.options
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Prepare the events
|
|
110
|
+
if (this.options.onSuccess) {
|
|
111
|
+
this.$form.on('success.form.bv', function(e) {
|
|
112
|
+
$.fn.bootstrapValidator.helpers.call(that.options.onSuccess, [e]);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
if (this.options.onError) {
|
|
116
|
+
this.$form.on('error.form.bv', function(e) {
|
|
117
|
+
$.fn.bootstrapValidator.helpers.call(that.options.onError, [e]);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Parse the validator options from HTML attributes
|
|
124
|
+
*
|
|
125
|
+
* @param {jQuery} $field The field element
|
|
126
|
+
* @returns {Object}
|
|
127
|
+
*/
|
|
128
|
+
_parseOptions: function($field) {
|
|
129
|
+
var field = $field.attr('name') || $field.attr('data-bv-field'),
|
|
130
|
+
validators = {},
|
|
131
|
+
validator,
|
|
132
|
+
v, // Validator name
|
|
133
|
+
enabled,
|
|
134
|
+
optionName,
|
|
135
|
+
optionValue,
|
|
136
|
+
html5AttrName,
|
|
137
|
+
html5AttrMap;
|
|
138
|
+
|
|
139
|
+
for (v in $.fn.bootstrapValidator.validators) {
|
|
140
|
+
validator = $.fn.bootstrapValidator.validators[v];
|
|
141
|
+
enabled = $field.attr('data-bv-' + v.toLowerCase()) + '';
|
|
142
|
+
html5AttrMap = ('function' === typeof validator.enableByHtml5) ? validator.enableByHtml5($field) : null;
|
|
143
|
+
|
|
144
|
+
if ((html5AttrMap && enabled !== 'false')
|
|
145
|
+
|| (html5AttrMap !== true && ('' === enabled || 'true' === enabled)))
|
|
146
|
+
{
|
|
147
|
+
// Try to parse the options via attributes
|
|
148
|
+
validator.html5Attributes = $.extend({}, { message: 'message', onerror: 'onError', onsuccess: 'onSuccess' }, validator.html5Attributes);
|
|
149
|
+
validators[v] = $.extend({}, html5AttrMap === true ? {} : html5AttrMap, validators[v]);
|
|
150
|
+
|
|
151
|
+
for (html5AttrName in validator.html5Attributes) {
|
|
152
|
+
optionName = validator.html5Attributes[html5AttrName];
|
|
153
|
+
optionValue = $field.attr('data-bv-' + v.toLowerCase() + '-' + html5AttrName);
|
|
154
|
+
if (optionValue) {
|
|
155
|
+
if ('true' === optionValue) {
|
|
156
|
+
optionValue = true;
|
|
157
|
+
} else if ('false' === optionValue) {
|
|
158
|
+
optionValue = false;
|
|
159
|
+
}
|
|
160
|
+
validators[v][optionName] = optionValue;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
var opts = {
|
|
167
|
+
excluded: $field.attr('data-bv-excluded'),
|
|
168
|
+
feedbackIcons: $field.attr('data-bv-feedbackicons'),
|
|
169
|
+
trigger: $field.attr('data-bv-trigger'),
|
|
170
|
+
message: $field.attr('data-bv-message'),
|
|
171
|
+
container: $field.attr('data-bv-container'),
|
|
172
|
+
group: $field.attr('data-bv-group'),
|
|
173
|
+
selector: $field.attr('data-bv-selector'),
|
|
174
|
+
threshold: $field.attr('data-bv-threshold'),
|
|
175
|
+
onStatus: $field.attr('data-bv-onstatus'),
|
|
176
|
+
onSuccess: $field.attr('data-bv-onsuccess'),
|
|
177
|
+
onError: $field.attr('data-bv-onerror'),
|
|
178
|
+
validators: validators
|
|
179
|
+
},
|
|
180
|
+
emptyOptions = $.isEmptyObject(opts), // Check if the field options are set using HTML attributes
|
|
181
|
+
emptyValidators = $.isEmptyObject(validators); // Check if the field validators are set using HTML attributes
|
|
182
|
+
|
|
183
|
+
if (!emptyValidators || (!emptyOptions && this.options.fields && this.options.fields[field])) {
|
|
184
|
+
opts.validators = validators;
|
|
185
|
+
return opts;
|
|
186
|
+
} else {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Init field
|
|
193
|
+
*
|
|
194
|
+
* @param {String|jQuery} field The field name or field element
|
|
195
|
+
*/
|
|
196
|
+
_initField: function(field) {
|
|
197
|
+
var fields = $([]);
|
|
198
|
+
switch (typeof field) {
|
|
199
|
+
case 'object':
|
|
200
|
+
fields = field;
|
|
201
|
+
field = field.attr('data-bv-field');
|
|
202
|
+
break;
|
|
203
|
+
case 'string':
|
|
204
|
+
fields = this.getFieldElements(field);
|
|
205
|
+
fields.attr('data-bv-field', field);
|
|
206
|
+
break;
|
|
207
|
+
default:
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (this.options.fields[field] === null || this.options.fields[field].validators === null) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// We don't need to validate non-existing fields
|
|
216
|
+
if (fields.length === 0) {
|
|
217
|
+
delete this.options.fields[field];
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
var validatorName;
|
|
221
|
+
for (validatorName in this.options.fields[field].validators) {
|
|
222
|
+
if (!$.fn.bootstrapValidator.validators[validatorName]) {
|
|
223
|
+
delete this.options.fields[field].validators[validatorName];
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (this.options.fields[field].enabled === null) {
|
|
227
|
+
this.options.fields[field].enabled = true;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
var that = this,
|
|
231
|
+
total = fields.length,
|
|
232
|
+
type = fields.attr('type'),
|
|
233
|
+
updateAll = (total === 1) || ('radio' === type) || ('checkbox' === type),
|
|
234
|
+
event = ('radio' === type || 'checkbox' === type || 'file' === type || 'SELECT' === fields.eq(0).get(0).tagName) ? 'change' : this._changeEvent,
|
|
235
|
+
trigger = (this.options.fields[field].trigger || this.options.trigger || event).split(' '),
|
|
236
|
+
events = $.map(trigger, function(item) {
|
|
237
|
+
return item + '.update.bv';
|
|
238
|
+
}).join(' ');
|
|
239
|
+
|
|
240
|
+
for (var i = 0; i < total; i++) {
|
|
241
|
+
var $field = fields.eq(i),
|
|
242
|
+
group = this.options.fields[field].group || this.options.group,
|
|
243
|
+
$parent = $field.parents(group),
|
|
244
|
+
// Allow user to indicate where the error messages are shown
|
|
245
|
+
container = this.options.fields[field].container || this.options.container,
|
|
246
|
+
$message = (container && container !== 'tooltip' && container !== 'popover') ? $(container) : this._getMessageContainer($field, group);
|
|
247
|
+
|
|
248
|
+
if (container && container !== 'tooltip' && container !== 'popover') {
|
|
249
|
+
$message.addClass('has-error');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Remove all error messages and feedback icons
|
|
253
|
+
$message.find('.help-block[data-bv-validator][data-bv-for="' + field + '"]').remove();
|
|
254
|
+
$parent.find('i[data-bv-icon-for="' + field + '"]').remove();
|
|
255
|
+
|
|
256
|
+
// Whenever the user change the field value, mark it as not validated yet
|
|
257
|
+
$field.off(events).on(events, function() {
|
|
258
|
+
that.updateStatus($(this), that.STATUS_NOT_VALIDATED);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Create help block elements for showing the error messages
|
|
262
|
+
$field.data('bv.messages', $message);
|
|
263
|
+
for (validatorName in this.options.fields[field].validators) {
|
|
264
|
+
$field.data('bv.result.' + validatorName, this.STATUS_NOT_VALIDATED);
|
|
265
|
+
|
|
266
|
+
if (!updateAll || i === total - 1) {
|
|
267
|
+
$('<small/>')
|
|
268
|
+
.css('display', 'none')
|
|
269
|
+
.addClass('help-block')
|
|
270
|
+
.attr('data-bv-validator', validatorName)
|
|
271
|
+
.attr('data-bv-for', field)
|
|
272
|
+
.attr('data-bv-result', this.STATUS_NOT_VALIDATED)
|
|
273
|
+
.html(this._getMessage(field, validatorName))
|
|
274
|
+
.appendTo($message);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Prepare the validator events
|
|
278
|
+
if (this.options.fields[field].validators[validatorName].onSuccess) {
|
|
279
|
+
$field.on('success.validator.bv', function(e, data) {
|
|
280
|
+
$.fn.bootstrapValidator.helpers.call(that.options.fields[field].validators[validatorName].onSuccess, [e, data]);
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
if (this.options.fields[field].validators[validatorName].onError) {
|
|
284
|
+
$field.on('error.validator.bv', function(e, data) {
|
|
285
|
+
$.fn.bootstrapValidator.helpers.call(that.options.fields[field].validators[validatorName].onError, [e, data]);
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Prepare the feedback icons
|
|
291
|
+
// Available from Bootstrap 3.1 (http://getbootstrap.com/css/#forms-control-validation)
|
|
292
|
+
if (this.options.fields[field].feedbackIcons !== false && this.options.fields[field].feedbackIcons !== 'false'
|
|
293
|
+
&& this.options.feedbackIcons
|
|
294
|
+
&& this.options.feedbackIcons.validating && this.options.feedbackIcons.invalid && this.options.feedbackIcons.valid
|
|
295
|
+
&& (!updateAll || i === total - 1))
|
|
296
|
+
{
|
|
297
|
+
$parent.removeClass('has-success').removeClass('has-error').addClass('has-feedback');
|
|
298
|
+
var $icon = $('<i/>')
|
|
299
|
+
.css('display', 'none')
|
|
300
|
+
.addClass('form-control-feedback')
|
|
301
|
+
.attr('data-bv-icon-for', field)
|
|
302
|
+
// Place it after the label containing the checkbox/radio
|
|
303
|
+
// so when clicking the icon, it doesn't effect to the checkbox/radio element
|
|
304
|
+
.insertAfter(('checkbox' === type || 'radio' === type) ? $field.parent() : $field);
|
|
305
|
+
|
|
306
|
+
// The feedback icon does not render correctly if there is no label
|
|
307
|
+
// https://github.com/twbs/bootstrap/issues/12873
|
|
308
|
+
if ($parent.find('label').length === 0) {
|
|
309
|
+
$icon.css('top', 0);
|
|
310
|
+
}
|
|
311
|
+
// Fix feedback icons in input-group
|
|
312
|
+
if ($parent.find('.input-group').length !== 0) {
|
|
313
|
+
$icon.css({
|
|
314
|
+
'top': 0,
|
|
315
|
+
'z-index': 100
|
|
316
|
+
}).insertAfter($parent.find('.input-group').eq(0));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Prepare the events
|
|
322
|
+
if (this.options.fields[field].onSuccess) {
|
|
323
|
+
fields.on('success.field.bv', function(e, data) {
|
|
324
|
+
$.fn.bootstrapValidator.helpers.call(that.options.fields[field].onSuccess, [e, data]);
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
if (this.options.fields[field].onError) {
|
|
328
|
+
fields.on('error.field.bv', function(e, data) {
|
|
329
|
+
$.fn.bootstrapValidator.helpers.call(that.options.fields[field].onError, [e, data]);
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
if (this.options.fields[field].onStatus) {
|
|
333
|
+
fields.on('status.field.bv', function(e, data) {
|
|
334
|
+
$.fn.bootstrapValidator.helpers.call(that.options.fields[field].onStatus, [e, data]);
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Set live mode
|
|
339
|
+
events = $.map(trigger, function(item) {
|
|
340
|
+
return item + '.live.bv';
|
|
341
|
+
}).join(' ');
|
|
342
|
+
switch (this.options.live) {
|
|
343
|
+
case 'submitted':
|
|
344
|
+
break;
|
|
345
|
+
case 'disabled':
|
|
346
|
+
fields.off(events);
|
|
347
|
+
break;
|
|
348
|
+
case 'enabled':
|
|
349
|
+
/* falls through */
|
|
350
|
+
default:
|
|
351
|
+
fields.off(events).on(events, function() {
|
|
352
|
+
if (that._exceedThreshold($(this))) {
|
|
353
|
+
that.validateField($(this));
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
fields.trigger($.Event('init.field.bv'), {
|
|
360
|
+
bv: this,
|
|
361
|
+
field: field,
|
|
362
|
+
element: fields
|
|
363
|
+
});
|
|
364
|
+
},
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Get the error message for given field and validator
|
|
368
|
+
*
|
|
369
|
+
* @param {String} field The field name
|
|
370
|
+
* @param {String} validatorName The validator name
|
|
371
|
+
* @returns {String}
|
|
372
|
+
*/
|
|
373
|
+
_getMessage: function(field, validatorName) {
|
|
374
|
+
if (!this.options.fields[field] || !$.fn.bootstrapValidator.validators[validatorName]
|
|
375
|
+
|| !this.options.fields[field].validators || !this.options.fields[field].validators[validatorName])
|
|
376
|
+
{
|
|
377
|
+
return '';
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
var options = this.options.fields[field].validators[validatorName];
|
|
381
|
+
switch (true) {
|
|
382
|
+
case (!!options.message):
|
|
383
|
+
return options.message;
|
|
384
|
+
case (!!this.options.fields[field].message):
|
|
385
|
+
return this.options.fields[field].message;
|
|
386
|
+
case (!!$.fn.bootstrapValidator.i18n[validatorName]):
|
|
387
|
+
return $.fn.bootstrapValidator.i18n[validatorName]['default'];
|
|
388
|
+
default:
|
|
389
|
+
return this.options.message;
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Get the element to place the error messages
|
|
395
|
+
*
|
|
396
|
+
* @param {jQuery} $field The field element
|
|
397
|
+
* @param {String} group
|
|
398
|
+
* @returns {jQuery}
|
|
399
|
+
*/
|
|
400
|
+
_getMessageContainer: function($field, group) {
|
|
401
|
+
var $parent = $field.parent();
|
|
402
|
+
if ($parent.is(group)) {
|
|
403
|
+
return $parent;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
var cssClasses = $parent.attr('class');
|
|
407
|
+
if (!cssClasses) {
|
|
408
|
+
return this._getMessageContainer($parent, group);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
cssClasses = cssClasses.split(' ');
|
|
412
|
+
var n = cssClasses.length;
|
|
413
|
+
for (var i = 0; i < n; i++) {
|
|
414
|
+
if (/^col-(xs|sm|md|lg)-\d+$/.test(cssClasses[i]) || /^col-(xs|sm|md|lg)-offset-\d+$/.test(cssClasses[i])) {
|
|
415
|
+
return $parent;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return this._getMessageContainer($parent, group);
|
|
420
|
+
},
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Called when all validations are completed
|
|
424
|
+
*/
|
|
425
|
+
_submit: function() {
|
|
426
|
+
var isValid = this.isValid(),
|
|
427
|
+
eventType = isValid ? 'success.form.bv' : 'error.form.bv',
|
|
428
|
+
e = $.Event(eventType);
|
|
429
|
+
|
|
430
|
+
this.$form.trigger(e);
|
|
431
|
+
|
|
432
|
+
// Call default handler
|
|
433
|
+
// Check if whether the submit button is clicked
|
|
434
|
+
if (this.$submitButton) {
|
|
435
|
+
isValid ? this._onSuccess(e) : this._onError(e);
|
|
436
|
+
}
|
|
437
|
+
},
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Check if the field is excluded.
|
|
441
|
+
* Returning true means that the field will not be validated
|
|
442
|
+
*
|
|
443
|
+
* @param {jQuery} $field The field element
|
|
444
|
+
* @returns {Boolean}
|
|
445
|
+
*/
|
|
446
|
+
_isExcluded: function($field) {
|
|
447
|
+
var excludedAttr = $field.attr('data-bv-excluded'),
|
|
448
|
+
// I still need to check the 'name' attribute while initializing the field
|
|
449
|
+
field = $field.attr('data-bv-field') || $field.attr('name');
|
|
450
|
+
|
|
451
|
+
switch (true) {
|
|
452
|
+
case (!!field && this.options.fields && this.options.fields[field] && (this.options.fields[field].excluded === 'true' || this.options.fields[field].excluded === true)):
|
|
453
|
+
case (excludedAttr === 'true'):
|
|
454
|
+
case (excludedAttr === ''):
|
|
455
|
+
return true;
|
|
456
|
+
|
|
457
|
+
case (!!field && this.options.fields && this.options.fields[field] && (this.options.fields[field].excluded === 'false' || this.options.fields[field].excluded === false)):
|
|
458
|
+
case (excludedAttr === 'false'):
|
|
459
|
+
return false;
|
|
460
|
+
|
|
461
|
+
default:
|
|
462
|
+
if (this.options.excluded) {
|
|
463
|
+
// Convert to array first
|
|
464
|
+
if ('string' === typeof this.options.excluded) {
|
|
465
|
+
this.options.excluded = $.map(this.options.excluded.split(','), function(item) {
|
|
466
|
+
// Trim the spaces
|
|
467
|
+
return $.trim(item);
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
var length = this.options.excluded.length;
|
|
472
|
+
for (var i = 0; i < length; i++) {
|
|
473
|
+
if (('string' === typeof this.options.excluded[i] && $field.is(this.options.excluded[i]))
|
|
474
|
+
|| ('function' === typeof this.options.excluded[i] && this.options.excluded[i].call(this, $field, this) === true))
|
|
475
|
+
{
|
|
476
|
+
return true;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
},
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Check if the number of characters of field value exceed the threshold or not
|
|
486
|
+
*
|
|
487
|
+
* @param {jQuery} $field The field element
|
|
488
|
+
* @returns {Boolean}
|
|
489
|
+
*/
|
|
490
|
+
_exceedThreshold: function($field) {
|
|
491
|
+
var field = $field.attr('data-bv-field'),
|
|
492
|
+
threshold = this.options.fields[field].threshold || this.options.threshold;
|
|
493
|
+
if (!threshold) {
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
496
|
+
var cannotType = $.inArray($field.attr('type'), ['button', 'checkbox', 'file', 'hidden', 'image', 'radio', 'reset', 'submit']) !== -1;
|
|
497
|
+
return (cannotType || $field.val().length >= threshold);
|
|
498
|
+
},
|
|
499
|
+
|
|
500
|
+
// ---
|
|
501
|
+
// Events
|
|
502
|
+
// ---
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* The default handler of error.form.bv event.
|
|
506
|
+
* It will be called when there is a invalid field
|
|
507
|
+
*
|
|
508
|
+
* @param {jQuery.Event} e The jQuery event object
|
|
509
|
+
*/
|
|
510
|
+
_onError: function(e) {
|
|
511
|
+
if (e.isDefaultPrevented()) {
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if ('submitted' === this.options.live) {
|
|
516
|
+
// Enable live mode
|
|
517
|
+
this.options.live = 'enabled';
|
|
518
|
+
var that = this;
|
|
519
|
+
for (var field in this.options.fields) {
|
|
520
|
+
(function(f) {
|
|
521
|
+
var fields = that.getFieldElements(f);
|
|
522
|
+
if (fields.length) {
|
|
523
|
+
var type = $(fields[0]).attr('type'),
|
|
524
|
+
event = ('radio' === type || 'checkbox' === type || 'file' === type || 'SELECT' === $(fields[0]).get(0).tagName) ? 'change' : that._changeEvent,
|
|
525
|
+
trigger = that.options.fields[field].trigger || that.options.trigger || event,
|
|
526
|
+
events = $.map(trigger.split(' '), function(item) {
|
|
527
|
+
return item + '.live.bv';
|
|
528
|
+
}).join(' ');
|
|
529
|
+
|
|
530
|
+
fields.off(events).on(events, function() {
|
|
531
|
+
if (that._exceedThreshold($(this))) {
|
|
532
|
+
that.validateField($(this));
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
})(field);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
var $invalidField = this.$invalidFields.eq(0);
|
|
541
|
+
if ($invalidField) {
|
|
542
|
+
// Activate the tab containing the invalid field if exists
|
|
543
|
+
var $tabPane = $invalidField.parents('.tab-pane'), tabId;
|
|
544
|
+
if ($tabPane && (tabId = $tabPane.attr('id'))) {
|
|
545
|
+
$('a[href="#' + tabId + '"][data-toggle="tab"]').tab('show');
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// Focus to the first invalid field
|
|
549
|
+
$invalidField.focus();
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* The default handler of success.form.bv event.
|
|
555
|
+
* It will be called when all the fields are valid
|
|
556
|
+
*
|
|
557
|
+
* @param {jQuery.Event} e The jQuery event object
|
|
558
|
+
*/
|
|
559
|
+
_onSuccess: function(e) {
|
|
560
|
+
if (e.isDefaultPrevented()) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// Submit the form
|
|
565
|
+
this.disableSubmitButtons(true).defaultSubmit();
|
|
566
|
+
},
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Called after validating a field element
|
|
570
|
+
*
|
|
571
|
+
* @param {jQuery} $field The field element
|
|
572
|
+
* @param {String} [validatorName] The validator name
|
|
573
|
+
*/
|
|
574
|
+
_onFieldValidated: function($field, validatorName) {
|
|
575
|
+
var field = $field.attr('data-bv-field'),
|
|
576
|
+
validators = this.options.fields[field].validators,
|
|
577
|
+
counter = {},
|
|
578
|
+
numValidators = 0,
|
|
579
|
+
data = {
|
|
580
|
+
bv: this,
|
|
581
|
+
field: field,
|
|
582
|
+
element: $field,
|
|
583
|
+
validator: validatorName
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
// Trigger an event after given validator completes
|
|
587
|
+
if (validatorName) {
|
|
588
|
+
switch ($field.data('bv.result.' + validatorName)) {
|
|
589
|
+
case this.STATUS_INVALID:
|
|
590
|
+
$field.trigger($.Event('error.validator.bv'), data);
|
|
591
|
+
break;
|
|
592
|
+
case this.STATUS_VALID:
|
|
593
|
+
$field.trigger($.Event('success.validator.bv'), data);
|
|
594
|
+
break;
|
|
595
|
+
default:
|
|
596
|
+
break;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
counter[this.STATUS_NOT_VALIDATED] = 0;
|
|
601
|
+
counter[this.STATUS_VALIDATING] = 0;
|
|
602
|
+
counter[this.STATUS_INVALID] = 0;
|
|
603
|
+
counter[this.STATUS_VALID] = 0;
|
|
604
|
+
|
|
605
|
+
for (var v in validators) {
|
|
606
|
+
if (validators[v].enabled === false) {
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
numValidators++;
|
|
611
|
+
var result = $field.data('bv.result.' + v);
|
|
612
|
+
if (result) {
|
|
613
|
+
counter[result]++;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
if (counter[this.STATUS_VALID] === numValidators) {
|
|
618
|
+
// Remove from the list of invalid fields
|
|
619
|
+
this.$invalidFields = this.$invalidFields.not($field);
|
|
620
|
+
|
|
621
|
+
$field.trigger($.Event('success.field.bv'), data);
|
|
622
|
+
}
|
|
623
|
+
// If all validators are completed and there is at least one validator which doesn't pass
|
|
624
|
+
else if (counter[this.STATUS_NOT_VALIDATED] === 0 && counter[this.STATUS_VALIDATING] === 0 && counter[this.STATUS_INVALID] > 0) {
|
|
625
|
+
// Add to the list of invalid fields
|
|
626
|
+
this.$invalidFields = this.$invalidFields.add($field);
|
|
627
|
+
|
|
628
|
+
$field.trigger($.Event('error.field.bv'), data);
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
|
|
632
|
+
// ---
|
|
633
|
+
// Public methods
|
|
634
|
+
// ---
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Retrieve the field elements by given name
|
|
638
|
+
*
|
|
639
|
+
* @param {String} field The field name
|
|
640
|
+
* @returns {null|jQuery[]}
|
|
641
|
+
*/
|
|
642
|
+
getFieldElements: function(field) {
|
|
643
|
+
if (!this._cacheFields[field]) {
|
|
644
|
+
this._cacheFields[field] = (this.options.fields[field] && this.options.fields[field].selector)
|
|
645
|
+
? $(this.options.fields[field].selector)
|
|
646
|
+
: this.$form.find('[name="' + field + '"]');
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
return this._cacheFields[field];
|
|
650
|
+
},
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Disable/enable submit buttons
|
|
654
|
+
*
|
|
655
|
+
* @param {Boolean} disabled Can be true or false
|
|
656
|
+
* @returns {BootstrapValidator}
|
|
657
|
+
*/
|
|
658
|
+
disableSubmitButtons: function(disabled) {
|
|
659
|
+
if (!disabled) {
|
|
660
|
+
this.$form.find(this.options.submitButtons).removeAttr('disabled');
|
|
661
|
+
} else if (this.options.live !== 'disabled') {
|
|
662
|
+
// Don't disable if the live validating mode is disabled
|
|
663
|
+
this.$form.find(this.options.submitButtons).attr('disabled', 'disabled');
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
return this;
|
|
667
|
+
},
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Validate the form
|
|
671
|
+
*
|
|
672
|
+
* @returns {BootstrapValidator}
|
|
673
|
+
*/
|
|
674
|
+
validate: function() {
|
|
675
|
+
if (!this.options.fields) {
|
|
676
|
+
return this;
|
|
677
|
+
}
|
|
678
|
+
this.disableSubmitButtons(true);
|
|
679
|
+
|
|
680
|
+
for (var field in this.options.fields) {
|
|
681
|
+
this.validateField(field);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
this._submit();
|
|
685
|
+
|
|
686
|
+
return this;
|
|
687
|
+
},
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* Validate given field
|
|
691
|
+
*
|
|
692
|
+
* @param {String|jQuery} field The field name or field element
|
|
693
|
+
* @returns {BootstrapValidator}
|
|
694
|
+
*/
|
|
695
|
+
validateField: function(field) {
|
|
696
|
+
var fields = $([]);
|
|
697
|
+
switch (typeof field) {
|
|
698
|
+
case 'object':
|
|
699
|
+
fields = field;
|
|
700
|
+
field = field.attr('data-bv-field');
|
|
701
|
+
break;
|
|
702
|
+
case 'string':
|
|
703
|
+
fields = this.getFieldElements(field);
|
|
704
|
+
break;
|
|
705
|
+
default:
|
|
706
|
+
break;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
if (this.options.fields[field] && this.options.fields[field].enabled === false) {
|
|
710
|
+
return this;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
var that = this,
|
|
714
|
+
type = fields.attr('type'),
|
|
715
|
+
total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length,
|
|
716
|
+
updateAll = ('radio' === type || 'checkbox' === type),
|
|
717
|
+
validators = this.options.fields[field].validators,
|
|
718
|
+
validatorName,
|
|
719
|
+
validateResult;
|
|
720
|
+
|
|
721
|
+
for (var i = 0; i < total; i++) {
|
|
722
|
+
var $field = fields.eq(i);
|
|
723
|
+
if (this._isExcluded($field)) {
|
|
724
|
+
continue;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
for (validatorName in validators) {
|
|
728
|
+
if ($field.data('bv.dfs.' + validatorName)) {
|
|
729
|
+
$field.data('bv.dfs.' + validatorName).reject();
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// Don't validate field if it is already done
|
|
733
|
+
var result = $field.data('bv.result.' + validatorName);
|
|
734
|
+
if (result === this.STATUS_VALID || result === this.STATUS_INVALID || validators[validatorName].enabled === false) {
|
|
735
|
+
this._onFieldValidated($field, validatorName);
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
$field.data('bv.result.' + validatorName, this.STATUS_VALIDATING);
|
|
740
|
+
validateResult = $.fn.bootstrapValidator.validators[validatorName].validate(this, $field, validators[validatorName]);
|
|
741
|
+
|
|
742
|
+
// validateResult can be a $.Deferred object ...
|
|
743
|
+
if ('object' === typeof validateResult && validateResult.resolve) {
|
|
744
|
+
this.updateStatus(updateAll ? field : $field, this.STATUS_VALIDATING, validatorName);
|
|
745
|
+
$field.data('bv.dfs.' + validatorName, validateResult);
|
|
746
|
+
|
|
747
|
+
validateResult.done(function($f, v, isValid, message) {
|
|
748
|
+
// v is validator name
|
|
749
|
+
$f.removeData('bv.dfs.' + v);
|
|
750
|
+
if (message) {
|
|
751
|
+
that.updateMessage($f, v, message);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
that.updateStatus(updateAll ? $f.attr('data-bv-field') : $f, isValid ? that.STATUS_VALID : that.STATUS_INVALID, v);
|
|
755
|
+
|
|
756
|
+
if (isValid && that._submitIfValid === true) {
|
|
757
|
+
// If a remote validator returns true and the form is ready to submit, then do it
|
|
758
|
+
that._submit();
|
|
759
|
+
}
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
// ... or object { valid: true/false, message: 'dynamic message' }
|
|
763
|
+
else if ('object' === typeof validateResult && validateResult.valid !== undefined && validateResult.message !== undefined) {
|
|
764
|
+
this.updateMessage(updateAll ? field : $field, validatorName, validateResult.message);
|
|
765
|
+
this.updateStatus(updateAll ? field : $field, validateResult.valid ? this.STATUS_VALID : this.STATUS_INVALID, validatorName);
|
|
766
|
+
}
|
|
767
|
+
// ... or a boolean value
|
|
768
|
+
else if ('boolean' === typeof validateResult) {
|
|
769
|
+
this.updateStatus(updateAll ? field : $field, validateResult ? this.STATUS_VALID : this.STATUS_INVALID, validatorName);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
return this;
|
|
775
|
+
},
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* Update the error message
|
|
779
|
+
*
|
|
780
|
+
* @param {String|jQuery} field The field name or field element
|
|
781
|
+
* @param {String} validator The validator name
|
|
782
|
+
* @param {String} message The message
|
|
783
|
+
* @returns {BootstrapValidator}
|
|
784
|
+
*/
|
|
785
|
+
updateMessage: function(field, validator, message) {
|
|
786
|
+
var $fields = $([]);
|
|
787
|
+
switch (typeof field) {
|
|
788
|
+
case 'object':
|
|
789
|
+
$fields = field;
|
|
790
|
+
field = field.attr('data-bv-field');
|
|
791
|
+
break;
|
|
792
|
+
case 'string':
|
|
793
|
+
$fields = this.getFieldElements(field);
|
|
794
|
+
break;
|
|
795
|
+
default:
|
|
796
|
+
break;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
$fields.each(function() {
|
|
800
|
+
$(this).data('bv.messages').find('.help-block[data-bv-validator="' + validator + '"][data-bv-for="' + field + '"]').html(message);
|
|
801
|
+
});
|
|
802
|
+
},
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* Update all validating results of field
|
|
806
|
+
*
|
|
807
|
+
* @param {String|jQuery} field The field name or field element
|
|
808
|
+
* @param {String} status The status. Can be 'NOT_VALIDATED', 'VALIDATING', 'INVALID' or 'VALID'
|
|
809
|
+
* @param {String} [validatorName] The validator name. If null, the method updates validity result for all validators
|
|
810
|
+
* @returns {BootstrapValidator}
|
|
811
|
+
*/
|
|
812
|
+
updateStatus: function(field, status, validatorName) {
|
|
813
|
+
var fields = $([]);
|
|
814
|
+
switch (typeof field) {
|
|
815
|
+
case 'object':
|
|
816
|
+
fields = field;
|
|
817
|
+
field = field.attr('data-bv-field');
|
|
818
|
+
break;
|
|
819
|
+
case 'string':
|
|
820
|
+
fields = this.getFieldElements(field);
|
|
821
|
+
break;
|
|
822
|
+
default:
|
|
823
|
+
break;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
if (status === this.STATUS_NOT_VALIDATED) {
|
|
827
|
+
// Reset the flag
|
|
828
|
+
this._submitIfValid = false;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
var that = this,
|
|
832
|
+
type = fields.attr('type'),
|
|
833
|
+
group = this.options.fields[field].group || this.options.group,
|
|
834
|
+
total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length;
|
|
835
|
+
|
|
836
|
+
for (var i = 0; i < total; i++) {
|
|
837
|
+
var $field = fields.eq(i);
|
|
838
|
+
if (this._isExcluded($field)) {
|
|
839
|
+
continue;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
var $parent = $field.parents(group),
|
|
843
|
+
$message = $field.data('bv.messages'),
|
|
844
|
+
$allErrors = $message.find('.help-block[data-bv-validator][data-bv-for="' + field + '"]'),
|
|
845
|
+
$errors = validatorName ? $allErrors.filter('[data-bv-validator="' + validatorName + '"]') : $allErrors,
|
|
846
|
+
$icon = $parent.find('.form-control-feedback[data-bv-icon-for="' + field + '"]'),
|
|
847
|
+
container = this.options.fields[field].container || this.options.container,
|
|
848
|
+
isValidField = null;
|
|
849
|
+
|
|
850
|
+
// Update status
|
|
851
|
+
if (validatorName) {
|
|
852
|
+
$field.data('bv.result.' + validatorName, status);
|
|
853
|
+
} else {
|
|
854
|
+
for (var v in this.options.fields[field].validators) {
|
|
855
|
+
$field.data('bv.result.' + v, status);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
// Show/hide error elements and feedback icons
|
|
860
|
+
$errors.attr('data-bv-result', status);
|
|
861
|
+
|
|
862
|
+
// Determine the tab containing the element
|
|
863
|
+
var $tabPane = $field.parents('.tab-pane'),
|
|
864
|
+
tabId, $tab;
|
|
865
|
+
if ($tabPane && (tabId = $tabPane.attr('id'))) {
|
|
866
|
+
$tab = $('a[href="#' + tabId + '"][data-toggle="tab"]').parent();
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
switch (status) {
|
|
870
|
+
case this.STATUS_VALIDATING:
|
|
871
|
+
isValidField = null;
|
|
872
|
+
this.disableSubmitButtons(true);
|
|
873
|
+
$parent.removeClass('has-success').removeClass('has-error');
|
|
874
|
+
if ($icon) {
|
|
875
|
+
$icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.invalid).addClass(this.options.feedbackIcons.validating).show();
|
|
876
|
+
}
|
|
877
|
+
if ($tab) {
|
|
878
|
+
$tab.removeClass('bv-tab-success').removeClass('bv-tab-error');
|
|
879
|
+
}
|
|
880
|
+
break;
|
|
881
|
+
|
|
882
|
+
case this.STATUS_INVALID:
|
|
883
|
+
isValidField = false;
|
|
884
|
+
this.disableSubmitButtons(true);
|
|
885
|
+
$parent.removeClass('has-success').addClass('has-error');
|
|
886
|
+
if ($icon) {
|
|
887
|
+
$icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.validating).addClass(this.options.feedbackIcons.invalid).show();
|
|
888
|
+
}
|
|
889
|
+
if ($tab) {
|
|
890
|
+
$tab.removeClass('bv-tab-success').addClass('bv-tab-error');
|
|
891
|
+
}
|
|
892
|
+
break;
|
|
893
|
+
|
|
894
|
+
case this.STATUS_VALID:
|
|
895
|
+
// If the field is valid (passes all validators)
|
|
896
|
+
isValidField = ($allErrors.filter('[data-bv-result="' + this.STATUS_NOT_VALIDATED +'"]').length === 0)
|
|
897
|
+
? ($allErrors.filter('[data-bv-result="' + this.STATUS_VALID +'"]').length === $allErrors.length) // All validators are completed
|
|
898
|
+
: null; // There are some validators that have not done
|
|
899
|
+
if (isValidField !== null) {
|
|
900
|
+
this.disableSubmitButtons(this.$submitButton ? !this.isValid() : !isValidField);
|
|
901
|
+
if ($icon) {
|
|
902
|
+
$icon
|
|
903
|
+
.removeClass(this.options.feedbackIcons.invalid).removeClass(this.options.feedbackIcons.validating).removeClass(this.options.feedbackIcons.valid)
|
|
904
|
+
.addClass(isValidField ? this.options.feedbackIcons.valid : this.options.feedbackIcons.invalid)
|
|
905
|
+
.show();
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
$parent.removeClass('has-error has-success').addClass(this.isValidContainer($parent) ? 'has-success' : 'has-error');
|
|
910
|
+
if ($tab) {
|
|
911
|
+
$tab.removeClass('bv-tab-success').removeClass('bv-tab-error').addClass(this.isValidContainer($tabPane) ? 'bv-tab-success' : 'bv-tab-error');
|
|
912
|
+
}
|
|
913
|
+
break;
|
|
914
|
+
|
|
915
|
+
case this.STATUS_NOT_VALIDATED:
|
|
916
|
+
/* falls through */
|
|
917
|
+
default:
|
|
918
|
+
isValidField = null;
|
|
919
|
+
this.disableSubmitButtons(false);
|
|
920
|
+
$parent.removeClass('has-success').removeClass('has-error');
|
|
921
|
+
if ($icon) {
|
|
922
|
+
$icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.invalid).removeClass(this.options.feedbackIcons.validating).hide();
|
|
923
|
+
}
|
|
924
|
+
if ($tab) {
|
|
925
|
+
$tab.removeClass('bv-tab-success').removeClass('bv-tab-error');
|
|
926
|
+
}
|
|
927
|
+
break;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
switch (true) {
|
|
931
|
+
// Only show the first error message if it is placed inside a tooltip ...
|
|
932
|
+
case ($icon && 'tooltip' === container):
|
|
933
|
+
(isValidField === false)
|
|
934
|
+
? $icon.css('cursor', 'pointer').tooltip('destroy').tooltip({
|
|
935
|
+
html: true,
|
|
936
|
+
placement: 'top',
|
|
937
|
+
title: $allErrors.filter('[data-bv-result="' + that.STATUS_INVALID + '"]').eq(0).html()
|
|
938
|
+
})
|
|
939
|
+
: $icon.css('cursor', '').tooltip('destroy');
|
|
940
|
+
break;
|
|
941
|
+
// ... or popover
|
|
942
|
+
case ($icon && 'popover' === container):
|
|
943
|
+
(isValidField === false)
|
|
944
|
+
? $icon.css('cursor', 'pointer').popover('destroy').popover({
|
|
945
|
+
content: $allErrors.filter('[data-bv-result="' + that.STATUS_INVALID + '"]').eq(0).html(),
|
|
946
|
+
html: true,
|
|
947
|
+
placement: 'top',
|
|
948
|
+
trigger: 'hover click'
|
|
949
|
+
})
|
|
950
|
+
: $icon.css('cursor', '').popover('destroy');
|
|
951
|
+
break;
|
|
952
|
+
default:
|
|
953
|
+
(status === this.STATUS_INVALID) ? $errors.show() : $errors.hide();
|
|
954
|
+
break;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// Trigger an event
|
|
958
|
+
$field.trigger($.Event('status.field.bv'), {
|
|
959
|
+
bv: this,
|
|
960
|
+
field: field,
|
|
961
|
+
element: $field,
|
|
962
|
+
status: status
|
|
963
|
+
});
|
|
964
|
+
this._onFieldValidated($field, validatorName);
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
return this;
|
|
968
|
+
},
|
|
969
|
+
|
|
970
|
+
/**
|
|
971
|
+
* Check the form validity
|
|
972
|
+
*
|
|
973
|
+
* @returns {Boolean}
|
|
974
|
+
*/
|
|
975
|
+
isValid: function() {
|
|
976
|
+
for (var field in this.options.fields) {
|
|
977
|
+
if (!this.isValidField(field)) {
|
|
978
|
+
return false;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
return true;
|
|
983
|
+
},
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* Check if the field is valid or not
|
|
987
|
+
*
|
|
988
|
+
* @param {String|jQuery} field The field name or field element
|
|
989
|
+
* @returns {Boolean}
|
|
990
|
+
*/
|
|
991
|
+
isValidField: function(field) {
|
|
992
|
+
var fields = $([]);
|
|
993
|
+
switch (typeof field) {
|
|
994
|
+
case 'object':
|
|
995
|
+
fields = field;
|
|
996
|
+
field = field.attr('data-bv-field');
|
|
997
|
+
break;
|
|
998
|
+
case 'string':
|
|
999
|
+
fields = this.getFieldElements(field);
|
|
1000
|
+
break;
|
|
1001
|
+
default:
|
|
1002
|
+
break;
|
|
1003
|
+
}
|
|
1004
|
+
if (fields.length === 0 || this.options.fields[field] === null || this.options.fields[field].enabled === false) {
|
|
1005
|
+
return true;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
var type = fields.attr('type'),
|
|
1009
|
+
total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length,
|
|
1010
|
+
$field, validatorName, status;
|
|
1011
|
+
for (var i = 0; i < total; i++) {
|
|
1012
|
+
$field = fields.eq(i);
|
|
1013
|
+
if (this._isExcluded($field)) {
|
|
1014
|
+
continue;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
for (validatorName in this.options.fields[field].validators) {
|
|
1018
|
+
if (this.options.fields[field].validators[validatorName].enabled === false) {
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
status = $field.data('bv.result.' + validatorName);
|
|
1023
|
+
if (status !== this.STATUS_VALID) {
|
|
1024
|
+
return false;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
return true;
|
|
1030
|
+
},
|
|
1031
|
+
|
|
1032
|
+
/**
|
|
1033
|
+
* Check if all fields inside a given container are valid.
|
|
1034
|
+
* It's useful when working with a wizard-like such as tab, collapse
|
|
1035
|
+
*
|
|
1036
|
+
* @param {String|jQuery} container The container selector or element
|
|
1037
|
+
* @returns {Boolean}
|
|
1038
|
+
*/
|
|
1039
|
+
isValidContainer: function(container) {
|
|
1040
|
+
var that = this,
|
|
1041
|
+
map = {},
|
|
1042
|
+
$container = ('string' === typeof container) ? $(container) : container;
|
|
1043
|
+
if ($container.length === 0) {
|
|
1044
|
+
return true;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
$container.find('[data-bv-field]').each(function() {
|
|
1048
|
+
var $field = $(this),
|
|
1049
|
+
field = $field.attr('data-bv-field');
|
|
1050
|
+
if (!that._isExcluded($field) && !map[field]) {
|
|
1051
|
+
map[field] = $field;
|
|
1052
|
+
}
|
|
1053
|
+
});
|
|
1054
|
+
|
|
1055
|
+
for (var field in map) {
|
|
1056
|
+
var $f = map[field];
|
|
1057
|
+
if ($f.data('bv.messages')
|
|
1058
|
+
.find('.help-block[data-bv-validator][data-bv-for="' + field + '"]')
|
|
1059
|
+
.filter(function() {
|
|
1060
|
+
var v = $(this).attr('data-bv-validator'),
|
|
1061
|
+
f = $(this).attr('data-bv-for');
|
|
1062
|
+
return (that.options.fields[f].validators[v].enabled !== false
|
|
1063
|
+
&& $f.data('bv.result.' + v) && $f.data('bv.result.' + v) !== that.STATUS_VALID);
|
|
1064
|
+
})
|
|
1065
|
+
.length !== 0)
|
|
1066
|
+
{
|
|
1067
|
+
// The field is not valid
|
|
1068
|
+
return false;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
return true;
|
|
1073
|
+
},
|
|
1074
|
+
|
|
1075
|
+
/**
|
|
1076
|
+
* Submit the form using default submission.
|
|
1077
|
+
* It also does not perform any validations when submitting the form
|
|
1078
|
+
*/
|
|
1079
|
+
defaultSubmit: function() {
|
|
1080
|
+
if (this.$submitButton) {
|
|
1081
|
+
// Create hidden input to send the submit buttons
|
|
1082
|
+
$('<input/>')
|
|
1083
|
+
.attr('type', 'hidden')
|
|
1084
|
+
.attr('data-bv-submit-hidden', '')
|
|
1085
|
+
.attr('name', this.$submitButton.attr('name'))
|
|
1086
|
+
.val(this.$submitButton.val())
|
|
1087
|
+
.appendTo(this.$form);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
// Submit form
|
|
1091
|
+
this.$form.off('submit.bv').submit();
|
|
1092
|
+
},
|
|
1093
|
+
|
|
1094
|
+
// ---
|
|
1095
|
+
// Useful APIs which aren't used internally
|
|
1096
|
+
// ---
|
|
1097
|
+
|
|
1098
|
+
/**
|
|
1099
|
+
* Get the list of invalid fields
|
|
1100
|
+
*
|
|
1101
|
+
* @returns {jQuery[]}
|
|
1102
|
+
*/
|
|
1103
|
+
getInvalidFields: function() {
|
|
1104
|
+
return this.$invalidFields;
|
|
1105
|
+
},
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* Returns the clicked submit button
|
|
1109
|
+
*
|
|
1110
|
+
* @returns {jQuery}
|
|
1111
|
+
*/
|
|
1112
|
+
getSubmitButton: function() {
|
|
1113
|
+
return this.$submitButton;
|
|
1114
|
+
},
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* Get the error messages
|
|
1118
|
+
*
|
|
1119
|
+
* @param {String|jQuery} [field] The field name or field element
|
|
1120
|
+
* If the field is not defined, the method returns all error messages of all fields
|
|
1121
|
+
* @param {String} [validator] The name of validator
|
|
1122
|
+
* If the validator is not defined, the method returns error messages of all validators
|
|
1123
|
+
* @returns {String[]}
|
|
1124
|
+
*/
|
|
1125
|
+
getMessages: function(field, validator) {
|
|
1126
|
+
var that = this,
|
|
1127
|
+
messages = [],
|
|
1128
|
+
$fields = $([]);
|
|
1129
|
+
|
|
1130
|
+
switch (true) {
|
|
1131
|
+
case (field && 'object' === typeof field):
|
|
1132
|
+
$fields = field;
|
|
1133
|
+
break;
|
|
1134
|
+
case (field && 'string' === typeof field):
|
|
1135
|
+
var f = this.getFieldElements(field);
|
|
1136
|
+
if (f.length > 0) {
|
|
1137
|
+
var type = f.attr('type');
|
|
1138
|
+
$fields = ('radio' === type || 'checkbox' === type) ? f.eq(0) : f;
|
|
1139
|
+
}
|
|
1140
|
+
break;
|
|
1141
|
+
default:
|
|
1142
|
+
$fields = this.$invalidFields;
|
|
1143
|
+
break;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
var filter = validator ? '[data-bv-validator="' + validator + '"]' : '';
|
|
1147
|
+
$fields.each(function() {
|
|
1148
|
+
messages = messages.concat(
|
|
1149
|
+
$(this)
|
|
1150
|
+
.data('bv.messages')
|
|
1151
|
+
.find('.help-block[data-bv-for="' + $(this).attr('data-bv-field') + '"][data-bv-result="' + that.STATUS_INVALID + '"]' + filter)
|
|
1152
|
+
.map(function() {
|
|
1153
|
+
var v = $(this).attr('data-bv-validator'),
|
|
1154
|
+
f = $(this).attr('data-bv-for');
|
|
1155
|
+
return (that.options.fields[f].validators[v].enabled === false) ? '' : $(this).html();
|
|
1156
|
+
})
|
|
1157
|
+
.get()
|
|
1158
|
+
);
|
|
1159
|
+
});
|
|
1160
|
+
|
|
1161
|
+
return messages;
|
|
1162
|
+
},
|
|
1163
|
+
|
|
1164
|
+
/**
|
|
1165
|
+
* Get the field options
|
|
1166
|
+
*
|
|
1167
|
+
* @param {String|jQuery} [field] The field name or field element. If it is not set, the method returns the form options
|
|
1168
|
+
* @param {String} [validator] The name of validator. It null, the method returns form options
|
|
1169
|
+
* @param {String} [option] The option name
|
|
1170
|
+
* @return {String|Object}
|
|
1171
|
+
*/
|
|
1172
|
+
getOptions: function(field, validator, option) {
|
|
1173
|
+
if (!field) {
|
|
1174
|
+
return this.options;
|
|
1175
|
+
}
|
|
1176
|
+
if ('object' === typeof field) {
|
|
1177
|
+
field = field.attr('data-bv-field');
|
|
1178
|
+
}
|
|
1179
|
+
if (!this.options.fields[field]) {
|
|
1180
|
+
return null;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
var options = this.options.fields[field];
|
|
1184
|
+
if (!validator) {
|
|
1185
|
+
return options;
|
|
1186
|
+
}
|
|
1187
|
+
if (!options.validators || !options.validators[validator]) {
|
|
1188
|
+
return null;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
return option ? options.validators[validator][option] : options.validators[validator];
|
|
1192
|
+
},
|
|
1193
|
+
|
|
1194
|
+
/**
|
|
1195
|
+
* Update the option of a specific validator
|
|
1196
|
+
*
|
|
1197
|
+
* @param {String|jQuery} field The field name or field element
|
|
1198
|
+
* @param {String} validator The validator name
|
|
1199
|
+
* @param {String} option The option name
|
|
1200
|
+
* @param {String} value The value to set
|
|
1201
|
+
* @returns {BootstrapValidator}
|
|
1202
|
+
*/
|
|
1203
|
+
updateOption: function(field, validator, option, value) {
|
|
1204
|
+
if ('object' === typeof field) {
|
|
1205
|
+
field = field.attr('data-bv-field');
|
|
1206
|
+
}
|
|
1207
|
+
if (this.options.fields[field] && this.options.fields[field].validators[validator]) {
|
|
1208
|
+
this.options.fields[field].validators[validator][option] = value;
|
|
1209
|
+
this.updateStatus(field, this.STATUS_NOT_VALIDATED, validator);
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
return this;
|
|
1213
|
+
},
|
|
1214
|
+
|
|
1215
|
+
/**
|
|
1216
|
+
* Add a new field
|
|
1217
|
+
*
|
|
1218
|
+
* @param {String|jQuery} field The field name or field element
|
|
1219
|
+
* @param {Object} [options] The validator rules
|
|
1220
|
+
* @returns {BootstrapValidator}
|
|
1221
|
+
*/
|
|
1222
|
+
addField: function(field, options) {
|
|
1223
|
+
var fields = $([]);
|
|
1224
|
+
switch (typeof field) {
|
|
1225
|
+
case 'object':
|
|
1226
|
+
fields = field;
|
|
1227
|
+
field = field.attr('data-bv-field') || field.attr('name');
|
|
1228
|
+
break;
|
|
1229
|
+
case 'string':
|
|
1230
|
+
delete this._cacheFields[field];
|
|
1231
|
+
fields = this.getFieldElements(field);
|
|
1232
|
+
break;
|
|
1233
|
+
default:
|
|
1234
|
+
break;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
fields.attr('data-bv-field', field);
|
|
1238
|
+
|
|
1239
|
+
var type = fields.attr('type'),
|
|
1240
|
+
total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length;
|
|
1241
|
+
|
|
1242
|
+
for (var i = 0; i < total; i++) {
|
|
1243
|
+
var $field = fields.eq(i);
|
|
1244
|
+
|
|
1245
|
+
// Try to parse the options from HTML attributes
|
|
1246
|
+
var opts = this._parseOptions($field);
|
|
1247
|
+
opts = (opts === null) ? options : $.extend(true, options, opts);
|
|
1248
|
+
|
|
1249
|
+
this.options.fields[field] = $.extend(true, this.options.fields[field], opts);
|
|
1250
|
+
|
|
1251
|
+
// Update the cache
|
|
1252
|
+
this._cacheFields[field] = this._cacheFields[field] ? this._cacheFields[field].add($field) : $field;
|
|
1253
|
+
|
|
1254
|
+
// Init the element
|
|
1255
|
+
this._initField(('checkbox' === type || 'radio' === type) ? field : $field);
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
this.disableSubmitButtons(false);
|
|
1259
|
+
// Trigger an event
|
|
1260
|
+
this.$form.trigger($.Event('added.field.bv'), {
|
|
1261
|
+
field: field,
|
|
1262
|
+
element: fields,
|
|
1263
|
+
options: this.options.fields[field]
|
|
1264
|
+
});
|
|
1265
|
+
|
|
1266
|
+
return this;
|
|
1267
|
+
},
|
|
1268
|
+
|
|
1269
|
+
/**
|
|
1270
|
+
* Remove a given field
|
|
1271
|
+
*
|
|
1272
|
+
* @param {String|jQuery} field The field name or field element
|
|
1273
|
+
* @returns {BootstrapValidator}
|
|
1274
|
+
*/
|
|
1275
|
+
removeField: function(field) {
|
|
1276
|
+
var fields = $([]);
|
|
1277
|
+
switch (typeof field) {
|
|
1278
|
+
case 'object':
|
|
1279
|
+
fields = field;
|
|
1280
|
+
field = field.attr('data-bv-field') || field.attr('name');
|
|
1281
|
+
fields.attr('data-bv-field', field);
|
|
1282
|
+
break;
|
|
1283
|
+
case 'string':
|
|
1284
|
+
fields = this.getFieldElements(field);
|
|
1285
|
+
break;
|
|
1286
|
+
default:
|
|
1287
|
+
break;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
if (fields.length === 0) {
|
|
1291
|
+
return this;
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
var type = fields.attr('type'),
|
|
1295
|
+
total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length;
|
|
1296
|
+
|
|
1297
|
+
for (var i = 0; i < total; i++) {
|
|
1298
|
+
var $field = fields.eq(i);
|
|
1299
|
+
|
|
1300
|
+
// Remove from the list of invalid fields
|
|
1301
|
+
this.$invalidFields = this.$invalidFields.not($field);
|
|
1302
|
+
|
|
1303
|
+
// Update the cache
|
|
1304
|
+
this._cacheFields[field] = this._cacheFields[field].not($field);
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
if (!this._cacheFields[field] || this._cacheFields[field].length === 0) {
|
|
1308
|
+
delete this.options.fields[field];
|
|
1309
|
+
}
|
|
1310
|
+
if ('checkbox' === type || 'radio' === type) {
|
|
1311
|
+
this._initField(field);
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
this.disableSubmitButtons(false);
|
|
1315
|
+
// Trigger an event
|
|
1316
|
+
this.$form.trigger($.Event('removed.field.bv'), {
|
|
1317
|
+
field: field,
|
|
1318
|
+
element: fields
|
|
1319
|
+
});
|
|
1320
|
+
|
|
1321
|
+
return this;
|
|
1322
|
+
},
|
|
1323
|
+
|
|
1324
|
+
/**
|
|
1325
|
+
* Reset given field
|
|
1326
|
+
*
|
|
1327
|
+
* @param {String|jQuery} field The field name or field element
|
|
1328
|
+
* @param {Boolean} [resetValue] If true, the method resets field value to empty or remove checked/selected attribute (for radio/checkbox)
|
|
1329
|
+
* @returns {BootstrapValidator}
|
|
1330
|
+
*/
|
|
1331
|
+
resetField: function(field, resetValue) {
|
|
1332
|
+
var $fields = $([]);
|
|
1333
|
+
switch (typeof field) {
|
|
1334
|
+
case 'object':
|
|
1335
|
+
$fields = field;
|
|
1336
|
+
field = field.attr('data-bv-field');
|
|
1337
|
+
break;
|
|
1338
|
+
case 'string':
|
|
1339
|
+
$fields = this.getFieldElements(field);
|
|
1340
|
+
break;
|
|
1341
|
+
default:
|
|
1342
|
+
break;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
var total = $fields.length;
|
|
1346
|
+
if (this.options.fields[field]) {
|
|
1347
|
+
for (var i = 0; i < total; i++) {
|
|
1348
|
+
for (var validator in this.options.fields[field].validators) {
|
|
1349
|
+
$fields.eq(i).removeData('bv.dfs.' + validator);
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
// Mark field as not validated yet
|
|
1355
|
+
this.updateStatus(field, this.STATUS_NOT_VALIDATED);
|
|
1356
|
+
|
|
1357
|
+
if (resetValue) {
|
|
1358
|
+
var type = $fields.attr('type');
|
|
1359
|
+
('radio' === type || 'checkbox' === type) ? $fields.removeAttr('checked').removeAttr('selected') : $fields.val('');
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
return this;
|
|
1363
|
+
},
|
|
1364
|
+
|
|
1365
|
+
/**
|
|
1366
|
+
* Reset the form
|
|
1367
|
+
*
|
|
1368
|
+
* @param {Boolean} [resetValue] If true, the method resets field value to empty or remove checked/selected attribute (for radio/checkbox)
|
|
1369
|
+
* @returns {BootstrapValidator}
|
|
1370
|
+
*/
|
|
1371
|
+
resetForm: function(resetValue) {
|
|
1372
|
+
for (var field in this.options.fields) {
|
|
1373
|
+
this.resetField(field, resetValue);
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
this.$invalidFields = $([]);
|
|
1377
|
+
this.$submitButton = null;
|
|
1378
|
+
|
|
1379
|
+
// Enable submit buttons
|
|
1380
|
+
this.disableSubmitButtons(false);
|
|
1381
|
+
|
|
1382
|
+
return this;
|
|
1383
|
+
},
|
|
1384
|
+
|
|
1385
|
+
/**
|
|
1386
|
+
* Revalidate given field
|
|
1387
|
+
* It's used when you need to revalidate the field which its value is updated by other plugin
|
|
1388
|
+
*
|
|
1389
|
+
* @param {String|jQuery} field The field name of field element
|
|
1390
|
+
* @returns {BootstrapValidator}
|
|
1391
|
+
*/
|
|
1392
|
+
revalidateField: function(field) {
|
|
1393
|
+
this.updateStatus(field, this.STATUS_NOT_VALIDATED)
|
|
1394
|
+
.validateField(field);
|
|
1395
|
+
|
|
1396
|
+
return this;
|
|
1397
|
+
},
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* Enable/Disable all validators to given field
|
|
1401
|
+
*
|
|
1402
|
+
* @param {String} field The field name
|
|
1403
|
+
* @param {Boolean} enabled Enable/Disable field validators
|
|
1404
|
+
* @param {String} [validatorName] The validator name. If null, all validators will be enabled/disabled
|
|
1405
|
+
* @returns {BootstrapValidator}
|
|
1406
|
+
*/
|
|
1407
|
+
enableFieldValidators: function(field, enabled, validatorName) {
|
|
1408
|
+
var validators = this.options.fields[field].validators;
|
|
1409
|
+
|
|
1410
|
+
// Enable/disable particular validator
|
|
1411
|
+
if (validatorName
|
|
1412
|
+
&& validators
|
|
1413
|
+
&& validators[validatorName] && validators[validatorName].enabled !== enabled)
|
|
1414
|
+
{
|
|
1415
|
+
this.options.fields[field].validators[validatorName].enabled = enabled;
|
|
1416
|
+
this.updateStatus(field, this.STATUS_NOT_VALIDATED, validatorName);
|
|
1417
|
+
}
|
|
1418
|
+
// Enable/disable all validators
|
|
1419
|
+
else if (!validatorName && this.options.fields[field].enabled !== enabled) {
|
|
1420
|
+
this.options.fields[field].enabled = enabled;
|
|
1421
|
+
for (var v in validators) {
|
|
1422
|
+
this.enableFieldValidators(field, enabled, v);
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
return this;
|
|
1427
|
+
},
|
|
1428
|
+
|
|
1429
|
+
/**
|
|
1430
|
+
* Some validators have option which its value is dynamic.
|
|
1431
|
+
* For example, the zipCode validator has the country option which might be changed dynamically by a select element.
|
|
1432
|
+
*
|
|
1433
|
+
* @param {jQuery|String} field The field name or element
|
|
1434
|
+
* @param {String|Function} option The option which can be determined by:
|
|
1435
|
+
* - a string
|
|
1436
|
+
* - name of field which defines the value
|
|
1437
|
+
* - name of function which returns the value
|
|
1438
|
+
* - a function returns the value
|
|
1439
|
+
*
|
|
1440
|
+
* The callback function has the format of
|
|
1441
|
+
* callback: function(value, validator, $field) {
|
|
1442
|
+
* // value is the value of field
|
|
1443
|
+
* // validator is the BootstrapValidator instance
|
|
1444
|
+
* // $field is the field element
|
|
1445
|
+
* }
|
|
1446
|
+
*
|
|
1447
|
+
* @returns {String}
|
|
1448
|
+
*/
|
|
1449
|
+
getDynamicOption: function(field, option) {
|
|
1450
|
+
var $field = ('string' === typeof field) ? this.getFieldElements(field) : field,
|
|
1451
|
+
value = $field.val();
|
|
1452
|
+
|
|
1453
|
+
// Option can be determined by
|
|
1454
|
+
// ... a function
|
|
1455
|
+
if ('function' === typeof option) {
|
|
1456
|
+
return $.fn.bootstrapValidator.helpers.call(option, [value, this, $field]);
|
|
1457
|
+
}
|
|
1458
|
+
// ... value of other field
|
|
1459
|
+
else if ('string' === typeof option) {
|
|
1460
|
+
var $f = this.getFieldElements(option);
|
|
1461
|
+
if ($f.length) {
|
|
1462
|
+
return $f.val();
|
|
1463
|
+
}
|
|
1464
|
+
// ... return value of callback
|
|
1465
|
+
else {
|
|
1466
|
+
return $.fn.bootstrapValidator.helpers.call(option, [value, this, $field]);
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
return null;
|
|
1471
|
+
},
|
|
1472
|
+
|
|
1473
|
+
/**
|
|
1474
|
+
* Destroy the plugin
|
|
1475
|
+
* It will remove all error messages, feedback icons and turn off the events
|
|
1476
|
+
*/
|
|
1477
|
+
destroy: function() {
|
|
1478
|
+
var field, fields, $field, validator, $icon, container, group;
|
|
1479
|
+
for (field in this.options.fields) {
|
|
1480
|
+
fields = this.getFieldElements(field);
|
|
1481
|
+
container = this.options.fields[field].container || this.options.container,
|
|
1482
|
+
group = this.options.fields[field].group || this.options.group;
|
|
1483
|
+
for (var i = 0; i < fields.length; i++) {
|
|
1484
|
+
$field = fields.eq(i);
|
|
1485
|
+
$field
|
|
1486
|
+
// Remove all error messages
|
|
1487
|
+
.data('bv.messages')
|
|
1488
|
+
.find('.help-block[data-bv-validator][data-bv-for="' + field + '"]').remove().end()
|
|
1489
|
+
.end()
|
|
1490
|
+
.removeData('bv.messages')
|
|
1491
|
+
// Remove feedback classes
|
|
1492
|
+
.parents(group)
|
|
1493
|
+
.removeClass('has-feedback has-error has-success')
|
|
1494
|
+
.end()
|
|
1495
|
+
// Turn off events
|
|
1496
|
+
.off('.bv')
|
|
1497
|
+
.removeAttr('data-bv-field');
|
|
1498
|
+
|
|
1499
|
+
// Remove feedback icons, tooltip/popover container
|
|
1500
|
+
$icon = $field.parents(group).find('i[data-bv-icon-for="' + field + '"]');
|
|
1501
|
+
if ($icon) {
|
|
1502
|
+
switch (container) {
|
|
1503
|
+
case 'tooltip':
|
|
1504
|
+
$icon.tooltip('destroy').remove();
|
|
1505
|
+
break;
|
|
1506
|
+
case 'popover':
|
|
1507
|
+
$icon.popover('destroy').remove();
|
|
1508
|
+
break;
|
|
1509
|
+
default:
|
|
1510
|
+
$icon.remove();
|
|
1511
|
+
break;
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
for (validator in this.options.fields[field].validators) {
|
|
1516
|
+
if ($field.data('bv.dfs.' + validator)) {
|
|
1517
|
+
$field.data('bv.dfs.' + validator).reject();
|
|
1518
|
+
}
|
|
1519
|
+
$field.removeData('bv.result.' + validator).removeData('bv.dfs.' + validator);
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
// Enable submit buttons
|
|
1525
|
+
this.disableSubmitButtons(false);
|
|
1526
|
+
|
|
1527
|
+
this.$form
|
|
1528
|
+
.removeClass(this.options.elementClass)
|
|
1529
|
+
.off('.bv')
|
|
1530
|
+
.removeData('bootstrapValidator')
|
|
1531
|
+
// Remove generated hidden elements
|
|
1532
|
+
.find('[data-bv-submit-hidden]').remove();
|
|
1533
|
+
}
|
|
1534
|
+
};
|
|
1535
|
+
|
|
1536
|
+
// Plugin definition
|
|
1537
|
+
$.fn.bootstrapValidator = function(option) {
|
|
1538
|
+
var params = arguments;
|
|
1539
|
+
return this.each(function() {
|
|
1540
|
+
var $this = $(this),
|
|
1541
|
+
data = $this.data('bootstrapValidator'),
|
|
1542
|
+
options = 'object' === typeof option && option;
|
|
1543
|
+
if (!data) {
|
|
1544
|
+
data = new BootstrapValidator(this, options);
|
|
1545
|
+
$this.data('bootstrapValidator', data);
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
// Allow to call plugin method
|
|
1549
|
+
if ('string' === typeof option) {
|
|
1550
|
+
data[option].apply(data, Array.prototype.slice.call(params, 1));
|
|
1551
|
+
}
|
|
1552
|
+
});
|
|
1553
|
+
};
|
|
1554
|
+
|
|
1555
|
+
// The default options
|
|
1556
|
+
$.fn.bootstrapValidator.DEFAULT_OPTIONS = {
|
|
1557
|
+
// The form CSS class
|
|
1558
|
+
elementClass: 'bv-form',
|
|
1559
|
+
|
|
1560
|
+
// Default invalid message
|
|
1561
|
+
message: 'This value is not valid',
|
|
1562
|
+
|
|
1563
|
+
// The CSS selector for indicating the element consists the field
|
|
1564
|
+
// By default, each field is placed inside the <div class="form-group"></div>
|
|
1565
|
+
// You should adjust this option if your form group consists of many fields which not all of them need to be validated
|
|
1566
|
+
group: '.form-group',
|
|
1567
|
+
|
|
1568
|
+
//The error messages container. It can be:
|
|
1569
|
+
// - 'tooltip' if you want to use Bootstrap tooltip to show error messages
|
|
1570
|
+
// - 'popover' if you want to use Bootstrap popover to show error messages
|
|
1571
|
+
// - a CSS selector indicating the container
|
|
1572
|
+
// In the first two cases, since the tooltip/popover should be small enough, the plugin only shows only one error message
|
|
1573
|
+
// You also can define the message container for particular field
|
|
1574
|
+
container: null,
|
|
1575
|
+
|
|
1576
|
+
// The field will not be live validated if its length is less than this number of characters
|
|
1577
|
+
threshold: null,
|
|
1578
|
+
|
|
1579
|
+
// Indicate fields which won't be validated
|
|
1580
|
+
// By default, the plugin will not validate the following kind of fields:
|
|
1581
|
+
// - disabled
|
|
1582
|
+
// - hidden
|
|
1583
|
+
// - invisible
|
|
1584
|
+
//
|
|
1585
|
+
// The setting consists of jQuery filters. Accept 3 formats:
|
|
1586
|
+
// - A string. Use a comma to separate filter
|
|
1587
|
+
// - An array. Each element is a filter
|
|
1588
|
+
// - An array. Each element can be a callback function
|
|
1589
|
+
// function($field, validator) {
|
|
1590
|
+
// $field is jQuery object representing the field element
|
|
1591
|
+
// validator is the BootstrapValidator instance
|
|
1592
|
+
// return true or false;
|
|
1593
|
+
// }
|
|
1594
|
+
//
|
|
1595
|
+
// The 3 following settings are equivalent:
|
|
1596
|
+
//
|
|
1597
|
+
// 1) ':disabled, :hidden, :not(:visible)'
|
|
1598
|
+
// 2) [':disabled', ':hidden', ':not(:visible)']
|
|
1599
|
+
// 3) [':disabled', ':hidden', function($field) {
|
|
1600
|
+
// return !$field.is(':visible');
|
|
1601
|
+
// }]
|
|
1602
|
+
excluded: [':disabled', ':hidden', ':not(:visible)'],
|
|
1603
|
+
|
|
1604
|
+
// Shows ok/error/loading icons based on the field validity.
|
|
1605
|
+
// This feature requires Bootstrap v3.1.0 or later (http://getbootstrap.com/css/#forms-control-validation).
|
|
1606
|
+
// Since Bootstrap doesn't provide any methods to know its version, this option cannot be on/off automatically.
|
|
1607
|
+
// In other word, to use this feature you have to upgrade your Bootstrap to v3.1.0 or later.
|
|
1608
|
+
//
|
|
1609
|
+
// Examples:
|
|
1610
|
+
// - Use Glyphicons icons:
|
|
1611
|
+
// feedbackIcons: {
|
|
1612
|
+
// valid: 'glyphicon glyphicon-ok',
|
|
1613
|
+
// invalid: 'glyphicon glyphicon-remove',
|
|
1614
|
+
// validating: 'glyphicon glyphicon-refresh'
|
|
1615
|
+
// }
|
|
1616
|
+
// - Use FontAwesome icons:
|
|
1617
|
+
// feedbackIcons: {
|
|
1618
|
+
// valid: 'fa fa-check',
|
|
1619
|
+
// invalid: 'fa fa-times',
|
|
1620
|
+
// validating: 'fa fa-refresh'
|
|
1621
|
+
// }
|
|
1622
|
+
feedbackIcons: {
|
|
1623
|
+
valid: null,
|
|
1624
|
+
invalid: null,
|
|
1625
|
+
validating: null
|
|
1626
|
+
},
|
|
1627
|
+
|
|
1628
|
+
// The submit buttons selector
|
|
1629
|
+
// These buttons will be disabled to prevent the valid form from multiple submissions
|
|
1630
|
+
submitButtons: '[type="submit"]',
|
|
1631
|
+
|
|
1632
|
+
// Live validating option
|
|
1633
|
+
// Can be one of 3 values:
|
|
1634
|
+
// - enabled: The plugin validates fields as soon as they are changed
|
|
1635
|
+
// - disabled: Disable the live validating. The error messages are only shown after the form is submitted
|
|
1636
|
+
// - submitted: The live validating is enabled after the form is submitted
|
|
1637
|
+
live: 'enabled',
|
|
1638
|
+
|
|
1639
|
+
// Map the field name with validator rules
|
|
1640
|
+
fields: null
|
|
1641
|
+
};
|
|
1642
|
+
|
|
1643
|
+
// Available validators
|
|
1644
|
+
$.fn.bootstrapValidator.validators = {};
|
|
1645
|
+
|
|
1646
|
+
// i18n
|
|
1647
|
+
$.fn.bootstrapValidator.i18n = {};
|
|
1648
|
+
|
|
1649
|
+
$.fn.bootstrapValidator.Constructor = BootstrapValidator;
|
|
1650
|
+
|
|
1651
|
+
// Helper methods, which can be used in validator class
|
|
1652
|
+
$.fn.bootstrapValidator.helpers = {
|
|
1653
|
+
/**
|
|
1654
|
+
* Execute a callback function
|
|
1655
|
+
*
|
|
1656
|
+
* @param {String|Function} functionName Can be
|
|
1657
|
+
* - name of global function
|
|
1658
|
+
* - name of namespace function (such as A.B.C)
|
|
1659
|
+
* - a function
|
|
1660
|
+
* @param {Array} args The callback arguments
|
|
1661
|
+
*/
|
|
1662
|
+
call: function(functionName, args) {
|
|
1663
|
+
if ('function' === typeof functionName) {
|
|
1664
|
+
return functionName.apply(this, args);
|
|
1665
|
+
} else if ('string' === typeof functionName) {
|
|
1666
|
+
if ('()' === functionName.substring(functionName.length - 2)) {
|
|
1667
|
+
functionName = functionName.substring(0, functionName.length - 2);
|
|
1668
|
+
}
|
|
1669
|
+
var ns = functionName.split('.'),
|
|
1670
|
+
func = ns.pop(),
|
|
1671
|
+
context = window;
|
|
1672
|
+
for (var i = 0; i < ns.length; i++) {
|
|
1673
|
+
context = context[ns[i]];
|
|
1674
|
+
}
|
|
1675
|
+
return context[func].apply(this, args);
|
|
1676
|
+
}
|
|
1677
|
+
},
|
|
1678
|
+
|
|
1679
|
+
/**
|
|
1680
|
+
* Format a string
|
|
1681
|
+
* It's used to format the error message
|
|
1682
|
+
* format('The field must between %s and %s', [10, 20]) = 'The field must between 10 and 20'
|
|
1683
|
+
*
|
|
1684
|
+
* @param {String} message
|
|
1685
|
+
* @param {Array} parameters
|
|
1686
|
+
* @returns {String}
|
|
1687
|
+
*/
|
|
1688
|
+
format: function(message, parameters) {
|
|
1689
|
+
if (!$.isArray(parameters)) {
|
|
1690
|
+
parameters = [parameters];
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
for (var i in parameters) {
|
|
1694
|
+
message = message.replace('%s', parameters[i]);
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
return message;
|
|
1698
|
+
},
|
|
1699
|
+
|
|
1700
|
+
/**
|
|
1701
|
+
* Validate a date
|
|
1702
|
+
*
|
|
1703
|
+
* @param {Number} year The full year in 4 digits
|
|
1704
|
+
* @param {Number} month The month number
|
|
1705
|
+
* @param {Number} day The day number
|
|
1706
|
+
* @param {Boolean} [notInFuture] If true, the date must not be in the future
|
|
1707
|
+
* @returns {Boolean}
|
|
1708
|
+
*/
|
|
1709
|
+
date: function(year, month, day, notInFuture) {
|
|
1710
|
+
if (isNaN(year) || isNaN(month) || isNaN(day)) {
|
|
1711
|
+
return false;
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
day = parseInt(day, 10);
|
|
1715
|
+
month = parseInt(month, 10);
|
|
1716
|
+
year = parseInt(year, 10);
|
|
1717
|
+
|
|
1718
|
+
if (year < 1000 || year > 9999 || month <= 0 || month > 12) {
|
|
1719
|
+
return false;
|
|
1720
|
+
}
|
|
1721
|
+
var numDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
1722
|
+
// Update the number of days in Feb of leap year
|
|
1723
|
+
if (year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0)) {
|
|
1724
|
+
numDays[1] = 29;
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
// Check the day
|
|
1728
|
+
if (day <= 0 || day > numDays[month - 1]) {
|
|
1729
|
+
return false;
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
if (notInFuture === true) {
|
|
1733
|
+
var currentDate = new Date(),
|
|
1734
|
+
currentYear = currentDate.getFullYear(),
|
|
1735
|
+
currentMonth = currentDate.getMonth(),
|
|
1736
|
+
currentDay = currentDate.getDate();
|
|
1737
|
+
return (year < currentYear
|
|
1738
|
+
|| (year === currentYear && month - 1 < currentMonth)
|
|
1739
|
+
|| (year === currentYear && month - 1 === currentMonth && day < currentDay));
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
return true;
|
|
1743
|
+
},
|
|
1744
|
+
|
|
1745
|
+
/**
|
|
1746
|
+
* Implement Luhn validation algorithm
|
|
1747
|
+
* Credit to https://gist.github.com/ShirtlessKirk/2134376
|
|
1748
|
+
*
|
|
1749
|
+
* @see http://en.wikipedia.org/wiki/Luhn
|
|
1750
|
+
* @param {String} value
|
|
1751
|
+
* @returns {Boolean}
|
|
1752
|
+
*/
|
|
1753
|
+
luhn: function(value) {
|
|
1754
|
+
var length = value.length,
|
|
1755
|
+
mul = 0,
|
|
1756
|
+
prodArr = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]],
|
|
1757
|
+
sum = 0;
|
|
1758
|
+
|
|
1759
|
+
while (length--) {
|
|
1760
|
+
sum += prodArr[mul][parseInt(value.charAt(length), 10)];
|
|
1761
|
+
mul ^= 1;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
return (sum % 10 === 0 && sum > 0);
|
|
1765
|
+
},
|
|
1766
|
+
|
|
1767
|
+
/**
|
|
1768
|
+
* Implement modulus 11, 10 (ISO 7064) algorithm
|
|
1769
|
+
*
|
|
1770
|
+
* @param {String} value
|
|
1771
|
+
* @returns {Boolean}
|
|
1772
|
+
*/
|
|
1773
|
+
mod11And10: function(value) {
|
|
1774
|
+
var check = 5,
|
|
1775
|
+
length = value.length;
|
|
1776
|
+
for (var i = 0; i < length; i++) {
|
|
1777
|
+
check = (((check || 10) * 2) % 11 + parseInt(value.charAt(i), 10)) % 10;
|
|
1778
|
+
}
|
|
1779
|
+
return (check === 1);
|
|
1780
|
+
},
|
|
1781
|
+
|
|
1782
|
+
/**
|
|
1783
|
+
* Implements Mod 37, 36 (ISO 7064) algorithm
|
|
1784
|
+
* Usages:
|
|
1785
|
+
* mod37And36('A12425GABC1234002M')
|
|
1786
|
+
* mod37And36('002006673085', '0123456789')
|
|
1787
|
+
*
|
|
1788
|
+
* @param {String} value
|
|
1789
|
+
* @param {String} [alphabet]
|
|
1790
|
+
* @returns {Boolean}
|
|
1791
|
+
*/
|
|
1792
|
+
mod37And36: function(value, alphabet) {
|
|
1793
|
+
alphabet = alphabet || '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
1794
|
+
var modulus = alphabet.length,
|
|
1795
|
+
length = value.length,
|
|
1796
|
+
check = Math.floor(modulus / 2);
|
|
1797
|
+
for (var i = 0; i < length; i++) {
|
|
1798
|
+
check = (((check || modulus) * 2) % (modulus + 1) + alphabet.indexOf(value.charAt(i))) % modulus;
|
|
1799
|
+
}
|
|
1800
|
+
return (check === 1);
|
|
1801
|
+
}
|
|
1802
|
+
};
|
|
1803
|
+
}(window.jQuery));
|