bootstrap_validator-rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README.md +4 -0
  4. data/lib/bootstrap_validator-rails.rb +5 -0
  5. data/lib/bootstrap_validator-rails/engine.rb +6 -0
  6. data/vendor/javascripts/bootstrapValidator.js +1803 -0
  7. data/vendor/javascripts/language/de_DE.js +326 -0
  8. data/vendor/javascripts/language/en_US.js +327 -0
  9. data/vendor/javascripts/language/es_CL.js +326 -0
  10. data/vendor/javascripts/language/hu_HU.js +326 -0
  11. data/vendor/javascripts/language/vi_VN.js +322 -0
  12. data/vendor/javascripts/language/zh_CN.js +326 -0
  13. data/vendor/javascripts/language/zh_TW.js +326 -0
  14. data/vendor/javascripts/validator/base64.js +25 -0
  15. data/vendor/javascripts/validator/between.js +66 -0
  16. data/vendor/javascripts/validator/callback.js +40 -0
  17. data/vendor/javascripts/validator/choice.js +68 -0
  18. data/vendor/javascripts/validator/creditCard.js +103 -0
  19. data/vendor/javascripts/validator/cusip.js +55 -0
  20. data/vendor/javascripts/validator/cvv.js +116 -0
  21. data/vendor/javascripts/validator/date.js +118 -0
  22. data/vendor/javascripts/validator/different.js +41 -0
  23. data/vendor/javascripts/validator/digits.js +24 -0
  24. data/vendor/javascripts/validator/ean.js +40 -0
  25. data/vendor/javascripts/validator/emailAddress.js +31 -0
  26. data/vendor/javascripts/validator/file.js +69 -0
  27. data/vendor/javascripts/validator/greaterThan.js +61 -0
  28. data/vendor/javascripts/validator/grid.js +37 -0
  29. data/vendor/javascripts/validator/hex.js +25 -0
  30. data/vendor/javascripts/validator/hexColor.js +28 -0
  31. data/vendor/javascripts/validator/iban.js +246 -0
  32. data/vendor/javascripts/validator/id.js +815 -0
  33. data/vendor/javascripts/validator/identical.js +40 -0
  34. data/vendor/javascripts/validator/imei.js +44 -0
  35. data/vendor/javascripts/validator/integer.js +28 -0
  36. data/vendor/javascripts/validator/ip.js +48 -0
  37. data/vendor/javascripts/validator/isbn.js +86 -0
  38. data/vendor/javascripts/validator/isin.js +59 -0
  39. data/vendor/javascripts/validator/ismn.js +59 -0
  40. data/vendor/javascripts/validator/issn.js +46 -0
  41. data/vendor/javascripts/validator/lessThan.js +61 -0
  42. data/vendor/javascripts/validator/mac.js +25 -0
  43. data/vendor/javascripts/validator/notEmpty.js +32 -0
  44. data/vendor/javascripts/validator/numeric.js +39 -0
  45. data/vendor/javascripts/validator/phone.js +84 -0
  46. data/vendor/javascripts/validator/regexp.js +42 -0
  47. data/vendor/javascripts/validator/remote.js +70 -0
  48. data/vendor/javascripts/validator/rtn.js +38 -0
  49. data/vendor/javascripts/validator/sedol.js +40 -0
  50. data/vendor/javascripts/validator/siren.js +28 -0
  51. data/vendor/javascripts/validator/siret.js +38 -0
  52. data/vendor/javascripts/validator/step.js +64 -0
  53. data/vendor/javascripts/validator/stringCase.js +36 -0
  54. data/vendor/javascripts/validator/stringLength.js +81 -0
  55. data/vendor/javascripts/validator/uri.js +101 -0
  56. data/vendor/javascripts/validator/uuid.js +46 -0
  57. data/vendor/javascripts/validator/vat.js +1220 -0
  58. data/vendor/javascripts/validator/vin.js +49 -0
  59. data/vendor/javascripts/validator/zipCode.js +162 -0
  60. data/vendor/stylesheets/bootstrapValidator.css +21 -0
  61. metadata +130 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 355988eeeba3e6db6de15677f184bfb19b9ae85e
4
+ data.tar.gz: 611d84cedd6048c6addf89af35b52a9dbe9f46f3
5
+ SHA512:
6
+ metadata.gz: 6de410831a1032af87793fe767afb88cd2c673f9cecc41ab03237cc1f06ee48c3892ec6f9c0f7012e3ab07325dd21543c3ec20d81b14550fddb019b5eef574b6
7
+ data.tar.gz: c36339d8fefce12c3420f5ff972c2d1db7d6f85b3c9cdbed90337130400dd7379fdfa92af17f1f6e74ddfa002a7bd821c64c4f9906a2cf9af032b18ee6986a92
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Jack A. Huang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ bootstrap_validator-rails
2
+ =========================
3
+
4
+ Bootstrap Validator Plugin for Rails: https://github.com/nghuuphuoc/bootstrapvalidator
@@ -0,0 +1,5 @@
1
+ module BootstrapValidatorRails
2
+ module Rails
3
+ require "bootstrap_validator-rails/engine"
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ module BootstrapValidatorRails
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -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));