diff --git a/src/parsley/field.js b/src/parsley/field.js index 415af7a1..a7e1699d 100644 --- a/src/parsley/field.js +++ b/src/parsley/field.js @@ -1,16 +1,16 @@ -import $ from "jquery"; -import Constraint from "./constraint"; -import UI from "./ui"; -import Utils from "./utils"; +import $ from 'jquery'; +import Constraint from './constraint'; +import UI from './ui'; +import Utils from './utils'; var Field = function (field, domOptions, options, parsleyFormInstance) { - this.__class__ = "Field"; + this.__class__ = 'Field'; this.element = field; this.$element = $(field); // Set parent if we have one - if ("undefined" !== typeof parsleyFormInstance) { + if ('undefined' !== typeof parsleyFormInstance) { this.parent = parsleyFormInstance; } @@ -26,7 +26,7 @@ var Field = function (field, domOptions, options, parsleyFormInstance) { this._bindConstraints(); }; -var statusMapping = { pending: null, resolved: true, rejected: false }; +var statusMapping = {pending: null, resolved: true, rejected: false}; Field.prototype = { // # Public API @@ -35,52 +35,39 @@ Field.prototype = { // `null` if validation is not finished. Prefer using whenValidate validate: function (options) { if (arguments.length >= 1 && !$.isPlainObject(options)) { - Utils.warnOnce( - "Calling validate on a parsley field without passing arguments as an object is deprecated." - ); - options = { options }; + Utils.warnOnce('Calling validate on a parsley field without passing arguments as an object is deprecated.'); + options = {options}; } var promise = this.whenValidate(options); - if (!promise) - // If excluded with `group` option + if (!promise) // If excluded with `group` option return true; switch (promise.state()) { - case "pending": - return null; - case "resolved": - return true; - case "rejected": - return this.validationResult; + case 'pending': return null; + case 'resolved': return true; + case 'rejected': return this.validationResult; } }, // Validate field and trigger some events for mainly `UI` // @returns a promise that succeeds only when all validations do // or `undefined` if field is not in the given `group`. - whenValidate: function ({ force, group } = {}) { + whenValidate: function ({force, group} = {}) { // do not validate a field if not the same as given validation group this.refresh(); - if (group && !this._isInGroup(group)) return; + if (group && !this._isInGroup(group)) + return; this.value = this.getValue(); // Field Validate event. `this.value` could be altered for custom needs - this._trigger("validate"); + this._trigger('validate'); return this._pipeAccordingToValidationResult( - this.whenValid({ force, value: this.value, _refreshed: true }) - .always(() => { - this._reflowUI(); - }) - .done(() => { - this._trigger("success"); - }) - .fail(() => { - this._trigger("error"); - }) - .always(() => { - this._trigger("validated"); - }) + this.whenValid({force, value: this.value, _refreshed: true}) + .always(() => { this._reflowUI(); }) + .done(() => { this._trigger('success'); }) + .fail(() => { this._trigger('error'); }) + .always(() => { this._trigger('validated'); }) ); }, @@ -90,15 +77,12 @@ Field.prototype = { // An empty optional field does not need validation needsValidation: function (value) { - if ("undefined" === typeof value) value = this.getValue(); + if ('undefined' === typeof value) + value = this.getValue(); // If a field is empty and not required, it is valid // Except if `data-parsley-validate-if-empty` explicitely added, useful for some custom validators - if ( - !value.length && - !this._isRequired() && - "undefined" === typeof this.options.validateIfEmpty - ) + if (!value.length && !this._isRequired() && 'undefined' === typeof this.options.validateIfEmpty) return false; return true; @@ -116,15 +100,12 @@ Field.prototype = { // See also `whenValid`. isValid: function (options) { if (arguments.length >= 1 && !$.isPlainObject(options)) { - Utils.warnOnce( - "Calling isValid on a parsley field without passing arguments as an object is deprecated." - ); + Utils.warnOnce('Calling isValid on a parsley field without passing arguments as an object is deprecated.'); var [force, value] = arguments; - options = { force, value }; + options = {force, value}; } var promise = this.whenValid(options); - if (!promise) - // Excluded via `group` + if (!promise) // Excluded via `group` return true; return statusMapping[promise.state()]; }, @@ -134,21 +115,26 @@ Field.prototype = { // or `undefined` if the field is not in the given `group`. // The argument `force` will force validation of empty fields. // If a `value` is given, it will be validated instead of the value of the input. - whenValid: function ({ force = false, value, group, _refreshed } = {}) { + whenValid: function ({force = false, value, group, _refreshed} = {}) { // Recompute options and rebind constraints to have latest changes - if (!_refreshed) this.refresh(); + if (!_refreshed) + this.refresh(); // do not validate a field if not the same as given validation group - if (group && !this._isInGroup(group)) return; + if (group && !this._isInGroup(group)) + return; this.validationResult = true; // A field without constraint is valid - if (!this.hasConstraints()) return $.when(); + if (!this.hasConstraints()) + return $.when(); // Value could be passed as argument, needed to add more power to 'field:validate' - if ("undefined" === typeof value || null === value) value = this.getValue(); + if ('undefined' === typeof value || null === value) + value = this.getValue(); - if (!this.needsValidation(value) && true !== force) return $.when(); + if (!this.needsValidation(value) && true !== force) + return $.when(); var groupedConstraints = this._getGroupedConstraints(); var promises = []; @@ -156,27 +142,28 @@ Field.prototype = { // Process one group of constraints at a time, we validate the constraints // and combine the promises together. var promise = Utils.all( - $.map(constraints, (constraint) => - this._validateConstraint(value, constraint) - ) + $.map(constraints, constraint => this._validateConstraint(value, constraint)) ); promises.push(promise); - if (promise.state() === "rejected") return false; // Interrupt processing if a group has already failed + if (promise.state() === 'rejected') + return false; // Interrupt processing if a group has already failed }); return Utils.all(promises); }, // @returns a promise - _validateConstraint: function (value, constraint) { + _validateConstraint: function(value, constraint) { var result = constraint.validate(value, this); // Map false to a failed promise - if (false === result) result = $.Deferred().reject(); + if (false === result) + result = $.Deferred().reject(); // Make sure we return a promise and that we record failures - return Utils.all([result]).fail((errorMessage) => { - if (!(this.validationResult instanceof Array)) this.validationResult = []; + return Utils.all([result]).fail(errorMessage => { + if (!(this.validationResult instanceof Array)) + this.validationResult = []; this.validationResult.push({ assert: constraint, - errorMessage: "string" === typeof errorMessage && errorMessage, + errorMessage: 'string' === typeof errorMessage && errorMessage }); }); }, @@ -186,14 +173,16 @@ Field.prototype = { var value; // Value could be overriden in DOM or with explicit options - if ("function" === typeof this.options.value) + if ('function' === typeof this.options.value) value = this.options.value(this); - else if ("undefined" !== typeof this.options.value) + else if ('undefined' !== typeof this.options.value) value = this.options.value; - else value = this.$element.val(); + else + value = this.$element.val(); // Handle wrong DOM or configurations - if ("undefined" === typeof value || null === value) return ""; + if ('undefined' === typeof value || null === value) + return ''; return this._handleWhitespace(value); }, @@ -201,16 +190,16 @@ Field.prototype = { // Reset UI reset: function () { this._resetUI(); - return this._trigger("reset"); + return this._trigger('reset'); }, // Destroy Parsley instance (+ UI) destroy: function () { // Field case: emit destroy event to clean UI and then destroy stored instance this._destroyUI(); - this.$element.removeData("Parsley"); - this.$element.removeData("FieldMultiple"); - this._trigger("destroy"); + this.$element.removeData('Parsley'); + this.$element.removeData('FieldMultiple'); + this._trigger('destroy'); }, // Actualize options and rebind constraints @@ -223,33 +212,26 @@ Field.prototype = { return this.actualizeOptions()._bindConstraints(); }, - refreshConstraints: function () { - Utils.warnOnce( - "Parsley's refreshConstraints is deprecated. Please use refresh" - ); + refreshConstraints: function() { + Utils.warnOnce("Parsley's refreshConstraints is deprecated. Please use refresh"); return this.refresh(); }, /** - * Add a new constraint to a field - * - * @param {String} name - * @param {Mixed} requirements optional - * @param {Number} priority optional - * @param {Boolean} isDomConstraint optional - */ + * Add a new constraint to a field + * + * @param {String} name + * @param {Mixed} requirements optional + * @param {Number} priority optional + * @param {Boolean} isDomConstraint optional + */ addConstraint: function (name, requirements, priority, isDomConstraint) { + if (window.Parsley._validatorRegistry.validators[name]) { - var constraint = new Constraint( - this, - name, - requirements, - priority, - isDomConstraint - ); + var constraint = new Constraint(this, name, requirements, priority, isDomConstraint); // if constraint already exist, delete it and push new version - if ("undefined" !== this.constraintsByName[constraint.name]) + if ('undefined' !== this.constraintsByName[constraint.name]) this.removeConstraint(constraint.name); this.constraints.push(constraint); @@ -272,11 +254,8 @@ Field.prototype = { // Update a constraint (Remove + re-add) updateConstraint: function (name, parameters, priority) { - return this.removeConstraint(name).addConstraint( - name, - parameters, - priority - ); + return this.removeConstraint(name) + .addConstraint(name, parameters, priority); }, // # Internals @@ -309,79 +288,53 @@ Field.prototype = { // Bind specific HTML5 constraints to be HTML5 compliant _bindHtml5Constraints: function () { // html5 required - if (null !== this.element.getAttribute("required")) - this.addConstraint("required", true, undefined, true); + if (null !== this.element.getAttribute('required')) + this.addConstraint('required', true, undefined, true); // html5 pattern - if (null !== this.element.getAttribute("pattern")) - this.addConstraint( - "pattern", - this.element.getAttribute("pattern"), - undefined, - true - ); + if (null !== this.element.getAttribute('pattern')) + this.addConstraint('pattern', this.element.getAttribute('pattern'), undefined, true); // range - let min = this.element.getAttribute("min"); - let max = this.element.getAttribute("max"); + let min = this.element.getAttribute('min'); + let max = this.element.getAttribute('max'); if (null !== min && null !== max) - this.addConstraint("range", [min, max], undefined, true); + this.addConstraint('range', [min, max], undefined, true); + // HTML5 min - else if (null !== min) this.addConstraint("min", min, undefined, true); + else if (null !== min) + this.addConstraint('min', min, undefined, true); + // HTML5 max - else if (null !== max) this.addConstraint("max", max, undefined, true); + else if (null !== max) + this.addConstraint('max', max, undefined, true); + // length - if ( - null !== this.element.getAttribute("minlength") && - null !== this.element.getAttribute("maxlength") - ) - this.addConstraint( - "length", - [ - this.element.getAttribute("minlength"), - this.element.getAttribute("maxlength"), - ], - undefined, - true - ); + if (null !== this.element.getAttribute('minlength') && null !== this.element.getAttribute('maxlength')) + this.addConstraint('length', [this.element.getAttribute('minlength'), this.element.getAttribute('maxlength')], undefined, true); + // HTML5 minlength - else if (null !== this.element.getAttribute("minlength")) - this.addConstraint( - "minlength", - this.element.getAttribute("minlength"), - undefined, - true - ); + else if (null !== this.element.getAttribute('minlength')) + this.addConstraint('minlength', this.element.getAttribute('minlength'), undefined, true); + // HTML5 maxlength - else if (null !== this.element.getAttribute("maxlength")) - this.addConstraint( - "maxlength", - this.element.getAttribute("maxlength"), - undefined, - true - ); + else if (null !== this.element.getAttribute('maxlength')) + this.addConstraint('maxlength', this.element.getAttribute('maxlength'), undefined, true); + // html5 types var type = Utils.getType(this.element); // Small special case here for HTML5 number: integer validator if step attribute is undefined or an integer value, number otherwise - if ("number" === type) { - return this.addConstraint( - "type", - [ - "number", - { - step: this.element.getAttribute("step") || "1", - base: min || this.element.getAttribute("value"), - }, - ], - undefined, - true - ); - // Regular other HTML5 supported types + if ('number' === type) { + return this.addConstraint('type', ['number', { + step: this.element.getAttribute('step') || '1', + base: min || this.element.getAttribute('value') + }], undefined, true); + // Regular other HTML5 supported types } else if (/^(email|url|range|date)$/i.test(type)) { - return this.addConstraint("type", type, undefined, true); + return this.addConstraint('type', type, undefined, true); } return this; }, @@ -389,7 +342,8 @@ Field.prototype = { // Internal only. // Field is required if have required constraint without `false` value _isRequired: function () { - if ("undefined" === typeof this.constraintsByName.required) return false; + if ('undefined' === typeof this.constraintsByName.required) + return false; return false !== this.constraintsByName.required.requirements; }, @@ -397,7 +351,7 @@ Field.prototype = { // Internal only. // Shortcut to trigger an event _trigger: function (eventName) { - return this.trigger("field:" + eventName); + return this.trigger('field:' + eventName); }, // Internal only @@ -406,33 +360,28 @@ Field.prototype = { // Use `data-parsley-whitespace="trim"` to auto trim input value _handleWhitespace: function (value) { if (true === this.options.trimValue) - Utils.warnOnce( - 'data-parsley-trim-value="true" is deprecated, please use data-parsley-whitespace="trim"' - ); + Utils.warnOnce('data-parsley-trim-value="true" is deprecated, please use data-parsley-whitespace="trim"'); - if ("squish" === this.options.whitespace) - value = value.replace(/\s{2,}/g, " "); + if ('squish' === this.options.whitespace) + value = value.replace(/\s{2,}/g, ' '); - if ( - "trim" === this.options.whitespace || - "squish" === this.options.whitespace || - true === this.options.trimValue - ) + if (('trim' === this.options.whitespace) || ('squish' === this.options.whitespace) || (true === this.options.trimValue)) value = Utils.trimString(value); return value; }, - _isDateInput: function () { + _isDateInput: function() { var c = this.constraintsByName.type; - return c && c.requirements === "date"; + return c && c.requirements === 'date'; }, // Internal only. // Returns the constraints, grouped by descending priority. // The result is thus an array of arrays of constraints. _getGroupedConstraints: function () { - if (false === this.options.priorityEnabled) return [this.constraints]; + if (false === this.options.priorityEnabled) + return [this.constraints]; var groupedConstraints = []; var index = {}; @@ -440,16 +389,16 @@ Field.prototype = { // Create array unique of priorities for (var i = 0; i < this.constraints.length; i++) { var p = this.constraints[i].priority; - if (!index[p]) groupedConstraints.push((index[p] = [])); + if (!index[p]) + groupedConstraints.push(index[p] = []); index[p].push(this.constraints[i]); } // Sort them by priority DESC - groupedConstraints.sort(function (a, b) { - return b[0].priority - a[0].priority; - }); + groupedConstraints.sort(function (a, b) { return b[0].priority - a[0].priority; }); return groupedConstraints; - }, + } + }; export default Field;