Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
21826 kshitij.so 1
/*!
2
 * BootstrapValidator (http://bootstrapvalidator.com)
3
 * The best jQuery plugin to validate form fields. Designed to use with Bootstrap 3
4
 *
5
 * @version     v0.5.3, built on 2014-11-05 9:14:18 PM
6
 * @author      https://twitter.com/nghuuphuoc
7
 * @copyright   (c) 2013 - 2014 Nguyen Huu Phuoc
8
 * @license     Commercial: http://bootstrapvalidator.com/license/
9
 *              Non-commercial: http://creativecommons.org/licenses/by-nc-nd/3.0/
10
 */
11
if (typeof jQuery === 'undefined') {
12
    throw new Error('BootstrapValidator requires jQuery');
13
}
14
 
15
(function($) {
16
    var version = $.fn.jquery.split(' ')[0].split('.');
17
    if ((+version[0] < 2 && +version[1] < 9) || (+version[0] === 1 && +version[1] === 9 && +version[2] < 1)) {
18
        throw new Error('BootstrapValidator requires jQuery version 1.9.1 or higher');
19
    }
20
}(window.jQuery));
21
 
22
(function($) {
23
    var BootstrapValidator = function(form, options) {
24
        this.$form   = $(form);
25
        this.options = $.extend({}, $.fn.bootstrapValidator.DEFAULT_OPTIONS, options);
26
 
27
        this.$invalidFields = $([]);    // Array of invalid fields
28
        this.$submitButton  = null;     // The submit button which is clicked to submit form
29
        this.$hiddenButton  = null;
30
 
31
        // Validating status
32
        this.STATUS_NOT_VALIDATED = 'NOT_VALIDATED';
33
        this.STATUS_VALIDATING    = 'VALIDATING';
34
        this.STATUS_INVALID       = 'INVALID';
35
        this.STATUS_VALID         = 'VALID';
36
 
37
        // Determine the event that is fired when user change the field value
38
        // Most modern browsers supports input event except IE 7, 8.
39
        // IE 9 supports input event but the event is still not fired if I press the backspace key.
40
        // Get IE version
41
        // https://gist.github.com/padolsey/527683/#comment-7595
42
        var ieVersion = (function() {
43
            var v = 3, div = document.createElement('div'), a = div.all || [];
44
            while (div.innerHTML = '<!--[if gt IE '+(++v)+']><br><![endif]-->', a[0]) {}
45
            return v > 4 ? v : !v;
46
        }());
47
 
48
        var el = document.createElement('div');
49
        this._changeEvent = (ieVersion === 9 || !('oninput' in el)) ? 'keyup' : 'input';
50
 
51
        // The flag to indicate that the form is ready to submit when a remote/callback validator returns
52
        this._submitIfValid = null;
53
 
54
        // Field elements
55
        this._cacheFields = {};
56
 
57
        this._init();
58
    };
59
 
60
    BootstrapValidator.prototype = {
61
        constructor: BootstrapValidator,
62
 
63
        /**
64
         * Init form
65
         */
66
        _init: function() {
67
            var that    = this,
68
                options = {
69
                    autoFocus:      this.$form.attr('data-bv-autofocus'),
70
                    container:      this.$form.attr('data-bv-container'),
71
                    events: {
72
                        formInit:         this.$form.attr('data-bv-events-form-init'),
73
                        formError:        this.$form.attr('data-bv-events-form-error'),
74
                        formSuccess:      this.$form.attr('data-bv-events-form-success'),
75
                        fieldAdded:       this.$form.attr('data-bv-events-field-added'),
76
                        fieldRemoved:     this.$form.attr('data-bv-events-field-removed'),
77
                        fieldInit:        this.$form.attr('data-bv-events-field-init'),
78
                        fieldError:       this.$form.attr('data-bv-events-field-error'),
79
                        fieldSuccess:     this.$form.attr('data-bv-events-field-success'),
80
                        fieldStatus:      this.$form.attr('data-bv-events-field-status'),
81
                        validatorError:   this.$form.attr('data-bv-events-validator-error'),
82
                        validatorSuccess: this.$form.attr('data-bv-events-validator-success')
83
                    },
84
                    excluded:       this.$form.attr('data-bv-excluded'),
85
                    feedbackIcons: {
86
                        valid:      this.$form.attr('data-bv-feedbackicons-valid'),
87
                        invalid:    this.$form.attr('data-bv-feedbackicons-invalid'),
88
                        validating: this.$form.attr('data-bv-feedbackicons-validating')
89
                    },
90
                    group:          this.$form.attr('data-bv-group'),
91
                    live:           this.$form.attr('data-bv-live'),
92
                    message:        this.$form.attr('data-bv-message'),
93
                    onError:        this.$form.attr('data-bv-onerror'),
94
                    onSuccess:      this.$form.attr('data-bv-onsuccess'),
95
                    submitButtons:  this.$form.attr('data-bv-submitbuttons'),
96
                    threshold:      this.$form.attr('data-bv-threshold'),
97
                    trigger:        this.$form.attr('data-bv-trigger'),
98
                    verbose:        this.$form.attr('data-bv-verbose'),
99
                    fields:         {}
100
                };
101
 
102
            this.$form
103
                // Disable client side validation in HTML 5
104
                .attr('novalidate', 'novalidate')
105
                .addClass(this.options.elementClass)
106
                // Disable the default submission first
107
                .on('submit.bv', function(e) {
108
                    e.preventDefault();
109
                    that.validate();
110
                })
111
                .on('click.bv', this.options.submitButtons, function() {
112
                    that.$submitButton  = $(this);
113
					// The user just click the submit button
114
					that._submitIfValid = true;
115
                })
116
                // Find all fields which have either "name" or "data-bv-field" attribute
117
                .find('[name], [data-bv-field]')
118
                    .each(function() {
119
                        var $field = $(this),
120
                            field  = $field.attr('name') || $field.attr('data-bv-field'),
121
                            opts   = that._parseOptions($field);
122
                        if (opts) {
123
                            $field.attr('data-bv-field', field);
124
                            options.fields[field] = $.extend({}, opts, options.fields[field]);
125
                        }
126
                    });
127
 
128
            this.options = $.extend(true, this.options, options);
129
 
130
            // When pressing Enter on any field in the form, the first submit button will do its job.
131
            // The form then will be submitted.
132
            // I create a first hidden submit button
133
            this.$hiddenButton = $('<button/>')
134
                                    .attr('type', 'submit')
135
                                    .prependTo(this.$form)
136
                                    .addClass('bv-hidden-submit')
137
                                    .css({ display: 'none', width: 0, height: 0 });
138
 
139
            this.$form
140
                .on('click.bv', '[type="submit"]', function(e) {
141
                    // #746: Check if the button click handler returns false
142
                    if (!e.isDefaultPrevented()) {
143
                        var $target = $(e.target),
144
                            // The button might contain HTML tag
145
                            $button = $target.is('[type="submit"]') ? $target.eq(0) : $target.parent('[type="submit"]').eq(0);
146
 
147
                        // Don't perform validation when clicking on the submit button/input
148
                        // which aren't defined by the 'submitButtons' option
149
                        if (that.options.submitButtons && !$button.is(that.options.submitButtons) && !$button.is(that.$hiddenButton)) {
150
                            that.$form.off('submit.bv').submit();
151
                        }
152
                    }
153
                });
154
 
155
            for (var field in this.options.fields) {
156
                this._initField(field);
157
            }
158
 
159
            this.$form.trigger($.Event(this.options.events.formInit), {
160
                bv: this,
161
                options: this.options
162
            });
163
 
164
            // Prepare the events
165
            if (this.options.onSuccess) {
166
                this.$form.on(this.options.events.formSuccess, function(e) {
167
                    $.fn.bootstrapValidator.helpers.call(that.options.onSuccess, [e]);
168
                });
169
            }
170
            if (this.options.onError) {
171
                this.$form.on(this.options.events.formError, function(e) {
172
                    $.fn.bootstrapValidator.helpers.call(that.options.onError, [e]);
173
                });
174
            }
175
        },
176
 
177
        /**
178
         * Parse the validator options from HTML attributes
179
         *
180
         * @param {jQuery} $field The field element
181
         * @returns {Object}
182
         */
183
        _parseOptions: function($field) {
184
            var field      = $field.attr('name') || $field.attr('data-bv-field'),
185
                validators = {},
186
                validator,
187
                v,          // Validator name
188
                attrName,
189
                enabled,
190
                optionName,
191
                optionAttrName,
192
                optionValue,
193
                html5AttrName,
194
                html5AttrMap;
195
 
196
            for (v in $.fn.bootstrapValidator.validators) {
197
                validator    = $.fn.bootstrapValidator.validators[v];
198
                attrName     = 'data-bv-' + v.toLowerCase(),
199
                enabled      = $field.attr(attrName) + '';
200
                html5AttrMap = ('function' === typeof validator.enableByHtml5) ? validator.enableByHtml5($field) : null;
201
 
202
                if ((html5AttrMap && enabled !== 'false')
203
                    || (html5AttrMap !== true && ('' === enabled || 'true' === enabled || attrName === enabled.toLowerCase())))
204
                {
205
                    // Try to parse the options via attributes
206
                    validator.html5Attributes = $.extend({}, { message: 'message', onerror: 'onError', onsuccess: 'onSuccess' }, validator.html5Attributes);
207
                    validators[v] = $.extend({}, html5AttrMap === true ? {} : html5AttrMap, validators[v]);
208
 
209
                    for (html5AttrName in validator.html5Attributes) {
210
                        optionName  = validator.html5Attributes[html5AttrName];
211
                        optionAttrName = 'data-bv-' + v.toLowerCase() + '-' + html5AttrName,
212
                        optionValue = $field.attr(optionAttrName);
213
                        if (optionValue) {
214
                            if ('true' === optionValue || optionAttrName === optionValue.toLowerCase()) {
215
                                optionValue = true;
216
                            } else if ('false' === optionValue) {
217
                                optionValue = false;
218
                            }
219
                            validators[v][optionName] = optionValue;
220
                        }
221
                    }
222
                }
223
            }
224
 
225
            var opts = {
226
                    autoFocus:     $field.attr('data-bv-autofocus'),
227
                    container:     $field.attr('data-bv-container'),
228
                    excluded:      $field.attr('data-bv-excluded'),
229
                    feedbackIcons: $field.attr('data-bv-feedbackicons'),
230
                    group:         $field.attr('data-bv-group'),
231
                    message:       $field.attr('data-bv-message'),
232
                    onError:       $field.attr('data-bv-onerror'),
233
                    onStatus:      $field.attr('data-bv-onstatus'),
234
                    onSuccess:     $field.attr('data-bv-onsuccess'),
235
                    selector:      $field.attr('data-bv-selector'),
236
                    threshold:     $field.attr('data-bv-threshold'),
237
                    trigger:       $field.attr('data-bv-trigger'),
238
                    verbose:       $field.attr('data-bv-verbose'),
239
                    validators:    validators
240
                },
241
                emptyOptions    = $.isEmptyObject(opts),        // Check if the field options are set using HTML attributes
242
                emptyValidators = $.isEmptyObject(validators);  // Check if the field validators are set using HTML attributes
243
 
244
            if (!emptyValidators || (!emptyOptions && this.options.fields && this.options.fields[field])) {
245
                opts.validators = validators;
246
                return opts;
247
            } else {
248
                return null;
249
            }
250
        },
251
 
252
        /**
253
         * Init field
254
         *
255
         * @param {String|jQuery} field The field name or field element
256
         */
257
        _initField: function(field) {
258
            var fields = $([]);
259
            switch (typeof field) {
260
                case 'object':
261
                    fields = field;
262
                    field  = field.attr('data-bv-field');
263
                    break;
264
                case 'string':
265
                    fields = this.getFieldElements(field);
266
                    fields.attr('data-bv-field', field);
267
                    break;
268
                default:
269
                    break;
270
            }
271
 
272
            // We don't need to validate non-existing fields
273
            if (fields.length === 0) {
274
                return;
275
            }
276
 
277
            if (this.options.fields[field] === null || this.options.fields[field].validators === null) {
278
                return;
279
            }
280
 
281
            var validatorName;
282
            for (validatorName in this.options.fields[field].validators) {
283
                if (!$.fn.bootstrapValidator.validators[validatorName]) {
284
                    delete this.options.fields[field].validators[validatorName];
285
                }
286
            }
287
            if (this.options.fields[field].enabled === null) {
288
                this.options.fields[field].enabled = true;
289
            }
290
 
291
            var that      = this,
292
                total     = fields.length,
293
                type      = fields.attr('type'),
294
                updateAll = (total === 1) || ('radio' === type) || ('checkbox' === type),
295
                event     = ('radio' === type || 'checkbox' === type || 'file' === type || 'SELECT' === fields.eq(0).get(0).tagName) ? 'change' : this._changeEvent,
296
                trigger   = (this.options.fields[field].trigger || this.options.trigger || event).split(' '),
297
                events    = $.map(trigger, function(item) {
298
                    return item + '.update.bv';
299
                }).join(' ');
300
 
301
            for (var i = 0; i < total; i++) {
302
                var $field    = fields.eq(i),
303
                    group     = this.options.fields[field].group || this.options.group,
304
                    $parent   = $field.parents(group),
305
                    // Allow user to indicate where the error messages are shown
306
                    container = ('function' === typeof (this.options.fields[field].container || this.options.container)) ? (this.options.fields[field].container || this.options.container).call(this, $field, this) : (this.options.fields[field].container || this.options.container),
307
                    $message  = (container && container !== 'tooltip' && container !== 'popover') ? $(container) : this._getMessageContainer($field, group);
308
 
309
                if (container && container !== 'tooltip' && container !== 'popover') {
310
                    $message.addClass('has-error');
311
                }
312
 
313
                // Remove all error messages and feedback icons
314
                $message.find('.help-block[data-bv-validator][data-bv-for="' + field + '"]').remove();
315
                $parent.find('i[data-bv-icon-for="' + field + '"]').remove();
316
 
317
                // Whenever the user change the field value, mark it as not validated yet
318
                $field.off(events).on(events, function() {
319
                    that.updateStatus($(this), that.STATUS_NOT_VALIDATED);
320
                });
321
 
322
                // Create help block elements for showing the error messages
323
                $field.data('bv.messages', $message);
324
                for (validatorName in this.options.fields[field].validators) {
325
                    $field.data('bv.result.' + validatorName, this.STATUS_NOT_VALIDATED);
326
 
327
                    if (!updateAll || i === total - 1) {
328
                        $('<small/>')
329
                            .css('display', 'none')
330
                            .addClass('help-block')
331
                            .attr('data-bv-validator', validatorName)
332
                            .attr('data-bv-for', field)
333
                            .attr('data-bv-result', this.STATUS_NOT_VALIDATED)
334
                            .html(this._getMessage(field, validatorName))
335
                            .appendTo($message);
336
                    }
337
 
338
                    // Init the validator
339
                    if ('function' === typeof $.fn.bootstrapValidator.validators[validatorName].init) {
340
                        $.fn.bootstrapValidator.validators[validatorName].init(this, $field, this.options.fields[field].validators[validatorName]);
341
                    }
342
                }
343
 
344
                // Prepare the feedback icons
345
                // Available from Bootstrap 3.1 (http://getbootstrap.com/css/#forms-control-validation)
346
                if (this.options.fields[field].feedbackIcons !== false && this.options.fields[field].feedbackIcons !== 'false'
347
                    && this.options.feedbackIcons
348
                    && this.options.feedbackIcons.validating && this.options.feedbackIcons.invalid && this.options.feedbackIcons.valid
349
                    && (!updateAll || i === total - 1))
350
                {
351
                    // $parent.removeClass('has-success').removeClass('has-error').addClass('has-feedback');
352
                    // Keep error messages which are populated from back-end
353
                    $parent.addClass('has-feedback');
354
                    var $icon = $('<i/>')
355
                                    .css('display', 'none')
356
                                    .addClass('form-control-feedback')
357
                                    .attr('data-bv-icon-for', field)
358
                                    .insertAfter($field);
359
 
360
                    // Place it after the container of checkbox/radio
361
                    // so when clicking the icon, it doesn't effect to the checkbox/radio element
362
                    if ('checkbox' === type || 'radio' === type) {
363
                        var $fieldParent = $field.parent();
364
                        if ($fieldParent.hasClass(type)) {
365
                            $icon.insertAfter($fieldParent);
366
                        } else if ($fieldParent.parent().hasClass(type)) {
367
                            $icon.insertAfter($fieldParent.parent());
368
                        }
369
                    }
370
 
371
                    // The feedback icon does not render correctly if there is no label
372
                    // https://github.com/twbs/bootstrap/issues/12873
373
                    if ($parent.find('label').length === 0) {
374
                        $icon.addClass('bv-no-label');
375
                    }
376
                    // Fix feedback icons in input-group
377
                    if ($parent.find('.input-group').length !== 0) {
378
                        $icon.addClass('bv-icon-input-group')
379
                             .insertAfter($parent.find('.input-group').eq(0));
380
                    }
381
 
382
                    // Store the icon as a data of field element
383
                    if (!updateAll) {
384
                        $field.data('bv.icon', $icon);
385
                    } else if (i === total - 1) {
386
                        // All fields with the same name have the same icon
387
                        fields.data('bv.icon', $icon);
388
                    }
389
 
390
                    if (container) {
391
                        $field
392
                            // Show tooltip/popover message when field gets focus
393
                            .off('focus.container.bv')
394
                            .on('focus.container.bv', function() {
395
                                switch (container) {
396
                                    case 'tooltip':
397
                                        $(this).data('bv.icon').tooltip('show');
398
                                        break;
399
                                    case 'popover':
400
                                        $(this).data('bv.icon').popover('show');
401
                                        break;
402
                                    default:
403
                                        break;
404
                                }
405
                            })
406
                            // and hide them when losing focus
407
                            .off('blur.container.bv')
408
                            .on('blur.container.bv', function() {
409
                                switch (container) {
410
                                    case 'tooltip':
411
                                        $(this).data('bv.icon').tooltip('hide');
412
                                        break;
413
                                    case 'popover':
414
                                        $(this).data('bv.icon').popover('hide');
415
                                        break;
416
                                    default:
417
                                        break;
418
                                }
419
                            });
420
                    }
421
                }
422
            }
423
 
424
            // Prepare the events
425
            fields
426
                .on(this.options.events.fieldSuccess, function(e, data) {
427
                    var onSuccess = that.getOptions(data.field, null, 'onSuccess');
428
                    if (onSuccess) {
429
                        $.fn.bootstrapValidator.helpers.call(onSuccess, [e, data]);
430
                    }
431
                })
432
                .on(this.options.events.fieldError, function(e, data) {
433
                    var onError = that.getOptions(data.field, null, 'onError');
434
                    if (onError) {
435
                        $.fn.bootstrapValidator.helpers.call(onError, [e, data]);
436
                    }
437
                })
438
                .on(this.options.events.fieldStatus, function(e, data) {
439
                    var onStatus = that.getOptions(data.field, null, 'onStatus');
440
                    if (onStatus) {
441
                        $.fn.bootstrapValidator.helpers.call(onStatus, [e, data]);
442
                    }
443
                })
444
                .on(this.options.events.validatorError, function(e, data) {
445
                    var onError = that.getOptions(data.field, data.validator, 'onError');
446
                    if (onError) {
447
                        $.fn.bootstrapValidator.helpers.call(onError, [e, data]);
448
                    }
449
                })
450
                .on(this.options.events.validatorSuccess, function(e, data) {
451
                    var onSuccess = that.getOptions(data.field, data.validator, 'onSuccess');
452
                    if (onSuccess) {
453
                        $.fn.bootstrapValidator.helpers.call(onSuccess, [e, data]);
454
                    }
455
                });
456
 
457
            // Set live mode
458
            events = $.map(trigger, function(item) {
459
                return item + '.live.bv';
460
            }).join(' ');
461
            switch (this.options.live) {
462
                case 'submitted':
463
                    break;
464
                case 'disabled':
465
                    fields.off(events);
466
                    break;
467
                case 'enabled':
468
                /* falls through */
469
                default:
470
                    fields.off(events).on(events, function() {
471
                        if (that._exceedThreshold($(this))) {
472
                            that.validateField($(this));
473
                        }
474
                    });
475
                    break;
476
            }
477
 
478
            fields.trigger($.Event(this.options.events.fieldInit), {
479
                bv: this,
480
                field: field,
481
                element: fields
482
            });
483
        },
484
 
485
        /**
486
         * Get the error message for given field and validator
487
         *
488
         * @param {String} field The field name
489
         * @param {String} validatorName The validator name
490
         * @returns {String}
491
         */
492
        _getMessage: function(field, validatorName) {
493
            if (!this.options.fields[field] || !$.fn.bootstrapValidator.validators[validatorName]
494
                || !this.options.fields[field].validators || !this.options.fields[field].validators[validatorName])
495
            {
496
                return '';
497
            }
498
 
499
            var options = this.options.fields[field].validators[validatorName];
500
            switch (true) {
501
                case (!!options.message):
502
                    return options.message;
503
                case (!!this.options.fields[field].message):
504
                    return this.options.fields[field].message;
505
                case (!!$.fn.bootstrapValidator.i18n[validatorName]):
506
                    return $.fn.bootstrapValidator.i18n[validatorName]['default'];
507
                default:
508
                    return this.options.message;
509
            }
510
        },
511
 
512
        /**
513
         * Get the element to place the error messages
514
         *
515
         * @param {jQuery} $field The field element
516
         * @param {String} group
517
         * @returns {jQuery}
518
         */
519
        _getMessageContainer: function($field, group) {
520
            var $parent = $field.parent();
521
            if ($parent.is(group)) {
522
                return $parent;
523
            }
524
 
525
            var cssClasses = $parent.attr('class');
526
            if (!cssClasses) {
527
                return this._getMessageContainer($parent, group);
528
            }
529
 
530
            cssClasses = cssClasses.split(' ');
531
            var n = cssClasses.length;
532
            for (var i = 0; i < n; i++) {
533
                if (/^col-(xs|sm|md|lg)-\d+$/.test(cssClasses[i]) || /^col-(xs|sm|md|lg)-offset-\d+$/.test(cssClasses[i])) {
534
                    return $parent;
535
                }
536
            }
537
 
538
            return this._getMessageContainer($parent, group);
539
        },
540
 
541
        /**
542
         * Called when all validations are completed
543
         */
544
        _submit: function() {
545
            var isValid   = this.isValid(),
546
                eventType = isValid ? this.options.events.formSuccess : this.options.events.formError,
547
                e         = $.Event(eventType);
548
 
549
            this.$form.trigger(e);
550
 
551
            // Call default handler
552
            // Check if whether the submit button is clicked
553
            if (this.$submitButton) {
554
                isValid ? this._onSuccess(e) : this._onError(e);
555
            }
556
        },
557
 
558
        /**
559
         * Check if the field is excluded.
560
         * Returning true means that the field will not be validated
561
         *
562
         * @param {jQuery} $field The field element
563
         * @returns {Boolean}
564
         */
565
        _isExcluded: function($field) {
566
            var excludedAttr = $field.attr('data-bv-excluded'),
567
                // I still need to check the 'name' attribute while initializing the field
568
                field        = $field.attr('data-bv-field') || $field.attr('name');
569
 
570
            switch (true) {
571
                case (!!field && this.options.fields && this.options.fields[field] && (this.options.fields[field].excluded === 'true' || this.options.fields[field].excluded === true)):
572
                case (excludedAttr === 'true'):
573
                case (excludedAttr === ''):
574
                    return true;
575
 
576
                case (!!field && this.options.fields && this.options.fields[field] && (this.options.fields[field].excluded === 'false' || this.options.fields[field].excluded === false)):
577
                case (excludedAttr === 'false'):
578
                    return false;
579
 
580
                default:
581
                    if (this.options.excluded) {
582
                        // Convert to array first
583
                        if ('string' === typeof this.options.excluded) {
584
                            this.options.excluded = $.map(this.options.excluded.split(','), function(item) {
585
                                // Trim the spaces
586
                                return $.trim(item);
587
                            });
588
                        }
589
 
590
                        var length = this.options.excluded.length;
591
                        for (var i = 0; i < length; i++) {
592
                            if (('string' === typeof this.options.excluded[i] && $field.is(this.options.excluded[i]))
593
                                || ('function' === typeof this.options.excluded[i] && this.options.excluded[i].call(this, $field, this) === true))
594
                            {
595
                                return true;
596
                            }
597
                        }
598
                    }
599
                    return false;
600
            }
601
        },
602
 
603
        /**
604
         * Check if the number of characters of field value exceed the threshold or not
605
         *
606
         * @param {jQuery} $field The field element
607
         * @returns {Boolean}
608
         */
609
        _exceedThreshold: function($field) {
610
            var field     = $field.attr('data-bv-field'),
611
                threshold = this.options.fields[field].threshold || this.options.threshold;
612
            if (!threshold) {
613
                return true;
614
            }
615
            var cannotType = $.inArray($field.attr('type'), ['button', 'checkbox', 'file', 'hidden', 'image', 'radio', 'reset', 'submit']) !== -1;
616
            return (cannotType || $field.val().length >= threshold);
617
        },
618
 
619
        // ---
620
        // Events
621
        // ---
622
 
623
        /**
624
         * The default handler of error.form.bv event.
625
         * It will be called when there is a invalid field
626
         *
627
         * @param {jQuery.Event} e The jQuery event object
628
         */
629
        _onError: function(e) {
630
            if (e.isDefaultPrevented()) {
631
                return;
632
            }
633
 
634
            if ('submitted' === this.options.live) {
635
                // Enable live mode
636
                this.options.live = 'enabled';
637
                var that = this;
638
                for (var field in this.options.fields) {
639
                    (function(f) {
640
                        var fields  = that.getFieldElements(f);
641
                        if (fields.length) {
642
                            var type    = $(fields[0]).attr('type'),
643
                                event   = ('radio' === type || 'checkbox' === type || 'file' === type || 'SELECT' === $(fields[0]).get(0).tagName) ? 'change' : that._changeEvent,
644
                                trigger = that.options.fields[field].trigger || that.options.trigger || event,
645
                                events  = $.map(trigger.split(' '), function(item) {
646
                                    return item + '.live.bv';
647
                                }).join(' ');
648
 
649
                            fields.off(events).on(events, function() {
650
                                if (that._exceedThreshold($(this))) {
651
                                    that.validateField($(this));
652
                                }
653
                            });
654
                        }
655
                    })(field);
656
                }
657
            }
658
 
659
            // Determined the first invalid field which will be focused on automatically
660
            for (var i = 0; i < this.$invalidFields.length; i++) {
661
                var $field    = this.$invalidFields.eq(i),
662
                    autoFocus = this._isOptionEnabled($field.attr('data-bv-field'), 'autoFocus');
663
                if (autoFocus) {
664
                    // Activate the tab containing the field if exists
665
                    var $tabPane = $field.parents('.tab-pane'), tabId;
666
                    if ($tabPane && (tabId = $tabPane.attr('id'))) {
667
                        $('a[href="#' + tabId + '"][data-toggle="tab"]').tab('show');
668
                    }
669
 
670
                    // Focus the field
671
                    $field.focus();
672
                    break;
673
                }
674
            }
675
        },
676
 
677
        /**
678
         * The default handler of success.form.bv event.
679
         * It will be called when all the fields are valid
680
         *
681
         * @param {jQuery.Event} e The jQuery event object
682
         */
683
        _onSuccess: function(e) {
684
            if (e.isDefaultPrevented()) {
685
                return;
686
            }
687
 
688
            // Submit the form
689
            this.disableSubmitButtons(true).defaultSubmit();
690
        },
691
 
692
        /**
693
         * Called after validating a field element
694
         *
695
         * @param {jQuery} $field The field element
696
         * @param {String} [validatorName] The validator name
697
         */
698
        _onFieldValidated: function($field, validatorName) {
699
            var field         = $field.attr('data-bv-field'),
700
                validators    = this.options.fields[field].validators,
701
                counter       = {},
702
                numValidators = 0,
703
                data          = {
704
                    bv: this,
705
                    field: field,
706
                    element: $field,
707
                    validator: validatorName,
708
                    result: $field.data('bv.response.' + validatorName)
709
                };
710
 
711
            // Trigger an event after given validator completes
712
            if (validatorName) {
713
                switch ($field.data('bv.result.' + validatorName)) {
714
                    case this.STATUS_INVALID:
715
                        $field.trigger($.Event(this.options.events.validatorError), data);
716
                        break;
717
                    case this.STATUS_VALID:
718
                        $field.trigger($.Event(this.options.events.validatorSuccess), data);
719
                        break;
720
                    default:
721
                        break;
722
                }
723
            }
724
 
725
            counter[this.STATUS_NOT_VALIDATED] = 0;
726
            counter[this.STATUS_VALIDATING]    = 0;
727
            counter[this.STATUS_INVALID]       = 0;
728
            counter[this.STATUS_VALID]         = 0;
729
 
730
            for (var v in validators) {
731
                if (validators[v].enabled === false) {
732
                    continue;
733
                }
734
 
735
                numValidators++;
736
                var result = $field.data('bv.result.' + v);
737
                if (result) {
738
                    counter[result]++;
739
                }
740
            }
741
 
742
            if (counter[this.STATUS_VALID] === numValidators) {
743
                // Remove from the list of invalid fields
744
                this.$invalidFields = this.$invalidFields.not($field);
745
 
746
                $field.trigger($.Event(this.options.events.fieldSuccess), data);
747
            }
748
            // If all validators are completed and there is at least one validator which doesn't pass
749
            else if ((counter[this.STATUS_NOT_VALIDATED] === 0 || !this._isOptionEnabled(field, 'verbose')) && counter[this.STATUS_VALIDATING] === 0 && counter[this.STATUS_INVALID] > 0) {
750
                // Add to the list of invalid fields
751
                this.$invalidFields = this.$invalidFields.add($field);
752
 
753
                $field.trigger($.Event(this.options.events.fieldError), data);
754
            }
755
        },
756
 
757
        /**
758
         * Check whether or not a field option is enabled
759
         *
760
         * @param {String} field The field name
761
         * @param {String} option The option name, "verbose", "autoFocus", for example
762
         * @returns {Boolean}
763
         */
764
        _isOptionEnabled: function(field, option) {
765
            if (this.options.fields[field] && (this.options.fields[field][option] === 'true' || this.options.fields[field][option] === true)) {
766
                return true;
767
            }
768
            if (this.options.fields[field] && (this.options.fields[field][option] === 'false' || this.options.fields[field][option] === false)) {
769
                return false;
770
            }
771
            return this.options[option] === 'true' || this.options[option] === true;
772
        },
773
 
774
        // ---
775
        // Public methods
776
        // ---
777
 
778
        /**
779
         * Retrieve the field elements by given name
780
         *
781
         * @param {String} field The field name
782
         * @returns {null|jQuery[]}
783
         */
784
        getFieldElements: function(field) {
785
            if (!this._cacheFields[field]) {
786
                this._cacheFields[field] = (this.options.fields[field] && this.options.fields[field].selector)
787
                                         ? $(this.options.fields[field].selector)
788
                                         : this.$form.find('[name="' + field + '"]');
789
            }
790
 
791
            return this._cacheFields[field];
792
        },
793
 
794
        /**
795
         * Get the field options
796
         *
797
         * @param {String|jQuery} [field] The field name or field element. If it is not set, the method returns the form options
798
         * @param {String} [validator] The name of validator. It null, the method returns form options
799
         * @param {String} [option] The option name
800
         * @return {String|Object}
801
         */
802
        getOptions: function(field, validator, option) {
803
            if (!field) {
804
                return option ? this.options[option] : this.options;
805
            }
806
            if ('object' === typeof field) {
807
                field = field.attr('data-bv-field');
808
            }
809
            if (!this.options.fields[field]) {
810
                return null;
811
            }
812
 
813
            var options = this.options.fields[field];
814
            if (!validator) {
815
                return option ? options[option] : options;
816
            }
817
            if (!options.validators || !options.validators[validator]) {
818
                return null;
819
            }
820
 
821
            return option ? options.validators[validator][option] : options.validators[validator];
822
        },
823
 
824
        /**
825
         * Disable/enable submit buttons
826
         *
827
         * @param {Boolean} disabled Can be true or false
828
         * @returns {BootstrapValidator}
829
         */
830
        disableSubmitButtons: function(disabled) {
831
            if (!disabled) {
832
                this.$form.find(this.options.submitButtons).removeAttr('disabled');
833
            } else if (this.options.live !== 'disabled') {
834
                // Don't disable if the live validating mode is disabled
835
                this.$form.find(this.options.submitButtons).attr('disabled', 'disabled');
836
            }
837
 
838
            return this;
839
        },
840
 
841
        /**
842
         * Validate the form
843
         *
844
         * @returns {BootstrapValidator}
845
         */
846
        validate: function() {
847
            if (!this.options.fields) {
848
                return this;
849
            }
850
            this.disableSubmitButtons(true);
851
 
852
            this._submitIfValid = false;
853
            for (var field in this.options.fields) {
854
                this.validateField(field);
855
            }
856
 
857
            this._submit();
858
            this._submitIfValid = true;
859
 
860
            return this;
861
        },
862
 
863
        /**
864
         * Validate given field
865
         *
866
         * @param {String|jQuery} field The field name or field element
867
         * @returns {BootstrapValidator}
868
         */
869
        validateField: function(field) {
870
            var fields = $([]);
871
            switch (typeof field) {
872
                case 'object':
873
                    fields = field;
874
                    field  = field.attr('data-bv-field');
875
                    break;
876
                case 'string':
877
                    fields = this.getFieldElements(field);
878
                    break;
879
                default:
880
                    break;
881
            }
882
 
883
            if (fields.length === 0 || !this.options.fields[field] || this.options.fields[field].enabled === false) {
884
                return this;
885
            }
886
 
887
            var that       = this,
888
                type       = fields.attr('type'),
889
                total      = ('radio' === type || 'checkbox' === type) ? 1 : fields.length,
890
                updateAll  = ('radio' === type || 'checkbox' === type),
891
                validators = this.options.fields[field].validators,
892
                verbose    = this._isOptionEnabled(field, 'verbose'),
893
                validatorName,
894
                validateResult;
895
 
896
            for (var i = 0; i < total; i++) {
897
                var $field = fields.eq(i);
898
                if (this._isExcluded($field)) {
899
                    continue;
900
                }
901
 
902
                var stop = false;
903
                for (validatorName in validators) {
904
                    if ($field.data('bv.dfs.' + validatorName)) {
905
                        $field.data('bv.dfs.' + validatorName).reject();
906
                    }
907
                    if (stop) {
908
                        break;
909
                    }
910
 
911
                    // Don't validate field if it is already done
912
                    var result = $field.data('bv.result.' + validatorName);
913
                    if (result === this.STATUS_VALID || result === this.STATUS_INVALID) {
914
                        this._onFieldValidated($field, validatorName);
915
                        continue;
916
                    } else if (validators[validatorName].enabled === false) {
917
                        this.updateStatus(updateAll ? field : $field, this.STATUS_VALID, validatorName);
918
                        continue;
919
                    }
920
 
921
                    $field.data('bv.result.' + validatorName, this.STATUS_VALIDATING);
922
                    validateResult = $.fn.bootstrapValidator.validators[validatorName].validate(this, $field, validators[validatorName]);
923
 
924
                    // validateResult can be a $.Deferred object ...
925
                    if ('object' === typeof validateResult && validateResult.resolve) {
926
                        this.updateStatus(updateAll ? field : $field, this.STATUS_VALIDATING, validatorName);
927
                        $field.data('bv.dfs.' + validatorName, validateResult);
928
 
929
                        validateResult.done(function($f, v, response) {
930
                            // v is validator name
931
                            $f.removeData('bv.dfs.' + v).data('bv.response.' + v, response);
932
                            if (response.message) {
933
                                that.updateMessage($f, v, response.message);
934
                            }
935
 
936
                            that.updateStatus(updateAll ? $f.attr('data-bv-field') : $f, response.valid ? that.STATUS_VALID : that.STATUS_INVALID, v);
937
 
938
                            if (response.valid && that._submitIfValid === true) {
939
                                // If a remote validator returns true and the form is ready to submit, then do it
940
                                that._submit();
941
                            } else if (!response.valid && !verbose) {
942
                                stop = true;
943
                            }
944
                        });
945
                    }
946
                    // ... or object { valid: true/false, message: 'dynamic message' }
947
                    else if ('object' === typeof validateResult && validateResult.valid !== undefined && validateResult.message !== undefined) {
948
                        $field.data('bv.response.' + validatorName, validateResult);
949
                        this.updateMessage(updateAll ? field : $field, validatorName, validateResult.message);
950
                        this.updateStatus(updateAll ? field : $field, validateResult.valid ? this.STATUS_VALID : this.STATUS_INVALID, validatorName);
951
                        if (!validateResult.valid && !verbose) {
952
                            break;
953
                        }
954
                    }
955
                    // ... or a boolean value
956
                    else if ('boolean' === typeof validateResult) {
957
                        $field.data('bv.response.' + validatorName, validateResult);
958
                        this.updateStatus(updateAll ? field : $field, validateResult ? this.STATUS_VALID : this.STATUS_INVALID, validatorName);
959
                        if (!validateResult && !verbose) {
960
                            break;
961
                        }
962
                    }
963
                }
964
            }
965
 
966
            return this;
967
        },
968
 
969
        /**
970
         * Update the error message
971
         *
972
         * @param {String|jQuery} field The field name or field element
973
         * @param {String} validator The validator name
974
         * @param {String} message The message
975
         * @returns {BootstrapValidator}
976
         */
977
        updateMessage: function(field, validator, message) {
978
            var $fields = $([]);
979
            switch (typeof field) {
980
                case 'object':
981
                    $fields = field;
982
                    field   = field.attr('data-bv-field');
983
                    break;
984
                case 'string':
985
                    $fields = this.getFieldElements(field);
986
                    break;
987
                default:
988
                    break;
989
            }
990
 
991
            $fields.each(function() {
992
                $(this).data('bv.messages').find('.help-block[data-bv-validator="' + validator + '"][data-bv-for="' + field + '"]').html(message);
993
            });
994
        },
995
 
996
        /**
997
         * Update all validating results of field
998
         *
999
         * @param {String|jQuery} field The field name or field element
1000
         * @param {String} status The status. Can be 'NOT_VALIDATED', 'VALIDATING', 'INVALID' or 'VALID'
1001
         * @param {String} [validatorName] The validator name. If null, the method updates validity result for all validators
1002
         * @returns {BootstrapValidator}
1003
         */
1004
        updateStatus: function(field, status, validatorName) {
1005
            var fields = $([]);
1006
            switch (typeof field) {
1007
                case 'object':
1008
                    fields = field;
1009
                    field  = field.attr('data-bv-field');
1010
                    break;
1011
                case 'string':
1012
                    fields = this.getFieldElements(field);
1013
                    break;
1014
                default:
1015
                    break;
1016
            }
1017
 
1018
            if (status === this.STATUS_NOT_VALIDATED) {
1019
                // Reset the flag
1020
                // To prevent the form from doing submit when a deferred validator returns true while typing
1021
                this._submitIfValid = false;
1022
            }
1023
 
1024
            var that  = this,
1025
                type  = fields.attr('type'),
1026
                group = this.options.fields[field].group || this.options.group,
1027
                total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length;
1028
 
1029
            for (var i = 0; i < total; i++) {
1030
                var $field       = fields.eq(i);
1031
                if (this._isExcluded($field)) {
1032
                    continue;
1033
                }
1034
 
1035
                var $parent      = $field.parents(group),
1036
                    $message     = $field.data('bv.messages'),
1037
                    $allErrors   = $message.find('.help-block[data-bv-validator][data-bv-for="' + field + '"]'),
1038
                    $errors      = validatorName ? $allErrors.filter('[data-bv-validator="' + validatorName + '"]') : $allErrors,
1039
                    $icon        = $field.data('bv.icon'),
1040
                    container    = ('function' === typeof (this.options.fields[field].container || this.options.container)) ? (this.options.fields[field].container || this.options.container).call(this, $field, this) : (this.options.fields[field].container || this.options.container),
1041
                    isValidField = null;
1042
 
1043
                // Update status
1044
                if (validatorName) {
1045
                    $field.data('bv.result.' + validatorName, status);
1046
                } else {
1047
                    for (var v in this.options.fields[field].validators) {
1048
                        $field.data('bv.result.' + v, status);
1049
                    }
1050
                }
1051
 
1052
                // Show/hide error elements and feedback icons
1053
                $errors.attr('data-bv-result', status);
1054
 
1055
                // Determine the tab containing the element
1056
                var $tabPane = $field.parents('.tab-pane'),
1057
                    tabId, $tab;
1058
                if ($tabPane && (tabId = $tabPane.attr('id'))) {
1059
                    $tab = $('a[href="#' + tabId + '"][data-toggle="tab"]').parent();
1060
                }
1061
 
1062
                switch (status) {
1063
                    case this.STATUS_VALIDATING:
1064
                        isValidField = null;
1065
                        this.disableSubmitButtons(true);
1066
                        $parent.removeClass('has-success').removeClass('has-error');
1067
                        if ($icon) {
1068
                            $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.invalid).addClass(this.options.feedbackIcons.validating).show();
1069
                        }
1070
                        if ($tab) {
1071
                            $tab.removeClass('bv-tab-success').removeClass('bv-tab-error');
1072
                        }
1073
                        break;
1074
 
1075
                    case this.STATUS_INVALID:
1076
                        isValidField = false;
1077
                        this.disableSubmitButtons(true);
1078
                        $parent.removeClass('has-success').addClass('has-error');
1079
                        if ($icon) {
1080
                            $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.validating).addClass(this.options.feedbackIcons.invalid).show();
1081
                        }
1082
                        if ($tab) {
1083
                            $tab.removeClass('bv-tab-success').addClass('bv-tab-error');
1084
                        }
1085
                        break;
1086
 
1087
                    case this.STATUS_VALID:
1088
                        // If the field is valid (passes all validators)
1089
                        isValidField = ($allErrors.filter('[data-bv-result="' + this.STATUS_NOT_VALIDATED +'"]').length === 0)
1090
                                     ? ($allErrors.filter('[data-bv-result="' + this.STATUS_VALID +'"]').length === $allErrors.length)  // All validators are completed
1091
                                     : null;                                                                                            // There are some validators that have not done
1092
                        if (isValidField !== null) {
1093
                            this.disableSubmitButtons(this.$submitButton ? !this.isValid() : !isValidField);
1094
                            if ($icon) {
1095
                                $icon
1096
                                    .removeClass(this.options.feedbackIcons.invalid).removeClass(this.options.feedbackIcons.validating).removeClass(this.options.feedbackIcons.valid)
1097
                                    .addClass(isValidField ? this.options.feedbackIcons.valid : this.options.feedbackIcons.invalid)
1098
                                    .show();
1099
                            }
1100
                        }
1101
 
1102
                        $parent.removeClass('has-error has-success').addClass(this.isValidContainer($parent) ? 'has-success' : 'has-error');
1103
                        if ($tab) {
1104
                            $tab.removeClass('bv-tab-success').removeClass('bv-tab-error').addClass(this.isValidContainer($tabPane) ? 'bv-tab-success' : 'bv-tab-error');
1105
                        }
1106
                        break;
1107
 
1108
                    case this.STATUS_NOT_VALIDATED:
1109
                    /* falls through */
1110
                    default:
1111
                        isValidField = null;
1112
                        this.disableSubmitButtons(false);
1113
                        $parent.removeClass('has-success').removeClass('has-error');
1114
                        if ($icon) {
1115
                            $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.invalid).removeClass(this.options.feedbackIcons.validating).hide();
1116
                        }
1117
                        if ($tab) {
1118
                            $tab.removeClass('bv-tab-success').removeClass('bv-tab-error');
1119
                        }
1120
                        break;
1121
                }
1122
 
1123
                switch (true) {
1124
                    // Only show the first error message if it is placed inside a tooltip ...
1125
                    case ($icon && 'tooltip' === container):
1126
                        (isValidField === false)
1127
                                ? $icon.css('cursor', 'pointer').tooltip('destroy').tooltip({
1128
                                    container: 'body',
1129
                                    html: true,
1130
                                    placement: 'auto top',
1131
                                    title: $allErrors.filter('[data-bv-result="' + that.STATUS_INVALID + '"]').eq(0).html()
1132
                                })
1133
                                : $icon.css('cursor', '').tooltip('destroy');
1134
                        break;
1135
                    // ... or popover
1136
                    case ($icon && 'popover' === container):
1137
                        (isValidField === false)
1138
                                ? $icon.css('cursor', 'pointer').popover('destroy').popover({
1139
                                    container: 'body',
1140
                                    content: $allErrors.filter('[data-bv-result="' + that.STATUS_INVALID + '"]').eq(0).html(),
1141
                                    html: true,
1142
                                    placement: 'auto top',
1143
                                    trigger: 'hover click'
1144
                                })
1145
                                : $icon.css('cursor', '').popover('destroy');
1146
                        break;
1147
                    default:
1148
                        (status === this.STATUS_INVALID) ? $errors.show() : $errors.hide();
1149
                        break;
1150
                }
1151
 
1152
                // Trigger an event
1153
                $field.trigger($.Event(this.options.events.fieldStatus), {
1154
                    bv: this,
1155
                    field: field,
1156
                    element: $field,
1157
                    status: status
1158
                });
1159
                this._onFieldValidated($field, validatorName);
1160
            }
1161
 
1162
            return this;
1163
        },
1164
 
1165
        /**
1166
         * Check the form validity
1167
         *
1168
         * @returns {Boolean}
1169
         */
1170
        isValid: function() {
1171
            for (var field in this.options.fields) {
1172
                if (!this.isValidField(field)) {
1173
                    return false;
1174
                }
1175
            }
1176
 
1177
            return true;
1178
        },
1179
 
1180
        /**
1181
         * Check if the field is valid or not
1182
         *
1183
         * @param {String|jQuery} field The field name or field element
1184
         * @returns {Boolean}
1185
         */
1186
        isValidField: function(field) {
1187
            var fields = $([]);
1188
            switch (typeof field) {
1189
                case 'object':
1190
                    fields = field;
1191
                    field  = field.attr('data-bv-field');
1192
                    break;
1193
                case 'string':
1194
                    fields = this.getFieldElements(field);
1195
                    break;
1196
                default:
1197
                    break;
1198
            }
1199
            if (fields.length === 0 || !this.options.fields[field] || this.options.fields[field].enabled === false) {
1200
                return true;
1201
            }
1202
 
1203
            var type  = fields.attr('type'),
1204
                total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length,
1205
                $field, validatorName, status;
1206
            for (var i = 0; i < total; i++) {
1207
                $field = fields.eq(i);
1208
                if (this._isExcluded($field)) {
1209
                    continue;
1210
                }
1211
 
1212
                for (validatorName in this.options.fields[field].validators) {
1213
                    if (this.options.fields[field].validators[validatorName].enabled === false) {
1214
                        continue;
1215
                    }
1216
 
1217
                    status = $field.data('bv.result.' + validatorName);
1218
                    if (status !== this.STATUS_VALID) {
1219
                        return false;
1220
                    }
1221
                }
1222
            }
1223
 
1224
            return true;
1225
        },
1226
 
1227
        /**
1228
         * Check if all fields inside a given container are valid.
1229
         * It's useful when working with a wizard-like such as tab, collapse
1230
         *
1231
         * @param {String|jQuery} container The container selector or element
1232
         * @returns {Boolean}
1233
         */
1234
        isValidContainer: function(container) {
1235
            var that       = this,
1236
                map        = {},
1237
                $container = ('string' === typeof container) ? $(container) : container;
1238
            if ($container.length === 0) {
1239
                return true;
1240
            }
1241
 
1242
            $container.find('[data-bv-field]').each(function() {
1243
                var $field = $(this),
1244
                    field  = $field.attr('data-bv-field');
1245
                if (!that._isExcluded($field) && !map[field]) {
1246
                    map[field] = $field;
1247
                }
1248
            });
1249
 
1250
            for (var field in map) {
1251
                var $f = map[field];
1252
                if ($f.data('bv.messages')
1253
                      .find('.help-block[data-bv-validator][data-bv-for="' + field + '"]')
1254
                      .filter('[data-bv-result="' + this.STATUS_INVALID +'"]')
1255
                      .length > 0)
1256
                {
1257
                    return false;
1258
                }
1259
            }
1260
 
1261
            return true;
1262
        },
1263
 
1264
        /**
1265
         * Submit the form using default submission.
1266
         * It also does not perform any validations when submitting the form
1267
         */
1268
        defaultSubmit: function() {
1269
            if (this.$submitButton) {
1270
                // Create hidden input to send the submit buttons
1271
                $('<input/>')
1272
                    .attr('type', 'hidden')
1273
                    .attr('data-bv-submit-hidden', '')
1274
                    .attr('name', this.$submitButton.attr('name'))
1275
                    .val(this.$submitButton.val())
1276
                    .appendTo(this.$form);
1277
            }
1278
 
1279
            // Submit form
1280
            this.$form.off('submit.bv').submit();
1281
        },
1282
 
1283
        // ---
1284
        // Useful APIs which aren't used internally
1285
        // ---
1286
 
1287
        /**
1288
         * Get the list of invalid fields
1289
         *
1290
         * @returns {jQuery[]}
1291
         */
1292
        getInvalidFields: function() {
1293
            return this.$invalidFields;
1294
        },
1295
 
1296
        /**
1297
         * Returns the clicked submit button
1298
         *
1299
         * @returns {jQuery}
1300
         */
1301
        getSubmitButton: function() {
1302
            return this.$submitButton;
1303
        },
1304
 
1305
        /**
1306
         * Get the error messages
1307
         *
1308
         * @param {String|jQuery} [field] The field name or field element
1309
         * If the field is not defined, the method returns all error messages of all fields
1310
         * @param {String} [validator] The name of validator
1311
         * If the validator is not defined, the method returns error messages of all validators
1312
         * @returns {String[]}
1313
         */
1314
        getMessages: function(field, validator) {
1315
            var that     = this,
1316
                messages = [],
1317
                $fields  = $([]);
1318
 
1319
            switch (true) {
1320
                case (field && 'object' === typeof field):
1321
                    $fields = field;
1322
                    break;
1323
                case (field && 'string' === typeof field):
1324
                    var f = this.getFieldElements(field);
1325
                    if (f.length > 0) {
1326
                        var type = f.attr('type');
1327
                        $fields = ('radio' === type || 'checkbox' === type) ? f.eq(0) : f;
1328
                    }
1329
                    break;
1330
                default:
1331
                    $fields = this.$invalidFields;
1332
                    break;
1333
            }
1334
 
1335
            var filter = validator ? '[data-bv-validator="' + validator + '"]' : '';
1336
            $fields.each(function() {
1337
                messages = messages.concat(
1338
                    $(this)
1339
                        .data('bv.messages')
1340
                        .find('.help-block[data-bv-for="' + $(this).attr('data-bv-field') + '"][data-bv-result="' + that.STATUS_INVALID + '"]' + filter)
1341
                        .map(function() {
1342
                            var v = $(this).attr('data-bv-validator'),
1343
                                f = $(this).attr('data-bv-for');
1344
                            return (that.options.fields[f].validators[v].enabled === false) ? '' : $(this).html();
1345
                        })
1346
                        .get()
1347
                );
1348
            });
1349
 
1350
            return messages;
1351
        },
1352
 
1353
        /**
1354
         * Update the option of a specific validator
1355
         *
1356
         * @param {String|jQuery} field The field name or field element
1357
         * @param {String} validator The validator name
1358
         * @param {String} option The option name
1359
         * @param {String} value The value to set
1360
         * @returns {BootstrapValidator}
1361
         */
1362
        updateOption: function(field, validator, option, value) {
1363
            if ('object' === typeof field) {
1364
                field = field.attr('data-bv-field');
1365
            }
1366
            if (this.options.fields[field] && this.options.fields[field].validators[validator]) {
1367
                this.options.fields[field].validators[validator][option] = value;
1368
                this.updateStatus(field, this.STATUS_NOT_VALIDATED, validator);
1369
            }
1370
 
1371
            return this;
1372
        },
1373
 
1374
        /**
1375
         * Add a new field
1376
         *
1377
         * @param {String|jQuery} field The field name or field element
1378
         * @param {Object} [options] The validator rules
1379
         * @returns {BootstrapValidator}
1380
         */
1381
        addField: function(field, options) {
1382
            var fields = $([]);
1383
            switch (typeof field) {
1384
                case 'object':
1385
                    fields = field;
1386
                    field  = field.attr('data-bv-field') || field.attr('name');
1387
                    break;
1388
                case 'string':
1389
                    delete this._cacheFields[field];
1390
                    fields = this.getFieldElements(field);
1391
                    break;
1392
                default:
1393
                    break;
1394
            }
1395
 
1396
            fields.attr('data-bv-field', field);
1397
 
1398
            var type  = fields.attr('type'),
1399
                total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length;
1400
 
1401
            for (var i = 0; i < total; i++) {
1402
                var $field = fields.eq(i);
1403
 
1404
                // Try to parse the options from HTML attributes
1405
                var opts = this._parseOptions($field);
1406
                opts = (opts === null) ? options : $.extend(true, options, opts);
1407
 
1408
                this.options.fields[field] = $.extend(true, this.options.fields[field], opts);
1409
 
1410
                // Update the cache
1411
                this._cacheFields[field] = this._cacheFields[field] ? this._cacheFields[field].add($field) : $field;
1412
 
1413
                // Init the element
1414
                this._initField(('checkbox' === type || 'radio' === type) ? field : $field);
1415
            }
1416
 
1417
            this.disableSubmitButtons(false);
1418
            // Trigger an event
1419
            this.$form.trigger($.Event(this.options.events.fieldAdded), {
1420
                field: field,
1421
                element: fields,
1422
                options: this.options.fields[field]
1423
            });
1424
 
1425
            return this;
1426
        },
1427
 
1428
        /**
1429
         * Remove a given field
1430
         *
1431
         * @param {String|jQuery} field The field name or field element
1432
         * @returns {BootstrapValidator}
1433
         */
1434
        removeField: function(field) {
1435
            var fields = $([]);
1436
            switch (typeof field) {
1437
                case 'object':
1438
                    fields = field;
1439
                    field  = field.attr('data-bv-field') || field.attr('name');
1440
                    fields.attr('data-bv-field', field);
1441
                    break;
1442
                case 'string':
1443
                    fields = this.getFieldElements(field);
1444
                    break;
1445
                default:
1446
                    break;
1447
            }
1448
 
1449
            if (fields.length === 0) {
1450
                return this;
1451
            }
1452
 
1453
            var type  = fields.attr('type'),
1454
                total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length;
1455
 
1456
            for (var i = 0; i < total; i++) {
1457
                var $field = fields.eq(i);
1458
 
1459
                // Remove from the list of invalid fields
1460
                this.$invalidFields = this.$invalidFields.not($field);
1461
 
1462
                // Update the cache
1463
                this._cacheFields[field] = this._cacheFields[field].not($field);
1464
            }
1465
 
1466
            if (!this._cacheFields[field] || this._cacheFields[field].length === 0) {
1467
                delete this.options.fields[field];
1468
            }
1469
            if ('checkbox' === type || 'radio' === type) {
1470
                this._initField(field);
1471
            }
1472
 
1473
            this.disableSubmitButtons(false);
1474
            // Trigger an event
1475
            this.$form.trigger($.Event(this.options.events.fieldRemoved), {
1476
                field: field,
1477
                element: fields
1478
            });
1479
 
1480
            return this;
1481
        },
1482
 
1483
        /**
1484
         * Reset given field
1485
         *
1486
         * @param {String|jQuery} field The field name or field element
1487
         * @param {Boolean} [resetValue] If true, the method resets field value to empty or remove checked/selected attribute (for radio/checkbox)
1488
         * @returns {BootstrapValidator}
1489
         */
1490
        resetField: function(field, resetValue) {
1491
            var $fields = $([]);
1492
            switch (typeof field) {
1493
                case 'object':
1494
                    $fields = field;
1495
                    field   = field.attr('data-bv-field');
1496
                    break;
1497
                case 'string':
1498
                    $fields = this.getFieldElements(field);
1499
                    break;
1500
                default:
1501
                    break;
1502
            }
1503
 
1504
            var total = $fields.length;
1505
            if (this.options.fields[field]) {
1506
                for (var i = 0; i < total; i++) {
1507
                    for (var validator in this.options.fields[field].validators) {
1508
                        $fields.eq(i).removeData('bv.dfs.' + validator);
1509
                    }
1510
                }
1511
            }
1512
 
1513
            // Mark field as not validated yet
1514
            this.updateStatus(field, this.STATUS_NOT_VALIDATED);
1515
 
1516
            if (resetValue) {
1517
                var type = $fields.attr('type');
1518
                ('radio' === type || 'checkbox' === type) ? $fields.removeAttr('checked').removeAttr('selected') : $fields.val('');
1519
            }
1520
 
1521
            return this;
1522
        },
1523
 
1524
        /**
1525
         * Reset the form
1526
         *
1527
         * @param {Boolean} [resetValue] If true, the method resets field value to empty or remove checked/selected attribute (for radio/checkbox)
1528
         * @returns {BootstrapValidator}
1529
         */
1530
        resetForm: function(resetValue) {
1531
            for (var field in this.options.fields) {
1532
                this.resetField(field, resetValue);
1533
            }
1534
 
1535
            this.$invalidFields = $([]);
1536
            this.$submitButton  = null;
1537
 
1538
            // Enable submit buttons
1539
            this.disableSubmitButtons(false);
1540
 
1541
            return this;
1542
        },
1543
 
1544
        /**
1545
         * Revalidate given field
1546
         * It's used when you need to revalidate the field which its value is updated by other plugin
1547
         *
1548
         * @param {String|jQuery} field The field name of field element
1549
         * @returns {BootstrapValidator}
1550
         */
1551
        revalidateField: function(field) {
1552
            this.updateStatus(field, this.STATUS_NOT_VALIDATED)
1553
                .validateField(field);
1554
 
1555
            return this;
1556
        },
1557
 
1558
        /**
1559
         * Enable/Disable all validators to given field
1560
         *
1561
         * @param {String} field The field name
1562
         * @param {Boolean} enabled Enable/Disable field validators
1563
         * @param {String} [validatorName] The validator name. If null, all validators will be enabled/disabled
1564
         * @returns {BootstrapValidator}
1565
         */
1566
        enableFieldValidators: function(field, enabled, validatorName) {
1567
            var validators = this.options.fields[field].validators;
1568
 
1569
            // Enable/disable particular validator
1570
            if (validatorName
1571
                && validators
1572
                && validators[validatorName] && validators[validatorName].enabled !== enabled)
1573
            {
1574
                this.options.fields[field].validators[validatorName].enabled = enabled;
1575
                this.updateStatus(field, this.STATUS_NOT_VALIDATED, validatorName);
1576
            }
1577
            // Enable/disable all validators
1578
            else if (!validatorName && this.options.fields[field].enabled !== enabled) {
1579
                this.options.fields[field].enabled = enabled;
1580
                for (var v in validators) {
1581
                    this.enableFieldValidators(field, enabled, v);
1582
                }
1583
            }
1584
 
1585
            return this;
1586
        },
1587
 
1588
        /**
1589
         * Some validators have option which its value is dynamic.
1590
         * For example, the zipCode validator has the country option which might be changed dynamically by a select element.
1591
         *
1592
         * @param {jQuery|String} field The field name or element
1593
         * @param {String|Function} option The option which can be determined by:
1594
         * - a string
1595
         * - name of field which defines the value
1596
         * - name of function which returns the value
1597
         * - a function returns the value
1598
         *
1599
         * The callback function has the format of
1600
         *      callback: function(value, validator, $field) {
1601
         *          // value is the value of field
1602
         *          // validator is the BootstrapValidator instance
1603
         *          // $field is the field element
1604
         *      }
1605
         *
1606
         * @returns {String}
1607
         */
1608
        getDynamicOption: function(field, option) {
1609
            var $field = ('string' === typeof field) ? this.getFieldElements(field) : field,
1610
                value  = $field.val();
1611
 
1612
            // Option can be determined by
1613
            // ... a function
1614
            if ('function' === typeof option) {
1615
                return $.fn.bootstrapValidator.helpers.call(option, [value, this, $field]);
1616
            }
1617
            // ... value of other field
1618
            else if ('string' === typeof option) {
1619
                var $f = this.getFieldElements(option);
1620
                if ($f.length) {
1621
                    return $f.val();
1622
                }
1623
                // ... return value of callback
1624
                else {
1625
                    return $.fn.bootstrapValidator.helpers.call(option, [value, this, $field]) || option;
1626
                }
1627
            }
1628
 
1629
            return null;
1630
        },
1631
 
1632
        /**
1633
         * Destroy the plugin
1634
         * It will remove all error messages, feedback icons and turn off the events
1635
         */
1636
        destroy: function() {
1637
            var field, fields, $field, validator, $icon, group;
1638
            for (field in this.options.fields) {
1639
                fields    = this.getFieldElements(field);
1640
                group     = this.options.fields[field].group || this.options.group;
1641
                for (var i = 0; i < fields.length; i++) {
1642
                    $field = fields.eq(i);
1643
                    $field
1644
                        // Remove all error messages
1645
                        .data('bv.messages')
1646
                            .find('.help-block[data-bv-validator][data-bv-for="' + field + '"]').remove().end()
1647
                            .end()
1648
                        .removeData('bv.messages')
1649
                        // Remove feedback classes
1650
                        .parents(group)
1651
                            .removeClass('has-feedback has-error has-success')
1652
                            .end()
1653
                        // Turn off events
1654
                        .off('.bv')
1655
                        .removeAttr('data-bv-field');
1656
 
1657
                    // Remove feedback icons, tooltip/popover container
1658
                    $icon = $field.data('bv.icon');
1659
                    if ($icon) {
1660
                        var container = ('function' === typeof (this.options.fields[field].container || this.options.container)) ? (this.options.fields[field].container || this.options.container).call(this, $field, this) : (this.options.fields[field].container || this.options.container);
1661
                        switch (container) {
1662
                            case 'tooltip':
1663
                                $icon.tooltip('destroy').remove();
1664
                                break;
1665
                            case 'popover':
1666
                                $icon.popover('destroy').remove();
1667
                                break;
1668
                            default:
1669
                                $icon.remove();
1670
                                break;
1671
                        }
1672
                    }
1673
                    $field.removeData('bv.icon');
1674
 
1675
                    for (validator in this.options.fields[field].validators) {
1676
                        if ($field.data('bv.dfs.' + validator)) {
1677
                            $field.data('bv.dfs.' + validator).reject();
1678
                        }
1679
                        $field.removeData('bv.result.' + validator)
1680
                              .removeData('bv.response.' + validator)
1681
                              .removeData('bv.dfs.' + validator);
1682
 
1683
                        // Destroy the validator
1684
                        if ('function' === typeof $.fn.bootstrapValidator.validators[validator].destroy) {
1685
                            $.fn.bootstrapValidator.validators[validator].destroy(this, $field, this.options.fields[field].validators[validator]);
1686
                        }
1687
                    }
1688
                }
1689
            }
1690
 
1691
            this.disableSubmitButtons(false);   // Enable submit buttons
1692
            this.$hiddenButton.remove();        // Remove the hidden button
1693
 
1694
            this.$form
1695
                .removeClass(this.options.elementClass)
1696
                .off('.bv')
1697
                .removeData('bootstrapValidator')
1698
                // Remove generated hidden elements
1699
                .find('[data-bv-submit-hidden]').remove().end()
1700
                .find('[type="submit"]').off('click.bv');
1701
        }
1702
    };
1703
 
1704
    // Plugin definition
1705
    $.fn.bootstrapValidator = function(option) {
1706
        var params = arguments;
1707
        return this.each(function() {
1708
            var $this   = $(this),
1709
                data    = $this.data('bootstrapValidator'),
1710
                options = 'object' === typeof option && option;
1711
            if (!data) {
1712
                data = new BootstrapValidator(this, options);
1713
                $this.data('bootstrapValidator', data);
1714
            }
1715
 
1716
            // Allow to call plugin method
1717
            if ('string' === typeof option) {
1718
                data[option].apply(data, Array.prototype.slice.call(params, 1));
1719
            }
1720
        });
1721
    };
1722
 
1723
    // The default options
1724
    // Sorted in alphabetical order
1725
    $.fn.bootstrapValidator.DEFAULT_OPTIONS = {
1726
        // The first invalid field will be focused automatically
1727
        autoFocus: true,
1728
 
1729
        //The error messages container. It can be:
1730
        // - 'tooltip' if you want to use Bootstrap tooltip to show error messages
1731
        // - 'popover' if you want to use Bootstrap popover to show error messages
1732
        // - a CSS selector indicating the container
1733
        // In the first two cases, since the tooltip/popover should be small enough, the plugin only shows only one error message
1734
        // You also can define the message container for particular field
1735
        container: null,
1736
 
1737
        // The form CSS class
1738
        elementClass: 'bv-form',
1739
 
1740
        // Use custom event name to avoid window.onerror being invoked by jQuery
1741
        // See https://github.com/nghuuphuoc/bootstrapvalidator/issues/630
1742
        events: {
1743
            formInit: 'init.form.bv',
1744
            formError: 'error.form.bv',
1745
            formSuccess: 'success.form.bv',
1746
            fieldAdded: 'added.field.bv',
1747
            fieldRemoved: 'removed.field.bv',
1748
            fieldInit: 'init.field.bv',
1749
            fieldError: 'error.field.bv',
1750
            fieldSuccess: 'success.field.bv',
1751
            fieldStatus: 'status.field.bv',
1752
            validatorError: 'error.validator.bv',
1753
            validatorSuccess: 'success.validator.bv'
1754
        },
1755
 
1756
        // Indicate fields which won't be validated
1757
        // By default, the plugin will not validate the following kind of fields:
1758
        // - disabled
1759
        // - hidden
1760
        // - invisible
1761
        //
1762
        // The setting consists of jQuery filters. Accept 3 formats:
1763
        // - A string. Use a comma to separate filter
1764
        // - An array. Each element is a filter
1765
        // - An array. Each element can be a callback function
1766
        //      function($field, validator) {
1767
        //          $field is jQuery object representing the field element
1768
        //          validator is the BootstrapValidator instance
1769
        //          return true or false;
1770
        //      }
1771
        //
1772
        // The 3 following settings are equivalent:
1773
        //
1774
        // 1) ':disabled, :hidden, :not(:visible)'
1775
        // 2) [':disabled', ':hidden', ':not(:visible)']
1776
        // 3) [':disabled', ':hidden', function($field) {
1777
        //        return !$field.is(':visible');
1778
        //    }]
1779
        excluded: [':disabled', ':hidden', ':not(:visible)'],
1780
 
1781
        // Shows ok/error/loading icons based on the field validity.
1782
        // This feature requires Bootstrap v3.1.0 or later (http://getbootstrap.com/css/#forms-control-validation).
1783
        // Since Bootstrap doesn't provide any methods to know its version, this option cannot be on/off automatically.
1784
        // In other word, to use this feature you have to upgrade your Bootstrap to v3.1.0 or later.
1785
        //
1786
        // Examples:
1787
        // - Use Glyphicons icons:
1788
        //  feedbackIcons: {
1789
        //      valid: 'glyphicon glyphicon-ok',
1790
        //      invalid: 'glyphicon glyphicon-remove',
1791
        //      validating: 'glyphicon glyphicon-refresh'
1792
        //  }
1793
        // - Use FontAwesome icons:
1794
        //  feedbackIcons: {
1795
        //      valid: 'fa fa-check',
1796
        //      invalid: 'fa fa-times',
1797
        //      validating: 'fa fa-refresh'
1798
        //  }
1799
        feedbackIcons: {
1800
            valid:      null,
1801
            invalid:    null,
1802
            validating: null
1803
        },
1804
 
1805
        // Map the field name with validator rules
1806
        fields: null,
1807
 
1808
        // The CSS selector for indicating the element consists the field
1809
        // By default, each field is placed inside the <div class="form-group"></div>
1810
        // You should adjust this option if your form group consists of many fields which not all of them need to be validated
1811
        group: '.form-group',
1812
 
1813
        // Live validating option
1814
        // Can be one of 3 values:
1815
        // - enabled: The plugin validates fields as soon as they are changed
1816
        // - disabled: Disable the live validating. The error messages are only shown after the form is submitted
1817
        // - submitted: The live validating is enabled after the form is submitted
1818
        live: 'enabled',
1819
 
1820
        // Default invalid message
1821
        message: 'This value is not valid',
1822
 
1823
        // The submit buttons selector
1824
        // These buttons will be disabled to prevent the valid form from multiple submissions
1825
        submitButtons: '[type="submit"]',
1826
 
1827
        // The field will not be live validated if its length is less than this number of characters
1828
        threshold: null,
1829
 
1830
        // Whether to be verbose when validating a field or not.
1831
        // Possible values:
1832
        // - true:  when a field has multiple validators, all of them will be checked, and respectively - if errors occur in
1833
        //          multiple validators, all of them will be displayed to the user
1834
        // - false: when a field has multiple validators, validation for this field will be terminated upon the first encountered error.
1835
        //          Thus, only the very first error message related to this field will be displayed to the user
1836
        verbose: true
1837
    };
1838
 
1839
    // Available validators
1840
    $.fn.bootstrapValidator.validators  = {};
1841
 
1842
    // i18n
1843
    $.fn.bootstrapValidator.i18n        = {};
1844
 
1845
    $.fn.bootstrapValidator.Constructor = BootstrapValidator;
1846
 
1847
    // Helper methods, which can be used in validator class
1848
    $.fn.bootstrapValidator.helpers = {
1849
        /**
1850
         * Execute a callback function
1851
         *
1852
         * @param {String|Function} functionName Can be
1853
         * - name of global function
1854
         * - name of namespace function (such as A.B.C)
1855
         * - a function
1856
         * @param {Array} args The callback arguments
1857
         */
1858
        call: function(functionName, args) {
1859
            if ('function' === typeof functionName) {
1860
                return functionName.apply(this, args);
1861
            } else if ('string' === typeof functionName) {
1862
                if ('()' === functionName.substring(functionName.length - 2)) {
1863
                    functionName = functionName.substring(0, functionName.length - 2);
1864
                }
1865
                var ns      = functionName.split('.'),
1866
                    func    = ns.pop(),
1867
                    context = window;
1868
                for (var i = 0; i < ns.length; i++) {
1869
                    context = context[ns[i]];
1870
                }
1871
 
1872
                return (typeof context[func] === 'undefined') ? null : context[func].apply(this, args);
1873
            }
1874
        },
1875
 
1876
        /**
1877
         * Format a string
1878
         * It's used to format the error message
1879
         * format('The field must between %s and %s', [10, 20]) = 'The field must between 10 and 20'
1880
         *
1881
         * @param {String} message
1882
         * @param {Array} parameters
1883
         * @returns {String}
1884
         */
1885
        format: function(message, parameters) {
1886
            if (!$.isArray(parameters)) {
1887
                parameters = [parameters];
1888
            }
1889
 
1890
            for (var i in parameters) {
1891
                message = message.replace('%s', parameters[i]);
1892
            }
1893
 
1894
            return message;
1895
        },
1896
 
1897
        /**
1898
         * Validate a date
1899
         *
1900
         * @param {Number} year The full year in 4 digits
1901
         * @param {Number} month The month number
1902
         * @param {Number} day The day number
1903
         * @param {Boolean} [notInFuture] If true, the date must not be in the future
1904
         * @returns {Boolean}
1905
         */
1906
        date: function(year, month, day, notInFuture) {
1907
            if (isNaN(year) || isNaN(month) || isNaN(day)) {
1908
                return false;
1909
            }
1910
            if (day.length > 2 || month.length > 2 || year.length > 4) {
1911
                return false;
1912
            }
1913
 
1914
            day   = parseInt(day, 10);
1915
            month = parseInt(month, 10);
1916
            year  = parseInt(year, 10);
1917
 
1918
            if (year < 1000 || year > 9999 || month <= 0 || month > 12) {
1919
                return false;
1920
            }
1921
            var numDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
1922
            // Update the number of days in Feb of leap year
1923
            if (year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0)) {
1924
                numDays[1] = 29;
1925
            }
1926
 
1927
            // Check the day
1928
            if (day <= 0 || day > numDays[month - 1]) {
1929
                return false;
1930
            }
1931
 
1932
            if (notInFuture === true) {
1933
                var currentDate  = new Date(),
1934
                    currentYear  = currentDate.getFullYear(),
1935
                    currentMonth = currentDate.getMonth(),
1936
                    currentDay   = currentDate.getDate();
1937
                return (year < currentYear
1938
                        || (year === currentYear && month - 1 < currentMonth)
1939
                        || (year === currentYear && month - 1 === currentMonth && day < currentDay));
1940
            }
1941
 
1942
            return true;
1943
        },
1944
 
1945
        /**
1946
         * Implement Luhn validation algorithm
1947
         * Credit to https://gist.github.com/ShirtlessKirk/2134376
1948
         *
1949
         * @see http://en.wikipedia.org/wiki/Luhn
1950
         * @param {String} value
1951
         * @returns {Boolean}
1952
         */
1953
        luhn: function(value) {
1954
            var length  = value.length,
1955
                mul     = 0,
1956
                prodArr = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]],
1957
                sum     = 0;
1958
 
1959
            while (length--) {
1960
                sum += prodArr[mul][parseInt(value.charAt(length), 10)];
1961
                mul ^= 1;
1962
            }
1963
 
1964
            return (sum % 10 === 0 && sum > 0);
1965
        },
1966
 
1967
        /**
1968
         * Implement modulus 11, 10 (ISO 7064) algorithm
1969
         *
1970
         * @param {String} value
1971
         * @returns {Boolean}
1972
         */
1973
        mod11And10: function(value) {
1974
            var check  = 5,
1975
                length = value.length;
1976
            for (var i = 0; i < length; i++) {
1977
                check = (((check || 10) * 2) % 11 + parseInt(value.charAt(i), 10)) % 10;
1978
            }
1979
            return (check === 1);
1980
        },
1981
 
1982
        /**
1983
         * Implements Mod 37, 36 (ISO 7064) algorithm
1984
         * Usages:
1985
         * mod37And36('A12425GABC1234002M')
1986
         * mod37And36('002006673085', '0123456789')
1987
         *
1988
         * @param {String} value
1989
         * @param {String} [alphabet]
1990
         * @returns {Boolean}
1991
         */
1992
        mod37And36: function(value, alphabet) {
1993
            alphabet = alphabet || '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
1994
            var modulus = alphabet.length,
1995
                length  = value.length,
1996
                check   = Math.floor(modulus / 2);
1997
            for (var i = 0; i < length; i++) {
1998
                check = (((check || modulus) * 2) % (modulus + 1) + alphabet.indexOf(value.charAt(i))) % modulus;
1999
            }
2000
            return (check === 1);
2001
        }
2002
    };
2003
}(window.jQuery));
2004
;(function($) {
2005
    $.fn.bootstrapValidator.i18n.base64 = $.extend($.fn.bootstrapValidator.i18n.base64 || {}, {
2006
        'default': 'Please enter a valid base 64 encoded'
2007
    });
2008
 
2009
    $.fn.bootstrapValidator.validators.base64 = {
2010
        /**
2011
         * Return true if the input value is a base 64 encoded string.
2012
         *
2013
         * @param {BootstrapValidator} validator The validator plugin instance
2014
         * @param {jQuery} $field Field element
2015
         * @param {Object} options Can consist of the following keys:
2016
         * - message: The invalid message
2017
         * @returns {Boolean}
2018
         */
2019
        validate: function(validator, $field, options) {
2020
            var value = $field.val();
2021
            if (value === '') {
2022
                return true;
2023
            }
2024
 
2025
            return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/.test(value);
2026
        }
2027
    };
2028
}(window.jQuery));
2029
;(function($) {
2030
    $.fn.bootstrapValidator.i18n.between = $.extend($.fn.bootstrapValidator.i18n.between || {}, {
2031
        'default': 'Please enter a value between %s and %s',
2032
        notInclusive: 'Please enter a value between %s and %s strictly'
2033
    });
2034
 
2035
    $.fn.bootstrapValidator.validators.between = {
2036
        html5Attributes: {
2037
            message: 'message',
2038
            min: 'min',
2039
            max: 'max',
2040
            inclusive: 'inclusive'
2041
        },
2042
 
2043
        enableByHtml5: function($field) {
2044
            if ('range' === $field.attr('type')) {
2045
                return {
2046
                    min: $field.attr('min'),
2047
                    max: $field.attr('max')
2048
                };
2049
            }
2050
 
2051
            return false;
2052
        },
2053
 
2054
        /**
2055
         * Return true if the input value is between (strictly or not) two given numbers
2056
         *
2057
         * @param {BootstrapValidator} validator The validator plugin instance
2058
         * @param {jQuery} $field Field element
2059
         * @param {Object} options Can consist of the following keys:
2060
         * - min
2061
         * - max
2062
         *
2063
         * The min, max keys define the number which the field value compares to. min, max can be
2064
         *      - A number
2065
         *      - Name of field which its value defines the number
2066
         *      - Name of callback function that returns the number
2067
         *      - A callback function that returns the number
2068
         *
2069
         * - inclusive [optional]: Can be true or false. Default is true
2070
         * - message: The invalid message
2071
         * @returns {Boolean|Object}
2072
         */
2073
        validate: function(validator, $field, options) {
2074
            var value = $field.val();
2075
            if (value === '') {
2076
                return true;
2077
            }
2078
 
2079
			value = this._format(value);
2080
            if (!$.isNumeric(value)) {
2081
                return false;
2082
            }
2083
 
2084
            var min      = $.isNumeric(options.min) ? options.min : validator.getDynamicOption($field, options.min),
2085
                max      = $.isNumeric(options.max) ? options.max : validator.getDynamicOption($field, options.max),
2086
                minValue = this._format(min),
2087
                maxValue = this._format(max);
2088
 
2089
            value = parseFloat(value);
2090
			return (options.inclusive === true || options.inclusive === undefined)
2091
                    ? {
2092
                        valid: value >= minValue && value <= maxValue,
2093
                        message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.between['default'], [min, max])
2094
                    }
2095
                    : {
2096
                        valid: value > minValue  && value <  maxValue,
2097
                        message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.between.notInclusive, [min, max])
2098
                    };
2099
        },
2100
 
2101
        _format: function(value) {
2102
            return (value + '').replace(',', '.');
2103
        }
2104
    };
2105
}(window.jQuery));
2106
;(function($) {
2107
    $.fn.bootstrapValidator.validators.blank = {
2108
        /**
2109
         * Placeholder validator that can be used to display a custom validation message
2110
         * returned from the server
2111
         * Example:
2112
         *
2113
         * (1) a "blank" validator is applied to an input field.
2114
         * (2) data is entered via the UI that is unable to be validated client-side.
2115
         * (3) server returns a 400 with JSON data that contains the field that failed
2116
         *     validation and an associated message.
2117
         * (4) ajax 400 call handler does the following:
2118
         *
2119
         *      bv.updateMessage(field, 'blank', errorMessage);
2120
         *      bv.updateStatus(field, 'INVALID');
2121
         *
2122
         * @see https://github.com/nghuuphuoc/bootstrapvalidator/issues/542
2123
         * @see https://github.com/nghuuphuoc/bootstrapvalidator/pull/666
2124
         * @param {BootstrapValidator} validator The validator plugin instance
2125
         * @param {jQuery} $field Field element
2126
         * @param {Object} options Can consist of the following keys:
2127
         * - message: The invalid message
2128
         * @returns {Boolean}
2129
         */
2130
        validate: function(validator, $field, options) {
2131
            return true;
2132
        }
2133
    };
2134
}(window.jQuery));
2135
;(function($) {
2136
    $.fn.bootstrapValidator.i18n.callback = $.extend($.fn.bootstrapValidator.i18n.callback || {}, {
2137
        'default': 'Please enter a valid value'
2138
    });
2139
 
2140
    $.fn.bootstrapValidator.validators.callback = {
2141
        html5Attributes: {
2142
            message: 'message',
2143
            callback: 'callback'
2144
        },
2145
 
2146
        /**
2147
         * Return result from the callback method
2148
         *
2149
         * @param {BootstrapValidator} validator The validator plugin instance
2150
         * @param {jQuery} $field Field element
2151
         * @param {Object} options Can consist of the following keys:
2152
         * - callback: The callback method that passes 2 parameters:
2153
         *      callback: function(fieldValue, validator, $field) {
2154
         *          // fieldValue is the value of field
2155
         *          // validator is instance of BootstrapValidator
2156
         *          // $field is the field element
2157
         *      }
2158
         * - message: The invalid message
2159
         * @returns {Deferred}
2160
         */
2161
        validate: function(validator, $field, options) {
2162
            var value  = $field.val(),
2163
                dfd    = new $.Deferred(),
2164
                result = { valid: true };
2165
 
2166
            if (options.callback) {
2167
                var response = $.fn.bootstrapValidator.helpers.call(options.callback, [value, validator, $field]);
2168
                result = ('boolean' === typeof response) ? { valid: response } :  response;
2169
            }
2170
 
2171
            dfd.resolve($field, 'callback', result);
2172
            return dfd;
2173
        }
2174
    };
2175
}(window.jQuery));
2176
;(function($) {
2177
    $.fn.bootstrapValidator.i18n.choice = $.extend($.fn.bootstrapValidator.i18n.choice || {}, {
2178
        'default': 'Please enter a valid value',
2179
        less: 'Please choose %s options at minimum',
2180
        more: 'Please choose %s options at maximum',
2181
        between: 'Please choose %s - %s options'
2182
    });
2183
 
2184
    $.fn.bootstrapValidator.validators.choice = {
2185
        html5Attributes: {
2186
            message: 'message',
2187
            min: 'min',
2188
            max: 'max'
2189
        },
2190
 
2191
        /**
2192
         * Check if the number of checked boxes are less or more than a given number
2193
         *
2194
         * @param {BootstrapValidator} validator The validator plugin instance
2195
         * @param {jQuery} $field Field element
2196
         * @param {Object} options Consists of following keys:
2197
         * - min
2198
         * - max
2199
         *
2200
         * At least one of two keys is required
2201
         * The min, max keys define the number which the field value compares to. min, max can be
2202
         *      - A number
2203
         *      - Name of field which its value defines the number
2204
         *      - Name of callback function that returns the number
2205
         *      - A callback function that returns the number
2206
         *
2207
         * - message: The invalid message
2208
         * @returns {Object}
2209
         */
2210
        validate: function(validator, $field, options) {
2211
            var numChoices = $field.is('select')
2212
                            ? validator.getFieldElements($field.attr('data-bv-field')).find('option').filter(':selected').length
2213
                            : validator.getFieldElements($field.attr('data-bv-field')).filter(':checked').length,
2214
                min        = options.min ? ($.isNumeric(options.min) ? options.min : validator.getDynamicOption($field, options.min)) : null,
2215
                max        = options.max ? ($.isNumeric(options.max) ? options.max : validator.getDynamicOption($field, options.max)) : null,
2216
                isValid    = true,
2217
                message    = options.message || $.fn.bootstrapValidator.i18n.choice['default'];
2218
 
2219
            if ((min && numChoices < parseInt(min, 10)) || (max && numChoices > parseInt(max, 10))) {
2220
                isValid = false;
2221
            }
2222
 
2223
            switch (true) {
2224
                case (!!min && !!max):
2225
                    message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.choice.between, [parseInt(min, 10), parseInt(max, 10)]);
2226
                    break;
2227
 
2228
                case (!!min):
2229
                    message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.choice.less, parseInt(min, 10));
2230
                    break;
2231
 
2232
                case (!!max):
2233
                    message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.choice.more, parseInt(max, 10));
2234
                    break;
2235
 
2236
                default:
2237
                    break;
2238
            }
2239
 
2240
            return { valid: isValid, message: message };
2241
        }
2242
    };
2243
}(window.jQuery));
2244
;(function($) {
2245
    $.fn.bootstrapValidator.i18n.color = $.extend($.fn.bootstrapValidator.i18n.color || {}, {
2246
        'default': 'Please enter a valid color'
2247
    });
2248
 
2249
    $.fn.bootstrapValidator.validators.color = {
2250
        SUPPORTED_TYPES: [
2251
            'hex', 'rgb', 'rgba', 'hsl', 'hsla', 'keyword'
2252
        ],
2253
 
2254
        KEYWORD_COLORS: [
2255
            // Colors start with A
2256
            'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure',
2257
            // B
2258
            'beige', 'bisque', 'black', 'blanchedalmond', 'blue', 'blueviolet', 'brown', 'burlywood',
2259
            // C
2260
            'cadetblue', 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 'cyan',
2261
            // D
2262
            'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkgrey', 'darkkhaki', 'darkmagenta',
2263
            'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 'darkslateblue',
2264
            'darkslategray', 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink', 'deepskyblue', 'dimgray',
2265
            'dimgrey', 'dodgerblue',
2266
            // F
2267
            'firebrick', 'floralwhite', 'forestgreen', 'fuchsia',
2268
            // G
2269
            'gainsboro', 'ghostwhite', 'gold', 'goldenrod', 'gray', 'green', 'greenyellow', 'grey',
2270
            // H
2271
            'honeydew', 'hotpink',
2272
            // I
2273
            'indianred', 'indigo', 'ivory',
2274
            // K
2275
            'khaki',
2276
            // L
2277
            'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan',
2278
            'lightgoldenrodyellow', 'lightgray', 'lightgreen', 'lightgrey', 'lightpink', 'lightsalmon', 'lightseagreen',
2279
            'lightskyblue', 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow', 'lime', 'limegreen',
2280
            'linen',
2281
            // M
2282
            'magenta', 'maroon', 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple', 'mediumseagreen',
2283
            'mediumslateblue', 'mediumspringgreen', 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream',
2284
            'mistyrose', 'moccasin',
2285
            // N
2286
            'navajowhite', 'navy',
2287
            // O
2288
            'oldlace', 'olive', 'olivedrab', 'orange', 'orangered', 'orchid',
2289
            // P
2290
            'palegoldenrod', 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff', 'peru', 'pink',
2291
            'plum', 'powderblue', 'purple',
2292
            // R
2293
            'red', 'rosybrown', 'royalblue',
2294
            // S
2295
            'saddlebrown', 'salmon', 'sandybrown', 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue',
2296
            'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue',
2297
            // T
2298
            'tan', 'teal', 'thistle', 'tomato', 'transparent', 'turquoise',
2299
            // V
2300
            'violet',
2301
            // W
2302
            'wheat', 'white', 'whitesmoke',
2303
            // Y
2304
            'yellow', 'yellowgreen'
2305
        ],
2306
 
2307
        /**
2308
         * Return true if the input value is a valid color
2309
         *
2310
         * @param {BootstrapValidator} validator The validator plugin instance
2311
         * @param {jQuery} $field Field element
2312
         * @param {Object} options Can consist of the following keys:
2313
         * - message: The invalid message
2314
         * - type: The array of valid color types
2315
         * @returns {Boolean}
2316
         */
2317
        validate: function(validator, $field, options) {
2318
            var value = $field.val();
2319
            if (value === '') {
2320
                return true;
2321
            }
2322
 
2323
            var types = options.type || this.SUPPORTED_TYPES;
2324
            if (!$.isArray(types)) {
2325
                types = types.replace(/s/g, '').split(',');
2326
            }
2327
 
2328
            var method,
2329
                type,
2330
                isValid = false;
2331
 
2332
            for (var i = 0; i < types.length; i++) {
2333
                type    = types[i];
2334
                method  = '_' + type.toLowerCase();
2335
                isValid = isValid || this[method](value);
2336
                if (isValid) {
2337
                    return true;
2338
                }
2339
            }
2340
 
2341
            return false;
2342
        },
2343
 
2344
        _hex: function(value) {
2345
            return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(value);
2346
        },
2347
 
2348
        _hsl: function(value) {
2349
            return /^hsl\((\s*(-?\d+)\s*,)(\s*(\b(0?\d{1,2}|100)\b%)\s*,)(\s*(\b(0?\d{1,2}|100)\b%)\s*)\)$/.test(value);
2350
        },
2351
 
2352
        _hsla: function(value) {
2353
            return /^hsla\((\s*(-?\d+)\s*,)(\s*(\b(0?\d{1,2}|100)\b%)\s*,){2}(\s*(0?(\.\d+)?|1(\.0+)?)\s*)\)$/.test(value);
2354
        },
2355
 
2356
        _keyword: function(value) {
2357
            return $.inArray(value, this.KEYWORD_COLORS) >= 0;
2358
        },
2359
 
2360
        _rgb: function(value) {
2361
            var regexInteger = /^rgb\((\s*(\b([01]?\d{1,2}|2[0-4]\d|25[0-5])\b)\s*,){2}(\s*(\b([01]?\d{1,2}|2[0-4]\d|25[0-5])\b)\s*)\)$/,
2362
                regexPercent = /^rgb\((\s*(\b(0?\d{1,2}|100)\b%)\s*,){2}(\s*(\b(0?\d{1,2}|100)\b%)\s*)\)$/;
2363
            return regexInteger.test(value) || regexPercent.test(value);
2364
        },
2365
 
2366
        _rgba: function(value) {
2367
            var regexInteger = /^rgba\((\s*(\b([01]?\d{1,2}|2[0-4]\d|25[0-5])\b)\s*,){3}(\s*(0?(\.\d+)?|1(\.0+)?)\s*)\)$/,
2368
                regexPercent = /^rgba\((\s*(\b(0?\d{1,2}|100)\b%)\s*,){3}(\s*(0?(\.\d+)?|1(\.0+)?)\s*)\)$/;
2369
            return regexInteger.test(value) || regexPercent.test(value);
2370
        }
2371
    };
2372
}(window.jQuery));
2373
;(function($) {
2374
    $.fn.bootstrapValidator.i18n.creditCard = $.extend($.fn.bootstrapValidator.i18n.creditCard || {}, {
2375
        'default': 'Please enter a valid credit card number'
2376
    });
2377
 
2378
    $.fn.bootstrapValidator.validators.creditCard = {
2379
        /**
2380
         * Return true if the input value is valid credit card number
2381
         * Based on https://gist.github.com/DiegoSalazar/4075533
2382
         *
2383
         * @param {BootstrapValidator} validator The validator plugin instance
2384
         * @param {jQuery} $field Field element
2385
         * @param {Object} [options] Can consist of the following key:
2386
         * - message: The invalid message
2387
         * @returns {Boolean}
2388
         */
2389
        validate: function(validator, $field, options) {
2390
            var value = $field.val();
2391
            if (value === '') {
2392
                return true;
2393
            }
2394
 
2395
            // Accept only digits, dashes or spaces
2396
            if (/[^0-9-\s]+/.test(value)) {
2397
                return false;
2398
            }
2399
            value = value.replace(/\D/g, '');
2400
 
2401
            if (!$.fn.bootstrapValidator.helpers.luhn(value)) {
2402
                return false;
2403
            }
2404
 
2405
            // Validate the card number based on prefix (IIN ranges) and length
2406
            var cards = {
2407
                AMERICAN_EXPRESS: {
2408
                    length: [15],
2409
                    prefix: ['34', '37']
2410
                },
2411
                DINERS_CLUB: {
2412
                    length: [14],
2413
                    prefix: ['300', '301', '302', '303', '304', '305', '36']
2414
                },
2415
                DINERS_CLUB_US: {
2416
                    length: [16],
2417
                    prefix: ['54', '55']
2418
                },
2419
                DISCOVER: {
2420
                    length: [16],
2421
                    prefix: ['6011', '622126', '622127', '622128', '622129', '62213',
2422
                             '62214', '62215', '62216', '62217', '62218', '62219',
2423
                             '6222', '6223', '6224', '6225', '6226', '6227', '6228',
2424
                             '62290', '62291', '622920', '622921', '622922', '622923',
2425
                             '622924', '622925', '644', '645', '646', '647', '648',
2426
                             '649', '65']
2427
                },
2428
                JCB: {
2429
                    length: [16],
2430
                    prefix: ['3528', '3529', '353', '354', '355', '356', '357', '358']
2431
                },
2432
                LASER: {
2433
                    length: [16, 17, 18, 19],
2434
                    prefix: ['6304', '6706', '6771', '6709']
2435
                },
2436
                MAESTRO: {
2437
                    length: [12, 13, 14, 15, 16, 17, 18, 19],
2438
                    prefix: ['5018', '5020', '5038', '6304', '6759', '6761', '6762', '6763', '6764', '6765', '6766']
2439
                },
2440
                MASTERCARD: {
2441
                    length: [16],
2442
                    prefix: ['51', '52', '53', '54', '55']
2443
                },
2444
                SOLO: {
2445
                    length: [16, 18, 19],
2446
                    prefix: ['6334', '6767']
2447
                },
2448
                UNIONPAY: {
2449
                    length: [16, 17, 18, 19],
2450
                    prefix: ['622126', '622127', '622128', '622129', '62213', '62214',
2451
                             '62215', '62216', '62217', '62218', '62219', '6222', '6223',
2452
                             '6224', '6225', '6226', '6227', '6228', '62290', '62291',
2453
                             '622920', '622921', '622922', '622923', '622924', '622925']
2454
                },
2455
                VISA: {
2456
                    length: [16],
2457
                    prefix: ['4']
2458
                }
2459
            };
2460
 
2461
            var type, i;
2462
            for (type in cards) {
2463
                for (i in cards[type].prefix) {
2464
                    if (value.substr(0, cards[type].prefix[i].length) === cards[type].prefix[i]     // Check the prefix
2465
                        && $.inArray(value.length, cards[type].length) !== -1)                      // and length
2466
                    {
2467
                        return true;
2468
                    }
2469
                }
2470
            }
2471
 
2472
            return false;
2473
        }
2474
    };
2475
}(window.jQuery));
2476
;(function($) {
2477
    $.fn.bootstrapValidator.i18n.cusip = $.extend($.fn.bootstrapValidator.i18n.cusip || {}, {
2478
        'default': 'Please enter a valid CUSIP number'
2479
    });
2480
 
2481
    $.fn.bootstrapValidator.validators.cusip = {
2482
        /**
2483
         * Validate a CUSIP
2484
         * Examples:
2485
         * - Valid: 037833100, 931142103, 14149YAR8, 126650BG6
2486
         * - Invalid: 31430F200, 022615AC2
2487
         *
2488
         * @see http://en.wikipedia.org/wiki/CUSIP
2489
         * @param {BootstrapValidator} validator The validator plugin instance
2490
         * @param {jQuery} $field Field element
2491
         * @param {Object} [options] Can consist of the following keys:
2492
         * - message: The invalid message
2493
         * @returns {Boolean}
2494
         */
2495
        validate: function(validator, $field, options) {
2496
            var value = $field.val();
2497
            if (value === '') {
2498
                return true;
2499
            }
2500
 
2501
            value = value.toUpperCase();
2502
            if (!/^[0-9A-Z]{9}$/.test(value)) {
2503
                return false;
2504
            }
2505
 
2506
            var converted = $.map(value.split(''), function(item) {
2507
                                var code = item.charCodeAt(0);
2508
                                return (code >= 'A'.charCodeAt(0) && code <= 'Z'.charCodeAt(0))
2509
                                            // Replace A, B, C, ..., Z with 10, 11, ..., 35
2510
                                            ? (code - 'A'.charCodeAt(0) + 10)
2511
                                            : item;
2512
                            }),
2513
                length    = converted.length,
2514
                sum       = 0;
2515
            for (var i = 0; i < length - 1; i++) {
2516
                var num = parseInt(converted[i], 10);
2517
                if (i % 2 !== 0) {
2518
                    num *= 2;
2519
                }
2520
                if (num > 9) {
2521
                    num -= 9;
2522
                }
2523
                sum += num;
2524
            }
2525
 
2526
            sum = (10 - (sum % 10)) % 10;
2527
            return sum === converted[length - 1];
2528
        }
2529
    };
2530
}(window.jQuery));
2531
;(function($) {
2532
    $.fn.bootstrapValidator.i18n.cvv = $.extend($.fn.bootstrapValidator.i18n.cvv || {}, {
2533
        'default': 'Please enter a valid CVV number'
2534
    });
2535
 
2536
    $.fn.bootstrapValidator.validators.cvv = {
2537
        html5Attributes: {
2538
            message: 'message',
2539
            ccfield: 'creditCardField'
2540
        },
2541
 
2542
        /**
2543
         * Return true if the input value is a valid CVV number.
2544
         *
2545
         * @param {BootstrapValidator} validator The validator plugin instance
2546
         * @param {jQuery} $field Field element
2547
         * @param {Object} options Can consist of the following keys:
2548
         * - creditCardField: The credit card number field. It can be null
2549
         * - message: The invalid message
2550
         * @returns {Boolean}
2551
         */
2552
        validate: function(validator, $field, options) {
2553
            var value = $field.val();
2554
            if (value === '') {
2555
                return true;
2556
            }
2557
 
2558
            if (!/^[0-9]{3,4}$/.test(value)) {
2559
                return false;
2560
            }
2561
 
2562
            if (!options.creditCardField) {
2563
                return true;
2564
            }
2565
 
2566
            // Get the credit card number
2567
            var creditCard = validator.getFieldElements(options.creditCardField).val();
2568
            if (creditCard === '') {
2569
                return true;
2570
            }
2571
 
2572
            creditCard = creditCard.replace(/\D/g, '');
2573
 
2574
            // Supported credit card types
2575
            var cards = {
2576
                AMERICAN_EXPRESS: {
2577
                    length: [15],
2578
                    prefix: ['34', '37']
2579
                },
2580
                DINERS_CLUB: {
2581
                    length: [14],
2582
                    prefix: ['300', '301', '302', '303', '304', '305', '36']
2583
                },
2584
                DINERS_CLUB_US: {
2585
                    length: [16],
2586
                    prefix: ['54', '55']
2587
                },
2588
                DISCOVER: {
2589
                    length: [16],
2590
                    prefix: ['6011', '622126', '622127', '622128', '622129', '62213',
2591
                             '62214', '62215', '62216', '62217', '62218', '62219',
2592
                             '6222', '6223', '6224', '6225', '6226', '6227', '6228',
2593
                             '62290', '62291', '622920', '622921', '622922', '622923',
2594
                             '622924', '622925', '644', '645', '646', '647', '648',
2595
                             '649', '65']
2596
                },
2597
                JCB: {
2598
                    length: [16],
2599
                    prefix: ['3528', '3529', '353', '354', '355', '356', '357', '358']
2600
                },
2601
                LASER: {
2602
                    length: [16, 17, 18, 19],
2603
                    prefix: ['6304', '6706', '6771', '6709']
2604
                },
2605
                MAESTRO: {
2606
                    length: [12, 13, 14, 15, 16, 17, 18, 19],
2607
                    prefix: ['5018', '5020', '5038', '6304', '6759', '6761', '6762', '6763', '6764', '6765', '6766']
2608
                },
2609
                MASTERCARD: {
2610
                    length: [16],
2611
                    prefix: ['51', '52', '53', '54', '55']
2612
                },
2613
                SOLO: {
2614
                    length: [16, 18, 19],
2615
                    prefix: ['6334', '6767']
2616
                },
2617
                UNIONPAY: {
2618
                    length: [16, 17, 18, 19],
2619
                    prefix: ['622126', '622127', '622128', '622129', '62213', '62214',
2620
                             '62215', '62216', '62217', '62218', '62219', '6222', '6223',
2621
                             '6224', '6225', '6226', '6227', '6228', '62290', '62291',
2622
                             '622920', '622921', '622922', '622923', '622924', '622925']
2623
                },
2624
                VISA: {
2625
                    length: [16],
2626
                    prefix: ['4']
2627
                }
2628
            };
2629
            var type, i, creditCardType = null;
2630
            for (type in cards) {
2631
                for (i in cards[type].prefix) {
2632
                    if (creditCard.substr(0, cards[type].prefix[i].length) === cards[type].prefix[i]    // Check the prefix
2633
                        && $.inArray(creditCard.length, cards[type].length) !== -1)                     // and length
2634
                    {
2635
                        creditCardType = type;
2636
                        break;
2637
                    }
2638
                }
2639
            }
2640
 
2641
            return (creditCardType === null)
2642
                        ? false
2643
                        : (('AMERICAN_EXPRESS' === creditCardType) ? (value.length === 4) : (value.length === 3));
2644
        }
2645
    };
2646
}(window.jQuery));
2647
;(function($) {
2648
    $.fn.bootstrapValidator.i18n.date = $.extend($.fn.bootstrapValidator.i18n.date || {}, {
2649
        'default': 'Please enter a valid date',
2650
        min: 'Please enter a date after %s',
2651
        max: 'Please enter a date before %s',
2652
        range: 'Please enter a date in the range %s - %s'
2653
    });
2654
 
2655
    $.fn.bootstrapValidator.validators.date = {
2656
        html5Attributes: {
2657
            message: 'message',
2658
            format: 'format',
2659
            min: 'min',
2660
            max: 'max',
2661
            separator: 'separator'
2662
        },
2663
 
2664
        /**
2665
         * Return true if the input value is valid date
2666
         *
2667
         * @param {BootstrapValidator} validator The validator plugin instance
2668
         * @param {jQuery} $field Field element
2669
         * @param {Object} options Can consist of the following keys:
2670
         * - message: The invalid message
2671
         * - min: the minimum date
2672
         * - max: the maximum date
2673
         * - separator: Use to separate the date, month, and year.
2674
         * By default, it is /
2675
         * - format: The date format. Default is MM/DD/YYYY
2676
         * The format can be:
2677
         *
2678
         * i) date: Consist of DD, MM, YYYY parts which are separated by the separator option
2679
         * ii) date and time:
2680
         * The time can consist of h, m, s parts which are separated by :
2681
         * ii) date, time and A (indicating AM or PM)
2682
         * @returns {Boolean|Object}
2683
         */
2684
        validate: function(validator, $field, options) {
2685
            var value = $field.val();
2686
            if (value === '') {
2687
                return true;
2688
            }
2689
 
2690
            options.format = options.format || 'MM/DD/YYYY';
2691
 
2692
            // #683: Force the format to YYYY-MM-DD as the default browser behaviour when using type="date" attribute
2693
            if ($field.attr('type') === 'date') {
2694
                options.format = 'YYYY-MM-DD';
2695
            }
2696
 
2697
            var formats    = options.format.split(' '),
2698
                dateFormat = formats[0],
2699
                timeFormat = (formats.length > 1) ? formats[1] : null,
2700
                amOrPm     = (formats.length > 2) ? formats[2] : null,
2701
                sections   = value.split(' '),
2702
                date       = sections[0],
2703
                time       = (sections.length > 1) ? sections[1] : null;
2704
 
2705
            if (formats.length !== sections.length) {
2706
                return {
2707
                    valid: false,
2708
                    message: options.message || $.fn.bootstrapValidator.i18n.date['default']
2709
                };
2710
            }
2711
 
2712
            // Determine the separator
2713
            var separator = options.separator;
2714
            if (!separator) {
2715
                separator = (date.indexOf('/') !== -1) ? '/' : ((date.indexOf('-') !== -1) ? '-' : null);
2716
            }
2717
            if (separator === null || date.indexOf(separator) === -1) {
2718
                return {
2719
                    valid: false,
2720
                    message: options.message || $.fn.bootstrapValidator.i18n.date['default']
2721
                };
2722
            }
2723
 
2724
            // Determine the date
2725
            date       = date.split(separator);
2726
            dateFormat = dateFormat.split(separator);
2727
            if (date.length !== dateFormat.length) {
2728
                return {
2729
                    valid: false,
2730
                    message: options.message || $.fn.bootstrapValidator.i18n.date['default']
2731
                };
2732
            }
2733
 
2734
            var year  = date[$.inArray('YYYY', dateFormat)],
2735
                month = date[$.inArray('MM', dateFormat)],
2736
                day   = date[$.inArray('DD', dateFormat)];
2737
 
2738
            if (!year || !month || !day || year.length !== 4) {
2739
                return {
2740
                    valid: false,
2741
                    message: options.message || $.fn.bootstrapValidator.i18n.date['default']
2742
                };
2743
            }
2744
 
2745
            // Determine the time
2746
            var minutes = null, hours = null, seconds = null;
2747
            if (timeFormat) {
2748
                timeFormat = timeFormat.split(':');
2749
                time       = time.split(':');
2750
 
2751
                if (timeFormat.length !== time.length) {
2752
                    return {
2753
                        valid: false,
2754
                        message: options.message || $.fn.bootstrapValidator.i18n.date['default']
2755
                    };
2756
                }
2757
 
2758
                hours   = time.length > 0 ? time[0] : null;
2759
                minutes = time.length > 1 ? time[1] : null;
2760
                seconds = time.length > 2 ? time[2] : null;
2761
 
2762
                // Validate seconds
2763
                if (seconds) {
2764
                    if (isNaN(seconds) || seconds.length > 2) {
2765
                        return {
2766
                            valid: false,
2767
                            message: options.message || $.fn.bootstrapValidator.i18n.date['default']
2768
                        };
2769
                    }
2770
                    seconds = parseInt(seconds, 10);
2771
                    if (seconds < 0 || seconds > 60) {
2772
                        return {
2773
                            valid: false,
2774
                            message: options.message || $.fn.bootstrapValidator.i18n.date['default']
2775
                        };
2776
                    }
2777
                }
2778
 
2779
                // Validate hours
2780
                if (hours) {
2781
                    if (isNaN(hours) || hours.length > 2) {
2782
                        return {
2783
                            valid: false,
2784
                            message: options.message || $.fn.bootstrapValidator.i18n.date['default']
2785
                        };
2786
                    }
2787
                    hours = parseInt(hours, 10);
2788
                    if (hours < 0 || hours >= 24 || (amOrPm && hours > 12)) {
2789
                        return {
2790
                            valid: false,
2791
                            message: options.message || $.fn.bootstrapValidator.i18n.date['default']
2792
                        };
2793
                    }
2794
                }
2795
 
2796
                // Validate minutes
2797
                if (minutes) {
2798
                    if (isNaN(minutes) || minutes.length > 2) {
2799
                        return {
2800
                            valid: false,
2801
                            message: options.message || $.fn.bootstrapValidator.i18n.date['default']
2802
                        };
2803
                    }
2804
                    minutes = parseInt(minutes, 10);
2805
                    if (minutes < 0 || minutes > 59) {
2806
                        return {
2807
                            valid: false,
2808
                            message: options.message || $.fn.bootstrapValidator.i18n.date['default']
2809
                        };
2810
                    }
2811
                }
2812
            }
2813
 
2814
            // Validate day, month, and year
2815
            var valid   = $.fn.bootstrapValidator.helpers.date(year, month, day),
2816
                message = options.message || $.fn.bootstrapValidator.i18n.date['default'];
2817
 
2818
            // declare the date, min and max objects
2819
            var min       = null,
2820
                max       = null,
2821
                minOption = options.min,
2822
                maxOption = options.max;
2823
 
2824
            if (minOption) {
2825
                if (isNaN(Date.parse(minOption))) {
2826
                    minOption = validator.getDynamicOption($field, minOption);
2827
                }
2828
                min = this._parseDate(minOption, dateFormat, separator);
2829
            }
2830
 
2831
            if (maxOption) {
2832
                if (isNaN(Date.parse(maxOption))) {
2833
                    maxOption = validator.getDynamicOption($field, maxOption);
2834
                }
2835
                max = this._parseDate(maxOption, dateFormat, separator);
2836
            }
2837
 
2838
            date = new Date(year, month, day, hours, minutes, seconds);
2839
 
2840
            switch (true) {
2841
                case (minOption && !maxOption && valid):
2842
                    valid   = date.getTime() >= min.getTime();
2843
                    message = options.message || $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.date.min, minOption);
2844
                    break;
2845
 
2846
                case (maxOption && !minOption && valid):
2847
                    valid   = date.getTime() <= max.getTime();
2848
                    message = options.message || $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.date.max, maxOption);
2849
                    break;
2850
 
2851
                case (maxOption && minOption && valid):
2852
                    valid   = date.getTime() <= max.getTime() && date.getTime() >= min.getTime();
2853
                    message = options.message || $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.date.range, [minOption, maxOption]);
2854
                    break;
2855
 
2856
                default:
2857
                    break;
2858
            }
2859
 
2860
            return {
2861
                valid: valid,
2862
                message: message
2863
            };
2864
        },
2865
 
2866
        /**
2867
         * Return a date object after parsing the date string
2868
         *
2869
         * @param {String} date   The date string to parse
2870
         * @param {String} format The date format
2871
         * The format can be:
2872
         *   - date: Consist of DD, MM, YYYY parts which are separated by the separator option
2873
         *   - date and time:
2874
         *     The time can consist of h, m, s parts which are separated by :
2875
         * @param {String} separator The separator used to separate the date, month, and year
2876
         * @returns {Date}
2877
         */
2878
        _parseDate: function(date, format, separator) {
2879
            var minutes     = 0, hours = 0, seconds = 0,
2880
                sections    = date.split(' '),
2881
                dateSection = sections[0],
2882
                timeSection = (sections.length > 1) ? sections[1] : null;
2883
 
2884
            dateSection = dateSection.split(separator);
2885
            var year  = dateSection[$.inArray('YYYY', format)],
2886
                month = dateSection[$.inArray('MM', format)],
2887
                day   = dateSection[$.inArray('DD', format)];
2888
            if (timeSection) {
2889
                timeSection = timeSection.split(':');
2890
                hours       = timeSection.length > 0 ? timeSection[0] : null;
2891
                minutes     = timeSection.length > 1 ? timeSection[1] : null;
2892
                seconds     = timeSection.length > 2 ? timeSection[2] : null;
2893
            }
2894
 
2895
            return new Date(year, month, day, hours, minutes, seconds);
2896
        }
2897
    };
2898
}(window.jQuery));
2899
;(function($) {
2900
    $.fn.bootstrapValidator.i18n.different = $.extend($.fn.bootstrapValidator.i18n.different || {}, {
2901
        'default': 'Please enter a different value'
2902
    });
2903
 
2904
    $.fn.bootstrapValidator.validators.different = {
2905
        html5Attributes: {
2906
            message: 'message',
2907
            field: 'field'
2908
        },
2909
 
2910
        /**
2911
         * Return true if the input value is different with given field's value
2912
         *
2913
         * @param {BootstrapValidator} validator The validator plugin instance
2914
         * @param {jQuery} $field Field element
2915
         * @param {Object} options Consists of the following key:
2916
         * - field: The name of field that will be used to compare with current one
2917
         * - message: The invalid message
2918
         * @returns {Boolean}
2919
         */
2920
        validate: function(validator, $field, options) {
2921
            var value = $field.val();
2922
            if (value === '') {
2923
                return true;
2924
            }
2925
 
2926
            var fields  = options.field.split(','),
2927
                isValid = true;
2928
 
2929
            for (var i = 0; i < fields.length; i++) {
2930
                var compareWith = validator.getFieldElements(fields[i]);
2931
                if (compareWith == null || compareWith.length === 0) {
2932
                    continue;
2933
                }
2934
 
2935
                var compareValue = compareWith.val();
2936
                if (value === compareValue) {
2937
                    isValid = false;
2938
                } else if (compareValue !== '') {
2939
                    validator.updateStatus(compareWith, validator.STATUS_VALID, 'different');
2940
                }
2941
            }
2942
 
2943
            return isValid;
2944
        }
2945
    };
2946
}(window.jQuery));
2947
;(function($) {
2948
    $.fn.bootstrapValidator.i18n.digits = $.extend($.fn.bootstrapValidator.i18n.digits || {}, {
2949
        'default': 'Please enter only digits'
2950
    });
2951
 
2952
    $.fn.bootstrapValidator.validators.digits = {
2953
        /**
2954
         * Return true if the input value contains digits only
2955
         *
2956
         * @param {BootstrapValidator} validator Validate plugin instance
2957
         * @param {jQuery} $field Field element
2958
         * @param {Object} [options]
2959
         * @returns {Boolean}
2960
         */
2961
        validate: function(validator, $field, options) {
2962
            var value = $field.val();
2963
            if (value === '') {
2964
                return true;
2965
            }
2966
 
2967
            return /^\d+$/.test(value);
2968
        }
2969
    };
2970
}(window.jQuery));
2971
;(function($) {
2972
    $.fn.bootstrapValidator.i18n.ean = $.extend($.fn.bootstrapValidator.i18n.ean || {}, {
2973
        'default': 'Please enter a valid EAN number'
2974
    });
2975
 
2976
    $.fn.bootstrapValidator.validators.ean = {
2977
        /**
2978
         * Validate EAN (International Article Number)
2979
         * Examples:
2980
         * - Valid: 73513537, 9780471117094, 4006381333931
2981
         * - Invalid: 73513536
2982
         *
2983
         * @see http://en.wikipedia.org/wiki/European_Article_Number
2984
         * @param {BootstrapValidator} validator The validator plugin instance
2985
         * @param {jQuery} $field Field element
2986
         * @param {Object} options Can consist of the following keys:
2987
         * - message: The invalid message
2988
         * @returns {Boolean}
2989
         */
2990
        validate: function(validator, $field, options) {
2991
            var value = $field.val();
2992
            if (value === '') {
2993
                return true;
2994
            }
2995
 
2996
            if (!/^(\d{8}|\d{12}|\d{13})$/.test(value)) {
2997
                return false;
2998
            }
2999
 
3000
            var length = value.length,
3001
                sum    = 0,
3002
                weight = (length === 8) ? [3, 1] : [1, 3];
3003
            for (var i = 0; i < length - 1; i++) {
3004
                sum += parseInt(value.charAt(i), 10) * weight[i % 2];
3005
            }
3006
            sum = (10 - sum % 10) % 10;
3007
            return (sum + '' === value.charAt(length - 1));
3008
        }
3009
    };
3010
}(window.jQuery));
3011
;(function($) {
3012
    $.fn.bootstrapValidator.i18n.emailAddress = $.extend($.fn.bootstrapValidator.i18n.emailAddress || {}, {
3013
        'default': 'Please enter a valid email address'
3014
    });
3015
 
3016
    $.fn.bootstrapValidator.validators.emailAddress = {
3017
        html5Attributes: {
3018
            message: 'message',
3019
            multiple: 'multiple',
3020
            separator: 'separator'
3021
        },
3022
 
3023
        enableByHtml5: function($field) {
3024
            return ('email' === $field.attr('type'));
3025
        },
3026
 
3027
        /**
3028
         * Return true if and only if the input value is a valid email address
3029
         *
3030
         * @param {BootstrapValidator} validator Validate plugin instance
3031
         * @param {jQuery} $field Field element
3032
         * @param {Object} [options]
3033
         * - multiple: Allow multiple email addresses, separated by a comma or semicolon; default is false.
3034
         * - separator: Regex for character or characters expected as separator between addresses; default is comma /[,;]/, i.e. comma or semicolon.
3035
         * @returns {Boolean}
3036
         */
3037
        validate: function(validator, $field, options) {
3038
            var value = $field.val();
3039
            if (value === '') {
3040
                return true;
3041
            }
3042
 
3043
            // Email address regular expression
3044
            // http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
3045
            var emailRegExp   = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
3046
                allowMultiple = options.multiple === true || options.multiple === 'true';
3047
 
3048
            if (allowMultiple) {
3049
                var separator = options.separator || /[,;]/,
3050
                    addresses = this._splitEmailAddresses(value, separator);
3051
 
3052
                for (var i = 0; i < addresses.length; i++) {
3053
                    if (!emailRegExp.test(addresses[i])) {
3054
                        return false;
3055
                    }
3056
                }
3057
 
3058
                return true;
3059
            } else {
3060
                return emailRegExp.test(value);
3061
            }
3062
        },
3063
 
3064
        _splitEmailAddresses: function(emailAddresses, separator) {
3065
            var quotedFragments     = emailAddresses.split(/"/),
3066
                quotedFragmentCount = quotedFragments.length,
3067
                emailAddressArray   = [],
3068
                nextEmailAddress    = '';
3069
 
3070
            for (var i = 0; i < quotedFragmentCount; i++) {
3071
                if (i % 2 === 0) {
3072
                    var splitEmailAddressFragments     = quotedFragments[i].split(separator),
3073
                        splitEmailAddressFragmentCount = splitEmailAddressFragments.length;
3074
 
3075
                    if (splitEmailAddressFragmentCount === 1) {
3076
                        nextEmailAddress += splitEmailAddressFragments[0];
3077
                    } else {
3078
                        emailAddressArray.push(nextEmailAddress + splitEmailAddressFragments[0]);
3079
 
3080
                        for (var j = 1; j < splitEmailAddressFragmentCount - 1; j++) {
3081
                            emailAddressArray.push(splitEmailAddressFragments[j]);
3082
                        }
3083
                        nextEmailAddress = splitEmailAddressFragments[splitEmailAddressFragmentCount - 1];
3084
                    }
3085
                } else {
3086
                    nextEmailAddress += '"' + quotedFragments[i];
3087
                    if (i < quotedFragmentCount - 1) {
3088
                        nextEmailAddress += '"';
3089
                    }
3090
                }
3091
            }
3092
 
3093
            emailAddressArray.push(nextEmailAddress);
3094
            return emailAddressArray;
3095
        }
3096
    };
3097
}(window.jQuery));
3098
;(function($) {
3099
    $.fn.bootstrapValidator.i18n.file = $.extend($.fn.bootstrapValidator.i18n.file || {}, {
3100
        'default': 'Please choose a valid file'
3101
    });
3102
 
3103
    $.fn.bootstrapValidator.validators.file = {
3104
        html5Attributes: {
3105
            extension: 'extension',
3106
            maxfiles: 'maxFiles',
3107
            minfiles: 'minFiles',
3108
            maxsize: 'maxSize',
3109
            minsize: 'minSize',
3110
            maxtotalsize: 'maxTotalSize',
3111
            mintotalsize: 'minTotalSize',
3112
            message: 'message',
3113
            type: 'type'
3114
        },
3115
 
3116
        /**
3117
         * Validate upload file. Use HTML 5 API if the browser supports
3118
         *
3119
         * @param {BootstrapValidator} validator The validator plugin instance
3120
         * @param {jQuery} $field Field element
3121
         * @param {Object} options Can consist of the following keys:
3122
         * - extension: The allowed extensions, separated by a comma
3123
         * - maxFiles: The maximum number of files
3124
         * - minFiles: The minimum number of files
3125
         * - maxSize: The maximum size in bytes
3126
         * - minSize: The minimum size in bytes
3127
         * - maxTotalSize: The maximum size in bytes for all files
3128
         * - minTotalSize: The minimum size in bytes for all files
3129
         * - message: The invalid message
3130
         * - type: The allowed MIME type, separated by a comma
3131
         * @returns {Boolean}
3132
         */
3133
        validate: function(validator, $field, options) {
3134
            var value = $field.val();
3135
            if (value === '') {
3136
                return true;
3137
            }
3138
 
3139
            var ext,
3140
                extensions = options.extension ? options.extension.toLowerCase().split(',') : null,
3141
                types      = options.type      ? options.type.toLowerCase().split(',')      : null,
3142
                html5      = (window.File && window.FileList && window.FileReader);
3143
 
3144
            if (html5) {
3145
                // Get FileList instance
3146
                var files     = $field.get(0).files,
3147
                    total     = files.length,
3148
                    totalSize = 0;
3149
 
3150
                if ((options.maxFiles && total > parseInt(options.maxFiles, 10))        // Check the maxFiles
3151
                    || (options.minFiles && total < parseInt(options.minFiles, 10)))    // Check the minFiles
3152
                {
3153
                    return false;
3154
                }
3155
 
3156
                for (var i = 0; i < total; i++) {
3157
                    totalSize += files[i].size;
3158
                    ext        = files[i].name.substr(files[i].name.lastIndexOf('.') + 1);
3159
 
3160
                    if ((options.minSize && files[i].size < parseInt(options.minSize, 10))                      // Check the minSize
3161
                        || (options.maxSize && files[i].size > parseInt(options.maxSize, 10))                   // Check the maxSize
3162
                        || (extensions && $.inArray(ext.toLowerCase(), extensions) === -1)                      // Check file extension
3163
                        || (files[i].type && types && $.inArray(files[i].type.toLowerCase(), types) === -1))    // Check file type
3164
                    {
3165
                        return false;
3166
                    }
3167
                }
3168
 
3169
                if ((options.maxTotalSize && totalSize > parseInt(options.maxTotalSize, 10))        // Check the maxTotalSize
3170
                    || (options.minTotalSize && totalSize < parseInt(options.minTotalSize, 10)))    // Check the minTotalSize
3171
                {
3172
                    return false;
3173
                }
3174
            } else {
3175
                // Check file extension
3176
                ext = value.substr(value.lastIndexOf('.') + 1);
3177
                if (extensions && $.inArray(ext.toLowerCase(), extensions) === -1) {
3178
                    return false;
3179
                }
3180
            }
3181
 
3182
            return true;
3183
        }
3184
    };
3185
}(window.jQuery));
3186
;(function($) {
3187
    $.fn.bootstrapValidator.i18n.greaterThan = $.extend($.fn.bootstrapValidator.i18n.greaterThan || {}, {
3188
        'default': 'Please enter a value greater than or equal to %s',
3189
        notInclusive: 'Please enter a value greater than %s'
3190
    });
3191
 
3192
    $.fn.bootstrapValidator.validators.greaterThan = {
3193
        html5Attributes: {
3194
            message: 'message',
3195
            value: 'value',
3196
            inclusive: 'inclusive'
3197
        },
3198
 
3199
        enableByHtml5: function($field) {
3200
            var type = $field.attr('type'),
3201
                min  = $field.attr('min');
3202
            if (min && type !== 'date') {
3203
                return {
3204
                    value: min
3205
                };
3206
            }
3207
 
3208
            return false;
3209
        },
3210
 
3211
        /**
3212
         * Return true if the input value is greater than or equals to given number
3213
         *
3214
         * @param {BootstrapValidator} validator Validate plugin instance
3215
         * @param {jQuery} $field Field element
3216
         * @param {Object} options Can consist of the following keys:
3217
         * - value: Define the number to compare with. It can be
3218
         *      - A number
3219
         *      - Name of field which its value defines the number
3220
         *      - Name of callback function that returns the number
3221
         *      - A callback function that returns the number
3222
         *
3223
         * - inclusive [optional]: Can be true or false. Default is true
3224
         * - message: The invalid message
3225
         * @returns {Boolean|Object}
3226
         */
3227
        validate: function(validator, $field, options) {
3228
            var value = $field.val();
3229
            if (value === '') {
3230
                return true;
3231
            }
3232
 
3233
            value = this._format(value);
3234
            if (!$.isNumeric(value)) {
3235
                return false;
3236
            }
3237
 
3238
            var compareTo      = $.isNumeric(options.value) ? options.value : validator.getDynamicOption($field, options.value),
3239
                compareToValue = this._format(compareTo);
3240
 
3241
            value = parseFloat(value);
3242
			return (options.inclusive === true || options.inclusive === undefined)
3243
                    ? {
3244
                        valid: value >= compareToValue,
3245
                        message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.greaterThan['default'], compareTo)
3246
                    }
3247
                    : {
3248
                        valid: value > compareToValue,
3249
                        message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.greaterThan.notInclusive, compareTo)
3250
                    };
3251
        },
3252
 
3253
        _format: function(value) {
3254
            return (value + '').replace(',', '.');
3255
        }
3256
    };
3257
}(window.jQuery));
3258
;(function($) {
3259
    $.fn.bootstrapValidator.i18n.grid = $.extend($.fn.bootstrapValidator.i18n.grid || {}, {
3260
        'default': 'Please enter a valid GRId number'
3261
    });
3262
 
3263
    $.fn.bootstrapValidator.validators.grid = {
3264
        /**
3265
         * Validate GRId (Global Release Identifier)
3266
         * Examples:
3267
         * - Valid: A12425GABC1234002M, A1-2425G-ABC1234002-M, A1 2425G ABC1234002 M, Grid:A1-2425G-ABC1234002-M
3268
         * - Invalid: A1-2425G-ABC1234002-Q
3269
         *
3270
         * @see http://en.wikipedia.org/wiki/Global_Release_Identifier
3271
         * @param {BootstrapValidator} validator The validator plugin instance
3272
         * @param {jQuery} $field Field element
3273
         * @param {Object} options Can consist of the following keys:
3274
         * - message: The invalid message
3275
         * @returns {Boolean}
3276
         */
3277
        validate: function(validator, $field, options) {
3278
            var value = $field.val();
3279
            if (value === '') {
3280
                return true;
3281
            }
3282
 
3283
            value = value.toUpperCase();
3284
            if (!/^[GRID:]*([0-9A-Z]{2})[-\s]*([0-9A-Z]{5})[-\s]*([0-9A-Z]{10})[-\s]*([0-9A-Z]{1})$/g.test(value)) {
3285
                return false;
3286
            }
3287
            value = value.replace(/\s/g, '').replace(/-/g, '');
3288
            if ('GRID:' === value.substr(0, 5)) {
3289
                value = value.substr(5);
3290
            }
3291
            return $.fn.bootstrapValidator.helpers.mod37And36(value);
3292
        }
3293
    };
3294
}(window.jQuery));
3295
;(function($) {
3296
    $.fn.bootstrapValidator.i18n.hex = $.extend($.fn.bootstrapValidator.i18n.hex || {}, {
3297
        'default': 'Please enter a valid hexadecimal number'
3298
    });
3299
 
3300
    $.fn.bootstrapValidator.validators.hex = {
3301
        /**
3302
         * Return true if and only if the input value is a valid hexadecimal number
3303
         *
3304
         * @param {BootstrapValidator} validator The validator plugin instance
3305
         * @param {jQuery} $field Field element
3306
         * @param {Object} options Consist of key:
3307
         * - message: The invalid message
3308
         * @returns {Boolean}
3309
         */
3310
        validate: function(validator, $field, options) {
3311
            var value = $field.val();
3312
            if (value === '') {
3313
                return true;
3314
            }
3315
 
3316
            return /^[0-9a-fA-F]+$/.test(value);
3317
        }
3318
    };
3319
}(window.jQuery));
3320
;(function($) {
3321
    $.fn.bootstrapValidator.i18n.hexColor = $.extend($.fn.bootstrapValidator.i18n.hexColor || {}, {
3322
        'default': 'Please enter a valid hex color'
3323
    });
3324
 
3325
    $.fn.bootstrapValidator.validators.hexColor = {
3326
        enableByHtml5: function($field) {
3327
            return ('color' === $field.attr('type'));
3328
        },
3329
 
3330
        /**
3331
         * Return true if the input value is a valid hex color
3332
         *
3333
         * @param {BootstrapValidator} validator The validator plugin instance
3334
         * @param {jQuery} $field Field element
3335
         * @param {Object} options Can consist of the following keys:
3336
         * - message: The invalid message
3337
         * @returns {Boolean}
3338
         */
3339
        validate: function(validator, $field, options) {
3340
            var value = $field.val();
3341
            if (value === '') {
3342
                return true;
3343
            }
3344
 
3345
            return ('color' === $field.attr('type'))
3346
                        // Only accept 6 hex character values due to the HTML 5 spec
3347
                        // See http://www.w3.org/TR/html-markup/input.color.html#input.color.attrs.value
3348
                        ? /^#[0-9A-F]{6}$/i.test(value)
3349
                        : /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(value);
3350
        }
3351
    };
3352
}(window.jQuery));
3353
;(function($) {
3354
    $.fn.bootstrapValidator.i18n.iban = $.extend($.fn.bootstrapValidator.i18n.iban || {}, {
3355
        'default': 'Please enter a valid IBAN number',
3356
        countryNotSupported: 'The country code %s is not supported',
3357
        country: 'Please enter a valid IBAN number in %s',
3358
        countries: {
3359
            AD: 'Andorra',
3360
            AE: 'United Arab Emirates',
3361
            AL: 'Albania',
3362
            AO: 'Angola',
3363
            AT: 'Austria',
3364
            AZ: 'Azerbaijan',
3365
            BA: 'Bosnia and Herzegovina',
3366
            BE: 'Belgium',
3367
            BF: 'Burkina Faso',
3368
            BG: 'Bulgaria',
3369
            BH: 'Bahrain',
3370
            BI: 'Burundi',
3371
            BJ: 'Benin',
3372
            BR: 'Brazil',
3373
            CH: 'Switzerland',
3374
            CI: 'Ivory Coast',
3375
            CM: 'Cameroon',
3376
            CR: 'Costa Rica',
3377
            CV: 'Cape Verde',
3378
            CY: 'Cyprus',
3379
            CZ: 'Czech Republic',
3380
            DE: 'Germany',
3381
            DK: 'Denmark',
3382
            DO: 'Dominican Republic',
3383
            DZ: 'Algeria',
3384
            EE: 'Estonia',
3385
            ES: 'Spain',
3386
            FI: 'Finland',
3387
            FO: 'Faroe Islands',
3388
            FR: 'France',
3389
            GB: 'United Kingdom',
3390
            GE: 'Georgia',
3391
            GI: 'Gibraltar',
3392
            GL: 'Greenland',
3393
            GR: 'Greece',
3394
            GT: 'Guatemala',
3395
            HR: 'Croatia',
3396
            HU: 'Hungary',
3397
            IE: 'Ireland',
3398
            IL: 'Israel',
3399
            IR: 'Iran',
3400
            IS: 'Iceland',
3401
            IT: 'Italy',
3402
            JO: 'Jordan',
3403
            KW: 'Kuwait',
3404
            KZ: 'Kazakhstan',
3405
            LB: 'Lebanon',
3406
            LI: 'Liechtenstein',
3407
            LT: 'Lithuania',
3408
            LU: 'Luxembourg',
3409
            LV: 'Latvia',
3410
            MC: 'Monaco',
3411
            MD: 'Moldova',
3412
            ME: 'Montenegro',
3413
            MG: 'Madagascar',
3414
            MK: 'Macedonia',
3415
            ML: 'Mali',
3416
            MR: 'Mauritania',
3417
            MT: 'Malta',
3418
            MU: 'Mauritius',
3419
            MZ: 'Mozambique',
3420
            NL: 'Netherlands',
3421
            NO: 'Norway',
3422
            PK: 'Pakistan',
3423
            PL: 'Poland',
3424
            PS: 'Palestine',
3425
            PT: 'Portugal',
3426
            QA: 'Qatar',
3427
            RO: 'Romania',
3428
            RS: 'Serbia',
3429
            SA: 'Saudi Arabia',
3430
            SE: 'Sweden',
3431
            SI: 'Slovenia',
3432
            SK: 'Slovakia',
3433
            SM: 'San Marino',
3434
            SN: 'Senegal',
3435
            TN: 'Tunisia',
3436
            TR: 'Turkey',
3437
            VG: 'Virgin Islands, British'
3438
        }
3439
    });
3440
 
3441
    $.fn.bootstrapValidator.validators.iban = {
3442
        html5Attributes: {
3443
            message: 'message',
3444
            country: 'country'
3445
        },
3446
 
3447
        // http://www.swift.com/dsp/resources/documents/IBAN_Registry.pdf
3448
        // http://en.wikipedia.org/wiki/International_Bank_Account_Number#IBAN_formats_by_country
3449
        REGEX: {
3450
            AD: 'AD[0-9]{2}[0-9]{4}[0-9]{4}[A-Z0-9]{12}',                       // Andorra
3451
            AE: 'AE[0-9]{2}[0-9]{3}[0-9]{16}',                                  // United Arab Emirates
3452
            AL: 'AL[0-9]{2}[0-9]{8}[A-Z0-9]{16}',                               // Albania
3453
            AO: 'AO[0-9]{2}[0-9]{21}',                                          // Angola
3454
            AT: 'AT[0-9]{2}[0-9]{5}[0-9]{11}',                                  // Austria
3455
            AZ: 'AZ[0-9]{2}[A-Z]{4}[A-Z0-9]{20}',                               // Azerbaijan
3456
            BA: 'BA[0-9]{2}[0-9]{3}[0-9]{3}[0-9]{8}[0-9]{2}',                   // Bosnia and Herzegovina
3457
            BE: 'BE[0-9]{2}[0-9]{3}[0-9]{7}[0-9]{2}',                           // Belgium
3458
            BF: 'BF[0-9]{2}[0-9]{23}',                                          // Burkina Faso
3459
            BG: 'BG[0-9]{2}[A-Z]{4}[0-9]{4}[0-9]{2}[A-Z0-9]{8}',                // Bulgaria
3460
            BH: 'BH[0-9]{2}[A-Z]{4}[A-Z0-9]{14}',                               // Bahrain
3461
            BI: 'BI[0-9]{2}[0-9]{12}',                                          // Burundi
3462
            BJ: 'BJ[0-9]{2}[A-Z]{1}[0-9]{23}',                                  // Benin
3463
            BR: 'BR[0-9]{2}[0-9]{8}[0-9]{5}[0-9]{10}[A-Z][A-Z0-9]',             // Brazil
3464
            CH: 'CH[0-9]{2}[0-9]{5}[A-Z0-9]{12}',                               // Switzerland
3465
            CI: 'CI[0-9]{2}[A-Z]{1}[0-9]{23}',                                  // Ivory Coast
3466
            CM: 'CM[0-9]{2}[0-9]{23}',                                          // Cameroon
3467
            CR: 'CR[0-9]{2}[0-9]{3}[0-9]{14}',                                  // Costa Rica
3468
            CV: 'CV[0-9]{2}[0-9]{21}',                                          // Cape Verde
3469
            CY: 'CY[0-9]{2}[0-9]{3}[0-9]{5}[A-Z0-9]{16}',                       // Cyprus
3470
            CZ: 'CZ[0-9]{2}[0-9]{20}',                                          // Czech Republic
3471
            DE: 'DE[0-9]{2}[0-9]{8}[0-9]{10}',                                  // Germany
3472
            DK: 'DK[0-9]{2}[0-9]{14}',                                          // Denmark
3473
            DO: 'DO[0-9]{2}[A-Z0-9]{4}[0-9]{20}',                               // Dominican Republic
3474
            DZ: 'DZ[0-9]{2}[0-9]{20}',                                          // Algeria
3475
            EE: 'EE[0-9]{2}[0-9]{2}[0-9]{2}[0-9]{11}[0-9]{1}',                  // Estonia
3476
            ES: 'ES[0-9]{2}[0-9]{4}[0-9]{4}[0-9]{1}[0-9]{1}[0-9]{10}',          // Spain
3477
            FI: 'FI[0-9]{2}[0-9]{6}[0-9]{7}[0-9]{1}',                           // Finland
3478
            FO: 'FO[0-9]{2}[0-9]{4}[0-9]{9}[0-9]{1}',                           // Faroe Islands
3479
            FR: 'FR[0-9]{2}[0-9]{5}[0-9]{5}[A-Z0-9]{11}[0-9]{2}',               // France
3480
            GB: 'GB[0-9]{2}[A-Z]{4}[0-9]{6}[0-9]{8}',                           // United Kingdom
3481
            GE: 'GE[0-9]{2}[A-Z]{2}[0-9]{16}',                                  // Georgia
3482
            GI: 'GI[0-9]{2}[A-Z]{4}[A-Z0-9]{15}',                               // Gibraltar
3483
            GL: 'GL[0-9]{2}[0-9]{4}[0-9]{9}[0-9]{1}',                           // Greenland
3484
            GR: 'GR[0-9]{2}[0-9]{3}[0-9]{4}[A-Z0-9]{16}',                       // Greece
3485
            GT: 'GT[0-9]{2}[A-Z0-9]{4}[A-Z0-9]{20}',                            // Guatemala
3486
            HR: 'HR[0-9]{2}[0-9]{7}[0-9]{10}',                                  // Croatia
3487
            HU: 'HU[0-9]{2}[0-9]{3}[0-9]{4}[0-9]{1}[0-9]{15}[0-9]{1}',          // Hungary
3488
            IE: 'IE[0-9]{2}[A-Z]{4}[0-9]{6}[0-9]{8}',                           // Ireland
3489
            IL: 'IL[0-9]{2}[0-9]{3}[0-9]{3}[0-9]{13}',                          // Israel
3490
            IR: 'IR[0-9]{2}[0-9]{22}',                                          // Iran
3491
            IS: 'IS[0-9]{2}[0-9]{4}[0-9]{2}[0-9]{6}[0-9]{10}',                  // Iceland
3492
            IT: 'IT[0-9]{2}[A-Z]{1}[0-9]{5}[0-9]{5}[A-Z0-9]{12}',               // Italy
3493
            JO: 'JO[0-9]{2}[A-Z]{4}[0-9]{4}[0]{8}[A-Z0-9]{10}',                 // Jordan
3494
            KW: 'KW[0-9]{2}[A-Z]{4}[0-9]{22}',                                  // Kuwait
3495
            KZ: 'KZ[0-9]{2}[0-9]{3}[A-Z0-9]{13}',                               // Kazakhstan
3496
            LB: 'LB[0-9]{2}[0-9]{4}[A-Z0-9]{20}',                               // Lebanon
3497
            LI: 'LI[0-9]{2}[0-9]{5}[A-Z0-9]{12}',                               // Liechtenstein
3498
            LT: 'LT[0-9]{2}[0-9]{5}[0-9]{11}',                                  // Lithuania
3499
            LU: 'LU[0-9]{2}[0-9]{3}[A-Z0-9]{13}',                               // Luxembourg
3500
            LV: 'LV[0-9]{2}[A-Z]{4}[A-Z0-9]{13}',                               // Latvia
3501
            MC: 'MC[0-9]{2}[0-9]{5}[0-9]{5}[A-Z0-9]{11}[0-9]{2}',               // Monaco
3502
            MD: 'MD[0-9]{2}[A-Z0-9]{20}',                                       // Moldova
3503
            ME: 'ME[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}',                          // Montenegro
3504
            MG: 'MG[0-9]{2}[0-9]{23}',                                          // Madagascar
3505
            MK: 'MK[0-9]{2}[0-9]{3}[A-Z0-9]{10}[0-9]{2}',                       // Macedonia
3506
            ML: 'ML[0-9]{2}[A-Z]{1}[0-9]{23}',                                  // Mali
3507
            MR: 'MR13[0-9]{5}[0-9]{5}[0-9]{11}[0-9]{2}',                        // Mauritania
3508
            MT: 'MT[0-9]{2}[A-Z]{4}[0-9]{5}[A-Z0-9]{18}',                       // Malta
3509
            MU: 'MU[0-9]{2}[A-Z]{4}[0-9]{2}[0-9]{2}[0-9]{12}[0-9]{3}[A-Z]{3}',  // Mauritius
3510
            MZ: 'MZ[0-9]{2}[0-9]{21}',                                          // Mozambique
3511
            NL: 'NL[0-9]{2}[A-Z]{4}[0-9]{10}',                                  // Netherlands
3512
            NO: 'NO[0-9]{2}[0-9]{4}[0-9]{6}[0-9]{1}',                           // Norway
3513
            PK: 'PK[0-9]{2}[A-Z]{4}[A-Z0-9]{16}',                               // Pakistan
3514
            PL: 'PL[0-9]{2}[0-9]{8}[0-9]{16}',                                  // Poland
3515
            PS: 'PS[0-9]{2}[A-Z]{4}[A-Z0-9]{21}',                               // Palestinian
3516
            PT: 'PT[0-9]{2}[0-9]{4}[0-9]{4}[0-9]{11}[0-9]{2}',                  // Portugal
3517
            QA: 'QA[0-9]{2}[A-Z]{4}[A-Z0-9]{21}',                               // Qatar
3518
            RO: 'RO[0-9]{2}[A-Z]{4}[A-Z0-9]{16}',                               // Romania
3519
            RS: 'RS[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}',                          // Serbia
3520
            SA: 'SA[0-9]{2}[0-9]{2}[A-Z0-9]{18}',                               // Saudi Arabia
3521
            SE: 'SE[0-9]{2}[0-9]{3}[0-9]{16}[0-9]{1}',                          // Sweden
3522
            SI: 'SI[0-9]{2}[0-9]{5}[0-9]{8}[0-9]{2}',                           // Slovenia
3523
            SK: 'SK[0-9]{2}[0-9]{4}[0-9]{6}[0-9]{10}',                          // Slovakia
3524
            SM: 'SM[0-9]{2}[A-Z]{1}[0-9]{5}[0-9]{5}[A-Z0-9]{12}',               // San Marino
3525
            SN: 'SN[0-9]{2}[A-Z]{1}[0-9]{23}',                                  // Senegal
3526
            TN: 'TN59[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}',                        // Tunisia
3527
            TR: 'TR[0-9]{2}[0-9]{5}[A-Z0-9]{1}[A-Z0-9]{16}',                    // Turkey
3528
            VG: 'VG[0-9]{2}[A-Z]{4}[0-9]{16}'                                   // Virgin Islands, British
3529
        },
3530
 
3531
        /**
3532
         * Validate an International Bank Account Number (IBAN)
3533
         * To test it, take the sample IBAN from
3534
         * http://www.nordea.com/Our+services/International+products+and+services/Cash+Management/IBAN+countries/908462.html
3535
         *
3536
         * @param {BootstrapValidator} validator The validator plugin instance
3537
         * @param {jQuery} $field Field element
3538
         * @param {Object} options Can consist of the following keys:
3539
         * - message: The invalid message
3540
         * - country: The ISO 3166-1 country code. It can be
3541
         *      - A country code
3542
         *      - Name of field which its value defines the country code
3543
         *      - Name of callback function that returns the country code
3544
         *      - A callback function that returns the country code
3545
         * @returns {Boolean|Object}
3546
         */
3547
        validate: function(validator, $field, options) {
3548
            var value = $field.val();
3549
            if (value === '') {
3550
                return true;
3551
            }
3552
 
3553
            value = value.replace(/[^a-zA-Z0-9]/g, '').toUpperCase();
3554
            var country = options.country;
3555
            if (!country) {
3556
                country = value.substr(0, 2);
3557
            } else if (typeof country !== 'string' || !this.REGEX[country]) {
3558
                // Determine the country code
3559
                country = validator.getDynamicOption($field, country);
3560
            }
3561
 
3562
            if (!this.REGEX[country]) {
3563
                return {
3564
                    valid: false,
3565
                    message: $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.iban.countryNotSupported, country)
3566
                };
3567
            }
3568
 
3569
            if (!(new RegExp('^' + this.REGEX[country] + '$')).test(value)) {
3570
                return {
3571
                    valid: false,
3572
                    message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.iban.country, $.fn.bootstrapValidator.i18n.iban.countries[country])
3573
                };
3574
            }
3575
 
3576
            value = value.substr(4) + value.substr(0, 4);
3577
            value = $.map(value.split(''), function(n) {
3578
                var code = n.charCodeAt(0);
3579
                return (code >= 'A'.charCodeAt(0) && code <= 'Z'.charCodeAt(0))
3580
                        // Replace A, B, C, ..., Z with 10, 11, ..., 35
3581
                        ? (code - 'A'.charCodeAt(0) + 10)
3582
                        : n;
3583
            });
3584
            value = value.join('');
3585
 
3586
            var temp   = parseInt(value.substr(0, 1), 10),
3587
                length = value.length;
3588
            for (var i = 1; i < length; ++i) {
3589
                temp = (temp * 10 + parseInt(value.substr(i, 1), 10)) % 97;
3590
            }
3591
 
3592
            return {
3593
                valid: (temp === 1),
3594
                message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.iban.country, $.fn.bootstrapValidator.i18n.iban.countries[country])
3595
            };
3596
        }
3597
    };
3598
}(window.jQuery));
3599
;(function($) {
3600
    $.fn.bootstrapValidator.i18n.id = $.extend($.fn.bootstrapValidator.i18n.id || {}, {
3601
        'default': 'Please enter a valid identification number',
3602
        countryNotSupported: 'The country code %s is not supported',
3603
        country: 'Please enter a valid identification number in %s',
3604
        countries: {
3605
            BA: 'Bosnia and Herzegovina',
3606
            BG: 'Bulgaria',
3607
            BR: 'Brazil',
3608
            CH: 'Switzerland',
3609
            CL: 'Chile',
3610
            CN: 'China',
3611
            CZ: 'Czech Republic',
3612
            DK: 'Denmark',
3613
            EE: 'Estonia',
3614
            ES: 'Spain',
3615
            FI: 'Finland',
3616
            HR: 'Croatia',
3617
            IE: 'Ireland',
3618
            IS: 'Iceland',
3619
            LT: 'Lithuania',
3620
            LV: 'Latvia',
3621
            ME: 'Montenegro',
3622
            MK: 'Macedonia',
3623
            NL: 'Netherlands',
3624
            RO: 'Romania',
3625
            RS: 'Serbia',
3626
            SE: 'Sweden',
3627
            SI: 'Slovenia',
3628
            SK: 'Slovakia',
3629
            SM: 'San Marino',
3630
            TH: 'Thailand',
3631
            ZA: 'South Africa'
3632
        }
3633
    });
3634
 
3635
    $.fn.bootstrapValidator.validators.id = {
3636
        html5Attributes: {
3637
            message: 'message',
3638
            country: 'country'
3639
        },
3640
 
3641
        // Supported country codes
3642
        COUNTRY_CODES: [
3643
            'BA', 'BG', 'BR', 'CH', 'CL', 'CN', 'CZ', 'DK', 'EE', 'ES', 'FI', 'HR', 'IE', 'IS', 'LT', 'LV', 'ME', 'MK', 'NL',
3644
            'RO', 'RS', 'SE', 'SI', 'SK', 'SM', 'TH', 'ZA'
3645
        ],
3646
 
3647
        /**
3648
         * Validate identification number in different countries
3649
         *
3650
         * @see http://en.wikipedia.org/wiki/National_identification_number
3651
         * @param {BootstrapValidator} validator The validator plugin instance
3652
         * @param {jQuery} $field Field element
3653
         * @param {Object} options Consist of key:
3654
         * - message: The invalid message
3655
         * - country: The ISO 3166-1 country code. It can be
3656
         *      - One of country code defined in COUNTRY_CODES
3657
         *      - Name of field which its value defines the country code
3658
         *      - Name of callback function that returns the country code
3659
         *      - A callback function that returns the country code
3660
         * @returns {Boolean|Object}
3661
         */
3662
        validate: function(validator, $field, options) {
3663
            var value = $field.val();
3664
            if (value === '') {
3665
                return true;
3666
            }
3667
 
3668
            var country = options.country;
3669
            if (!country) {
3670
                country = value.substr(0, 2);
3671
            } else if (typeof country !== 'string' || $.inArray(country.toUpperCase(), this.COUNTRY_CODES) === -1) {
3672
                // Determine the country code
3673
                country = validator.getDynamicOption($field, country);
3674
            }
3675
 
3676
            if ($.inArray(country, this.COUNTRY_CODES) === -1) {
3677
                return { valid: false, message: $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.id.countryNotSupported, country) };
3678
            }
3679
 
3680
            var method  = ['_', country.toLowerCase()].join('');
3681
            return this[method](value)
3682
                    ? true
3683
                    : {
3684
                        valid: false,
3685
                        message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.id.country, $.fn.bootstrapValidator.i18n.id.countries[country.toUpperCase()])
3686
                    };
3687
        },
3688
 
3689
        /**
3690
         * Validate Unique Master Citizen Number which uses in
3691
         * - Bosnia and Herzegovina (country code: BA)
3692
         * - Macedonia (MK)
3693
         * - Montenegro (ME)
3694
         * - Serbia (RS)
3695
         * - Slovenia (SI)
3696
         *
3697
         * @see http://en.wikipedia.org/wiki/Unique_Master_Citizen_Number
3698
         * @param {String} value The ID
3699
         * @param {String} countryCode The ISO country code, can be BA, MK, ME, RS, SI
3700
         * @returns {Boolean}
3701
         */
3702
        _validateJMBG: function(value, countryCode) {
3703
            if (!/^\d{13}$/.test(value)) {
3704
                return false;
3705
            }
3706
            var day   = parseInt(value.substr(0, 2), 10),
3707
                month = parseInt(value.substr(2, 2), 10),
3708
                year  = parseInt(value.substr(4, 3), 10),
3709
                rr    = parseInt(value.substr(7, 2), 10),
3710
                k     = parseInt(value.substr(12, 1), 10);
3711
 
3712
            // Validate date of birth
3713
            // FIXME: Validate the year of birth
3714
            if (day > 31 || month > 12) {
3715
                return false;
3716
            }
3717
 
3718
            // Validate checksum
3719
            var sum = 0;
3720
            for (var i = 0; i < 6; i++) {
3721
                sum += (7 - i) * (parseInt(value.charAt(i), 10) + parseInt(value.charAt(i + 6), 10));
3722
            }
3723
            sum = 11 - sum % 11;
3724
            if (sum === 10 || sum === 11) {
3725
                sum = 0;
3726
            }
3727
            if (sum !== k) {
3728
                return false;
3729
            }
3730
 
3731
            // Validate political region
3732
            // rr is the political region of birth, which can be in ranges:
3733
            // 10-19: Bosnia and Herzegovina
3734
            // 20-29: Montenegro
3735
            // 30-39: Croatia (not used anymore)
3736
            // 41-49: Macedonia
3737
            // 50-59: Slovenia (only 50 is used)
3738
            // 70-79: Central Serbia
3739
            // 80-89: Serbian province of Vojvodina
3740
            // 90-99: Kosovo
3741
            switch (countryCode.toUpperCase()) {
3742
                case 'BA':
3743
                    return (10 <= rr && rr <= 19);
3744
                case 'MK':
3745
                    return (41 <= rr && rr <= 49);
3746
                case 'ME':
3747
                    return (20 <= rr && rr <= 29);
3748
                case 'RS':
3749
                    return (70 <= rr && rr <= 99);
3750
                case 'SI':
3751
                    return (50 <= rr && rr <= 59);
3752
                default:
3753
                    return true;
3754
            }
3755
        },
3756
 
3757
        _ba: function(value) {
3758
            return this._validateJMBG(value, 'BA');
3759
        },
3760
        _mk: function(value) {
3761
            return this._validateJMBG(value, 'MK');
3762
        },
3763
        _me: function(value) {
3764
            return this._validateJMBG(value, 'ME');
3765
        },
3766
        _rs: function(value) {
3767
            return this._validateJMBG(value, 'RS');
3768
        },
3769
 
3770
        /**
3771
         * Examples: 0101006500006
3772
         */
3773
        _si: function(value) {
3774
            return this._validateJMBG(value, 'SI');
3775
        },
3776
 
3777
        /**
3778
         * Validate Bulgarian national identification number (EGN)
3779
         * Examples:
3780
         * - Valid: 7523169263, 8032056031, 803205 603 1, 8001010008, 7501020018, 7552010005, 7542011030
3781
         * - Invalid: 8019010008
3782
         *
3783
         * @see http://en.wikipedia.org/wiki/Uniform_civil_number
3784
         * @param {String} value The ID
3785
         * @returns {Boolean}
3786
         */
3787
        _bg: function(value) {
3788
            if (!/^\d{10}$/.test(value) && !/^\d{6}\s\d{3}\s\d{1}$/.test(value)) {
3789
                return false;
3790
            }
3791
            value = value.replace(/\s/g, '');
3792
            // Check the birth date
3793
            var year  = parseInt(value.substr(0, 2), 10) + 1900,
3794
                month = parseInt(value.substr(2, 2), 10),
3795
                day   = parseInt(value.substr(4, 2), 10);
3796
            if (month > 40) {
3797
                year += 100;
3798
                month -= 40;
3799
            } else if (month > 20) {
3800
                year -= 100;
3801
                month -= 20;
3802
            }
3803
 
3804
            if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
3805
                return false;
3806
            }
3807
 
3808
            var sum    = 0,
3809
                weight = [2, 4, 8, 5, 10, 9, 7, 3, 6];
3810
            for (var i = 0; i < 9; i++) {
3811
                sum += parseInt(value.charAt(i), 10) * weight[i];
3812
            }
3813
            sum = (sum % 11) % 10;
3814
            return (sum + '' === value.substr(9, 1));
3815
        },
3816
 
3817
        /**
3818
         * Validate Brazilian national identification number (CPF)
3819
         * Examples:
3820
         * - Valid: 39053344705, 390.533.447-05, 111.444.777-35
3821
         * - Invalid: 231.002.999-00
3822
         *
3823
         * @see http://en.wikipedia.org/wiki/Cadastro_de_Pessoas_F%C3%ADsicas
3824
         * @param {String} value The ID
3825
         * @returns {Boolean}
3826
         */
3827
        _br: function(value) {
3828
            if (/^1{11}|2{11}|3{11}|4{11}|5{11}|6{11}|7{11}|8{11}|9{11}|0{11}$/.test(value)) {
3829
                return false;
3830
            }
3831
            if (!/^\d{11}$/.test(value) && !/^\d{3}\.\d{3}\.\d{3}-\d{2}$/.test(value)) {
3832
                return false;
3833
            }
3834
            value = value.replace(/\./g, '').replace(/-/g, '');
3835
 
3836
            var d1 = 0;
3837
            for (var i = 0; i < 9; i++) {
3838
                d1 += (10 - i) * parseInt(value.charAt(i), 10);
3839
            }
3840
            d1 = 11 - d1 % 11;
3841
            if (d1 === 10 || d1 === 11) {
3842
                d1 = 0;
3843
            }
3844
            if (d1 + '' !== value.charAt(9)) {
3845
                return false;
3846
            }
3847
 
3848
            var d2 = 0;
3849
            for (i = 0; i < 10; i++) {
3850
                d2 += (11 - i) * parseInt(value.charAt(i), 10);
3851
            }
3852
            d2 = 11 - d2 % 11;
3853
            if (d2 === 10 || d2 === 11) {
3854
                d2 = 0;
3855
            }
3856
 
3857
            return (d2 + '' === value.charAt(10));
3858
        },
3859
 
3860
        /**
3861
         * Validate Swiss Social Security Number (AHV-Nr/No AVS)
3862
         * Examples:
3863
         * - Valid: 756.1234.5678.95, 7561234567895
3864
         *
3865
         * @see http://en.wikipedia.org/wiki/National_identification_number#Switzerland
3866
         * @see http://www.bsv.admin.ch/themen/ahv/00011/02185/index.html?lang=de
3867
         * @param {String} value The ID
3868
         * @returns {Boolean}
3869
         */
3870
        _ch: function(value) {
3871
            if (!/^756[\.]{0,1}[0-9]{4}[\.]{0,1}[0-9]{4}[\.]{0,1}[0-9]{2}$/.test(value)) {
3872
                return false;
3873
            }
3874
            value = value.replace(/\D/g, '').substr(3);
3875
            var length = value.length,
3876
                sum    = 0,
3877
                weight = (length === 8) ? [3, 1] : [1, 3];
3878
            for (var i = 0; i < length - 1; i++) {
3879
                sum += parseInt(value.charAt(i), 10) * weight[i % 2];
3880
            }
3881
            sum = 10 - sum % 10;
3882
            return (sum + '' === value.charAt(length - 1));
3883
        },
3884
 
3885
        /**
3886
         * Validate Chilean national identification number (RUN/RUT)
3887
         * Examples:
3888
         * - Valid: 76086428-5, 22060449-7, 12531909-2
3889
         *
3890
         * @see http://en.wikipedia.org/wiki/National_identification_number#Chile
3891
         * @see https://palena.sii.cl/cvc/dte/ee_empresas_emisoras.html for samples
3892
         * @param {String} value The ID
3893
         * @returns {Boolean}
3894
         */
3895
        _cl: function(value) {
3896
            if (!/^\d{7,8}[-]{0,1}[0-9K]$/i.test(value)) {
3897
                return false;
3898
            }
3899
            value = value.replace(/\-/g, '');
3900
            while (value.length < 9) {
3901
                value = '0' + value;
3902
            }
3903
            var sum    = 0,
3904
                weight = [3, 2, 7, 6, 5, 4, 3, 2];
3905
            for (var i = 0; i < 8; i++) {
3906
                sum += parseInt(value.charAt(i), 10) * weight[i];
3907
            }
3908
            sum = 11 - sum % 11;
3909
            if (sum === 11) {
3910
                sum = 0;
3911
            } else if (sum === 10) {
3912
                sum = 'K';
3913
            }
3914
            return sum + '' === value.charAt(8).toUpperCase();
3915
        },
3916
 
3917
        /**
3918
         * Validate Chinese citizen identification number
3919
         *
3920
         * Rules:
3921
         * - For current 18-digit system (since 1st Oct 1999, defined by GB11643—1999 national standard):
3922
         *     - Digit 0-5: Must be a valid administrative division code of China PR.
3923
         *     - Digit 6-13: Must be a valid YYYYMMDD date of birth. A future date is tolerated.
3924
         *     - Digit 14-16: Order code, any integer.
3925
         *     - Digit 17: An ISO 7064:1983, MOD 11-2 checksum.
3926
         *       Both upper/lower case of X are tolerated.
3927
         * - For deprecated 15-digit system:
3928
         *     - Digit 0-5: Must be a valid administrative division code of China PR.
3929
         *     - Digit 6-11: Must be a valid YYMMDD date of birth, indicating the year of 19XX.
3930
         *     - Digit 12-14: Order code, any integer.
3931
         * Lists of valid administrative division codes of China PR can be seen here:
3932
         * <http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/>
3933
         * Published and maintained by National Bureau of Statistics of China PR.
3934
         * NOTE: Current and deprecated codes MUST BOTH be considered valid.
3935
         * Many Chinese citizens born in once existed administrative divisions!
3936
         *
3937
         * @see http://en.wikipedia.org/wiki/Resident_Identity_Card#Identity_card_number
3938
         * @param {String} value The ID
3939
         * @returns {Boolean}
3940
         */
3941
        _cn: function(value) {
3942
            // Basic format check (18 or 15 digits, considering X in checksum)
3943
            value = value.trim();
3944
            if (!/^\d{15}$/.test(value) && !/^\d{17}[\dXx]{1}$/.test(value)) {
3945
                return false;
3946
            }
3947
 
3948
            // Check China PR Administrative division code
3949
            var adminDivisionCodes = {
3950
                11: {
3951
                    0: [0],
3952
                    1: [[0, 9], [11, 17]],
3953
                    2: [0, 28, 29]
3954
                },
3955
                12: {
3956
                    0: [0],
3957
                    1: [[0, 16]],
3958
                    2: [0, 21, 23, 25]
3959
                },
3960
                13: {
3961
                    0: [0],
3962
                    1: [[0, 5], 7, 8, 21, [23, 33], [81, 85]],
3963
                    2: [[0, 5], [7, 9], [23, 25], 27, 29, 30, 81, 83],
3964
                    3: [[0, 4], [21, 24]],
3965
                    4: [[0, 4], 6, 21, [23, 35], 81],
3966
                    5: [[0, 3], [21, 35], 81, 82],
3967
                    6: [[0, 4], [21, 38], [81, 84]],
3968
                    7: [[0, 3], 5, 6, [21, 33]],
3969
                    8: [[0, 4], [21, 28]],
3970
                    9: [[0, 3], [21, 30], [81, 84]],
3971
                    10: [[0, 3], [22, 26], 28, 81, 82],
3972
                    11: [[0, 2], [21, 28], 81, 82]
3973
                },
3974
                14: {
3975
                    0: [0],
3976
                    1: [0, 1, [5, 10], [21, 23], 81],
3977
                    2: [[0, 3], 11, 12, [21, 27]],
3978
                    3: [[0, 3], 11, 21, 22],
3979
                    4: [[0, 2], 11, 21, [23, 31], 81],
3980
                    5: [[0, 2], 21, 22, 24, 25, 81],
3981
                    6: [[0, 3], [21, 24]],
3982
                    7: [[0, 2], [21, 29], 81],
3983
                    8: [[0, 2], [21, 30], 81, 82],
3984
                    9: [[0, 2], [21, 32], 81],
3985
                    10: [[0, 2], [21, 34], 81, 82],
3986
                    11: [[0, 2], [21, 30], 81, 82],
3987
                    23: [[0, 3], 22, 23, [25, 30], 32, 33]
3988
                },
3989
                15: {
3990
                    0: [0],
3991
                    1: [[0, 5], [21, 25]],
3992
                    2: [[0, 7], [21, 23]],
3993
                    3: [[0, 4]],
3994
                    4: [[0, 4], [21, 26], [28, 30]],
3995
                    5: [[0, 2], [21, 26], 81],
3996
                    6: [[0, 2], [21, 27]],
3997
                    7: [[0, 3], [21, 27], [81, 85]],
3998
                    8: [[0, 2], [21, 26]],
3999
                    9: [[0, 2], [21, 29], 81],
4000
                    22: [[0, 2], [21, 24]],
4001
                    25: [[0, 2], [22, 31]],
4002
                    26: [[0, 2], [24, 27], [29, 32], 34],
4003
                    28: [0, 1, [22, 27]],
4004
                    29: [0, [21, 23]]
4005
                },
4006
                21: {
4007
                    0: [0],
4008
                    1: [[0, 6], [11, 14], [22, 24], 81],
4009
                    2: [[0, 4], [11, 13], 24, [81, 83]],
4010
                    3: [[0, 4], 11, 21, 23, 81],
4011
                    4: [[0, 4], 11, [21, 23]],
4012
                    5: [[0, 5], 21, 22],
4013
                    6: [[0, 4], 24, 81, 82],
4014
                    7: [[0, 3], 11, 26, 27, 81, 82],
4015
                    8: [[0, 4], 11, 81, 82],
4016
                    9: [[0, 5], 11, 21, 22],
4017
                    10: [[0, 5], 11, 21, 81],
4018
                    11: [[0, 3], 21, 22],
4019
                    12: [[0, 2], 4, 21, 23, 24, 81, 82],
4020
                    13: [[0, 3], 21, 22, 24, 81, 82],
4021
                    14: [[0, 4], 21, 22, 81]
4022
                },
4023
                22: {
4024
                    0: [0],
4025
                    1: [[0, 6], 12, 22, [81, 83]],
4026
                    2: [[0, 4], 11, 21, [81, 84]],
4027
                    3: [[0, 3], 22, 23, 81, 82],
4028
                    4: [[0, 3], 21, 22],
4029
                    5: [[0, 3], 21, 23, 24, 81, 82],
4030
                    6: [[0, 2], 4, 5, [21, 23], 25, 81],
4031
                    7: [[0, 2], [21, 24], 81],
4032
                    8: [[0, 2], 21, 22, 81, 82],
4033
                    24: [[0, 6], 24, 26]
4034
                },
4035
                23: {
4036
                    0: [0],
4037
                    1: [[0, 12], 21, [23, 29], [81, 84]],
4038
                    2: [[0, 8], 21, [23, 25], 27, [29, 31], 81],
4039
                    3: [[0, 7], 21, 81, 82],
4040
                    4: [[0, 7], 21, 22],
4041
                    5: [[0, 3], 5, 6, [21, 24]],
4042
                    6: [[0, 6], [21, 24]],
4043
                    7: [[0, 16], 22, 81],
4044
                    8: [[0, 5], 11, 22, 26, 28, 33, 81, 82],
4045
                    9: [[0, 4], 21],
4046
                    10: [[0, 5], 24, 25, 81, [83, 85]],
4047
                    11: [[0, 2], 21, 23, 24, 81, 82],
4048
                    12: [[0, 2], [21, 26], [81, 83]],
4049
                    27: [[0, 4], [21, 23]]
4050
                },
4051
                31: {
4052
                    0: [0],
4053
                    1: [0, 1, [3, 10], [12, 20]],
4054
                    2: [0, 30]
4055
                },
4056
                32: {
4057
                    0: [0],
4058
                    1: [[0, 7], 11, [13, 18], 24, 25],
4059
                    2: [[0, 6], 11, 81, 82],
4060
                    3: [[0, 5], 11, 12, [21, 24], 81, 82],
4061
                    4: [[0, 2], 4, 5, 11, 12, 81, 82],
4062
                    5: [[0, 9], [81, 85]],
4063
                    6: [[0, 2], 11, 12, 21, 23, [81, 84]],
4064
                    7: [0, 1, 3, 5, 6, [21, 24]],
4065
                    8: [[0, 4], 11, 26, [29, 31]],
4066
                    9: [[0, 3], [21, 25], 28, 81, 82],
4067
                    10: [[0, 3], 11, 12, 23, 81, 84, 88],
4068
                    11: [[0, 2], 11, 12, [81, 83]],
4069
                    12: [[0, 4], [81, 84]],
4070
                    13: [[0, 2], 11, [21, 24]]
4071
                },
4072
                33: {
4073
                    0: [0],
4074
                    1: [[0, 6], [8, 10], 22, 27, 82, 83, 85],
4075
                    2: [0, 1, [3, 6], 11, 12, 25, 26, [81, 83]],
4076
                    3: [[0, 4], 22, 24, [26, 29], 81, 82],
4077
                    4: [[0, 2], 11, 21, 24, [81, 83]],
4078
                    5: [[0, 3], [21, 23]],
4079
                    6: [[0, 2], 21, 24, [81, 83]],
4080
                    7: [[0, 3], 23, 26, 27, [81, 84]],
4081
                    8: [[0, 3], 22, 24, 25, 81],
4082
                    9: [[0, 3], 21, 22],
4083
                    10: [[0, 4], [21, 24], 81, 82],
4084
                    11: [[0, 2], [21, 27], 81]
4085
                },
4086
                34: {
4087
                    0: [0],
4088
                    1: [[0, 4], 11, [21, 24], 81],
4089
                    2: [[0, 4], 7, 8, [21, 23], 25],
4090
                    3: [[0, 4], 11, [21, 23]],
4091
                    4: [[0, 6], 21],
4092
                    5: [[0, 4], 6, [21, 23]],
4093
                    6: [[0, 4], 21],
4094
                    7: [[0, 3], 11, 21],
4095
                    8: [[0, 3], 11, [22, 28], 81],
4096
                    10: [[0, 4], [21, 24]],
4097
                    11: [[0, 3], 22, [24, 26], 81, 82],
4098
                    12: [[0, 4], 21, 22, 25, 26, 82],
4099
                    13: [[0, 2], [21, 24]],
4100
                    14: [[0, 2], [21, 24]],
4101
                    15: [[0, 3], [21, 25]],
4102
                    16: [[0, 2], [21, 23]],
4103
                    17: [[0, 2], [21, 23]],
4104
                    18: [[0, 2], [21, 25], 81]
4105
                },
4106
                35: {
4107
                    0: [0],
4108
                    1: [[0, 5], 11, [21, 25], 28, 81, 82],
4109
                    2: [[0, 6], [11, 13]],
4110
                    3: [[0, 5], 22],
4111
                    4: [[0, 3], 21, [23, 30], 81],
4112
                    5: [[0, 5], 21, [24, 27], [81, 83]],
4113
                    6: [[0, 3], [22, 29], 81],
4114
                    7: [[0, 2], [21, 25], [81, 84]],
4115
                    8: [[0, 2], [21, 25], 81],
4116
                    9: [[0, 2], [21, 26], 81, 82]
4117
                },
4118
                36: {
4119
                    0: [0],
4120
                    1: [[0, 5], 11, [21, 24]],
4121
                    2: [[0, 3], 22, 81],
4122
                    3: [[0, 2], 13, [21, 23]],
4123
                    4: [[0, 3], 21, [23, 30], 81, 82],
4124
                    5: [[0, 2], 21],
4125
                    6: [[0, 2], 22, 81],
4126
                    7: [[0, 2], [21, 35], 81, 82],
4127
                    8: [[0, 3], [21, 30], 81],
4128
                    9: [[0, 2], [21, 26], [81, 83]],
4129
                    10: [[0, 2], [21, 30]],
4130
                    11: [[0, 2], [21, 30], 81]
4131
                },
4132
                37: {
4133
                    0: [0],
4134
                    1: [[0, 5], 12, 13, [24, 26], 81],
4135
                    2: [[0, 3], 5, [11, 14], [81, 85]],
4136
                    3: [[0, 6], [21, 23]],
4137
                    4: [[0, 6], 81],
4138
                    5: [[0, 3], [21, 23]],
4139
                    6: [[0, 2], [11, 13], 34, [81, 87]],
4140
                    7: [[0, 5], 24, 25, [81, 86]],
4141
                    8: [[0, 2], 11, [26, 32], [81, 83]],
4142
                    9: [[0, 3], 11, 21, 23, 82, 83],
4143
                    10: [[0, 2], [81, 83]],
4144
                    11: [[0, 3], 21, 22],
4145
                    12: [[0, 3]],
4146
                    13: [[0, 2], 11, 12, [21, 29]],
4147
                    14: [[0, 2], [21, 28], 81, 82],
4148
                    15: [[0, 2], [21, 26], 81],
4149
                    16: [[0, 2], [21, 26]],
4150
                    17: [[0, 2], [21, 28]]
4151
                },
4152
                41: {
4153
                    0: [0],
4154
                    1: [[0, 6], 8, 22, [81, 85]],
4155
                    2: [[0, 5], 11, [21, 25]],
4156
                    3: [[0, 7], 11, [22, 29], 81],
4157
                    4: [[0, 4], 11, [21, 23], 25, 81, 82],
4158
                    5: [[0, 3], 5, 6, 22, 23, 26, 27, 81],
4159
                    6: [[0, 3], 11, 21, 22],
4160
                    7: [[0, 4], 11, 21, [24, 28], 81, 82],
4161
                    8: [[0, 4], 11, [21, 23], 25, [81, 83]],
4162
                    9: [[0, 2], 22, 23, [26, 28]],
4163
                    10: [[0, 2], [23, 25], 81, 82],
4164
                    11: [[0, 4], [21, 23]],
4165
                    12: [[0, 2], 21, 22, 24, 81, 82],
4166
                    13: [[0, 3], [21, 30], 81],
4167
                    14: [[0, 3], [21, 26], 81],
4168
                    15: [[0, 3], [21, 28]],
4169
                    16: [[0, 2], [21, 28], 81],
4170
                    17: [[0, 2], [21, 29]],
4171
                    90: [0, 1]
4172
                },
4173
                42: {
4174
                    0: [0],
4175
                    1: [[0, 7], [11, 17]],
4176
                    2: [[0, 5], 22, 81],
4177
                    3: [[0, 3], [21, 25], 81],
4178
                    5: [[0, 6], [25, 29], [81, 83]],
4179
                    6: [[0, 2], 6, 7, [24, 26], [82, 84]],
4180
                    7: [[0, 4]],
4181
                    8: [[0, 2], 4, 21, 22, 81],
4182
                    9: [[0, 2], [21, 23], 81, 82, 84],
4183
                    10: [[0, 3], [22, 24], 81, 83, 87],
4184
                    11: [[0, 2], [21, 27], 81, 82],
4185
                    12: [[0, 2], [21, 24], 81],
4186
                    13: [[0, 3], 21, 81],
4187
                    28: [[0, 2], 22, 23, [25, 28]],
4188
                    90: [0, [4, 6], 21]
4189
                },
4190
                43: {
4191
                    0: [0],
4192
                    1: [[0, 5], 11, 12, 21, 22, 24, 81],
4193
                    2: [[0, 4], 11, 21, [23, 25], 81],
4194
                    3: [[0, 2], 4, 21, 81, 82],
4195
                    4: [0, 1, [5, 8], 12, [21, 24], 26, 81, 82],
4196
                    5: [[0, 3], 11, [21, 25], [27, 29], 81],
4197
                    6: [[0, 3], 11, 21, 23, 24, 26, 81, 82],
4198
                    7: [[0, 3], [21, 26], 81],
4199
                    8: [[0, 2], 11, 21, 22],
4200
                    9: [[0, 3], [21, 23], 81],
4201
                    10: [[0, 3], [21, 28], 81],
4202
                    11: [[0, 3], [21, 29]],
4203
                    12: [[0, 2], [21, 30], 81],
4204
                    13: [[0, 2], 21, 22, 81, 82],
4205
                    31: [0, 1, [22, 27], 30]
4206
                },
4207
                44: {
4208
                    0: [0],
4209
                    1: [[0, 7], [11, 16], 83, 84],
4210
                    2: [[0, 5], 21, 22, 24, 29, 32, 33, 81, 82],
4211
                    3: [0, 1, [3, 8]],
4212
                    4: [[0, 4]],
4213
                    5: [0, 1, [6, 15], 23, 82, 83],
4214
                    6: [0, 1, [4, 8]],
4215
                    7: [0, 1, [3, 5], 81, [83, 85]],
4216
                    8: [[0, 4], 11, 23, 25, [81, 83]],
4217
                    9: [[0, 3], 23, [81, 83]],
4218
                    12: [[0, 3], [23, 26], 83, 84],
4219
                    13: [[0, 3], [22, 24], 81],
4220
                    14: [[0, 2], [21, 24], 26, 27, 81],
4221
                    15: [[0, 2], 21, 23, 81],
4222
                    16: [[0, 2], [21, 25]],
4223
                    17: [[0, 2], 21, 23, 81],
4224
                    18: [[0, 3], 21, 23, [25, 27], 81, 82],
4225
                    19: [0],
4226
                    20: [0],
4227
                    51: [[0, 3], 21, 22],
4228
                    52: [[0, 3], 21, 22, 24, 81],
4229
                    53: [[0, 2], [21, 23], 81]
4230
                },
4231
                45: {
4232
                    0: [0],
4233
                    1: [[0, 9], [21, 27]],
4234
                    2: [[0, 5], [21, 26]],
4235
                    3: [[0, 5], 11, 12, [21, 32]],
4236
                    4: [0, 1, [3, 6], 11, [21, 23], 81],
4237
                    5: [[0, 3], 12, 21],
4238
                    6: [[0, 3], 21, 81],
4239
                    7: [[0, 3], 21, 22],
4240
                    8: [[0, 4], 21, 81],
4241
                    9: [[0, 3], [21, 24], 81],
4242
                    10: [[0, 2], [21, 31]],
4243
                    11: [[0, 2], [21, 23]],
4244
                    12: [[0, 2], [21, 29], 81],
4245
                    13: [[0, 2], [21, 24], 81],
4246
                    14: [[0, 2], [21, 25], 81]
4247
                },
4248
                46: {
4249
                    0: [0],
4250
                    1: [0, 1, [5, 8]],
4251
                    2: [0, 1],
4252
                    3: [0, [21, 23]],
4253
                    90: [[0, 3], [5, 7], [21, 39]]
4254
                },
4255
                50: {
4256
                    0: [0],
4257
                    1: [[0, 19]],
4258
                    2: [0, [22, 38], [40, 43]],
4259
                    3: [0, [81, 84]]
4260
                },
4261
                51: {
4262
                    0: [0],
4263
                    1: [0, 1, [4, 8], [12, 15], [21, 24], 29, 31, 32, [81, 84]],
4264
                    3: [[0, 4], 11, 21, 22],
4265
                    4: [[0, 3], 11, 21, 22],
4266
                    5: [[0, 4], 21, 22, 24, 25],
4267
                    6: [0, 1, 3, 23, 26, [81, 83]],
4268
                    7: [0, 1, 3, 4, [22, 27], 81],
4269
                    8: [[0, 2], 11, 12, [21, 24]],
4270
                    9: [[0, 4], [21, 23]],
4271
                    10: [[0, 2], 11, 24, 25, 28],
4272
                    11: [[0, 2], [11, 13], 23, 24, 26, 29, 32, 33, 81],
4273
                    13: [[0, 4], [21, 25], 81],
4274
                    14: [[0, 2], [21, 25]],
4275
                    15: [[0, 3], [21, 29]],
4276
                    16: [[0, 3], [21, 23], 81],
4277
                    17: [[0, 3], [21, 25], 81],
4278
                    18: [[0, 3], [21, 27]],
4279
                    19: [[0, 3], [21, 23]],
4280
                    20: [[0, 2], 21, 22, 81],
4281
                    32: [0, [21, 33]],
4282
                    33: [0, [21, 38]],
4283
                    34: [0, 1, [22, 37]]
4284
                },
4285
                52: {
4286
                    0: [0],
4287
                    1: [[0, 3], [11, 15], [21, 23], 81],
4288
                    2: [0, 1, 3, 21, 22],
4289
                    3: [[0, 3], [21, 30], 81, 82],
4290
                    4: [[0, 2], [21, 25]],
4291
                    5: [[0, 2], [21, 27]],
4292
                    6: [[0, 3], [21, 28]],
4293
                    22: [0, 1, [22, 30]],
4294
                    23: [0, 1, [22, 28]],
4295
                    24: [0, 1, [22, 28]],
4296
                    26: [0, 1, [22, 36]],
4297
                    27: [[0, 2], 22, 23, [25, 32]]
4298
                },
4299
                53: {
4300
                    0: [0],
4301
                    1: [[0, 3], [11, 14], 21, 22, [24, 29], 81],
4302
                    3: [[0, 2], [21, 26], 28, 81],
4303
                    4: [[0, 2], [21, 28]],
4304
                    5: [[0, 2], [21, 24]],
4305
                    6: [[0, 2], [21, 30]],
4306
                    7: [[0, 2], [21, 24]],
4307
                    8: [[0, 2], [21, 29]],
4308
                    9: [[0, 2], [21, 27]],
4309
                    23: [0, 1, [22, 29], 31],
4310
                    25: [[0, 4], [22, 32]],
4311
                    26: [0, 1, [21, 28]],
4312
                    27: [0, 1, [22, 30]], 28: [0, 1, 22, 23],
4313
                    29: [0, 1, [22, 32]],
4314
                    31: [0, 2, 3, [22, 24]],
4315
                    34: [0, [21, 23]],
4316
                    33: [0, 21, [23, 25]],
4317
                    35: [0, [21, 28]]
4318
                },
4319
                54: {
4320
                    0: [0],
4321
                    1: [[0, 2], [21, 27]],
4322
                    21: [0, [21, 29], 32, 33],
4323
                    22: [0, [21, 29], [31, 33]],
4324
                    23: [0, 1, [22, 38]],
4325
                    24: [0, [21, 31]],
4326
                    25: [0, [21, 27]],
4327
                    26: [0, [21, 27]]
4328
                },
4329
                61: {
4330
                    0: [0],
4331
                    1: [[0, 4], [11, 16], 22, [24, 26]],
4332
                    2: [[0, 4], 22],
4333
                    3: [[0, 4], [21, 24], [26, 31]],
4334
                    4: [[0, 4], [22, 31], 81],
4335
                    5: [[0, 2], [21, 28], 81, 82],
4336
                    6: [[0, 2], [21, 32]],
4337
                    7: [[0, 2], [21, 30]],
4338
                    8: [[0, 2], [21, 31]],
4339
                    9: [[0, 2], [21, 29]],
4340
                    10: [[0, 2], [21, 26]]
4341
                },
4342
                62: {
4343
                    0: [0],
4344
                    1: [[0, 5], 11, [21, 23]],
4345
                    2: [0, 1],
4346
                    3: [[0, 2], 21],
4347
                    4: [[0, 3], [21, 23]],
4348
                    5: [[0, 3], [21, 25]],
4349
                    6: [[0, 2], [21, 23]],
4350
                    7: [[0, 2], [21, 25]],
4351
                    8: [[0, 2], [21, 26]],
4352
                    9: [[0, 2], [21, 24], 81, 82],
4353
                    10: [[0, 2], [21, 27]],
4354
                    11: [[0, 2], [21, 26]],
4355
                    12: [[0, 2], [21, 28]],
4356
                    24: [0, 21, [24, 29]],
4357
                    26: [0, 21, [23, 30]],
4358
                    29: [0, 1, [21, 27]],
4359
                    30: [0, 1, [21, 27]]
4360
                },
4361
                63: {
4362
                    0: [0],
4363
                    1: [[0, 5], [21, 23]],
4364
                    2: [0, 2, [21, 25]],
4365
                    21: [0, [21, 23], [26, 28]],
4366
                    22: [0, [21, 24]],
4367
                    23: [0, [21, 24]],
4368
                    25: [0, [21, 25]],
4369
                    26: [0, [21, 26]],
4370
                    27: [0, 1, [21, 26]],
4371
                    28: [[0, 2], [21, 23]]
4372
                },
4373
                64: {
4374
                    0: [0],
4375
                    1: [0, 1, [4, 6], 21, 22, 81],
4376
                    2: [[0, 3], 5, [21, 23]],
4377
                    3: [[0, 3], [21, 24], 81],
4378
                    4: [[0, 2], [21, 25]],
4379
                    5: [[0, 2], 21, 22]
4380
                },
4381
                65: {
4382
                    0: [0],
4383
                    1: [[0, 9], 21],
4384
                    2: [[0, 5]],
4385
                    21: [0, 1, 22, 23],
4386
                    22: [0, 1, 22, 23],
4387
                    23: [[0, 3], [23, 25], 27, 28],
4388
                    28: [0, 1, [22, 29]],
4389
                    29: [0, 1, [22, 29]],
4390
                    30: [0, 1, [22, 24]], 31: [0, 1, [21, 31]],
4391
                    32: [0, 1, [21, 27]],
4392
                    40: [0, 2, 3, [21, 28]],
4393
                    42: [[0, 2], 21, [23, 26]],
4394
                    43: [0, 1, [21, 26]],
4395
                    90: [[0, 4]], 27: [[0, 2], 22, 23]
4396
                },
4397
                71: { 0: [0] },
4398
                81: { 0: [0] },
4399
                82: { 0: [0] }
4400
            };
4401
 
4402
            var provincial  = parseInt(value.substr(0, 2), 10),
4403
                prefectural = parseInt(value.substr(2, 2), 10),
4404
                county      = parseInt(value.substr(4, 2), 10);
4405
 
4406
            if (!adminDivisionCodes[provincial] || !adminDivisionCodes[provincial][prefectural]) {
4407
                return false;
4408
            }
4409
            var inRange  = false,
4410
                rangeDef = adminDivisionCodes[provincial][prefectural];
4411
            for (var i = 0; i < rangeDef.length; i++) {
4412
                if (($.isArray(rangeDef[i]) && rangeDef[i][0] <= county && county <= rangeDef[i][1])
4413
                    || (!$.isArray(rangeDef[i]) && county === rangeDef[i]))
4414
                {
4415
                    inRange = true;
4416
                    break;
4417
                }
4418
            }
4419
 
4420
            if (!inRange) {
4421
                return false;
4422
            }
4423
 
4424
            // Check date of birth
4425
            var dob;
4426
            if (value.length === 18) {
4427
                dob = value.substr(6, 8);
4428
            } else /* length == 15 */ { 
4429
                dob = '19' + value.substr(6, 6);
4430
            }
4431
            var year  = parseInt(dob.substr(0, 4), 10),
4432
                month = parseInt(dob.substr(4, 2), 10),
4433
                day   = parseInt(dob.substr(6, 2), 10);
4434
            if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
4435
                return false;
4436
            }
4437
 
4438
            // Check checksum (18-digit system only)
4439
            if (value.length === 18) {
4440
                var sum    = 0,
4441
                    weight = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
4442
                for (i = 0; i < 17; i++) {
4443
                    sum += parseInt(value.charAt(i), 10) * weight[i];
4444
                }
4445
                sum = (12 - (sum % 11)) % 11;
4446
                var checksum = (value.charAt(17).toUpperCase() !== 'X') ? parseInt(value.charAt(17), 10) : 10;
4447
                return checksum === sum;
4448
            }
4449
 
4450
            return true;
4451
        },
4452
 
4453
        /**
4454
         * Validate Czech national identification number (RC)
4455
         * Examples:
4456
         * - Valid: 7103192745, 991231123
4457
         * - Invalid: 1103492745, 590312123
4458
         *
4459
         * @param {String} value The ID
4460
         * @returns {Boolean}
4461
         */
4462
        _cz: function(value) {
4463
            if (!/^\d{9,10}$/.test(value)) {
4464
                return false;
4465
            }
4466
            var year  = 1900 + parseInt(value.substr(0, 2), 10),
4467
                month = parseInt(value.substr(2, 2), 10) % 50 % 20,
4468
                day   = parseInt(value.substr(4, 2), 10);
4469
            if (value.length === 9) {
4470
                if (year >= 1980) {
4471
                    year -= 100;
4472
                }
4473
                if (year > 1953) {
4474
                    return false;
4475
                }
4476
            } else if (year < 1954) {
4477
                year += 100;
4478
            }
4479
 
4480
            if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
4481
                return false;
4482
            }
4483
 
4484
            // Check that the birth date is not in the future
4485
            if (value.length === 10) {
4486
                var check = parseInt(value.substr(0, 9), 10) % 11;
4487
                if (year < 1985) {
4488
                    check = check % 10;
4489
                }
4490
                return (check + '' === value.substr(9, 1));
4491
            }
4492
 
4493
            return true;
4494
        },
4495
 
4496
        /**
4497
         * Validate Danish Personal Identification number (CPR)
4498
         * Examples:
4499
         * - Valid: 2110625629, 211062-5629
4500
         * - Invalid: 511062-5629
4501
         *
4502
         * @see https://en.wikipedia.org/wiki/Personal_identification_number_(Denmark)
4503
         * @param {String} value The ID
4504
         * @returns {Boolean}
4505
         */
4506
        _dk: function(value) {
4507
            if (!/^[0-9]{6}[-]{0,1}[0-9]{4}$/.test(value)) {
4508
                return false;
4509
            }
4510
            value = value.replace(/-/g, '');
4511
            var day   = parseInt(value.substr(0, 2), 10),
4512
                month = parseInt(value.substr(2, 2), 10),
4513
                year  = parseInt(value.substr(4, 2), 10);
4514
 
4515
            switch (true) {
4516
                case ('5678'.indexOf(value.charAt(6)) !== -1 && year >= 58):
4517
                    year += 1800;
4518
                    break;
4519
                case ('0123'.indexOf(value.charAt(6)) !== -1):
4520
                case ('49'.indexOf(value.charAt(6)) !== -1 && year >= 37):
4521
                    year += 1900;
4522
                    break;
4523
                default:
4524
                    year += 2000;
4525
                    break;
4526
            }
4527
 
4528
            return $.fn.bootstrapValidator.helpers.date(year, month, day);
4529
        },
4530
 
4531
        /**
4532
         * Validate Estonian Personal Identification Code (isikukood)
4533
         * Examples:
4534
         * - Valid: 37605030299
4535
         *
4536
         * @see http://et.wikipedia.org/wiki/Isikukood
4537
         * @param {String} value The ID
4538
         * @returns {Boolean}
4539
         */
4540
        _ee: function(value) {
4541
            // Use the same format as Lithuanian Personal Code
4542
            return this._lt(value);
4543
        },
4544
 
4545
        /**
4546
         * Validate Spanish personal identity code (DNI)
4547
         * Support i) DNI (for Spanish citizens) and ii) NIE (for foreign people)
4548
         *
4549
         * Examples:
4550
         * - Valid: i) 54362315K, 54362315-K; ii) X2482300W, X-2482300W, X-2482300-W
4551
         * - Invalid: i) 54362315Z; ii) X-2482300A
4552
         *
4553
         * @see https://en.wikipedia.org/wiki/National_identification_number#Spain
4554
         * @param {String} value The ID
4555
         * @returns {Boolean}
4556
         */
4557
        _es: function(value) {
4558
            if (!/^[0-9A-Z]{8}[-]{0,1}[0-9A-Z]$/.test(value)                    // DNI
4559
                && !/^[XYZ][-]{0,1}[0-9]{7}[-]{0,1}[0-9A-Z]$/.test(value)) {    // NIE
4560
                return false;
4561
            }
4562
 
4563
            value = value.replace(/-/g, '');
4564
            var index = 'XYZ'.indexOf(value.charAt(0));
4565
            if (index !== -1) {
4566
                // It is NIE number
4567
                value = index + value.substr(1) + '';
4568
            }
4569
 
4570
            var check = parseInt(value.substr(0, 8), 10);
4571
            check = 'TRWAGMYFPDXBNJZSQVHLCKE'[check % 23];
4572
            return (check === value.substr(8, 1));
4573
        },
4574
 
4575
        /**
4576
         * Validate Finnish Personal Identity Code (HETU)
4577
         * Examples:
4578
         * - Valid: 311280-888Y, 131052-308T
4579
         * - Invalid: 131052-308U, 310252-308Y
4580
         *
4581
         * @param {String} value The ID
4582
         * @returns {Boolean}
4583
         */
4584
        _fi: function(value) {
4585
            if (!/^[0-9]{6}[-+A][0-9]{3}[0-9ABCDEFHJKLMNPRSTUVWXY]$/.test(value)) {
4586
                return false;
4587
            }
4588
            var day       = parseInt(value.substr(0, 2), 10),
4589
                month     = parseInt(value.substr(2, 2), 10),
4590
                year      = parseInt(value.substr(4, 2), 10),
4591
                centuries = {
4592
                    '+': 1800,
4593
                    '-': 1900,
4594
                    'A': 2000
4595
                };
4596
            year = centuries[value.charAt(6)] + year;
4597
 
4598
            if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
4599
                return false;
4600
            }
4601
 
4602
            var individual = parseInt(value.substr(7, 3), 10);
4603
            if (individual < 2) {
4604
                return false;
4605
            }
4606
            var n = value.substr(0, 6) + value.substr(7, 3) + '';
4607
            n = parseInt(n, 10);
4608
            return '0123456789ABCDEFHJKLMNPRSTUVWXY'.charAt(n % 31) === value.charAt(10);
4609
        },
4610
 
4611
        /**
4612
         * Validate Croatian personal identification number (OIB)
4613
         * Examples:
4614
         * - Valid: 33392005961
4615
         * - Invalid: 33392005962
4616
         *
4617
         * @param {String} value The ID
4618
         * @returns {Boolean}
4619
         */
4620
        _hr: function(value) {
4621
            if (!/^[0-9]{11}$/.test(value)) {
4622
                return false;
4623
            }
4624
            return $.fn.bootstrapValidator.helpers.mod11And10(value);
4625
        },
4626
 
4627
        /**
4628
         * Validate Irish Personal Public Service Number (PPS)
4629
         * Examples:
4630
         * - Valid: 6433435F, 6433435FT, 6433435FW, 6433435OA, 6433435IH, 1234567TW, 1234567FA
4631
         * - Invalid: 6433435E, 6433435VH
4632
         *
4633
         * @see https://en.wikipedia.org/wiki/Personal_Public_Service_Number
4634
         * @param {String} value The ID
4635
         * @returns {Boolean}
4636
         */
4637
        _ie: function(value) {
4638
            if (!/^\d{7}[A-W][AHWTX]?$/.test(value)) {
4639
                return false;
4640
            }
4641
 
4642
            var getCheckDigit = function(value) {
4643
                while (value.length < 7) {
4644
                    value = '0' + value;
4645
                }
4646
                var alphabet = 'WABCDEFGHIJKLMNOPQRSTUV',
4647
                    sum      = 0;
4648
                for (var i = 0; i < 7; i++) {
4649
                    sum += parseInt(value.charAt(i), 10) * (8 - i);
4650
                }
4651
                sum += 9 * alphabet.indexOf(value.substr(7));
4652
                return alphabet[sum % 23];
4653
            };
4654
 
4655
            // 2013 format
4656
            if (value.length === 9 && ('A' === value.charAt(8) || 'H' === value.charAt(8))) {
4657
                return value.charAt(7) === getCheckDigit(value.substr(0, 7) + value.substr(8) + '');
4658
            }
4659
            // The old format
4660
            else {
4661
                return value.charAt(7) === getCheckDigit(value.substr(0, 7));
4662
            }
4663
        },
4664
 
4665
        /**
4666
         * Validate Iceland national identification number (Kennitala)
4667
         * Examples:
4668
         * - Valid: 120174-3399, 1201743399, 0902862349
4669
         *
4670
         * @see http://en.wikipedia.org/wiki/Kennitala
4671
         * @param {String} value The ID
4672
         * @returns {Boolean}
4673
         */
4674
        _is: function(value) {
4675
            if (!/^[0-9]{6}[-]{0,1}[0-9]{4}$/.test(value)) {
4676
                return false;
4677
            }
4678
            value = value.replace(/-/g, '');
4679
            var day     = parseInt(value.substr(0, 2), 10),
4680
                month   = parseInt(value.substr(2, 2), 10),
4681
                year    = parseInt(value.substr(4, 2), 10),
4682
                century = parseInt(value.charAt(9), 10);
4683
 
4684
            year = (century === 9) ? (1900 + year) : ((20 + century) * 100 + year);
4685
            if (!$.fn.bootstrapValidator.helpers.date(year, month, day, true)) {
4686
                return false;
4687
            }
4688
            // Validate the check digit
4689
            var sum    = 0,
4690
                weight = [3, 2, 7, 6, 5, 4, 3, 2];
4691
            for (var i = 0; i < 8; i++) {
4692
                sum += parseInt(value.charAt(i), 10) * weight[i];
4693
            }
4694
            sum = 11 - sum % 11;
4695
            return (sum + '' === value.charAt(8));
4696
        },
4697
 
4698
        /**
4699
         * Validate Lithuanian Personal Code (Asmens kodas)
4700
         * Examples:
4701
         * - Valid: 38703181745
4702
         * - Invalid: 38703181746, 78703181745, 38703421745
4703
         *
4704
         * @see http://en.wikipedia.org/wiki/National_identification_number#Lithuania
4705
         * @see http://www.adomas.org/midi2007/pcode.html
4706
         * @param {String} value The ID
4707
         * @returns {Boolean}
4708
         */
4709
        _lt: function(value) {
4710
            if (!/^[0-9]{11}$/.test(value)) {
4711
                return false;
4712
            }
4713
            var gender  = parseInt(value.charAt(0), 10),
4714
                year    = parseInt(value.substr(1, 2), 10),
4715
                month   = parseInt(value.substr(3, 2), 10),
4716
                day     = parseInt(value.substr(5, 2), 10),
4717
                century = (gender % 2 === 0) ? (17 + gender / 2) : (17 + (gender + 1) / 2);
4718
            year = century * 100 + year;
4719
            if (!$.fn.bootstrapValidator.helpers.date(year, month, day, true)) {
4720
                return false;
4721
            }
4722
 
4723
            // Validate the check digit
4724
            var sum    = 0,
4725
                weight = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1];
4726
            for (var i = 0; i < 10; i++) {
4727
                sum += parseInt(value.charAt(i), 10) * weight[i];
4728
            }
4729
            sum = sum % 11;
4730
            if (sum !== 10) {
4731
                return sum + '' === value.charAt(10);
4732
            }
4733
 
4734
            // Re-calculate the check digit
4735
            sum    = 0;
4736
            weight = [3, 4, 5, 6, 7, 8, 9, 1, 2, 3];
4737
            for (i = 0; i < 10; i++) {
4738
                sum += parseInt(value.charAt(i), 10) * weight[i];
4739
            }
4740
            sum = sum % 11;
4741
            if (sum === 10) {
4742
                sum = 0;
4743
            }
4744
            return (sum + '' === value.charAt(10));
4745
        },
4746
 
4747
        /**
4748
         * Validate Latvian Personal Code (Personas kods)
4749
         * Examples:
4750
         * - Valid: 161175-19997, 16117519997
4751
         * - Invalid: 161375-19997
4752
         *
4753
         * @see http://laacz.lv/2006/11/25/pk-parbaudes-algoritms/
4754
         * @param {String} value The ID
4755
         * @returns {Boolean}
4756
         */
4757
        _lv: function(value) {
4758
            if (!/^[0-9]{6}[-]{0,1}[0-9]{5}$/.test(value)) {
4759
                return false;
4760
            }
4761
            value = value.replace(/\D/g, '');
4762
            // Check birth date
4763
            var day   = parseInt(value.substr(0, 2), 10),
4764
                month = parseInt(value.substr(2, 2), 10),
4765
                year  = parseInt(value.substr(4, 2), 10);
4766
            year = year + 1800 + parseInt(value.charAt(6), 10) * 100;
4767
 
4768
            if (!$.fn.bootstrapValidator.helpers.date(year, month, day, true)) {
4769
                return false;
4770
            }
4771
 
4772
            // Check personal code
4773
            var sum    = 0,
4774
                weight = [10, 5, 8, 4, 2, 1, 6, 3, 7, 9];
4775
            for (var i = 0; i < 10; i++) {
4776
                sum += parseInt(value.charAt(i), 10) * weight[i];
4777
            }
4778
            sum = (sum + 1) % 11 % 10;
4779
            return (sum + '' === value.charAt(10));
4780
        },
4781
 
4782
        /**
4783
         * Validate Dutch national identification number (BSN)
4784
         * Examples:
4785
         * - Valid: 111222333, 941331490, 9413.31.490
4786
         * - Invalid: 111252333
4787
         *
4788
         * @see https://nl.wikipedia.org/wiki/Burgerservicenummer
4789
         * @param {String} value The ID
4790
         * @returns {Boolean}
4791
         */
4792
        _nl: function(value) {
4793
            while (value.length < 9) {
4794
                value = '0' + value;
4795
            }
4796
            if (!/^[0-9]{4}[.]{0,1}[0-9]{2}[.]{0,1}[0-9]{3}$/.test(value)) {
4797
                return false;
4798
            }
4799
            value = value.replace(/\./g, '');
4800
            if (parseInt(value, 10) === 0) {
4801
                return false;
4802
            }
4803
            var sum    = 0,
4804
                length = value.length;
4805
            for (var i = 0; i < length - 1; i++) {
4806
                sum += (9 - i) * parseInt(value.charAt(i), 10);
4807
            }
4808
            sum = sum % 11;
4809
            if (sum === 10) {
4810
                sum = 0;
4811
            }
4812
            return (sum + '' === value.charAt(length - 1));
4813
        },
4814
 
4815
        /**
4816
         * Validate Romanian numerical personal code (CNP)
4817
         * Examples:
4818
         * - Valid: 1630615123457, 1800101221144
4819
         * - Invalid: 8800101221144, 1632215123457, 1630615123458
4820
         *
4821
         * @see http://en.wikipedia.org/wiki/National_identification_number#Romania
4822
         * @param {String} value The ID
4823
         * @returns {Boolean}
4824
         */
4825
        _ro: function(value) {
4826
            if (!/^[0-9]{13}$/.test(value)) {
4827
                return false;
4828
            }
4829
            var gender = parseInt(value.charAt(0), 10);
4830
            if (gender === 0 || gender === 7 || gender === 8) {
4831
                return false;
4832
            }
4833
 
4834
            // Determine the date of birth
4835
            var year      = parseInt(value.substr(1, 2), 10),
4836
                month     = parseInt(value.substr(3, 2), 10),
4837
                day       = parseInt(value.substr(5, 2), 10),
4838
                // The year of date is determined base on the gender
4839
                centuries = {
4840
                    '1': 1900,  // Male born between 1900 and 1999
4841
                    '2': 1900,  // Female born between 1900 and 1999
4842
                    '3': 1800,  // Male born between 1800 and 1899
4843
                    '4': 1800,  // Female born between 1800 and 1899
4844
                    '5': 2000,  // Male born after 2000
4845
                    '6': 2000   // Female born after 2000
4846
                };
4847
            if (day > 31 && month > 12) {
4848
                return false;
4849
            }
4850
            if (gender !== 9) {
4851
                year = centuries[gender + ''] + year;
4852
                if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
4853
                    return false;
4854
                }
4855
            }
4856
 
4857
            // Validate the check digit
4858
            var sum    = 0,
4859
                weight = [2, 7, 9, 1, 4, 6, 3, 5, 8, 2, 7, 9],
4860
                length = value.length;
4861
            for (var i = 0; i < length - 1; i++) {
4862
                sum += parseInt(value.charAt(i), 10) * weight[i];
4863
            }
4864
            sum = sum % 11;
4865
            if (sum === 10) {
4866
                sum = 1;
4867
            }
4868
            return (sum + '' === value.charAt(length - 1));
4869
        },
4870
 
4871
        /**
4872
         * Validate Swedish personal identity number (personnummer)
4873
         * Examples:
4874
         * - Valid: 8112289874, 811228-9874, 811228+9874
4875
         * - Invalid: 811228-9873
4876
         *
4877
         * @see http://en.wikipedia.org/wiki/Personal_identity_number_(Sweden)
4878
         * @param {String} value The ID
4879
         * @returns {Boolean}
4880
         */
4881
        _se: function(value) {
4882
            if (!/^[0-9]{10}$/.test(value) && !/^[0-9]{6}[-|+][0-9]{4}$/.test(value)) {
4883
                return false;
4884
            }
4885
            value = value.replace(/[^0-9]/g, '');
4886
 
4887
            var year  = parseInt(value.substr(0, 2), 10) + 1900,
4888
                month = parseInt(value.substr(2, 2), 10),
4889
                day   = parseInt(value.substr(4, 2), 10);
4890
            if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
4891
                return false;
4892
            }
4893
 
4894
            // Validate the last check digit
4895
            return $.fn.bootstrapValidator.helpers.luhn(value);
4896
        },
4897
 
4898
        /**
4899
         * Validate Slovak national identifier number (RC)
4900
         * Examples:
4901
         * - Valid: 7103192745, 991231123
4902
         * - Invalid: 7103192746, 1103492745
4903
         *
4904
         * @param {String} value The ID
4905
         * @returns {Boolean}
4906
         */
4907
        _sk: function(value) {
4908
            // Slovakia uses the same format as Czech Republic
4909
            return this._cz(value);
4910
        },
4911
 
4912
        /**
4913
         * Validate San Marino citizen number
4914
         *
4915
         * @see http://en.wikipedia.org/wiki/National_identification_number#San_Marino
4916
         * @param {String} value The ID
4917
         * @returns {Boolean}
4918
         */
4919
        _sm: function(value) {
4920
            return /^\d{5}$/.test(value);
4921
        },
4922
 
4923
        /**
4924
         * Validate Thailand citizen number
4925
         * Examples:
4926
         * - Valid: 7145620509547, 3688699975685, 2368719339716
4927
         * - Invalid: 1100800092310
4928
         *
4929
         * @see http://en.wikipedia.org/wiki/National_identification_number#Thailand
4930
         * @param {String} value The ID
4931
         * @returns {Boolean}
4932
         */
4933
        _th: function(value) {
4934
            if (value.length !== 13) {
4935
                return false;
4936
            }
4937
 
4938
            var sum = 0;
4939
            for (var i = 0; i < 12; i++) {
4940
                sum += parseInt(value.charAt(i), 10) * (13 - i);
4941
            }
4942
 
4943
            return (11 - sum % 11) % 10 === parseInt(value.charAt(12), 10);
4944
        },
4945
 
4946
        /**
4947
         * Validate South African ID
4948
         * Example:
4949
         * - Valid: 8001015009087
4950
         * - Invalid: 8001015009287, 8001015009086
4951
         *
4952
         * @see http://en.wikipedia.org/wiki/National_identification_number#South_Africa
4953
         * @param {String} value The ID
4954
         * @returns {Boolean}
4955
         */
4956
        _za: function(value) {
4957
            if (!/^[0-9]{10}[0|1][8|9][0-9]$/.test(value)) {
4958
                return false;
4959
            }
4960
            var year        = parseInt(value.substr(0, 2), 10),
4961
                currentYear = new Date().getFullYear() % 100,
4962
                month       = parseInt(value.substr(2, 2), 10),
4963
                day         = parseInt(value.substr(4, 2), 10);
4964
            year = (year >= currentYear) ? (year + 1900) : (year + 2000);
4965
 
4966
            if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
4967
                return false;
4968
            }
4969
 
4970
            // Validate the last check digit
4971
            return $.fn.bootstrapValidator.helpers.luhn(value);
4972
        }
4973
    };
4974
}(window.jQuery));
4975
;(function($) {
4976
    $.fn.bootstrapValidator.i18n.identical = $.extend($.fn.bootstrapValidator.i18n.identical || {}, {
4977
        'default': 'Please enter the same value'
4978
    });
4979
 
4980
    $.fn.bootstrapValidator.validators.identical = {
4981
        html5Attributes: {
4982
            message: 'message',
4983
            field: 'field'
4984
        },
4985
 
4986
        /**
4987
         * Check if input value equals to value of particular one
4988
         *
4989
         * @param {BootstrapValidator} validator The validator plugin instance
4990
         * @param {jQuery} $field Field element
4991
         * @param {Object} options Consists of the following key:
4992
         * - field: The name of field that will be used to compare with current one
4993
         * @returns {Boolean}
4994
         */
4995
        validate: function(validator, $field, options) {
4996
            var value = $field.val();
4997
            if (value === '') {
4998
                return true;
4999
            }
5000
 
5001
            var compareWith = validator.getFieldElements(options.field);
5002
            if (compareWith === null || compareWith.length === 0) {
5003
                return true;
5004
            }
5005
 
5006
            if (value === compareWith.val()) {
5007
                validator.updateStatus(options.field, validator.STATUS_VALID, 'identical');
5008
                return true;
5009
            } else {
5010
                return false;
5011
            }
5012
        }
5013
    };
5014
}(window.jQuery));
5015
;(function($) {
5016
    $.fn.bootstrapValidator.i18n.imei = $.extend($.fn.bootstrapValidator.i18n.imei || {}, {
5017
        'default': 'Please enter a valid IMEI number'
5018
    });
5019
 
5020
    $.fn.bootstrapValidator.validators.imei = {
5021
        /**
5022
         * Validate IMEI (International Mobile Station Equipment Identity)
5023
         * Examples:
5024
         * - Valid: 35-209900-176148-1, 35-209900-176148-23, 3568680000414120, 490154203237518
5025
         * - Invalid: 490154203237517
5026
         *
5027
         * @see http://en.wikipedia.org/wiki/International_Mobile_Station_Equipment_Identity
5028
         * @param {BootstrapValidator} validator The validator plugin instance
5029
         * @param {jQuery} $field Field element
5030
         * @param {Object} options Can consist of the following keys:
5031
         * - message: The invalid message
5032
         * @returns {Boolean}
5033
         */
5034
        validate: function(validator, $field, options) {
5035
            var value = $field.val();
5036
            if (value === '') {
5037
                return true;
5038
            }
5039
 
5040
            switch (true) {
5041
                case /^\d{15}$/.test(value):
5042
                case /^\d{2}-\d{6}-\d{6}-\d{1}$/.test(value):
5043
                case /^\d{2}\s\d{6}\s\d{6}\s\d{1}$/.test(value):
5044
                    value = value.replace(/[^0-9]/g, '');
5045
                    return $.fn.bootstrapValidator.helpers.luhn(value);
5046
 
5047
                case /^\d{14}$/.test(value):
5048
                case /^\d{16}$/.test(value):
5049
                case /^\d{2}-\d{6}-\d{6}(|-\d{2})$/.test(value):
5050
                case /^\d{2}\s\d{6}\s\d{6}(|\s\d{2})$/.test(value):
5051
                    return true;
5052
 
5053
                default:
5054
                    return false;
5055
            }
5056
        }
5057
    };
5058
}(window.jQuery));
5059
;(function($) {
5060
    $.fn.bootstrapValidator.i18n.imo = $.extend($.fn.bootstrapValidator.i18n.imo || {}, {
5061
        'default': 'Please enter a valid IMO number'
5062
    });
5063
 
5064
    $.fn.bootstrapValidator.validators.imo = {
5065
        /**
5066
         * Validate IMO (International Maritime Organization)
5067
         * Examples:
5068
         * - Valid: IMO 8814275, IMO 9176187
5069
         * - Invalid: IMO 8814274
5070
         *
5071
         * @see http://en.wikipedia.org/wiki/IMO_Number
5072
         * @param {BootstrapValidator} validator The validator plugin instance
5073
         * @param {jQuery} $field Field element
5074
         * @param {Object} options Can consist of the following keys:
5075
         * - message: The invalid message
5076
         * @returns {Boolean}
5077
         */
5078
        validate: function(validator, $field, options) {
5079
            var value = $field.val();
5080
            if (value === '') {
5081
                return true;
5082
            }
5083
 
5084
            if (!/^IMO \d{7}$/i.test(value)) {
5085
                return false;
5086
            }
5087
 
5088
            // Grab just the digits
5089
            var sum    = 0,
5090
                digits = value.replace(/^.*(\d{7})$/, '$1');
5091
 
5092
            // Go over each char, multiplying by the inverse of it's position
5093
            // IMO 9176187
5094
            // (9 * 7) + (1 * 6) + (7 * 5) + (6 * 4) + (1 * 3) + (8 * 2) = 147
5095
            // Take the last digit of that, that's the check digit (7)
5096
            for (var i = 6; i >= 1; i--) {
5097
                sum += (digits.slice((6 - i), -i) * (i + 1));
5098
            }
5099
 
5100
            return sum % 10 === parseInt(digits.charAt(6), 10);
5101
        }
5102
    };
5103
}(window.jQuery));
5104
;(function($) {
5105
    $.fn.bootstrapValidator.i18n.integer = $.extend($.fn.bootstrapValidator.i18n.integer || {}, {
5106
        'default': 'Please enter a valid number'
5107
    });
5108
 
5109
    $.fn.bootstrapValidator.validators.integer = {
5110
        enableByHtml5: function($field) {
5111
            return ('number' === $field.attr('type')) && ($field.attr('step') === undefined || $field.attr('step') % 1 === 0);
5112
        },
5113
 
5114
        /**
5115
         * Return true if the input value is an integer
5116
         *
5117
         * @param {BootstrapValidator} validator The validator plugin instance
5118
         * @param {jQuery} $field Field element
5119
         * @param {Object} options Can consist of the following key:
5120
         * - message: The invalid message
5121
         * @returns {Boolean}
5122
         */
5123
        validate: function(validator, $field, options) {
5124
            if (this.enableByHtml5($field) && $field.get(0).validity && $field.get(0).validity.badInput === true) {
5125
                return false;
5126
            }
5127
 
5128
            var value = $field.val();
5129
            if (value === '') {
5130
                return true;
5131
            }
5132
            return /^(?:-?(?:0|[1-9][0-9]*))$/.test(value);
5133
        }
5134
    };
5135
}(window.jQuery));
5136
;(function($) {
5137
    $.fn.bootstrapValidator.i18n.ip = $.extend($.fn.bootstrapValidator.i18n.ip || {}, {
5138
        'default': 'Please enter a valid IP address',
5139
        ipv4: 'Please enter a valid IPv4 address',
5140
        ipv6: 'Please enter a valid IPv6 address'
5141
    });
5142
 
5143
    $.fn.bootstrapValidator.validators.ip = {
5144
        html5Attributes: {
5145
            message: 'message',
5146
            ipv4: 'ipv4',
5147
            ipv6: 'ipv6'
5148
        },
5149
 
5150
        /**
5151
         * Return true if the input value is a IP address.
5152
         *
5153
         * @param {BootstrapValidator} validator The validator plugin instance
5154
         * @param {jQuery} $field Field element
5155
         * @param {Object} options Can consist of the following keys:
5156
         * - ipv4: Enable IPv4 validator, default to true
5157
         * - ipv6: Enable IPv6 validator, default to true
5158
         * - message: The invalid message
5159
         * @returns {Boolean|Object}
5160
         */
5161
        validate: function(validator, $field, options) {
5162
            var value = $field.val();
5163
            if (value === '') {
5164
                return true;
5165
            }
5166
            options = $.extend({}, { ipv4: true, ipv6: true }, options);
5167
 
5168
            var ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
5169
                ipv6Regex = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/,
5170
                valid     = false,
5171
                message;
5172
 
5173
            switch (true) {
5174
                case (options.ipv4 && !options.ipv6):
5175
                    valid   = ipv4Regex.test(value);
5176
                    message = options.message || $.fn.bootstrapValidator.i18n.ip.ipv4;
5177
                    break;
5178
 
5179
                case (!options.ipv4 && options.ipv6):
5180
                    valid   = ipv6Regex.test(value);
5181
                    message = options.message || $.fn.bootstrapValidator.i18n.ip.ipv6;
5182
                    break;
5183
 
5184
                case (options.ipv4 && options.ipv6):
5185
                /* falls through */
5186
                default:
5187
                    valid   = ipv4Regex.test(value) || ipv6Regex.test(value);
5188
                    message = options.message || $.fn.bootstrapValidator.i18n.ip['default'];
5189
                    break;
5190
            }
5191
 
5192
            return {
5193
                valid: valid,
5194
                message: message
5195
            };
5196
        }
5197
    };
5198
}(window.jQuery));;(function($) {
5199
    $.fn.bootstrapValidator.i18n.isbn = $.extend($.fn.bootstrapValidator.i18n.isbn || {}, {
5200
        'default': 'Please enter a valid ISBN number'
5201
    });
5202
 
5203
    $.fn.bootstrapValidator.validators.isbn = {
5204
        /**
5205
         * Return true if the input value is a valid ISBN 10 or ISBN 13 number
5206
         * Examples:
5207
         * - Valid:
5208
         * ISBN 10: 99921-58-10-7, 9971-5-0210-0, 960-425-059-0, 80-902734-1-6, 85-359-0277-5, 1-84356-028-3, 0-684-84328-5, 0-8044-2957-X, 0-85131-041-9, 0-943396-04-2, 0-9752298-0-X
5209
         * ISBN 13: 978-0-306-40615-7
5210
         * - Invalid:
5211
         * ISBN 10: 99921-58-10-6
5212
         * ISBN 13: 978-0-306-40615-6
5213
         *
5214
         * @see http://en.wikipedia.org/wiki/International_Standard_Book_Number
5215
         * @param {BootstrapValidator} validator The validator plugin instance
5216
         * @param {jQuery} $field Field element
5217
         * @param {Object} [options] Can consist of the following keys:
5218
         * - message: The invalid message
5219
         * @returns {Boolean}
5220
         */
5221
        validate: function(validator, $field, options) {
5222
            var value = $field.val();
5223
            if (value === '') {
5224
                return true;
5225
            }
5226
 
5227
            // http://en.wikipedia.org/wiki/International_Standard_Book_Number#Overview
5228
            // Groups are separated by a hyphen or a space
5229
            var type;
5230
            switch (true) {
5231
                case /^\d{9}[\dX]$/.test(value):
5232
                case (value.length === 13 && /^(\d+)-(\d+)-(\d+)-([\dX])$/.test(value)):
5233
                case (value.length === 13 && /^(\d+)\s(\d+)\s(\d+)\s([\dX])$/.test(value)):
5234
                    type = 'ISBN10';
5235
                    break;
5236
                case /^(978|979)\d{9}[\dX]$/.test(value):
5237
                case (value.length === 17 && /^(978|979)-(\d+)-(\d+)-(\d+)-([\dX])$/.test(value)):
5238
                case (value.length === 17 && /^(978|979)\s(\d+)\s(\d+)\s(\d+)\s([\dX])$/.test(value)):
5239
                    type = 'ISBN13';
5240
                    break;
5241
                default:
5242
                    return false;
5243
            }
5244
 
5245
            // Replace all special characters except digits and X
5246
            value = value.replace(/[^0-9X]/gi, '');
5247
            var chars  = value.split(''),
5248
                length = chars.length,
5249
                sum    = 0,
5250
                i,
5251
                checksum;
5252
 
5253
            switch (type) {
5254
                case 'ISBN10':
5255
                    sum = 0;
5256
                    for (i = 0; i < length - 1; i++) {
5257
                        sum += parseInt(chars[i], 10) * (10 - i);
5258
                    }
5259
                    checksum = 11 - (sum % 11);
5260
                    if (checksum === 11) {
5261
                        checksum = 0;
5262
                    } else if (checksum === 10) {
5263
                        checksum = 'X';
5264
                    }
5265
                    return (checksum + '' === chars[length - 1]);
5266
 
5267
                case 'ISBN13':
5268
                    sum = 0;
5269
                    for (i = 0; i < length - 1; i++) {
5270
                        sum += ((i % 2 === 0) ? parseInt(chars[i], 10) : (parseInt(chars[i], 10) * 3));
5271
                    }
5272
                    checksum = 10 - (sum % 10);
5273
                    if (checksum === 10) {
5274
                        checksum = '0';
5275
                    }
5276
                    return (checksum + '' === chars[length - 1]);
5277
 
5278
                default:
5279
                    return false;
5280
            }
5281
        }
5282
    };
5283
}(window.jQuery));
5284
;(function($) {
5285
    $.fn.bootstrapValidator.i18n.isin = $.extend($.fn.bootstrapValidator.i18n.isin || {}, {
5286
        'default': 'Please enter a valid ISIN number'
5287
    });
5288
 
5289
    $.fn.bootstrapValidator.validators.isin = {
5290
        // Available country codes
5291
        // See http://isin.net/country-codes/
5292
        COUNTRY_CODES: 'AF|AX|AL|DZ|AS|AD|AO|AI|AQ|AG|AR|AM|AW|AU|AT|AZ|BS|BH|BD|BB|BY|BE|BZ|BJ|BM|BT|BO|BQ|BA|BW|BV|BR|IO|BN|BG|BF|BI|KH|CM|CA|CV|KY|CF|TD|CL|CN|CX|CC|CO|KM|CG|CD|CK|CR|CI|HR|CU|CW|CY|CZ|DK|DJ|DM|DO|EC|EG|SV|GQ|ER|EE|ET|FK|FO|FJ|FI|FR|GF|PF|TF|GA|GM|GE|DE|GH|GI|GR|GL|GD|GP|GU|GT|GG|GN|GW|GY|HT|HM|VA|HN|HK|HU|IS|IN|ID|IR|IQ|IE|IM|IL|IT|JM|JP|JE|JO|KZ|KE|KI|KP|KR|KW|KG|LA|LV|LB|LS|LR|LY|LI|LT|LU|MO|MK|MG|MW|MY|MV|ML|MT|MH|MQ|MR|MU|YT|MX|FM|MD|MC|MN|ME|MS|MA|MZ|MM|NA|NR|NP|NL|NC|NZ|NI|NE|NG|NU|NF|MP|NO|OM|PK|PW|PS|PA|PG|PY|PE|PH|PN|PL|PT|PR|QA|RE|RO|RU|RW|BL|SH|KN|LC|MF|PM|VC|WS|SM|ST|SA|SN|RS|SC|SL|SG|SX|SK|SI|SB|SO|ZA|GS|SS|ES|LK|SD|SR|SJ|SZ|SE|CH|SY|TW|TJ|TZ|TH|TL|TG|TK|TO|TT|TN|TR|TM|TC|TV|UG|UA|AE|GB|US|UM|UY|UZ|VU|VE|VN|VG|VI|WF|EH|YE|ZM|ZW',
5293
 
5294
        /**
5295
         * Validate an ISIN (International Securities Identification Number)
5296
         * Examples:
5297
         * - Valid: US0378331005, AU0000XVGZA3, GB0002634946
5298
         * - Invalid: US0378331004, AA0000XVGZA3
5299
         *
5300
         * @see http://en.wikipedia.org/wiki/International_Securities_Identifying_Number
5301
         * @param {BootstrapValidator} validator The validator plugin instance
5302
         * @param {jQuery} $field Field element
5303
         * @param {Object} options Can consist of the following keys:
5304
         * - message: The invalid message
5305
         * @returns {Boolean}
5306
         */
5307
        validate: function(validator, $field, options) {
5308
            var value = $field.val();
5309
            if (value === '') {
5310
                return true;
5311
            }
5312
 
5313
            value = value.toUpperCase();
5314
            var regex = new RegExp('^(' + this.COUNTRY_CODES + ')[0-9A-Z]{10}$');
5315
            if (!regex.test(value)) {
5316
                return false;
5317
            }
5318
 
5319
            var converted = '',
5320
                length    = value.length;
5321
            // Convert letters to number
5322
            for (var i = 0; i < length - 1; i++) {
5323
                var c = value.charCodeAt(i);
5324
                converted += ((c > 57) ? (c - 55).toString() : value.charAt(i));
5325
            }
5326
 
5327
            var digits = '',
5328
                n      = converted.length,
5329
                group  = (n % 2 !== 0) ? 0 : 1;
5330
            for (i = 0; i < n; i++) {
5331
                digits += (parseInt(converted[i], 10) * ((i % 2) === group ? 2 : 1) + '');
5332
            }
5333
 
5334
            var sum = 0;
5335
            for (i = 0; i < digits.length; i++) {
5336
                sum += parseInt(digits.charAt(i), 10);
5337
            }
5338
            sum = (10 - (sum % 10)) % 10;
5339
            return sum + '' === value.charAt(length - 1);
5340
        }
5341
    };
5342
}(window.jQuery));
5343
;(function($) {
5344
    $.fn.bootstrapValidator.i18n.ismn = $.extend($.fn.bootstrapValidator.i18n.ismn || {}, {
5345
        'default': 'Please enter a valid ISMN number'
5346
    });
5347
 
5348
    $.fn.bootstrapValidator.validators.ismn = {
5349
        /**
5350
         * Validate ISMN (International Standard Music Number)
5351
         * Examples:
5352
         * - Valid: M230671187, 979-0-0601-1561-5, 979 0 3452 4680 5, 9790060115615
5353
         * - Invalid: 9790060115614
5354
         *
5355
         * @see http://en.wikipedia.org/wiki/International_Standard_Music_Number
5356
         * @param {BootstrapValidator} validator The validator plugin instance
5357
         * @param {jQuery} $field Field element
5358
         * @param {Object} options Can consist of the following keys:
5359
         * - message: The invalid message
5360
         * @returns {Boolean}
5361
         */
5362
        validate: function(validator, $field, options) {
5363
            var value = $field.val();
5364
            if (value === '') {
5365
                return true;
5366
            }
5367
 
5368
            // Groups are separated by a hyphen or a space
5369
            var type;
5370
            switch (true) {
5371
                case /^M\d{9}$/.test(value):
5372
                case /^M-\d{4}-\d{4}-\d{1}$/.test(value):
5373
                case /^M\s\d{4}\s\d{4}\s\d{1}$/.test(value):
5374
                    type = 'ISMN10';
5375
                    break;
5376
                case /^9790\d{9}$/.test(value):
5377
                case /^979-0-\d{4}-\d{4}-\d{1}$/.test(value):
5378
                case /^979\s0\s\d{4}\s\d{4}\s\d{1}$/.test(value):
5379
                    type = 'ISMN13';
5380
                    break;
5381
                default:
5382
                    return false;
5383
            }
5384
 
5385
            if ('ISMN10' === type) {
5386
                value = '9790' + value.substr(1);
5387
            }
5388
 
5389
            // Replace all special characters except digits
5390
            value = value.replace(/[^0-9]/gi, '');
5391
            var length = value.length,
5392
                sum    = 0,
5393
                weight = [1, 3];
5394
            for (var i = 0; i < length - 1; i++) {
5395
                sum += parseInt(value.charAt(i), 10) * weight[i % 2];
5396
            }
5397
            sum = 10 - sum % 10;
5398
            return (sum + '' === value.charAt(length - 1));
5399
        }
5400
    };
5401
}(window.jQuery));
5402
;(function($) {
5403
    $.fn.bootstrapValidator.i18n.issn = $.extend($.fn.bootstrapValidator.i18n.issn || {}, {
5404
        'default': 'Please enter a valid ISSN number'
5405
    });
5406
 
5407
    $.fn.bootstrapValidator.validators.issn = {
5408
        /**
5409
         * Validate ISSN (International Standard Serial Number)
5410
         * Examples:
5411
         * - Valid: 0378-5955, 0024-9319, 0032-1478
5412
         * - Invalid: 0032-147X
5413
         *
5414
         * @see http://en.wikipedia.org/wiki/International_Standard_Serial_Number
5415
         * @param {BootstrapValidator} validator The validator plugin instance
5416
         * @param {jQuery} $field Field element
5417
         * @param {Object} options Can consist of the following keys:
5418
         * - message: The invalid message
5419
         * @returns {Boolean}
5420
         */
5421
        validate: function(validator, $field, options) {
5422
            var value = $field.val();
5423
            if (value === '') {
5424
                return true;
5425
            }
5426
 
5427
            // Groups are separated by a hyphen or a space
5428
            if (!/^\d{4}\-\d{3}[\dX]$/.test(value)) {
5429
                return false;
5430
            }
5431
 
5432
            // Replace all special characters except digits and X
5433
            value = value.replace(/[^0-9X]/gi, '');
5434
            var chars  = value.split(''),
5435
                length = chars.length,
5436
                sum    = 0;
5437
 
5438
            if (chars[7] === 'X') {
5439
                chars[7] = 10;
5440
            }
5441
            for (var i = 0; i < length; i++) {
5442
                sum += parseInt(chars[i], 10) * (8 - i);
5443
            }
5444
            return (sum % 11 === 0);
5445
        }
5446
    };
5447
}(window.jQuery));
5448
;(function($) {
5449
    $.fn.bootstrapValidator.i18n.lessThan = $.extend($.fn.bootstrapValidator.i18n.lessThan || {}, {
5450
        'default': 'Please enter a value less than or equal to %s',
5451
        notInclusive: 'Please enter a value less than %s'
5452
    });
5453
 
5454
    $.fn.bootstrapValidator.validators.lessThan = {
5455
        html5Attributes: {
5456
            message: 'message',
5457
            value: 'value',
5458
            inclusive: 'inclusive'
5459
        },
5460
 
5461
        enableByHtml5: function($field) {
5462
            var type = $field.attr('type'),
5463
                max  = $field.attr('max');
5464
            if (max && type !== 'date') {
5465
                return {
5466
                    value: max
5467
                };
5468
            }
5469
 
5470
            return false;
5471
        },
5472
 
5473
        /**
5474
         * Return true if the input value is less than or equal to given number
5475
         *
5476
         * @param {BootstrapValidator} validator The validator plugin instance
5477
         * @param {jQuery} $field Field element
5478
         * @param {Object} options Can consist of the following keys:
5479
         * - value: The number used to compare to. It can be
5480
         *      - A number
5481
         *      - Name of field which its value defines the number
5482
         *      - Name of callback function that returns the number
5483
         *      - A callback function that returns the number
5484
         *
5485
         * - inclusive [optional]: Can be true or false. Default is true
5486
         * - message: The invalid message
5487
         * @returns {Boolean|Object}
5488
         */
5489
        validate: function(validator, $field, options) {
5490
            var value = $field.val();
5491
            if (value === '') {
5492
                return true;
5493
            }
5494
 
5495
			value = this._format(value);
5496
            if (!$.isNumeric(value)) {
5497
                return false;
5498
            }
5499
 
5500
            var compareTo      = $.isNumeric(options.value) ? options.value : validator.getDynamicOption($field, options.value),
5501
                compareToValue = this._format(compareTo);
5502
 
5503
            value = parseFloat(value);
5504
            return (options.inclusive === true || options.inclusive === undefined)
5505
                    ? {
5506
                        valid: value <= compareToValue,
5507
                        message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.lessThan['default'], compareTo)
5508
                    }
5509
                    : {
5510
                        valid: value < compareToValue,
5511
                        message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.lessThan.notInclusive, compareTo)
5512
                    };
5513
        },
5514
 
5515
        _format: function(value) {
5516
            return (value + '').replace(',', '.');
5517
        }
5518
    };
5519
}(window.jQuery));
5520
;(function($) {
5521
    $.fn.bootstrapValidator.i18n.mac = $.extend($.fn.bootstrapValidator.i18n.mac || {}, {
5522
        'default': 'Please enter a valid MAC address'
5523
    });
5524
 
5525
    $.fn.bootstrapValidator.validators.mac = {
5526
        /**
5527
         * Return true if the input value is a MAC address.
5528
         *
5529
         * @param {BootstrapValidator} validator The validator plugin instance
5530
         * @param {jQuery} $field Field element
5531
         * @param {Object} options Can consist of the following keys:
5532
         * - message: The invalid message
5533
         * @returns {Boolean}
5534
         */
5535
        validate: function(validator, $field, options) {
5536
            var value = $field.val();
5537
            if (value === '') {
5538
                return true;
5539
            }
5540
 
5541
            return /^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$/.test(value);
5542
        }
5543
    };
5544
}(window.jQuery));
5545
;(function($) {
5546
    $.fn.bootstrapValidator.i18n.meid = $.extend($.fn.bootstrapValidator.i18n.meid || {}, {
5547
        'default': 'Please enter a valid MEID number'
5548
    });
5549
 
5550
    $.fn.bootstrapValidator.validators.meid = {
5551
        /**
5552
         * Validate MEID (Mobile Equipment Identifier)
5553
         * Examples:
5554
         * - Valid: 293608736500703710, 29360-87365-0070-3710, AF0123450ABCDE, AF-012345-0ABCDE
5555
         * - Invalid: 2936087365007037101
5556
         *
5557
         * @see http://en.wikipedia.org/wiki/Mobile_equipment_identifier
5558
         * @param {BootstrapValidator} validator The validator plugin instance
5559
         * @param {jQuery} $field Field element
5560
         * @param {Object} options Can consist of the following keys:
5561
         * - message: The invalid message
5562
         * @returns {Boolean}
5563
         */
5564
        validate: function(validator, $field, options) {
5565
            var value = $field.val();
5566
            if (value === '') {
5567
                return true;
5568
            }
5569
 
5570
            switch (true) {
5571
                // 14 digit hex representation (no check digit)
5572
                case /^[0-9A-F]{15}$/i.test(value):
5573
                // 14 digit hex representation + dashes or spaces (no check digit)
5574
                case /^[0-9A-F]{2}[- ][0-9A-F]{6}[- ][0-9A-F]{6}[- ][0-9A-F]$/i.test(value):
5575
                // 18 digit decimal representation (no check digit)
5576
                case /^\d{19}$/.test(value):
5577
                // 18 digit decimal representation + dashes or spaces (no check digit)
5578
                case /^\d{5}[- ]\d{5}[- ]\d{4}[- ]\d{4}[- ]\d$/.test(value):
5579
                    // Grab the check digit
5580
                    var cd = value.charAt(value.length - 1);
5581
 
5582
                    // Strip any non-hex chars
5583
                    value = value.replace(/[- ]/g, '');
5584
 
5585
                    // If it's all digits, luhn base 10 is used
5586
                    if (value.match(/^\d*$/i)) {
5587
                        return $.fn.bootstrapValidator.helpers.luhn(value);
5588
                    }
5589
 
5590
                    // Strip the check digit
5591
                    value = value.slice(0, -1);
5592
 
5593
                    // Get every other char, and double it
5594
                    var cdCalc = '';
5595
                    for (var i = 1; i <= 13; i += 2) {
5596
                        cdCalc += (parseInt(value.charAt(i), 16) * 2).toString(16);
5597
                    }
5598
 
5599
                    // Get the sum of each char in the string
5600
                    var sum = 0;
5601
                    for (i = 0; i < cdCalc.length; i++) {
5602
                        sum += parseInt(cdCalc.charAt(i), 16);
5603
                    }
5604
 
5605
                    // If the last digit of the calc is 0, the check digit is 0
5606
                    return (sum % 10 === 0)
5607
                            ? (cd === '0')
5608
                            // Subtract it from the next highest 10s number (64 goes to 70) and subtract the sum
5609
                            // Double it and turn it into a hex char
5610
                            : (cd === ((Math.floor((sum + 10) / 10) * 10 - sum) * 2).toString(16));
5611
 
5612
                // 14 digit hex representation (no check digit)
5613
                case /^[0-9A-F]{14}$/i.test(value):
5614
                // 14 digit hex representation + dashes or spaces (no check digit)
5615
                case /^[0-9A-F]{2}[- ][0-9A-F]{6}[- ][0-9A-F]{6}$/i.test(value):
5616
                // 18 digit decimal representation (no check digit)
5617
                case /^\d{18}$/.test(value):
5618
                // 18 digit decimal representation + dashes or spaces (no check digit)
5619
                case /^\d{5}[- ]\d{5}[- ]\d{4}[- ]\d{4}$/.test(value):
5620
                    return true;
5621
 
5622
                default:
5623
                    return false;
5624
            }
5625
        }
5626
    };
5627
}(window.jQuery));
5628
;(function($) {
5629
    $.fn.bootstrapValidator.i18n.notEmpty = $.extend($.fn.bootstrapValidator.i18n.notEmpty || {}, {
5630
        'default': 'Please enter a value'
5631
    });
5632
 
5633
    $.fn.bootstrapValidator.validators.notEmpty = {
5634
        enableByHtml5: function($field) {
5635
            var required = $field.attr('required') + '';
5636
            return ('required' === required || 'true' === required);
5637
        },
5638
 
5639
        /**
5640
         * Check if input value is empty or not
5641
         *
5642
         * @param {BootstrapValidator} validator The validator plugin instance
5643
         * @param {jQuery} $field Field element
5644
         * @param {Object} options
5645
         * @returns {Boolean}
5646
         */
5647
        validate: function(validator, $field, options) {
5648
            var type = $field.attr('type');
5649
            if ('radio' === type || 'checkbox' === type) {
5650
                return validator
5651
                            .getFieldElements($field.attr('data-bv-field'))
5652
                            .filter(':checked')
5653
                            .length > 0;
5654
            }
5655
 
5656
            if ('number' === type && $field.get(0).validity && $field.get(0).validity.badInput === true) {
5657
                return true;
5658
            }
5659
 
5660
            return $.trim($field.val()) !== '';
5661
        }
5662
    };
5663
}(window.jQuery));
5664
;(function($) {
5665
    $.fn.bootstrapValidator.i18n.numeric = $.extend($.fn.bootstrapValidator.i18n.numeric || {}, {
5666
        'default': 'Please enter a valid float number'
5667
    });
5668
 
5669
    $.fn.bootstrapValidator.validators.numeric = {
5670
        html5Attributes: {
5671
            message: 'message',
5672
            separator: 'separator'
5673
        },
5674
 
5675
        enableByHtml5: function($field) {
5676
            return ('number' === $field.attr('type')) && ($field.attr('step') !== undefined) && ($field.attr('step') % 1 !== 0);
5677
        },
5678
 
5679
        /**
5680
         * Validate decimal number
5681
         *
5682
         * @param {BootstrapValidator} validator The validator plugin instance
5683
         * @param {jQuery} $field Field element
5684
         * @param {Object} options Consist of key:
5685
         * - message: The invalid message
5686
         * - separator: The decimal separator. Can be "." (default), ","
5687
         * @returns {Boolean}
5688
         */
5689
        validate: function(validator, $field, options) {
5690
            if (this.enableByHtml5($field) && $field.get(0).validity && $field.get(0).validity.badInput === true) {
5691
                return false;
5692
            }
5693
 
5694
            var value = $field.val();
5695
            if (value === '') {
5696
                return true;
5697
            }
5698
            var separator = options.separator || '.';
5699
            if (separator !== '.') {
5700
                value = value.replace(separator, '.');
5701
            }
5702
 
5703
            return !isNaN(parseFloat(value)) && isFinite(value);
5704
        }
5705
    };
5706
}(window.jQuery));
5707
;(function($) {
5708
    $.fn.bootstrapValidator.i18n.phone = $.extend($.fn.bootstrapValidator.i18n.phone || {}, {
5709
        'default': 'Please enter a valid phone number',
5710
        countryNotSupported: 'The country code %s is not supported',
5711
        country: 'Please enter a valid phone number in %s',
5712
        countries: {
5713
            BR: 'Brazil',
5714
            CN: 'China',
5715
            CZ: 'Czech Republic',
5716
            DE: 'Germany',
5717
            DK: 'Denmark',
5718
            ES: 'Spain',
5719
            FR: 'France',
5720
            GB: 'United Kingdom',
5721
            MA: 'Morocco',
5722
            PK: 'Pakistan',
5723
            RO: 'Romania',
5724
            RU: 'Russia',
5725
            SK: 'Slovakia',
5726
            TH: 'Thailand',
5727
            US: 'USA',
5728
            VE: 'Venezuela'
5729
        }
5730
    });
5731
 
5732
    $.fn.bootstrapValidator.validators.phone = {
5733
        html5Attributes: {
5734
            message: 'message',
5735
            country: 'country'
5736
        },
5737
 
5738
        // The supported countries
5739
        COUNTRY_CODES: ['BR', 'CN', 'CZ', 'DE', 'DK', 'ES', 'FR', 'GB', 'MA', 'PK', 'RO', 'RU', 'SK', 'TH', 'US', 'VE'],
5740
 
5741
        /**
5742
         * Return true if the input value contains a valid phone number for the country
5743
         * selected in the options
5744
         *
5745
         * @param {BootstrapValidator} validator Validate plugin instance
5746
         * @param {jQuery} $field Field element
5747
         * @param {Object} options Consist of key:
5748
         * - message: The invalid message
5749
         * - country: The ISO-3166 country code. It can be
5750
         *      - A country code
5751
         *      - Name of field which its value defines the country code
5752
         *      - Name of callback function that returns the country code
5753
         *      - A callback function that returns the country code
5754
         *
5755
         * @returns {Boolean|Object}
5756
         */
5757
        validate: function(validator, $field, options) {
5758
            var value = $field.val();
5759
            if (value === '') {
5760
                return true;
5761
            }
5762
 
5763
            var country = options.country;
5764
            if (typeof country !== 'string' || $.inArray(country, this.COUNTRY_CODES) === -1) {
5765
                // Try to determine the country
5766
                country = validator.getDynamicOption($field, country);
5767
            }
5768
 
5769
            if (!country || $.inArray(country.toUpperCase(), this.COUNTRY_CODES) === -1) {
5770
                return {
5771
                    valid: false,
5772
                    message: $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.phone.countryNotSupported, country)
5773
                };
5774
            }
5775
 
5776
            var isValid = true;
5777
            switch (country.toUpperCase()) {
5778
                case 'BR':
5779
                    // Test: http://regexr.com/399m1
5780
                    value   = $.trim(value);
5781
                    isValid = (/^(([\d]{4}[-.\s]{1}[\d]{2,3}[-.\s]{1}[\d]{2}[-.\s]{1}[\d]{2})|([\d]{4}[-.\s]{1}[\d]{3}[-.\s]{1}[\d]{4})|((\(?\+?[0-9]{2}\)?\s?)?(\(?\d{2}\)?\s?)?\d{4,5}[-.\s]?\d{4}))$/).test(value);
5782
                    break;
5783
 
5784
                case 'CN':
5785
                    // http://regexr.com/39dq4
5786
                    value   = $.trim(value);
5787
                    isValid = (/^((00|\+)?(86(?:-| )))?((\d{11})|(\d{3}[- ]{1}\d{4}[- ]{1}\d{4})|((\d{2,4}[- ]){1}(\d{7,8}|(\d{3,4}[- ]{1}\d{4}))([- ]{1}\d{1,4})?))$/).test(value);
5788
                    break;
5789
 
5790
                case 'CZ':
5791
                    // Test: http://regexr.com/39hhl
5792
                    isValid = /^(((00)([- ]?)|\+)(420)([- ]?))?((\d{3})([- ]?)){2}(\d{3})$/.test(value);
5793
                    break;
5794
 
5795
                case 'DE':
5796
                    // Test: http://regexr.com/39pkg
5797
                    value   = $.trim(value);
5798
                    isValid = (/^(((((((00|\+)49[ \-/]?)|0)[1-9][0-9]{1,4})[ \-/]?)|((((00|\+)49\()|\(0)[1-9][0-9]{1,4}\)[ \-/]?))[0-9]{1,7}([ \-/]?[0-9]{1,5})?)$/).test(value);
5799
                    break;
5800
 
5801
                case 'DK':
5802
                    // Mathing DK phone numbers with country code in 1 of 3 formats and an
5803
                    // 8 digit phone number not starting with a 0 or 1. Can have 1 space
5804
                    // between each character except inside the country code.
5805
                    // Test: http://regex101.com/r/sS8fO4/1
5806
                    value   = $.trim(value);
5807
                    isValid = (/^(\+45|0045|\(45\))?\s?[2-9](\s?\d){7}$/).test(value);
5808
                    break;
5809
 
5810
                case 'ES':
5811
                    // http://regex101.com/r/rB9mA9/1
5812
                    value   = $.trim(value);
5813
                    isValid = (/^(?:(?:(?:\+|00)34\D?))?(?:9|6)(?:\d\D?){8}$/).test(value);
5814
                    break;
5815
 
5816
                case 'FR':
5817
                    // http://regexr.com/39a2p
5818
                    value   = $.trim(value);
5819
                    isValid = (/^(?:(?:(?:\+|00)33[ ]?(?:\(0\)[ ]?)?)|0){1}[1-9]{1}([ .-]?)(?:\d{2}\1?){3}\d{2}$/).test(value);
5820
                    break;
5821
 
5822
            	case 'GB':
5823
            		// http://aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers#Match_GB_telephone_number_in_any_format
5824
            		// Test: http://regexr.com/38uhv
5825
            		value   = $.trim(value);
5826
            		isValid = (/^\(?(?:(?:0(?:0|11)\)?[\s-]?\(?|\+)44\)?[\s-]?\(?(?:0\)?[\s-]?\(?)?|0)(?:\d{2}\)?[\s-]?\d{4}[\s-]?\d{4}|\d{3}\)?[\s-]?\d{3}[\s-]?\d{3,4}|\d{4}\)?[\s-]?(?:\d{5}|\d{3}[\s-]?\d{3})|\d{5}\)?[\s-]?\d{4,5}|8(?:00[\s-]?11[\s-]?11|45[\s-]?46[\s-]?4\d))(?:(?:[\s-]?(?:x|ext\.?\s?|\#)\d+)?)$/).test(value);
5827
                    break;
5828
 
5829
                case 'MA':
5830
                    // http://en.wikipedia.org/wiki/Telephone_numbers_in_Morocco
5831
                    // Test: http://regexr.com/399n8
5832
                    value   = $.trim(value);
5833
                    isValid = (/^(?:(?:(?:\+|00)212[\s]?(?:[\s]?\(0\)[\s]?)?)|0){1}(?:5[\s.-]?[2-3]|6[\s.-]?[13-9]){1}[0-9]{1}(?:[\s.-]?\d{2}){3}$/).test(value);
5834
                    break;
5835
 
5836
                case 'PK':
5837
                    // http://regex101.com/r/yH8aV9/2
5838
                    value   = $.trim(value);
5839
                    isValid = (/^0?3[0-9]{2}[0-9]{7}$/).test(value);
5840
                    break;
5841
 
5842
        		case 'RO':
5843
        		    // All mobile network and land line
5844
                    // http://regexr.com/39fv1
5845
        		    isValid = (/^(\+4|)?(07[0-8]{1}[0-9]{1}|02[0-9]{2}|03[0-9]{2}){1}?(\s|\.|\-)?([0-9]{3}(\s|\.|\-|)){2}$/g).test(value);
5846
        		    break;
5847
 
5848
                case 'RU':
5849
                    // http://regex101.com/r/gW7yT5/5
5850
                    isValid = (/^((8|\+7|007)[\-\.\/ ]?)?([\(\/\.]?\d{3}[\)\/\.]?[\-\.\/ ]?)?[\d\-\.\/ ]{7,10}$/g).test(value);
5851
                    break;
5852
 
5853
                case 'SK':
5854
                    // Test: http://regexr.com/39hhl
5855
                    isValid = /^(((00)([- ]?)|\+)(420)([- ]?))?((\d{3})([- ]?)){2}(\d{3})$/.test(value);
5856
                    break;
5857
 
5858
                case 'TH':
5859
        		    // http://regex101.com/r/vM5mZ4/2
5860
        		    isValid = (/^0\(?([6|8-9]{2})*-([0-9]{3})*-([0-9]{4})$/).test(value);
5861
        		    break;
5862
 
5863
                case 'VE':
5864
                    // http://regex101.com/r/eM2yY0/6
5865
                    value   = $.trim(value);
5866
                    isValid = (/^0(?:2(?:12|4[0-9]|5[1-9]|6[0-9]|7[0-8]|8[1-35-8]|9[1-5]|3[45789])|4(?:1[246]|2[46]))\d{7}$/).test(value);
5867
                    break;
5868
 
5869
                case 'US':
5870
                /* falls through */
5871
                default:
5872
                    // Make sure US phone numbers have 10 digits
5873
                    // May start with 1, +1, or 1-; should discard
5874
                    // Area code may be delimited with (), & sections may be delimited with . or -
5875
                    // Test: http://regexr.com/38mqi
5876
                    value   = value.replace(/\D/g, '');
5877
                    isValid = (/^(?:(1\-?)|(\+1 ?))?\(?(\d{3})[\)\-\.]?(\d{3})[\-\.]?(\d{4})$/).test(value) && (value.length === 10);
5878
                    break;
5879
            }
5880
 
5881
            return {
5882
                valid: isValid,
5883
                message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.phone.country, $.fn.bootstrapValidator.i18n.phone.countries[country])
5884
            };
5885
        }
5886
    };
5887
}(window.jQuery));
5888
;(function($) {
5889
    $.fn.bootstrapValidator.i18n.regexp = $.extend($.fn.bootstrapValidator.i18n.regexp || {}, {
5890
        'default': 'Please enter a value matching the pattern'
5891
    });
5892
 
5893
    $.fn.bootstrapValidator.validators.regexp = {
5894
        html5Attributes: {
5895
            message: 'message',
5896
            regexp: 'regexp'
5897
        },
5898
 
5899
        enableByHtml5: function($field) {
5900
            var pattern = $field.attr('pattern');
5901
            if (pattern) {
5902
                return {
5903
                    regexp: pattern
5904
                };
5905
            }
5906
 
5907
            return false;
5908
        },
5909
 
5910
        /**
5911
         * Check if the element value matches given regular expression
5912
         *
5913
         * @param {BootstrapValidator} validator The validator plugin instance
5914
         * @param {jQuery} $field Field element
5915
         * @param {Object} options Consists of the following key:
5916
         * - regexp: The regular expression you need to check
5917
         * @returns {Boolean}
5918
         */
5919
        validate: function(validator, $field, options) {
5920
            var value = $field.val();
5921
            if (value === '') {
5922
                return true;
5923
            }
5924
 
5925
            var regexp = ('string' === typeof options.regexp) ? new RegExp(options.regexp) : options.regexp;
5926
            return regexp.test(value);
5927
        }
5928
    };
5929
}(window.jQuery));
5930
;(function($) {
5931
    $.fn.bootstrapValidator.i18n.remote = $.extend($.fn.bootstrapValidator.i18n.remote || {}, {
5932
        'default': 'Please enter a valid value'
5933
    });
5934
 
5935
    $.fn.bootstrapValidator.validators.remote = {
5936
        html5Attributes: {
5937
            message: 'message',
5938
            name: 'name',
5939
            type: 'type',
5940
            url: 'url',
5941
            data: 'data',
5942
            delay: 'delay'
5943
        },
5944
 
5945
        /**
5946
         * Destroy the timer when destroying the bootstrapValidator (using validator.destroy() method)
5947
         */
5948
        destroy: function(validator, $field, options) {
5949
            if ($field.data('bv.remote.timer')) {
5950
                clearTimeout($field.data('bv.remote.timer'));
5951
                $field.removeData('bv.remote.timer');
5952
            }
5953
        },
5954
 
5955
        /**
5956
         * Request a remote server to check the input value
5957
         *
5958
         * @param {BootstrapValidator} validator Plugin instance
5959
         * @param {jQuery} $field Field element
5960
         * @param {Object} options Can consist of the following keys:
5961
         * - url {String|Function}
5962
         * - type {String} [optional] Can be GET or POST (default)
5963
         * - data {Object|Function} [optional]: By default, it will take the value
5964
         *  {
5965
         *      <fieldName>: <fieldValue>
5966
         *  }
5967
         * - delay
5968
         * - name {String} [optional]: Override the field name for the request.
5969
         * - message: The invalid message
5970
         * - headers: Additional headers
5971
         * @returns {Deferred}
5972
         */
5973
        validate: function(validator, $field, options) {
5974
            var value = $field.val(),
5975
                dfd   = new $.Deferred();
5976
            if (value === '') {
5977
                dfd.resolve($field, 'remote', { valid: true });
5978
                return dfd;
5979
            }
5980
 
5981
            var name    = $field.attr('data-bv-field'),
5982
                data    = options.data || {},
5983
                url     = options.url,
5984
                type    = options.type || 'GET',
5985
                headers = options.headers || {};
5986
 
5987
            // Support dynamic data
5988
            if ('function' === typeof data) {
5989
                data = data.call(this, validator);
5990
            }
5991
 
5992
            // Parse string data from HTML5 attribute
5993
            if ('string' === typeof data) {
5994
                data = JSON.parse(data);
5995
            }
5996
 
5997
            // Support dynamic url
5998
            if ('function' === typeof url) {
5999
                url = url.call(this, validator);
6000
            }
6001
 
6002
            data[options.name || name] = value;
6003
            function runCallback() {
6004
                var xhr = $.ajax({
6005
                    type: type,
6006
                    headers: headers,
6007
                    url: url,
6008
                    dataType: 'json',
6009
                    data: data
6010
                });
6011
                xhr.then(function(response) {
6012
                    response.valid = response.valid === true || response.valid === 'true';
6013
                    dfd.resolve($field, 'remote', response);
6014
                });
6015
 
6016
                dfd.fail(function() {
6017
                    xhr.abort();
6018
                });
6019
 
6020
                return dfd;
6021
            }
6022
 
6023
            if (options.delay) {
6024
                // Since the form might have multiple fields with the same name
6025
                // I have to attach the timer to the field element
6026
                if ($field.data('bv.remote.timer')) {
6027
                    clearTimeout($field.data('bv.remote.timer'));
6028
                }
6029
 
6030
                $field.data('bv.remote.timer', setTimeout(runCallback, options.delay));
6031
                return dfd;
6032
            } else {
6033
                return runCallback();
6034
            }
6035
        }
6036
    };
6037
}(window.jQuery));
6038
;(function($) {
6039
    $.fn.bootstrapValidator.i18n.rtn = $.extend($.fn.bootstrapValidator.i18n.rtn || {}, {
6040
        'default': 'Please enter a valid RTN number'
6041
    });
6042
 
6043
    $.fn.bootstrapValidator.validators.rtn = {
6044
        /**
6045
         * Validate a RTN (Routing transit number)
6046
         * Examples:
6047
         * - Valid: 021200025, 789456124
6048
         *
6049
         * @see http://en.wikipedia.org/wiki/Routing_transit_number
6050
         * @param {BootstrapValidator} validator The validator plugin instance
6051
         * @param {jQuery} $field Field element
6052
         * @param {Object} options Can consist of the following keys:
6053
         * - message: The invalid message
6054
         * @returns {Boolean}
6055
         */
6056
        validate: function(validator, $field, options) {
6057
            var value = $field.val();
6058
            if (value === '') {
6059
                return true;
6060
            }
6061
 
6062
            if (!/^\d{9}$/.test(value)) {
6063
                return false;
6064
            }
6065
 
6066
            var sum = 0;
6067
            for (var i = 0; i < value.length; i += 3) {
6068
                sum += parseInt(value.charAt(i),     10) * 3
6069
                    +  parseInt(value.charAt(i + 1), 10) * 7
6070
                    +  parseInt(value.charAt(i + 2), 10);
6071
            }
6072
            return (sum !== 0 && sum % 10 === 0);
6073
        }
6074
    };
6075
}(window.jQuery));
6076
;(function($) {
6077
    $.fn.bootstrapValidator.i18n.sedol = $.extend($.fn.bootstrapValidator.i18n.sedol || {}, {
6078
        'default': 'Please enter a valid SEDOL number'
6079
    });
6080
 
6081
    $.fn.bootstrapValidator.validators.sedol = {
6082
        /**
6083
         * Validate a SEDOL (Stock Exchange Daily Official List)
6084
         * Examples:
6085
         * - Valid: 0263494, B0WNLY7
6086
         *
6087
         * @see http://en.wikipedia.org/wiki/SEDOL
6088
         * @param {BootstrapValidator} validator The validator plugin instance
6089
         * @param {jQuery} $field Field element
6090
         * @param {Object} options Can consist of the following keys:
6091
         * - message: The invalid message
6092
         * @returns {Boolean}
6093
         */
6094
        validate: function(validator, $field, options) {
6095
            var value = $field.val();
6096
            if (value === '') {
6097
                return true;
6098
            }
6099
 
6100
            value = value.toUpperCase();
6101
            if (!/^[0-9A-Z]{7}$/.test(value)) {
6102
                return false;
6103
            }
6104
 
6105
            var sum    = 0,
6106
                weight = [1, 3, 1, 7, 3, 9, 1],
6107
                length = value.length;
6108
            for (var i = 0; i < length - 1; i++) {
6109
	            sum += weight[i] * parseInt(value.charAt(i), 36);
6110
	        }
6111
	        sum = (10 - sum % 10) % 10;
6112
            return sum + '' === value.charAt(length - 1);
6113
        }
6114
    };
6115
}(window.jQuery));
6116
;(function($) {
6117
    $.fn.bootstrapValidator.i18n.siren = $.extend($.fn.bootstrapValidator.i18n.siren || {}, {
6118
        'default': 'Please enter a valid SIREN number'
6119
    });
6120
 
6121
	$.fn.bootstrapValidator.validators.siren = {
6122
		/**
6123
		 * Check if a string is a siren number
6124
		 *
6125
		 * @param {BootstrapValidator} validator The validator plugin instance
6126
		 * @param {jQuery} $field Field element
6127
		 * @param {Object} options Consist of key:
6128
         * - message: The invalid message
6129
		 * @returns {Boolean}
6130
		 */
6131
		validate: function(validator, $field, options) {
6132
			var value = $field.val();
6133
			if (value === '') {
6134
				return true;
6135
			}
6136
 
6137
            if (!/^\d{9}$/.test(value)) {
6138
                return false;
6139
            }
6140
            return $.fn.bootstrapValidator.helpers.luhn(value);
6141
		}
6142
	};
6143
}(window.jQuery));
6144
;(function($) {
6145
    $.fn.bootstrapValidator.i18n.siret = $.extend($.fn.bootstrapValidator.i18n.siret || {}, {
6146
        'default': 'Please enter a valid SIRET number'
6147
    });
6148
 
6149
	$.fn.bootstrapValidator.validators.siret = {
6150
        /**
6151
         * Check if a string is a siret number
6152
         *
6153
         * @param {BootstrapValidator} validator The validator plugin instance
6154
         * @param {jQuery} $field Field element
6155
         * @param {Object} options Consist of key:
6156
         * - message: The invalid message
6157
         * @returns {Boolean}
6158
         */
6159
		validate: function(validator, $field, options) {
6160
			var value = $field.val();
6161
			if (value === '') {
6162
				return true;
6163
			}
6164
 
6165
			var sum    = 0,
6166
                length = value.length,
6167
                tmp;
6168
			for (var i = 0; i < length; i++) {
6169
                tmp = parseInt(value.charAt(i), 10);
6170
				if ((i % 2) === 0) {
6171
					tmp = tmp * 2;
6172
					if (tmp > 9) {
6173
						tmp -= 9;
6174
					}
6175
				}
6176
				sum += tmp;
6177
			}
6178
			return (sum % 10 === 0);
6179
		}
6180
	};
6181
}(window.jQuery));
6182
;(function($) {
6183
    $.fn.bootstrapValidator.i18n.step = $.extend($.fn.bootstrapValidator.i18n.step || {}, {
6184
        'default': 'Please enter a valid step of %s'
6185
    });
6186
 
6187
    $.fn.bootstrapValidator.validators.step = {
6188
        html5Attributes: {
6189
            message: 'message',
6190
            base: 'baseValue',
6191
            step: 'step'
6192
        },
6193
 
6194
        /**
6195
         * Return true if the input value is valid step one
6196
         *
6197
         * @param {BootstrapValidator} validator The validator plugin instance
6198
         * @param {jQuery} $field Field element
6199
         * @param {Object} options Can consist of the following keys:
6200
         * - baseValue: The base value
6201
         * - step: The step
6202
         * - message: The invalid message
6203
         * @returns {Boolean|Object}
6204
         */
6205
        validate: function(validator, $field, options) {
6206
            var value = $field.val();
6207
            if (value === '') {
6208
                return true;
6209
            }
6210
 
6211
            options = $.extend({}, { baseValue: 0, step: 1 }, options);
6212
            value   = parseFloat(value);
6213
            if (!$.isNumeric(value)) {
6214
                return false;
6215
            }
6216
 
6217
            var round = function(x, precision) {
6218
                    var m = Math.pow(10, precision);
6219
                    x = x * m;
6220
                    var sign   = (x > 0) | -(x < 0),
6221
                        isHalf = (x % 1 === 0.5 * sign);
6222
                    if (isHalf) {
6223
                        return (Math.floor(x) + (sign > 0)) / m;
6224
                    } else {
6225
                        return Math.round(x) / m;
6226
                    }
6227
                },
6228
                floatMod = function(x, y) {
6229
                    if (y === 0.0) {
6230
                        return 1.0;
6231
                    }
6232
                    var dotX      = (x + '').split('.'),
6233
                        dotY      = (y + '').split('.'),
6234
                        precision = ((dotX.length === 1) ? 0 : dotX[1].length) + ((dotY.length === 1) ? 0 : dotY[1].length);
6235
                    return round(x - y * Math.floor(x / y), precision);
6236
                };
6237
 
6238
            var mod = floatMod(value - options.baseValue, options.step);
6239
            return {
6240
                valid: mod === 0.0 || mod === options.step,
6241
                message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.step['default'], [options.step])
6242
            };
6243
        }
6244
    };
6245
}(window.jQuery));
6246
;(function($) {
6247
    $.fn.bootstrapValidator.i18n.stringCase = $.extend($.fn.bootstrapValidator.i18n.stringCase || {}, {
6248
        'default': 'Please enter only lowercase characters',
6249
        upper: 'Please enter only uppercase characters'
6250
    });
6251
 
6252
    $.fn.bootstrapValidator.validators.stringCase = {
6253
        html5Attributes: {
6254
            message: 'message',
6255
            'case': 'case'
6256
        },
6257
 
6258
        /**
6259
         * Check if a string is a lower or upper case one
6260
         *
6261
         * @param {BootstrapValidator} validator The validator plugin instance
6262
         * @param {jQuery} $field Field element
6263
         * @param {Object} options Consist of key:
6264
         * - message: The invalid message
6265
         * - case: Can be 'lower' (default) or 'upper'
6266
         * @returns {Object}
6267
         */
6268
        validate: function(validator, $field, options) {
6269
            var value = $field.val();
6270
            if (value === '') {
6271
                return true;
6272
            }
6273
 
6274
            var stringCase = (options['case'] || 'lower').toLowerCase();
6275
            return {
6276
                valid: ('upper' === stringCase) ? value === value.toUpperCase() : value === value.toLowerCase(),
6277
                message: options.message || (('upper' === stringCase) ? $.fn.bootstrapValidator.i18n.stringCase.upper : $.fn.bootstrapValidator.i18n.stringCase['default'])
6278
            };
6279
        }
6280
    };
6281
}(window.jQuery));
6282
;(function($) {
6283
    $.fn.bootstrapValidator.i18n.stringLength = $.extend($.fn.bootstrapValidator.i18n.stringLength || {}, {
6284
        'default': 'Please enter a value with valid length',
6285
        less: 'Please enter less than %s characters',
6286
        more: 'Please enter more than %s characters',
6287
        between: 'Please enter value between %s and %s characters long'
6288
    });
6289
 
6290
    $.fn.bootstrapValidator.validators.stringLength = {
6291
        html5Attributes: {
6292
            message: 'message',
6293
            min: 'min',
6294
            max: 'max',
6295
            trim: 'trim',
6296
            utf8bytes: 'utf8Bytes'
6297
        },
6298
 
6299
        enableByHtml5: function($field) {
6300
            var options   = {},
6301
                maxLength = $field.attr('maxlength'),
6302
                minLength = $field.attr('minlength');
6303
            if (maxLength) {
6304
                options.max = parseInt(maxLength, 10);
6305
            }
6306
            if (minLength) {
6307
                options.min = parseInt(minLength, 10);
6308
            }
6309
 
6310
            return $.isEmptyObject(options) ? false : options;
6311
        },
6312
 
6313
        /**
6314
         * Check if the length of element value is less or more than given number
6315
         *
6316
         * @param {BootstrapValidator} validator The validator plugin instance
6317
         * @param {jQuery} $field Field element
6318
         * @param {Object} options Consists of following keys:
6319
         * - min
6320
         * - max
6321
         * At least one of two keys is required
6322
         * The min, max keys define the number which the field value compares to. min, max can be
6323
         *      - A number
6324
         *      - Name of field which its value defines the number
6325
         *      - Name of callback function that returns the number
6326
         *      - A callback function that returns the number
6327
         *
6328
         * - message: The invalid message
6329
         * - trim: Indicate the length will be calculated after trimming the value or not. It is false, by default
6330
         * - utf8bytes: Evaluate string length in UTF-8 bytes, default to false
6331
         * @returns {Object}
6332
         */
6333
        validate: function(validator, $field, options) {
6334
            var value = $field.val();
6335
            if (options.trim === true || options.trim === 'true') {
6336
                value = $.trim(value);
6337
            }
6338
 
6339
            if (value === '') {
6340
                return true;
6341
            }
6342
 
6343
            var min        = $.isNumeric(options.min) ? options.min : validator.getDynamicOption($field, options.min),
6344
                max        = $.isNumeric(options.max) ? options.max : validator.getDynamicOption($field, options.max),
6345
                // Credit to http://stackoverflow.com/a/23329386 (@lovasoa) for UTF-8 byte length code
6346
                utf8Length = function(str) {
6347
                                 var s = str.length;
6348
                                 for (var i = str.length - 1; i >= 0; i--) {
6349
                                     var code = str.charCodeAt(i);
6350
                                     if (code > 0x7f && code <= 0x7ff) {
6351
                                         s++;
6352
                                     } else if (code > 0x7ff && code <= 0xffff) {
6353
                                         s += 2;
6354
                                     }
6355
                                     if (code >= 0xDC00 && code <= 0xDFFF) {
6356
                                         i--;
6357
                                     }
6358
                                 }
6359
                                 return s;
6360
                             },
6361
                length     = options.utf8Bytes ? utf8Length(value) : value.length,
6362
                isValid    = true,
6363
                message    = options.message || $.fn.bootstrapValidator.i18n.stringLength['default'];
6364
 
6365
            if ((min && length < parseInt(min, 10)) || (max && length > parseInt(max, 10))) {
6366
                isValid = false;
6367
            }
6368
 
6369
            switch (true) {
6370
                case (!!min && !!max):
6371
                    message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.stringLength.between, [parseInt(min, 10), parseInt(max, 10)]);
6372
                    break;
6373
 
6374
                case (!!min):
6375
                    message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.stringLength.more, parseInt(min, 10));
6376
                    break;
6377
 
6378
                case (!!max):
6379
                    message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.stringLength.less, parseInt(max, 10));
6380
                    break;
6381
 
6382
                default:
6383
                    break;
6384
            }
6385
 
6386
            return { valid: isValid, message: message };
6387
        }
6388
    };
6389
}(window.jQuery));
6390
;(function($) {
6391
    $.fn.bootstrapValidator.i18n.uri = $.extend($.fn.bootstrapValidator.i18n.uri || {}, {
6392
        'default': 'Please enter a valid URI'
6393
    });
6394
 
6395
    $.fn.bootstrapValidator.validators.uri = {
6396
        html5Attributes: {
6397
            message: 'message',
6398
            allowlocal: 'allowLocal',
6399
            protocol: 'protocol'
6400
        },
6401
 
6402
        enableByHtml5: function($field) {
6403
            return ('url' === $field.attr('type'));
6404
        },
6405
 
6406
        /**
6407
         * Return true if the input value is a valid URL
6408
         *
6409
         * @param {BootstrapValidator} validator The validator plugin instance
6410
         * @param {jQuery} $field Field element
6411
         * @param {Object} options
6412
         * - message: The error message
6413
         * - allowLocal: Allow the private and local network IP. Default to false
6414
         * - protocol: The protocols, separated by a comma. Default to "http, https, ftp"
6415
         * @returns {Boolean}
6416
         */
6417
        validate: function(validator, $field, options) {
6418
            var value = $field.val();
6419
            if (value === '') {
6420
                return true;
6421
            }
6422
 
6423
            // Credit to https://gist.github.com/dperini/729294
6424
            //
6425
            // Regular Expression for URL validation
6426
            //
6427
            // Author: Diego Perini
6428
            // Updated: 2010/12/05
6429
            //
6430
            // the regular expression composed & commented
6431
            // could be easily tweaked for RFC compliance,
6432
            // it was expressly modified to fit & satisfy
6433
            // these test for an URL shortener:
6434
            //
6435
            //   http://mathiasbynens.be/demo/url-regex
6436
            //
6437
            // Notes on possible differences from a standard/generic validation:
6438
            //
6439
            // - utf-8 char class take in consideration the full Unicode range
6440
            // - TLDs are mandatory unless `allowLocal` is true
6441
            // - protocols have been restricted to ftp, http and https only as requested
6442
            //
6443
            // Changes:
6444
            //
6445
            // - IP address dotted notation validation, range: 1.0.0.0 - 223.255.255.255
6446
            //   first and last IP address of each class is considered invalid
6447
            //   (since they are broadcast/network addresses)
6448
            //
6449
            // - Added exclusion of private, reserved and/or local networks ranges
6450
            //   unless `allowLocal` is true
6451
            //
6452
            // - Added possibility of choosing a custom protocol
6453
            //
6454
            var allowLocal = options.allowLocal === true || options.allowLocal === 'true',
6455
                protocol   = (options.protocol || 'http, https, ftp').split(',').join('|').replace(/\s/g, ''),
6456
                urlExp     = new RegExp(
6457
                    "^" +
6458
                    // protocol identifier
6459
                    "(?:(?:" + protocol + ")://)" +
6460
                    // user:pass authentication
6461
                    "(?:\\S+(?::\\S*)?@)?" +
6462
                    "(?:" +
6463
                    // IP address exclusion
6464
                    // private & local networks
6465
                    (allowLocal
6466
                        ? ''
6467
                        : ("(?!(?:10|127)(?:\\.\\d{1,3}){3})" +
6468
                           "(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})" +
6469
                           "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})")) +
6470
                    // IP address dotted notation octets
6471
                    // excludes loopback network 0.0.0.0
6472
                    // excludes reserved space >= 224.0.0.0
6473
                    // excludes network & broadcast addresses
6474
                    // (first & last IP address of each class)
6475
                    "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
6476
                    "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
6477
                    "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
6478
                    "|" +
6479
                    // host name
6480
                    "(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)" +
6481
                    // domain name
6482
                    "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*" +
6483
                    // TLD identifier
6484
                    "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" +
6485
                    // Allow intranet sites (no TLD) if `allowLocal` is true
6486
                    (allowLocal ? '?' : '') +
6487
                    ")" +
6488
                    // port number
6489
                    "(?::\\d{2,5})?" +
6490
                    // resource path
6491
                    "(?:/[^\\s]*)?" +
6492
                    "$", "i"
6493
            );
6494
 
6495
            return urlExp.test(value);
6496
        }
6497
    };
6498
}(window.jQuery));
6499
;(function($) {
6500
    $.fn.bootstrapValidator.i18n.uuid = $.extend($.fn.bootstrapValidator.i18n.uuid || {}, {
6501
        'default': 'Please enter a valid UUID number',
6502
        version: 'Please enter a valid UUID version %s number'
6503
    });
6504
 
6505
    $.fn.bootstrapValidator.validators.uuid = {
6506
        html5Attributes: {
6507
            message: 'message',
6508
            version: 'version'
6509
        },
6510
 
6511
        /**
6512
         * Return true if and only if the input value is a valid UUID string
6513
         *
6514
         * @see http://en.wikipedia.org/wiki/Universally_unique_identifier
6515
         * @param {BootstrapValidator} validator The validator plugin instance
6516
         * @param {jQuery} $field Field element
6517
         * @param {Object} options Consist of key:
6518
         * - message: The invalid message
6519
         * - version: Can be 3, 4, 5, null
6520
         * @returns {Boolean|Object}
6521
         */
6522
        validate: function(validator, $field, options) {
6523
            var value = $field.val();
6524
            if (value === '') {
6525
                return true;
6526
            }
6527
 
6528
            // See the format at http://en.wikipedia.org/wiki/Universally_unique_identifier#Variants_and_versions
6529
            var patterns = {
6530
                    '3': /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i,
6531
                    '4': /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
6532
                    '5': /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
6533
                    all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i
6534
                },
6535
                version = options.version ? (options.version + '') : 'all';
6536
            return {
6537
                valid: (null === patterns[version]) ? true : patterns[version].test(value),
6538
                message: options.version
6539
                            ? $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.uuid.version, options.version)
6540
                            : (options.message || $.fn.bootstrapValidator.i18n.uuid['default'])
6541
            };
6542
        }
6543
    };
6544
}(window.jQuery));
6545
;(function($) {
6546
    $.fn.bootstrapValidator.i18n.vat = $.extend($.fn.bootstrapValidator.i18n.vat || {}, {
6547
        'default': 'Please enter a valid VAT number',
6548
        countryNotSupported: 'The country code %s is not supported',
6549
        country: 'Please enter a valid VAT number in %s',
6550
        countries: {
6551
            AT: 'Austria',
6552
            BE: 'Belgium',
6553
            BG: 'Bulgaria',
6554
            BR: 'Brazil',
6555
            CH: 'Switzerland',
6556
            CY: 'Cyprus',
6557
            CZ: 'Czech Republic',
6558
            DE: 'Germany',
6559
            DK: 'Denmark',
6560
            EE: 'Estonia',
6561
            ES: 'Spain',
6562
            FI: 'Finland',
6563
            FR: 'France',
6564
            GB: 'United Kingdom',
6565
            GR: 'Greek',
6566
            EL: 'Greek',
6567
            HU: 'Hungary',
6568
            HR: 'Croatia',
6569
            IE: 'Ireland',
6570
            IS: 'Iceland',
6571
            IT: 'Italy',
6572
            LT: 'Lithuania',
6573
            LU: 'Luxembourg',
6574
            LV: 'Latvia',
6575
            MT: 'Malta',
6576
            NL: 'Netherlands',
6577
            NO: 'Norway',
6578
            PL: 'Poland',
6579
            PT: 'Portugal',
6580
            RO: 'Romania',
6581
            RU: 'Russia',
6582
            RS: 'Serbia',
6583
            SE: 'Sweden',
6584
            SI: 'Slovenia',
6585
            SK: 'Slovakia',
6586
            VE: 'Venezuela',
6587
            ZA: 'South Africa'
6588
        }
6589
    });
6590
 
6591
    $.fn.bootstrapValidator.validators.vat = {
6592
        html5Attributes: {
6593
            message: 'message',
6594
            country: 'country'
6595
        },
6596
 
6597
        // Supported country codes
6598
        COUNTRY_CODES: [
6599
            'AT', 'BE', 'BG', 'BR', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'EL', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU',
6600
            'IE', 'IS', 'IT', 'LT', 'LU', 'LV', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'RU', 'RS', 'SE', 'SK', 'SI', 'VE',
6601
            'ZA'
6602
        ],
6603
 
6604
        /**
6605
         * Validate an European VAT number
6606
         *
6607
         * @param {BootstrapValidator} validator The validator plugin instance
6608
         * @param {jQuery} $field Field element
6609
         * @param {Object} options Consist of key:
6610
         * - message: The invalid message
6611
         * - country: The ISO 3166-1 country code. It can be
6612
         *      - One of country code defined in COUNTRY_CODES
6613
         *      - Name of field which its value defines the country code
6614
         *      - Name of callback function that returns the country code
6615
         *      - A callback function that returns the country code
6616
         * @returns {Boolean|Object}
6617
         */
6618
        validate: function(validator, $field, options) {
6619
            var value = $field.val();
6620
            if (value === '') {
6621
                return true;
6622
            }
6623
 
6624
            var country = options.country;
6625
            if (!country) {
6626
                country = value.substr(0, 2);
6627
            } else if (typeof country !== 'string' || $.inArray(country.toUpperCase(), this.COUNTRY_CODES) === -1) {
6628
                // Determine the country code
6629
                country = validator.getDynamicOption($field, country);
6630
            }
6631
 
6632
            if ($.inArray(country, this.COUNTRY_CODES) === -1) {
6633
                return {
6634
                    valid: false,
6635
                    message: $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.vat.countryNotSupported, country)
6636
                };
6637
            }
6638
 
6639
            var method  = ['_', country.toLowerCase()].join('');
6640
            return this[method](value)
6641
                ? true
6642
                : {
6643
                    valid: false,
6644
                    message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.vat.country, $.fn.bootstrapValidator.i18n.vat.countries[country.toUpperCase()])
6645
                };
6646
        },
6647
 
6648
        // VAT validators
6649
 
6650
        /**
6651
         * Validate Austrian VAT number
6652
         * Example:
6653
         * - Valid: ATU13585627
6654
         * - Invalid: ATU13585626
6655
         *
6656
         * @param {String} value VAT number
6657
         * @returns {Boolean}
6658
         */
6659
        _at: function(value) {
6660
            if (/^ATU[0-9]{8}$/.test(value)) {
6661
                value = value.substr(2);
6662
            }
6663
            if (!/^U[0-9]{8}$/.test(value)) {
6664
                return false;
6665
            }
6666
 
6667
            value = value.substr(1);
6668
            var sum    = 0,
6669
                weight = [1, 2, 1, 2, 1, 2, 1],
6670
                temp   = 0;
6671
            for (var i = 0; i < 7; i++) {
6672
                temp = parseInt(value.charAt(i), 10) * weight[i];
6673
                if (temp > 9) {
6674
                    temp = Math.floor(temp / 10) + temp % 10;
6675
                }
6676
                sum += temp;
6677
            }
6678
 
6679
            sum = 10 - (sum + 4) % 10;
6680
            if (sum === 10) {
6681
                sum = 0;
6682
            }
6683
 
6684
            return (sum + '' === value.substr(7, 1));
6685
        },
6686
 
6687
        /**
6688
         * Validate Belgian VAT number
6689
         * Example:
6690
         * - Valid: BE0428759497
6691
         * - Invalid: BE431150351
6692
         *
6693
         * @param {String} value VAT number
6694
         * @returns {Boolean}
6695
         */
6696
        _be: function(value) {
6697
            if (/^BE[0]{0,1}[0-9]{9}$/.test(value)) {
6698
                value = value.substr(2);
6699
            }
6700
            if (!/^[0]{0,1}[0-9]{9}$/.test(value)) {
6701
                return false;
6702
            }
6703
 
6704
            if (value.length === 9) {
6705
                value = '0' + value;
6706
            }
6707
            if (value.substr(1, 1) === '0') {
6708
                return false;
6709
            }
6710
 
6711
            var sum = parseInt(value.substr(0, 8), 10) + parseInt(value.substr(8, 2), 10);
6712
            return (sum % 97 === 0);
6713
        },
6714
 
6715
        /**
6716
         * Validate Bulgarian VAT number
6717
         * Example:
6718
         * - Valid: BG175074752,
6719
         * BG7523169263, BG8032056031,
6720
         * BG7542011030,
6721
         * BG7111042925
6722
         * - Invalid: BG175074753, BG7552A10004, BG7111042922
6723
         *
6724
         * @param {String} value VAT number
6725
         * @returns {Boolean}
6726
         */
6727
        _bg: function(value) {
6728
            if (/^BG[0-9]{9,10}$/.test(value)) {
6729
                value = value.substr(2);
6730
            }
6731
            if (!/^[0-9]{9,10}$/.test(value)) {
6732
                return false;
6733
            }
6734
 
6735
            var sum = 0, i = 0;
6736
 
6737
            // Legal entities
6738
            if (value.length === 9) {
6739
                for (i = 0; i < 8; i++) {
6740
                    sum += parseInt(value.charAt(i), 10) * (i + 1);
6741
                }
6742
                sum = sum % 11;
6743
                if (sum === 10) {
6744
                    sum = 0;
6745
                    for (i = 0; i < 8; i++) {
6746
                        sum += parseInt(value.charAt(i), 10) * (i + 3);
6747
                    }
6748
                }
6749
                sum = sum % 10;
6750
                return (sum + '' === value.substr(8));
6751
            }
6752
            // Physical persons, foreigners and others
6753
            else if (value.length === 10) {
6754
                // Validate Bulgarian national identification numbers
6755
                var egn = function(value) {
6756
                        // Check the birth date
6757
                        var year  = parseInt(value.substr(0, 2), 10) + 1900,
6758
                            month = parseInt(value.substr(2, 2), 10),
6759
                            day   = parseInt(value.substr(4, 2), 10);
6760
                        if (month > 40) {
6761
                            year += 100;
6762
                            month -= 40;
6763
                        } else if (month > 20) {
6764
                            year -= 100;
6765
                            month -= 20;
6766
                        }
6767
 
6768
                        if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
6769
                            return false;
6770
                        }
6771
 
6772
                        var sum    = 0,
6773
                            weight = [2, 4, 8, 5, 10, 9, 7, 3, 6];
6774
                        for (var i = 0; i < 9; i++) {
6775
                            sum += parseInt(value.charAt(i), 10) * weight[i];
6776
                        }
6777
                        sum = (sum % 11) % 10;
6778
                        return (sum + '' === value.substr(9, 1));
6779
                    },
6780
                    // Validate Bulgarian personal number of a foreigner
6781
                    pnf = function(value) {
6782
                        var sum    = 0,
6783
                            weight = [21, 19, 17, 13, 11, 9, 7, 3, 1];
6784
                        for (var i = 0; i < 9; i++) {
6785
                            sum += parseInt(value.charAt(i), 10) * weight[i];
6786
                        }
6787
                        sum = sum % 10;
6788
                        return (sum + '' === value.substr(9, 1));
6789
                    },
6790
                    // Finally, consider it as a VAT number
6791
                    vat = function(value) {
6792
                        var sum    = 0,
6793
                            weight = [4, 3, 2, 7, 6, 5, 4, 3, 2];
6794
                        for (var i = 0; i < 9; i++) {
6795
                            sum += parseInt(value.charAt(i), 10) * weight[i];
6796
                        }
6797
                        sum = 11 - sum % 11;
6798
                        if (sum === 10) {
6799
                            return false;
6800
                        }
6801
                        if (sum === 11) {
6802
                            sum = 0;
6803
                        }
6804
                        return (sum + '' === value.substr(9, 1));
6805
                    };
6806
                return (egn(value) || pnf(value) || vat(value));
6807
            }
6808
 
6809
            return false;
6810
        },
6811
 
6812
        /**
6813
         * Validate Brazilian VAT number (CNPJ)
6814
         *
6815
         * @param {String} value VAT number
6816
         * @returns {Boolean}
6817
         */
6818
        _br: function(value) {
6819
            if (value === '') {
6820
                return true;
6821
            }
6822
            var cnpj = value.replace(/[^\d]+/g, '');
6823
            if (cnpj === '' || cnpj.length !== 14) {
6824
                return false;
6825
            }
6826
 
6827
            // Remove invalids CNPJs
6828
            if (cnpj === '00000000000000' || cnpj === '11111111111111' || cnpj === '22222222222222' ||
6829
                cnpj === '33333333333333' || cnpj === '44444444444444' || cnpj === '55555555555555' ||
6830
                cnpj === '66666666666666' || cnpj === '77777777777777' || cnpj === '88888888888888' ||
6831
                cnpj === '99999999999999')
6832
            {
6833
                return false;
6834
            }
6835
 
6836
            // Validate verification digits
6837
            var length  = cnpj.length - 2,
6838
                numbers = cnpj.substring(0, length),
6839
                digits  = cnpj.substring(length),
6840
                sum     = 0,
6841
                pos     = length - 7;
6842
 
6843
            for (var i = length; i >= 1; i--) {
6844
                sum += parseInt(numbers.charAt(length - i), 10) * pos--;
6845
                if (pos < 2) {
6846
                    pos = 9;
6847
                }
6848
            }
6849
 
6850
            var result = sum % 11 < 2 ? 0 : 11 - sum % 11;
6851
            if (result !== parseInt(digits.charAt(0), 10)) {
6852
                return false;
6853
            }
6854
 
6855
            length  = length + 1;
6856
            numbers = cnpj.substring(0, length);
6857
            sum     = 0;
6858
            pos     = length - 7;
6859
            for (i = length; i >= 1; i--) {
6860
                sum += parseInt(numbers.charAt(length - i), 10) * pos--;
6861
                if (pos < 2) {
6862
                    pos = 9;
6863
                }
6864
            }
6865
 
6866
            result = sum % 11 < 2 ? 0 : 11 - sum % 11;
6867
            return (result === parseInt(digits.charAt(1), 10));
6868
        },
6869
 
6870
        /**
6871
         * Validate Swiss VAT number
6872
         *
6873
         * @param {String} value VAT number
6874
         * @returns {Boolean}
6875
         */
6876
        _ch: function(value) {
6877
            if (/^CHE[0-9]{9}(MWST)?$/.test(value)) {
6878
                value = value.substr(2);
6879
            }
6880
            if (!/^E[0-9]{9}(MWST)?$/.test(value)) {
6881
                return false;
6882
            }
6883
 
6884
            value = value.substr(1);
6885
            var sum    = 0,
6886
                weight = [5, 4, 3, 2, 7, 6, 5, 4];
6887
            for (var i = 0; i < 8; i++) {
6888
                sum += parseInt(value.charAt(i), 10) * weight[i];
6889
            }
6890
 
6891
            sum = 11 - sum % 11;
6892
            if (sum === 10) {
6893
                return false;
6894
            }
6895
            if (sum === 11) {
6896
                sum = 0;
6897
            }
6898
 
6899
            return (sum + '' === value.substr(8, 1));
6900
        },
6901
 
6902
        /**
6903
         * Validate Cypriot VAT number
6904
         * Examples:
6905
         * - Valid: CY10259033P
6906
         * - Invalid: CY10259033Z
6907
         *
6908
         * @param {String} value VAT number
6909
         * @returns {Boolean}
6910
         */
6911
        _cy: function(value) {
6912
            if (/^CY[0-5|9]{1}[0-9]{7}[A-Z]{1}$/.test(value)) {
6913
                value = value.substr(2);
6914
            }
6915
            if (!/^[0-5|9]{1}[0-9]{7}[A-Z]{1}$/.test(value)) {
6916
                return false;
6917
            }
6918
 
6919
            // Do not allow to start with "12"
6920
            if (value.substr(0, 2) === '12') {
6921
                return false;
6922
            }
6923
 
6924
            // Extract the next digit and multiply by the counter.
6925
            var sum         = 0,
6926
                translation = {
6927
                    '0': 1,  '1': 0,  '2': 5,  '3': 7,  '4': 9,
6928
                    '5': 13, '6': 15, '7': 17, '8': 19, '9': 21
6929
                };
6930
            for (var i = 0; i < 8; i++) {
6931
                var temp = parseInt(value.charAt(i), 10);
6932
                if (i % 2 === 0) {
6933
                    temp = translation[temp + ''];
6934
                }
6935
                sum += temp;
6936
            }
6937
 
6938
            sum = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[sum % 26];
6939
            return (sum + '' === value.substr(8, 1));
6940
        },
6941
 
6942
        /**
6943
         * Validate Czech Republic VAT number
6944
         * Can be:
6945
         * i) Legal entities (8 digit numbers)
6946
         * ii) Individuals with a RC (the 9 or 10 digit Czech birth number)
6947
         * iii) Individuals without a RC (9 digit numbers beginning with 6)
6948
         *
6949
         * Examples:
6950
         * - Valid: i) CZ25123891; ii) CZ7103192745, CZ991231123; iii) CZ640903926
6951
         * - Invalid: i) CZ25123890; ii) CZ1103492745, CZ590312123
6952
         *
6953
         * @param {String} value VAT number
6954
         * @returns {Boolean}
6955
         */
6956
        _cz: function(value) {
6957
            if (/^CZ[0-9]{8,10}$/.test(value)) {
6958
                value = value.substr(2);
6959
            }
6960
            if (!/^[0-9]{8,10}$/.test(value)) {
6961
                return false;
6962
            }
6963
 
6964
            var sum = 0,
6965
                i   = 0;
6966
            if (value.length === 8) {
6967
                // Do not allow to start with '9'
6968
                if (value.charAt(0) + '' === '9') {
6969
                    return false;
6970
                }
6971
 
6972
                sum = 0;
6973
                for (i = 0; i < 7; i++) {
6974
                    sum += parseInt(value.charAt(i), 10) * (8 - i);
6975
                }
6976
                sum = 11 - sum % 11;
6977
                if (sum === 10) {
6978
                    sum = 0;
6979
                }
6980
                if (sum === 11) {
6981
                    sum = 1;
6982
                }
6983
 
6984
                return (sum + '' === value.substr(7, 1));
6985
            } else if (value.length === 9 && (value.charAt(0) + '' === '6')) {
6986
                sum = 0;
6987
                // Skip the first (which is 6)
6988
                for (i = 0; i < 7; i++) {
6989
                    sum += parseInt(value.charAt(i + 1), 10) * (8 - i);
6990
                }
6991
                sum = 11 - sum % 11;
6992
                if (sum === 10) {
6993
                    sum = 0;
6994
                }
6995
                if (sum === 11) {
6996
                    sum = 1;
6997
                }
6998
                sum = [8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 10][sum - 1];
6999
                return (sum + '' === value.substr(8, 1));
7000
            } else if (value.length === 9 || value.length === 10) {
7001
                // Validate Czech birth number (Rodné číslo), which is also national identifier
7002
                var year  = 1900 + parseInt(value.substr(0, 2), 10),
7003
                    month = parseInt(value.substr(2, 2), 10) % 50 % 20,
7004
                    day   = parseInt(value.substr(4, 2), 10);
7005
                if (value.length === 9) {
7006
                    if (year >= 1980) {
7007
                        year -= 100;
7008
                    }
7009
                    if (year > 1953) {
7010
                        return false;
7011
                    }
7012
                } else if (year < 1954) {
7013
                    year += 100;
7014
                }
7015
 
7016
                if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
7017
                    return false;
7018
                }
7019
 
7020
                // Check that the birth date is not in the future
7021
                if (value.length === 10) {
7022
                    var check = parseInt(value.substr(0, 9), 10) % 11;
7023
                    if (year < 1985) {
7024
                        check = check % 10;
7025
                    }
7026
                    return (check + '' === value.substr(9, 1));
7027
                }
7028
 
7029
                return true;
7030
            }
7031
 
7032
            return false;
7033
        },
7034
 
7035
        /**
7036
         * Validate German VAT number
7037
         * Examples:
7038
         * - Valid: DE136695976
7039
         * - Invalid: DE136695978
7040
         *
7041
         * @param {String} value VAT number
7042
         * @returns {Boolean}
7043
         */
7044
        _de: function(value) {
7045
            if (/^DE[0-9]{9}$/.test(value)) {
7046
                value = value.substr(2);
7047
            }
7048
            if (!/^[0-9]{9}$/.test(value)) {
7049
                return false;
7050
            }
7051
 
7052
            return $.fn.bootstrapValidator.helpers.mod11And10(value);
7053
        },
7054
 
7055
        /**
7056
         * Validate Danish VAT number
7057
         * Example:
7058
         * - Valid: DK13585628
7059
         * - Invalid: DK13585627
7060
         *
7061
         * @param {String} value VAT number
7062
         * @returns {Boolean}
7063
         */
7064
        _dk: function(value) {
7065
            if (/^DK[0-9]{8}$/.test(value)) {
7066
                value = value.substr(2);
7067
            }
7068
            if (!/^[0-9]{8}$/.test(value)) {
7069
                return false;
7070
            }
7071
 
7072
            var sum    = 0,
7073
                weight = [2, 7, 6, 5, 4, 3, 2, 1];
7074
            for (var i = 0; i < 8; i++) {
7075
                sum += parseInt(value.charAt(i), 10) * weight[i];
7076
            }
7077
 
7078
            return (sum % 11 === 0);
7079
        },
7080
 
7081
        /**
7082
         * Validate Estonian VAT number
7083
         * Examples:
7084
         * - Valid: EE100931558, EE100594102
7085
         * - Invalid: EE100594103
7086
         *
7087
         * @param {String} value VAT number
7088
         * @returns {Boolean}
7089
         */
7090
        _ee: function(value) {
7091
            if (/^EE[0-9]{9}$/.test(value)) {
7092
                value = value.substr(2);
7093
            }
7094
            if (!/^[0-9]{9}$/.test(value)) {
7095
                return false;
7096
            }
7097
 
7098
            var sum    = 0,
7099
                weight = [3, 7, 1, 3, 7, 1, 3, 7, 1];
7100
            for (var i = 0; i < 9; i++) {
7101
                sum += parseInt(value.charAt(i), 10) * weight[i];
7102
            }
7103
 
7104
            return (sum % 10 === 0);
7105
        },
7106
 
7107
        /**
7108
         * Validate Spanish VAT number (NIF - Número de Identificación Fiscal)
7109
         * Can be:
7110
         * i) DNI (Documento nacional de identidad), for Spaniards
7111
         * ii) NIE (Número de Identificación de Extranjeros), for foreigners
7112
         * iii) CIF (Certificado de Identificación Fiscal), for legal entities and others
7113
         *
7114
         * Examples:
7115
         * - Valid: i) ES54362315K; ii) ESX2482300W, ESX5253868R; iii) ESM1234567L, ESJ99216582, ESB58378431, ESB64717838
7116
         * - Invalid: i) ES54362315Z; ii) ESX2482300A; iii) ESJ99216583
7117
         *
7118
         * @param {String} value VAT number
7119
         * @returns {Boolean}
7120
         */
7121
        _es: function(value) {
7122
            if (/^ES[0-9A-Z][0-9]{7}[0-9A-Z]$/.test(value)) {
7123
                value = value.substr(2);
7124
            }
7125
            if (!/^[0-9A-Z][0-9]{7}[0-9A-Z]$/.test(value)) {
7126
                return false;
7127
            }
7128
 
7129
            var dni = function(value) {
7130
                    var check = parseInt(value.substr(0, 8), 10);
7131
                    check = 'TRWAGMYFPDXBNJZSQVHLCKE'[check % 23];
7132
                    return (check + '' === value.substr(8, 1));
7133
                },
7134
                nie = function(value) {
7135
                    var check = ['XYZ'.indexOf(value.charAt(0)), value.substr(1)].join('');
7136
                    check = parseInt(check, 10);
7137
                    check = 'TRWAGMYFPDXBNJZSQVHLCKE'[check % 23];
7138
                    return (check + '' === value.substr(8, 1));
7139
                },
7140
                cif = function(value) {
7141
                    var first = value.charAt(0), check;
7142
                    if ('KLM'.indexOf(first) !== -1) {
7143
                        // K: Spanish younger than 14 year old
7144
                        // L: Spanish living outside Spain without DNI
7145
                        // M: Granted the tax to foreigners who have no NIE
7146
                        check = parseInt(value.substr(1, 8), 10);
7147
                        check = 'TRWAGMYFPDXBNJZSQVHLCKE'[check % 23];
7148
                        return (check + '' === value.substr(8, 1));
7149
                    } else if ('ABCDEFGHJNPQRSUVW'.indexOf(first) !== -1) {
7150
                        var sum    = 0,
7151
                            weight = [2, 1, 2, 1, 2, 1, 2],
7152
                            temp   = 0;
7153
 
7154
                        for (var i = 0; i < 7; i++) {
7155
                            temp = parseInt(value.charAt(i + 1), 10) * weight[i];
7156
                            if (temp > 9) {
7157
                                temp = Math.floor(temp / 10) + temp % 10;
7158
                            }
7159
                            sum += temp;
7160
                        }
7161
                        sum = 10 - sum % 10;
7162
                        return (sum + '' === value.substr(8, 1) || 'JABCDEFGHI'[sum] === value.substr(8, 1));
7163
                    }
7164
 
7165
                    return false;
7166
                };
7167
 
7168
            var first = value.charAt(0);
7169
            if (/^[0-9]$/.test(first)) {
7170
                return dni(value);
7171
            } else if (/^[XYZ]$/.test(first)) {
7172
                return nie(value);
7173
            } else {
7174
                return cif(value);
7175
            }
7176
        },
7177
 
7178
        /**
7179
         * Validate Finnish VAT number
7180
         * Examples:
7181
         * - Valid: FI20774740
7182
         * - Invalid: FI20774741
7183
         *
7184
         * @param {String} value VAT number
7185
         * @returns {Boolean}
7186
         */
7187
        _fi: function(value) {
7188
            if (/^FI[0-9]{8}$/.test(value)) {
7189
                value = value.substr(2);
7190
            }
7191
            if (!/^[0-9]{8}$/.test(value)) {
7192
                return false;
7193
            }
7194
 
7195
            var sum    = 0,
7196
                weight = [7, 9, 10, 5, 8, 4, 2, 1];
7197
            for (var i = 0; i < 8; i++) {
7198
                sum += parseInt(value.charAt(i), 10) * weight[i];
7199
            }
7200
 
7201
            return (sum % 11 === 0);
7202
        },
7203
 
7204
        /**
7205
         * Validate French VAT number (TVA - taxe sur la valeur ajoutée)
7206
         * It's constructed by a SIREN number, prefixed by two characters.
7207
         *
7208
         * Examples:
7209
         * - Valid: FR40303265045, FR23334175221, FRK7399859412, FR4Z123456782
7210
         * - Invalid: FR84323140391
7211
         *
7212
         * @param {String} value VAT number
7213
         * @returns {Boolean}
7214
         */
7215
        _fr: function(value) {
7216
            if (/^FR[0-9A-Z]{2}[0-9]{9}$/.test(value)) {
7217
                value = value.substr(2);
7218
            }
7219
            if (!/^[0-9A-Z]{2}[0-9]{9}$/.test(value)) {
7220
                return false;
7221
            }
7222
 
7223
            if (!$.fn.bootstrapValidator.helpers.luhn(value.substr(2))) {
7224
                return false;
7225
            }
7226
 
7227
            if (/^[0-9]{2}$/.test(value.substr(0, 2))) {
7228
                // First two characters are digits
7229
                return value.substr(0, 2) === (parseInt(value.substr(2) + '12', 10) % 97 + '');
7230
            } else {
7231
                // The first characters cann't be O and I
7232
                var alphabet = '0123456789ABCDEFGHJKLMNPQRSTUVWXYZ',
7233
                    check;
7234
                // First one is digit
7235
                if (/^[0-9]{1}$/.test(value.charAt(0))) {
7236
                    check = alphabet.indexOf(value.charAt(0)) * 24 + alphabet.indexOf(value.charAt(1)) - 10;
7237
                } else {
7238
                    check = alphabet.indexOf(value.charAt(0)) * 34 + alphabet.indexOf(value.charAt(1)) - 100;
7239
                }
7240
                return ((parseInt(value.substr(2), 10) + 1 + Math.floor(check / 11)) % 11) === (check % 11);
7241
            }
7242
        },
7243
 
7244
        /**
7245
         * Validate United Kingdom VAT number
7246
         * Example:
7247
         * - Valid: GB980780684
7248
         * - Invalid: GB802311781
7249
         *
7250
         * @param {String} value VAT number
7251
         * @returns {Boolean}
7252
         */
7253
        _gb: function(value) {
7254
            if (/^GB[0-9]{9}$/.test(value)             /* Standard */
7255
                || /^GB[0-9]{12}$/.test(value)         /* Branches */
7256
                || /^GBGD[0-9]{3}$/.test(value)        /* Government department */
7257
                || /^GBHA[0-9]{3}$/.test(value)        /* Health authority */
7258
                || /^GB(GD|HA)8888[0-9]{5}$/.test(value))
7259
            {
7260
                value = value.substr(2);
7261
            }
7262
            if (!/^[0-9]{9}$/.test(value)
7263
                && !/^[0-9]{12}$/.test(value)
7264
                && !/^GD[0-9]{3}$/.test(value)
7265
                && !/^HA[0-9]{3}$/.test(value)
7266
                && !/^(GD|HA)8888[0-9]{5}$/.test(value))
7267
            {
7268
                return false;
7269
            }
7270
 
7271
            var length = value.length;
7272
            if (length === 5) {
7273
                var firstTwo  = value.substr(0, 2),
7274
                    lastThree = parseInt(value.substr(2), 10);
7275
                return ('GD' === firstTwo && lastThree < 500) || ('HA' === firstTwo && lastThree >= 500);
7276
            } else if (length === 11 && ('GD8888' === value.substr(0, 6) || 'HA8888' === value.substr(0, 6))) {
7277
                if (('GD' === value.substr(0, 2) && parseInt(value.substr(6, 3), 10) >= 500)
7278
                    || ('HA' === value.substr(0, 2) && parseInt(value.substr(6, 3), 10) < 500))
7279
                {
7280
                    return false;
7281
                }
7282
                return (parseInt(value.substr(6, 3), 10) % 97 === parseInt(value.substr(9, 2), 10));
7283
            } else if (length === 9 || length === 12) {
7284
                var sum    = 0,
7285
                    weight = [8, 7, 6, 5, 4, 3, 2, 10, 1];
7286
                for (var i = 0; i < 9; i++) {
7287
                    sum += parseInt(value.charAt(i), 10) * weight[i];
7288
                }
7289
                sum = sum % 97;
7290
 
7291
                if (parseInt(value.substr(0, 3), 10) >= 100) {
7292
                    return (sum === 0 || sum === 42 || sum === 55);
7293
                } else {
7294
                    return (sum === 0);
7295
                }
7296
            }
7297
 
7298
            return true;
7299
        },
7300
 
7301
        /**
7302
         * Validate Greek VAT number
7303
         * Examples:
7304
         * - Valid: GR023456780, EL094259216
7305
         * - Invalid: EL123456781
7306
         *
7307
         * @param {String} value VAT number
7308
         * @returns {Boolean}
7309
         */
7310
        _gr: function(value) {
7311
            if (/^(GR|EL)[0-9]{9}$/.test(value)) {
7312
                value = value.substr(2);
7313
            }
7314
            if (!/^[0-9]{9}$/.test(value)) {
7315
                return false;
7316
            }
7317
 
7318
            if (value.length === 8) {
7319
                value = '0' + value;
7320
            }
7321
 
7322
            var sum    = 0,
7323
                weight = [256, 128, 64, 32, 16, 8, 4, 2];
7324
            for (var i = 0; i < 8; i++) {
7325
                sum += parseInt(value.charAt(i), 10) * weight[i];
7326
            }
7327
            sum = (sum % 11) % 10;
7328
 
7329
            return (sum + '' === value.substr(8, 1));
7330
        },
7331
 
7332
        // EL is traditionally prefix of Greek VAT numbers
7333
        _el: function(value) {
7334
            return this._gr(value);
7335
        },
7336
 
7337
        /**
7338
         * Validate Hungarian VAT number
7339
         * Examples:
7340
         * - Valid: HU12892312
7341
         * - Invalid: HU12892313
7342
         *
7343
         * @param {String} value VAT number
7344
         * @returns {Boolean}
7345
         */
7346
        _hu: function(value) {
7347
            if (/^HU[0-9]{8}$/.test(value)) {
7348
                value = value.substr(2);
7349
            }
7350
            if (!/^[0-9]{8}$/.test(value)) {
7351
                return false;
7352
            }
7353
 
7354
            var sum    = 0,
7355
                weight = [9, 7, 3, 1, 9, 7, 3, 1];
7356
 
7357
            for (var i = 0; i < 8; i++) {
7358
                sum += parseInt(value.charAt(i), 10) * weight[i];
7359
            }
7360
 
7361
            return (sum % 10 === 0);
7362
        },
7363
 
7364
        /**
7365
         * Validate Croatian VAT number
7366
         * Examples:
7367
         * - Valid: HR33392005961
7368
         * - Invalid: HR33392005962
7369
         *
7370
         * @param {String} value VAT number
7371
         * @returns {Boolean}
7372
         */
7373
        _hr: function(value) {
7374
            if (/^HR[0-9]{11}$/.test(value)) {
7375
                value = value.substr(2);
7376
            }
7377
            if (!/^[0-9]{11}$/.test(value)) {
7378
                return false;
7379
            }
7380
 
7381
            return $.fn.bootstrapValidator.helpers.mod11And10(value);
7382
        },
7383
 
7384
        /**
7385
         * Validate Irish VAT number
7386
         * Examples:
7387
         * - Valid: IE6433435F, IE6433435OA, IE8D79739I
7388
         * - Invalid: IE8D79738J
7389
         *
7390
         * @param {String} value VAT number
7391
         * @returns {Boolean}
7392
         */
7393
        _ie: function(value) {
7394
            if (/^IE[0-9]{1}[0-9A-Z\*\+]{1}[0-9]{5}[A-Z]{1,2}$/.test(value)) {
7395
                value = value.substr(2);
7396
            }
7397
            if (!/^[0-9]{1}[0-9A-Z\*\+]{1}[0-9]{5}[A-Z]{1,2}$/.test(value)) {
7398
                return false;
7399
            }
7400
 
7401
            var getCheckDigit = function(value) {
7402
                while (value.length < 7) {
7403
                    value = '0' + value;
7404
                }
7405
                var alphabet = 'WABCDEFGHIJKLMNOPQRSTUV',
7406
                    sum      = 0;
7407
                for (var i = 0; i < 7; i++) {
7408
                    sum += parseInt(value.charAt(i), 10) * (8 - i);
7409
                }
7410
                sum += 9 * alphabet.indexOf(value.substr(7));
7411
                return alphabet[sum % 23];
7412
            };
7413
 
7414
            // The first 7 characters are digits
7415
            if (/^[0-9]+$/.test(value.substr(0, 7))) {
7416
                // New system
7417
                return value.charAt(7) === getCheckDigit(value.substr(0, 7) + value.substr(8) + '');
7418
            } else if ('ABCDEFGHIJKLMNOPQRSTUVWXYZ+*'.indexOf(value.charAt(1)) !== -1) {
7419
                // Old system
7420
                return value.charAt(7) === getCheckDigit(value.substr(2, 5) + value.substr(0, 1) + '');
7421
            }
7422
 
7423
            return true;
7424
        },
7425
 
7426
        /**
7427
         * Validate Icelandic VAT (VSK) number
7428
         * Examples:
7429
         * - Valid: 12345, 123456
7430
         * - Invalid: 1234567
7431
         *
7432
         * @params {String} value VAT number
7433
         * @returns {Boolean}
7434
         */
7435
        _is: function(value) {
7436
            if (/^IS[0-9]{5,6}$/.test(value)) {
7437
                value = value.substr(2);
7438
            }
7439
            return /^[0-9]{5,6}$/.test(value);
7440
        },
7441
 
7442
        /**
7443
         * Validate Italian VAT number, which consists of 11 digits.
7444
         * - First 7 digits are a company identifier
7445
         * - Next 3 are the province of residence
7446
         * - The last one is a check digit
7447
         *
7448
         * Examples:
7449
         * - Valid: IT00743110157
7450
         * - Invalid: IT00743110158
7451
         *
7452
         * @param {String} value VAT number
7453
         * @returns {Boolean}
7454
         */
7455
        _it: function(value) {
7456
            if (/^IT[0-9]{11}$/.test(value)) {
7457
                value = value.substr(2);
7458
            }
7459
            if (!/^[0-9]{11}$/.test(value)) {
7460
                return false;
7461
            }
7462
 
7463
            if (parseInt(value.substr(0, 7), 10) === 0) {
7464
                return false;
7465
            }
7466
 
7467
            var lastThree = parseInt(value.substr(7, 3), 10);
7468
            if ((lastThree < 1) || (lastThree > 201) && lastThree !== 999 && lastThree !== 888) {
7469
                return false;
7470
            }
7471
 
7472
            return $.fn.bootstrapValidator.helpers.luhn(value);
7473
        },
7474
 
7475
        /**
7476
         * Validate Lithuanian VAT number
7477
         * It can be:
7478
         * - 9 digits, for legal entities
7479
         * - 12 digits, for temporarily registered taxpayers
7480
         *
7481
         * Examples:
7482
         * - Valid: LT119511515, LT100001919017, LT100004801610
7483
         * - Invalid: LT100001919018
7484
         *
7485
         * @param {String} value VAT number
7486
         * @returns {Boolean}
7487
         */
7488
        _lt: function(value) {
7489
            if (/^LT([0-9]{7}1[0-9]{1}|[0-9]{10}1[0-9]{1})$/.test(value)) {
7490
                value = value.substr(2);
7491
            }
7492
            if (!/^([0-9]{7}1[0-9]{1}|[0-9]{10}1[0-9]{1})$/.test(value)) {
7493
                return false;
7494
            }
7495
 
7496
            var length = value.length,
7497
                sum    = 0,
7498
                i;
7499
            for (i = 0; i < length - 1; i++) {
7500
                sum += parseInt(value.charAt(i), 10) * (1 + i % 9);
7501
            }
7502
            var check = sum % 11;
7503
            if (check === 10) {
7504
                sum = 0;
7505
                for (i = 0; i < length - 1; i++) {
7506
                    sum += parseInt(value.charAt(i), 10) * (1 + (i + 2) % 9);
7507
                }
7508
            }
7509
            check = check % 11 % 10;
7510
            return (check + '' === value.charAt(length - 1));
7511
        },
7512
 
7513
        /**
7514
         * Validate Luxembourg VAT number
7515
         * Examples:
7516
         * - Valid: LU15027442
7517
         * - Invalid: LU15027443
7518
         *
7519
         * @param {String} value VAT number
7520
         * @returns {Boolean}
7521
         */
7522
        _lu: function(value) {
7523
            if (/^LU[0-9]{8}$/.test(value)) {
7524
                value = value.substr(2);
7525
            }
7526
            if (!/^[0-9]{8}$/.test(value)) {
7527
                return false;
7528
            }
7529
 
7530
            return ((parseInt(value.substr(0, 6), 10) % 89) + '' === value.substr(6, 2));
7531
        },
7532
 
7533
        /**
7534
         * Validate Latvian VAT number
7535
         * Examples:
7536
         * - Valid: LV40003521600, LV16117519997
7537
         * - Invalid: LV40003521601, LV16137519997
7538
         *
7539
         * @param {String} value VAT number
7540
         * @returns {Boolean}
7541
         */
7542
        _lv: function(value) {
7543
            if (/^LV[0-9]{11}$/.test(value)) {
7544
                value = value.substr(2);
7545
            }
7546
            if (!/^[0-9]{11}$/.test(value)) {
7547
                return false;
7548
            }
7549
 
7550
            var first  = parseInt(value.charAt(0), 10),
7551
                sum    = 0,
7552
                weight = [],
7553
                i,
7554
                length = value.length;
7555
            if (first > 3) {
7556
                // Legal entity
7557
                sum    = 0;
7558
                weight = [9, 1, 4, 8, 3, 10, 2, 5, 7, 6, 1];
7559
                for (i = 0; i < length; i++) {
7560
                    sum += parseInt(value.charAt(i), 10) * weight[i];
7561
                }
7562
                sum = sum % 11;
7563
                return (sum === 3);
7564
            } else {
7565
                // Check birth date
7566
                var day   = parseInt(value.substr(0, 2), 10),
7567
                    month = parseInt(value.substr(2, 2), 10),
7568
                    year  = parseInt(value.substr(4, 2), 10);
7569
                year = year + 1800 + parseInt(value.charAt(6), 10) * 100;
7570
 
7571
                if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) {
7572
                    return false;
7573
                }
7574
 
7575
                // Check personal code
7576
                sum    = 0;
7577
                weight = [10, 5, 8, 4, 2, 1, 6, 3, 7, 9];
7578
                for (i = 0; i < length - 1; i++) {
7579
                    sum += parseInt(value.charAt(i), 10) * weight[i];
7580
                }
7581
                sum = (sum + 1) % 11 % 10;
7582
                return (sum + '' === value.charAt(length - 1));
7583
            }
7584
        },
7585
 
7586
        /**
7587
         * Validate Maltese VAT number
7588
         * Examples:
7589
         * - Valid: MT11679112
7590
         * - Invalid: MT11679113
7591
         *
7592
         * @param {String} value VAT number
7593
         * @returns {Boolean}
7594
         */
7595
        _mt: function(value) {
7596
            if (/^MT[0-9]{8}$/.test(value)) {
7597
                value = value.substr(2);
7598
            }
7599
            if (!/^[0-9]{8}$/.test(value)) {
7600
                return false;
7601
            }
7602
 
7603
            var sum    = 0,
7604
                weight = [3, 4, 6, 7, 8, 9, 10, 1];
7605
 
7606
            for (var i = 0; i < 8; i++) {
7607
                sum += parseInt(value.charAt(i), 10) * weight[i];
7608
            }
7609
 
7610
            return (sum % 37 === 0);
7611
        },
7612
 
7613
        /**
7614
         * Validate Dutch VAT number
7615
         * Examples:
7616
         * - Valid: NL004495445B01
7617
         * - Invalid: NL123456789B90
7618
         *
7619
         * @param {String} value VAT number
7620
         * @returns {Boolean}
7621
         */
7622
        _nl: function(value) {
7623
            if (/^NL[0-9]{9}B[0-9]{2}$/.test(value)) {
7624
               value = value.substr(2);
7625
            }
7626
            if (!/^[0-9]{9}B[0-9]{2}$/.test(value)) {
7627
               return false;
7628
            }
7629
 
7630
            var sum    = 0,
7631
                weight = [9, 8, 7, 6, 5, 4, 3, 2];
7632
            for (var i = 0; i < 8; i++) {
7633
                sum += parseInt(value.charAt(i), 10) * weight[i];
7634
            }
7635
 
7636
            sum = sum % 11;
7637
            if (sum > 9) {
7638
                sum = 0;
7639
            }
7640
            return (sum + '' === value.substr(8, 1));
7641
        },
7642
 
7643
        /**
7644
         * Validate Norwegian VAT number
7645
         *
7646
         * @see http://www.brreg.no/english/coordination/number.html
7647
         * @param {String} value VAT number
7648
         * @returns {Boolean}
7649
         */
7650
        _no: function(value) {
7651
            if (/^NO[0-9]{9}$/.test(value)) {
7652
               value = value.substr(2);
7653
            }
7654
            if (!/^[0-9]{9}$/.test(value)) {
7655
               return false;
7656
            }
7657
 
7658
            var sum    = 0,
7659
                weight = [3, 2, 7, 6, 5, 4, 3, 2];
7660
            for (var i = 0; i < 8; i++) {
7661
                sum += parseInt(value.charAt(i), 10) * weight[i];
7662
            }
7663
 
7664
            sum = 11 - sum % 11;
7665
            if (sum === 11) {
7666
                sum = 0;
7667
            }
7668
            return (sum + '' === value.substr(8, 1));
7669
        },
7670
 
7671
        /**
7672
         * Validate Polish VAT number
7673
         * Examples:
7674
         * - Valid: PL8567346215
7675
         * - Invalid: PL8567346216
7676
         *
7677
         * @param {String} value VAT number
7678
         * @returns {Boolean}
7679
         */
7680
        _pl: function(value) {
7681
            if (/^PL[0-9]{10}$/.test(value)) {
7682
                value = value.substr(2);
7683
            }
7684
            if (!/^[0-9]{10}$/.test(value)) {
7685
                return false;
7686
            }
7687
 
7688
            var sum    = 0,
7689
                weight = [6, 5, 7, 2, 3, 4, 5, 6, 7, -1];
7690
 
7691
            for (var i = 0; i < 10; i++) {
7692
                sum += parseInt(value.charAt(i), 10) * weight[i];
7693
            }
7694
 
7695
            return (sum % 11 === 0);
7696
        },
7697
 
7698
        /**
7699
         * Validate Portuguese VAT number
7700
         * Examples:
7701
         * - Valid: PT501964843
7702
         * - Invalid: PT501964842
7703
         *
7704
         * @param {String} value VAT number
7705
         * @returns {Boolean}
7706
         */
7707
        _pt: function(value) {
7708
            if (/^PT[0-9]{9}$/.test(value)) {
7709
                value = value.substr(2);
7710
            }
7711
            if (!/^[0-9]{9}$/.test(value)) {
7712
                return false;
7713
            }
7714
 
7715
            var sum    = 0,
7716
                weight = [9, 8, 7, 6, 5, 4, 3, 2];
7717
 
7718
            for (var i = 0; i < 8; i++) {
7719
                sum += parseInt(value.charAt(i), 10) * weight[i];
7720
            }
7721
            sum = 11 - sum % 11;
7722
            if (sum > 9) {
7723
                sum = 0;
7724
            }
7725
            return (sum + '' === value.substr(8, 1));
7726
        },
7727
 
7728
        /**
7729
         * Validate Romanian VAT number
7730
         * Examples:
7731
         * - Valid: RO18547290
7732
         * - Invalid: RO18547291
7733
         *
7734
         * @param {String} value VAT number
7735
         * @returns {Boolean}
7736
         */
7737
        _ro: function(value) {
7738
            if (/^RO[1-9][0-9]{1,9}$/.test(value)) {
7739
                value = value.substr(2);
7740
            }
7741
            if (!/^[1-9][0-9]{1,9}$/.test(value)) {
7742
                return false;
7743
            }
7744
 
7745
            var length = value.length,
7746
                weight = [7, 5, 3, 2, 1, 7, 5, 3, 2].slice(10 - length),
7747
                sum    = 0;
7748
            for (var i = 0; i < length - 1; i++) {
7749
                sum += parseInt(value.charAt(i), 10) * weight[i];
7750
            }
7751
 
7752
            sum = (10 * sum) % 11 % 10;
7753
            return (sum + '' === value.substr(length - 1, 1));
7754
        },
7755
 
7756
        /**
7757
         * Validate Russian VAT number (Taxpayer Identification Number - INN)
7758
         *
7759
         * @param {String} value VAT number
7760
         * @returns {Boolean}
7761
         */
7762
        _ru: function(value) {
7763
            if (/^RU([0-9]{10}|[0-9]{12})$/.test(value)) {
7764
                value = value.substr(2);
7765
            }
7766
            if (!/^([0-9]{10}|[0-9]{12})$/.test(value)) {
7767
                return false;
7768
            }
7769
 
7770
            var i = 0;
7771
            if (value.length === 10) {
7772
                var sum    = 0,
7773
                    weight = [2, 4, 10, 3, 5, 9, 4, 6, 8, 0];
7774
                for (i = 0; i < 10; i++) {
7775
                    sum += parseInt(value.charAt(i), 10) * weight[i];
7776
                }
7777
                sum = sum % 11;
7778
                if (sum > 9) {
7779
                    sum = sum % 10;
7780
                }
7781
 
7782
                return (sum + '' === value.substr(9, 1));
7783
            } else if (value.length === 12) {
7784
                var sum1    = 0,
7785
                    weight1 = [7, 2, 4, 10, 3, 5, 9, 4, 6, 8, 0],
7786
                    sum2    = 0,
7787
                    weight2 = [3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8, 0];
7788
 
7789
                for (i = 0; i < 11; i++) {
7790
                    sum1 += parseInt(value.charAt(i), 10) * weight1[i];
7791
                    sum2 += parseInt(value.charAt(i), 10) * weight2[i];
7792
                }
7793
                sum1 = sum1 % 11;
7794
                if (sum1 > 9) {
7795
                    sum1 = sum1 % 10;
7796
                }
7797
                sum2 = sum2 % 11;
7798
                if (sum2 > 9) {
7799
                    sum2 = sum2 % 10;
7800
                }
7801
 
7802
                return (sum1 + '' === value.substr(10, 1) && sum2 + '' === value.substr(11, 1));
7803
            }
7804
 
7805
            return false;
7806
        },
7807
 
7808
        /**
7809
         * Validate Serbian VAT number
7810
         *
7811
         * @param {String} value VAT number
7812
         * @returns {Boolean}
7813
         */
7814
        _rs: function(value) {
7815
            if (/^RS[0-9]{9}$/.test(value)) {
7816
                value = value.substr(2);
7817
            }
7818
            if (!/^[0-9]{9}$/.test(value)) {
7819
                return false;
7820
            }
7821
 
7822
            var sum  = 10,
7823
                temp = 0;
7824
            for (var i = 0; i < 8; i++) {
7825
                temp = (parseInt(value.charAt(i), 10) + sum) % 10;
7826
                if (temp === 0) {
7827
                    temp = 10;
7828
                }
7829
                sum = (2 * temp) % 11;
7830
            }
7831
 
7832
            return ((sum + parseInt(value.substr(8, 1), 10)) % 10 === 1);
7833
        },
7834
 
7835
        /**
7836
         * Validate Swedish VAT number
7837
         * Examples:
7838
         * - Valid: SE123456789701
7839
         * - Invalid: SE123456789101
7840
         *
7841
         * @param {String} value VAT number
7842
         * @returns {Boolean}
7843
         */
7844
        _se: function(value) {
7845
            if (/^SE[0-9]{10}01$/.test(value)) {
7846
                value = value.substr(2);
7847
            }
7848
            if (!/^[0-9]{10}01$/.test(value)) {
7849
                return false;
7850
            }
7851
 
7852
            value = value.substr(0, 10);
7853
            return $.fn.bootstrapValidator.helpers.luhn(value);
7854
        },
7855
 
7856
        /**
7857
         * Validate Slovenian VAT number
7858
         * Examples:
7859
         * - Valid: SI50223054
7860
         * - Invalid: SI50223055
7861
         *
7862
         * @param {String} value VAT number
7863
         * @returns {Boolean}
7864
         */
7865
        _si: function(value) {
7866
            if (/^SI[0-9]{8}$/.test(value)) {
7867
                value = value.substr(2);
7868
            }
7869
            if (!/^[0-9]{8}$/.test(value)) {
7870
                return false;
7871
            }
7872
 
7873
            var sum    = 0,
7874
                weight = [8, 7, 6, 5, 4, 3, 2];
7875
 
7876
            for (var i = 0; i < 7; i++) {
7877
                sum += parseInt(value.charAt(i), 10) * weight[i];
7878
            }
7879
            sum = 11 - sum % 11;
7880
            if (sum === 10) {
7881
                sum = 0;
7882
            }
7883
            return (sum + '' === value.substr(7, 1));
7884
        },
7885
 
7886
        /**
7887
         * Validate Slovak VAT number
7888
         * Examples:
7889
         * - Valid: SK2022749619
7890
         * - Invalid: SK2022749618
7891
         *
7892
         * @param {String} value VAT number
7893
         * @returns {Boolean}
7894
         */
7895
        _sk: function(value) {
7896
            if (/^SK[1-9][0-9][(2-4)|(6-9)][0-9]{7}$/.test(value)) {
7897
                value = value.substr(2);
7898
            }
7899
            if (!/^[1-9][0-9][(2-4)|(6-9)][0-9]{7}$/.test(value)) {
7900
                return false;
7901
            }
7902
 
7903
            return (parseInt(value, 10) % 11 === 0);
7904
        },
7905
 
7906
        /**
7907
         * Validate Venezuelan VAT number (RIF)
7908
         * Examples:
7909
         * - Valid: VEJ309272292, VEV242818101, VEJ000126518, VEJ000458324, J309272292, V242818101, J000126518, J000458324
7910
         * - Invalid: VEJ309272293, VEV242818100, J000126519, J000458323
7911
         *
7912
         * @param {String} value VAT number
7913
         * @returns {Boolean}
7914
         */
7915
        _ve: function(value) {
7916
            if (/^VE[VEJPG][0-9]{9}$/.test(value)) {
7917
                value = value.substr(2);
7918
            }
7919
            if (!/^[VEJPG][0-9]{9}$/.test(value)) {
7920
                return false;
7921
            }
7922
 
7923
            var types  = {
7924
                    'V': 4,
7925
                    'E': 8,
7926
                    'J': 12,
7927
                    'P': 16,
7928
                    'G': 20
7929
                },
7930
                sum    = types[value.charAt(0)],
7931
                weight = [3, 2, 7, 6, 5, 4, 3, 2];
7932
 
7933
            for (var i = 0; i < 8; i++) {
7934
                sum += parseInt(value.charAt(i + 1), 10) * weight[i];
7935
            }
7936
 
7937
            sum = 11 - sum % 11;
7938
            if (sum === 11 || sum === 10) {
7939
                sum = 0;
7940
            }
7941
            return (sum + '' === value.substr(9, 1));
7942
        },
7943
 
7944
        /**
7945
         * Validate South African VAT number
7946
         * Examples:
7947
         * - Valid: 4012345678
7948
         * - Invalid: 40123456789, 3012345678
7949
         *
7950
         * @params {String} value VAT number
7951
         * @returns {Boolean}
7952
         */
7953
         _za: function(value) {
7954
            if (/^ZA4[0-9]{9}$/.test(value)) {
7955
                value = value.substr(2);
7956
            }
7957
 
7958
            return /^4[0-9]{9}$/.test(value);
7959
        }
7960
    };
7961
}(window.jQuery));
7962
;(function($) {
7963
    $.fn.bootstrapValidator.i18n.vin = $.extend($.fn.bootstrapValidator.i18n.vin || {}, {
7964
        'default': 'Please enter a valid VIN number'
7965
    });
7966
 
7967
    $.fn.bootstrapValidator.validators.vin = {
7968
        /**
7969
         * Validate an US VIN (Vehicle Identification Number)
7970
         *
7971
         * @param {BootstrapValidator} validator The validator plugin instance
7972
         * @param {jQuery} $field Field element
7973
         * @param {Object} options Consist of key:
7974
         * - message: The invalid message
7975
         * @returns {Boolean}
7976
         */
7977
        validate: function(validator, $field, options) {
7978
            var value = $field.val();
7979
            if (value === '') {
7980
                return true;
7981
            }
7982
 
7983
            // Don't accept I, O, Q characters
7984
            if (!/^[a-hj-npr-z0-9]{8}[0-9xX][a-hj-npr-z0-9]{8}$/i.test(value)) {
7985
                return false;
7986
            }
7987
 
7988
            value = value.toUpperCase();
7989
            var chars   = {
7990
                    A: 1,   B: 2,   C: 3,   D: 4,   E: 5,   F: 6,   G: 7,   H: 8,
7991
                    J: 1,   K: 2,   L: 3,   M: 4,   N: 5,           P: 7,           R: 9,
7992
                            S: 2,   T: 3,   U: 4,   V: 5,   W: 6,   X: 7,   Y: 8,   Z: 9,
7993
                    '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, '0': 0
7994
                },
7995
                weights = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2],
7996
                sum     = 0,
7997
                length  = value.length;
7998
            for (var i = 0; i < length; i++) {
7999
                sum += chars[value.charAt(i) + ''] * weights[i];
8000
            }
8001
 
8002
            var reminder = sum % 11;
8003
            if (reminder === 10) {
8004
                reminder = 'X';
8005
            }
8006
 
8007
            return (reminder + '') === value.charAt(8);
8008
        }
8009
    };
8010
}(window.jQuery));
8011
;(function($) {
8012
    $.fn.bootstrapValidator.i18n.zipCode = $.extend($.fn.bootstrapValidator.i18n.zipCode || {}, {
8013
        'default': 'Please enter a valid postal code',
8014
        countryNotSupported: 'The country code %s is not supported',
8015
        country: 'Please enter a valid postal code in %s',
8016
        countries: {
8017
            AT: 'Austria',
8018
            BR: 'Brazil',
8019
            CA: 'Canada',
8020
            CH: 'Switzerland',
8021
            CZ: 'Czech Republic',
8022
            DE: 'Germany',
8023
            DK: 'Denmark',
8024
            FR: 'France',
8025
            GB: 'United Kingdom',
8026
            IE: 'Ireland',
8027
            IT: 'Italy',
8028
            MA: 'Morocco',
8029
            NL: 'Netherlands',
8030
            PT: 'Portugal',
8031
            RO: 'Romania',
8032
            RU: 'Russia',
8033
            SE: 'Sweden',
8034
            SG: 'Singapore',
8035
            SK: 'Slovakia',
8036
            US: 'USA'
8037
        }
8038
    });
8039
 
8040
    $.fn.bootstrapValidator.validators.zipCode = {
8041
        html5Attributes: {
8042
            message: 'message',
8043
            country: 'country'
8044
        },
8045
 
8046
        COUNTRY_CODES: [ 'AT', 'BR', 'CA', 'CH', 'CZ', 'DE', 'DK', 'FR', 'GB', 'IE', 'IT', 'MA', 'NL', 'PT', 'RO', 'RU', 'SE', 'SG', 'SK', 'US'],
8047
 
8048
        /**
8049
         * Return true if and only if the input value is a valid country zip code
8050
         *
8051
         * @param {BootstrapValidator} validator The validator plugin instance
8052
         * @param {jQuery} $field Field element
8053
         * @param {Object} options Consist of key:
8054
         * - message: The invalid message
8055
         * - country: The country
8056
         *
8057
         * The country can be defined by:
8058
         * - An ISO 3166 country code
8059
         * - Name of field which its value defines the country code
8060
         * - Name of callback function that returns the country code
8061
         * - A callback function that returns the country code
8062
         *
8063
         * callback: function(value, validator, $field) {
8064
         *      // value is the value of field
8065
         *      // validator is the BootstrapValidator instance
8066
         *      // $field is jQuery element representing the field
8067
         * }
8068
         *
8069
         * @returns {Boolean|Object}
8070
         */
8071
        validate: function(validator, $field, options) {
8072
            var value = $field.val();
8073
            if (value === '' || !options.country) {
8074
                return true;
8075
            }
8076
 
8077
            var country = options.country;
8078
            if (typeof country !== 'string' || $.inArray(country, this.COUNTRY_CODES) === -1) {
8079
                // Try to determine the country
8080
                country = validator.getDynamicOption($field, country);
8081
            }
8082
 
8083
            if (!country || $.inArray(country.toUpperCase(), this.COUNTRY_CODES) === -1) {
8084
                return { valid: false, message: $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.zipCode.countryNotSupported, country) };
8085
            }
8086
 
8087
            var isValid = false;
8088
            country = country.toUpperCase();
8089
            switch (country) {
8090
                // http://en.wikipedia.org/wiki/List_of_postal_codes_in_Austria
8091
                case 'AT':
8092
                    isValid = /^([1-9]{1})(\d{3})$/.test(value);
8093
                    break;
8094
 
8095
                case 'BR':
8096
                    isValid = /^(\d{2})([\.]?)(\d{3})([\-]?)(\d{3})$/.test(value);
8097
                    break;
8098
 
8099
                case 'CA':
8100
                    isValid = /^(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|X|Y){1}[0-9]{1}(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|W|X|Y|Z){1}\s?[0-9]{1}(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|W|X|Y|Z){1}[0-9]{1}$/i.test(value);
8101
                    break;
8102
 
8103
                case 'CH':
8104
                    isValid = /^([1-9]{1})(\d{3})$/.test(value);
8105
                    break;
8106
 
8107
                case 'CZ':
8108
                    // Test: http://regexr.com/39hhr
8109
                    isValid = /^(\d{3})([ ]?)(\d{2})$/.test(value);
8110
                    break;
8111
 
8112
                // http://stackoverflow.com/questions/7926687/regular-expression-german-zip-codes
8113
                case 'DE':
8114
                    isValid = /^(?!01000|99999)(0[1-9]\d{3}|[1-9]\d{4})$/.test(value);
8115
                    break;
8116
 
8117
                case 'DK':
8118
                    isValid = /^(DK(-|\s)?)?\d{4}$/i.test(value);
8119
                    break;
8120
 
8121
                // http://en.wikipedia.org/wiki/Postal_codes_in_France
8122
                case 'FR':
8123
                    isValid = /^[0-9]{5}$/i.test(value);
8124
                    break;
8125
 
8126
                case 'GB':
8127
                    isValid = this._gb(value);
8128
                    break;
8129
 
8130
                // http://www.eircode.ie/docs/default-source/Common/prepare-your-business-for-eircode---published-v2.pdf?sfvrsn=2
8131
                // Test: http://refiddle.com/1kpl
8132
                case 'IE':
8133
                    isValid = /^(D6W|[ACDEFHKNPRTVWXY]\d{2})\s[0-9ACDEFHKNPRTVWXY]{4}$/.test(value);
8134
                    break;
8135
 
8136
                // http://en.wikipedia.org/wiki/List_of_postal_codes_in_Italy
8137
                case 'IT':
8138
                    isValid = /^(I-|IT-)?\d{5}$/i.test(value);
8139
                    break;
8140
 
8141
                // http://en.wikipedia.org/wiki/List_of_postal_codes_in_Morocco
8142
                case 'MA':
8143
                    isValid = /^[1-9][0-9]{4}$/i.test(value);
8144
                    break;
8145
 
8146
                // http://en.wikipedia.org/wiki/Postal_codes_in_the_Netherlands
8147
                case 'NL':
8148
                    isValid = /^[1-9][0-9]{3} ?(?!sa|sd|ss)[a-z]{2}$/i.test(value);
8149
                    break;
8150
 
8151
                // Test: http://refiddle.com/1l2t
8152
                case 'PT':
8153
                    isValid = /^[1-9]\d{3}-\d{3}$/.test(value);
8154
                    break;
8155
 
8156
                case 'RO':
8157
                    isValid = /^(0[1-8]{1}|[1-9]{1}[0-5]{1})?[0-9]{4}$/i.test(value);
8158
                    break;
8159
 
8160
                case 'RU':
8161
                    isValid = /^[0-9]{6}$/i.test(value);
8162
                    break;
8163
 
8164
                case 'SE':
8165
                    isValid = /^(S-)?\d{3}\s?\d{2}$/i.test(value);
8166
                    break;
8167
 
8168
                case 'SG':
8169
                    isValid = /^([0][1-9]|[1-6][0-9]|[7]([0-3]|[5-9])|[8][0-2])(\d{4})$/i.test(value);
8170
                    break;
8171
 
8172
                case 'SK':
8173
                    // Test: http://regexr.com/39hhr
8174
                    isValid = /^(\d{3})([ ]?)(\d{2})$/.test(value);
8175
                    break;
8176
 
8177
                case 'US':
8178
                /* falls through */
8179
                default:
8180
                    isValid = /^\d{4,5}([\-]?\d{4})?$/.test(value);
8181
                    break;
8182
            }
8183
 
8184
            return {
8185
                valid: isValid,
8186
                message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.zipCode.country, $.fn.bootstrapValidator.i18n.zipCode.countries[country])
8187
            };
8188
        },
8189
 
8190
        /**
8191
         * Validate United Kingdom postcode
8192
         * Examples:
8193
         * - Standard: EC1A 1BB, W1A 1HQ, M1 1AA, B33 8TH, CR2 6XH, DN55 1PT
8194
         * - Special cases:
8195
         * AI-2640, ASCN 1ZZ, GIR 0AA
8196
         *
8197
         * @see http://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom
8198
         * @param {String} value The postcode
8199
         * @returns {Boolean}
8200
         */
8201
        _gb: function(value) {
8202
            var firstChar  = '[ABCDEFGHIJKLMNOPRSTUWYZ]',     // Does not accept QVX
8203
                secondChar = '[ABCDEFGHKLMNOPQRSTUVWXY]',     // Does not accept IJZ
8204
                thirdChar  = '[ABCDEFGHJKPMNRSTUVWXY]',
8205
                fourthChar = '[ABEHMNPRVWXY]',
8206
                fifthChar  = '[ABDEFGHJLNPQRSTUWXYZ]',
8207
                regexps    = [
8208
                    // AN NAA, ANN NAA, AAN NAA, AANN NAA format
8209
                    new RegExp('^(' + firstChar + '{1}' + secondChar + '?[0-9]{1,2})(\\s*)([0-9]{1}' + fifthChar + '{2})$', 'i'),
8210
                    // ANA NAA
8211
                    new RegExp('^(' + firstChar + '{1}[0-9]{1}' + thirdChar + '{1})(\\s*)([0-9]{1}' + fifthChar + '{2})$', 'i'),
8212
                    // AANA NAA
8213
                    new RegExp('^(' + firstChar + '{1}' + secondChar + '{1}?[0-9]{1}' + fourthChar + '{1})(\\s*)([0-9]{1}' + fifthChar + '{2})$', 'i'),
8214
 
8215
                    new RegExp('^(BF1)(\\s*)([0-6]{1}[ABDEFGHJLNPQRST]{1}[ABDEFGHJLNPQRSTUWZYZ]{1})$', 'i'),        // BFPO postcodes
8216
                    /^(GIR)(\s*)(0AA)$/i,                       // Special postcode GIR 0AA
8217
                    /^(BFPO)(\s*)([0-9]{1,4})$/i,               // Standard BFPO numbers
8218
                    /^(BFPO)(\s*)(c\/o\s*[0-9]{1,3})$/i,        // c/o BFPO numbers
8219
                    /^([A-Z]{4})(\s*)(1ZZ)$/i,                  // Overseas Territories
8220
                    /^(AI-2640)$/i                              // Anguilla
8221
                ];
8222
            for (var i = 0; i < regexps.length; i++) {
8223
                if (regexps[i].test(value)) {
8224
                    return true;
8225
                }
8226
            }
8227
 
8228
            return false;
8229
        }
8230
    };
8231
}(window.jQuery));