/*! * FormValidation (http://formvalidation.io) * The best jQuery plugin to validate form fields. Support Bootstrap, Foundation, Pure, SemanticUI, UIKit and custom frameworks * * @version v0.7.0, built on 2015-08-01 4:57:16 PM * @author https://twitter.com/formvalidation * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc * @license http://formvalidation.io/license/ */ // Register the namespace window.FormValidation = { AddOn: {}, // Add-ons Framework: {}, // Supported frameworks I18n: {}, // i18n Validator: {} // Available validators }; if (typeof jQuery === 'undefined') { throw new Error('FormValidation requires jQuery'); } (function($) { var version = $.fn.jquery.split(' ')[0].split('.'); if ((+version[0] < 2 && +version[1] < 9) || (+version[0] === 1 && +version[1] === 9 && +version[2] < 1)) { throw new Error('FormValidation requires jQuery version 1.9.1 or higher'); } }(jQuery)); (function($) { // TODO: Remove backward compatibility /** * Constructor * * @param {jQuery|String} form The form element or selector * @param {Object} options The options * @param {String} [namespace] The optional namespace which is used for data-{namespace}-xxx attributes and internal data. * Currently, it's used to support backward version * @constructor */ FormValidation.Base = function(form, options, namespace) { this.$form = $(form); this.options = $.extend({}, $.fn.formValidation.DEFAULT_OPTIONS, options); this._namespace = namespace || 'fv'; this.$invalidFields = $([]); // Array of invalid fields this.$submitButton = null; // The submit button which is clicked to submit form this.$hiddenButton = null; // Validating status this.STATUS_NOT_VALIDATED = 'NOT_VALIDATED'; this.STATUS_VALIDATING = 'VALIDATING'; this.STATUS_INVALID = 'INVALID'; this.STATUS_VALID = 'VALID'; this.STATUS_IGNORED = 'IGNORED'; // Default message this.DEFAULT_MESSAGE = $.fn.formValidation.DEFAULT_MESSAGE; // Determine the event that is fired when user change the field value // Most modern browsers supports input event except IE 7, 8. // IE 9 supports input event but the event is still not fired if I press the backspace key. // Get IE version // https://gist.github.com/padolsey/527683/#comment-7595 this._ieVersion = (function() { var v = 3, div = document.createElement('div'), a = div.all || []; while (div.innerHTML = '', a[0]) {} return v > 4 ? v : document.documentMode; }()); var el = document.createElement('div'); this._changeEvent = (this._ieVersion === 9 || !('oninput' in el)) ? 'keyup' : 'input'; // The flag to indicate that the form is ready to submit when a remote/callback validator returns this._submitIfValid = null; // Field elements this._cacheFields = {}; this._init(); }; FormValidation.Base.prototype = { constructor: FormValidation.Base, /** * Check if the number of characters of field value exceed the threshold or not * * @param {jQuery} $field The field element * @returns {Boolean} */ _exceedThreshold: function($field) { var ns = this._namespace, field = $field.attr('data-' + ns + '-field'), threshold = this.options.fields[field].threshold || this.options.threshold; if (!threshold) { return true; } var cannotType = $.inArray($field.attr('type'), ['button', 'checkbox', 'file', 'hidden', 'image', 'radio', 'reset', 'submit']) !== -1; return (cannotType || $field.val().length >= threshold); }, /** * Init form */ _init: function() { var that = this, ns = this._namespace, options = { addOns: {}, autoFocus: this.$form.attr('data-' + ns + '-autofocus'), button: { selector: this.$form.attr('data-' + ns + '-button-selector') || this.$form.attr('data-' + ns + '-submitbuttons'), // Support backward disabled: this.$form.attr('data-' + ns + '-button-disabled') }, control: { valid: this.$form.attr('data-' + ns + '-control-valid'), invalid: this.$form.attr('data-' + ns + '-control-invalid') }, err: { clazz: this.$form.attr('data-' + ns + '-err-clazz'), container: this.$form.attr('data-' + ns + '-err-container') || this.$form.attr('data-' + ns + '-container'), // Support backward parent: this.$form.attr('data-' + ns + '-err-parent') }, events: { formInit: this.$form.attr('data-' + ns + '-events-form-init'), formPreValidate: this.$form.attr('data-' + ns + '-events-form-prevalidate'), formError: this.$form.attr('data-' + ns + '-events-form-error'), formSuccess: this.$form.attr('data-' + ns + '-events-form-success'), fieldAdded: this.$form.attr('data-' + ns + '-events-field-added'), fieldRemoved: this.$form.attr('data-' + ns + '-events-field-removed'), fieldInit: this.$form.attr('data-' + ns + '-events-field-init'), fieldError: this.$form.attr('data-' + ns + '-events-field-error'), fieldSuccess: this.$form.attr('data-' + ns + '-events-field-success'), fieldStatus: this.$form.attr('data-' + ns + '-events-field-status'), localeChanged: this.$form.attr('data-' + ns + '-events-locale-changed'), validatorError: this.$form.attr('data-' + ns + '-events-validator-error'), validatorSuccess: this.$form.attr('data-' + ns + '-events-validator-success'), validatorIgnored: this.$form.attr('data-' + ns + '-events-validator-ignored') }, excluded: this.$form.attr('data-' + ns + '-excluded'), icon: { valid: this.$form.attr('data-' + ns + '-icon-valid') || this.$form.attr('data-' + ns + '-feedbackicons-valid'), // Support backward invalid: this.$form.attr('data-' + ns + '-icon-invalid') || this.$form.attr('data-' + ns + '-feedbackicons-invalid'), // Support backward validating: this.$form.attr('data-' + ns + '-icon-validating') || this.$form.attr('data-' + ns + '-feedbackicons-validating'), // Support backward feedback: this.$form.attr('data-' + ns + '-icon-feedback') }, live: this.$form.attr('data-' + ns + '-live'), locale: this.$form.attr('data-' + ns + '-locale'), message: this.$form.attr('data-' + ns + '-message'), onPreValidate: this.$form.attr('data-' + ns + '-onprevalidate'), onError: this.$form.attr('data-' + ns + '-onerror'), onSuccess: this.$form.attr('data-' + ns + '-onsuccess'), row: { selector: this.$form.attr('data-' + ns + '-row-selector') || this.$form.attr('data-' + ns + '-group'), // Support backward valid: this.$form.attr('data-' + ns + '-row-valid'), invalid: this.$form.attr('data-' + ns + '-row-invalid'), feedback: this.$form.attr('data-' + ns + '-row-feedback') }, threshold: this.$form.attr('data-' + ns + '-threshold'), trigger: this.$form.attr('data-' + ns + '-trigger'), verbose: this.$form.attr('data-' + ns + '-verbose'), fields: {} }; this.$form // Disable client side validation in HTML 5 .attr('novalidate', 'novalidate') .addClass(this.options.elementClass) // Disable the default submission first .on('submit.' + ns, function(e) { e.preventDefault(); that.validate(); }) .on('click.' + ns, this.options.button.selector, function() { that.$submitButton = $(this); // The user just click the submit button that._submitIfValid = true; }); if (this.options.declarative === true || this.options.declarative === 'true') { // Find all fields which have either "name" or "data-{namespace}-field" attribute this.$form .find('[name], [data-' + ns + '-field]') .each(function() { var $field = $(this), field = $field.attr('name') || $field.attr('data-' + ns + '-field'), opts = that._parseOptions($field); if (opts) { $field.attr('data-' + ns + '-field', field); options.fields[field] = $.extend({}, opts, options.fields[field]); } }); } this.options = $.extend(true, this.options, options); // Normalize the err.parent option if ('string' === typeof this.options.err.parent) { this.options.err.parent = new RegExp(this.options.err.parent); } // Support backward if (this.options.container) { this.options.err.container = this.options.container; delete this.options.container; } if (this.options.feedbackIcons) { this.options.icon = $.extend(true, this.options.icon, this.options.feedbackIcons); delete this.options.feedbackIcons; } if (this.options.group) { this.options.row.selector = this.options.group; delete this.options.group; } if (this.options.submitButtons) { this.options.button.selector = this.options.submitButtons; delete this.options.submitButtons; } // If the locale is not found, reset it to default one if (!FormValidation.I18n[this.options.locale]) { this.options.locale = $.fn.formValidation.DEFAULT_OPTIONS.locale; } // Parse the add-on options from HTML attributes if (this.options.declarative === true || this.options.declarative === 'true') { this.options = $.extend(true, this.options, { addOns: this._parseAddOnOptions() }); } // When pressing Enter on any field in the form, the first submit button will do its job. // The form then will be submitted. // I create a first hidden submit button this.$hiddenButton = $('