/files/parsleyjs/2.3.5/parsley.js
JavaScript | 1340 lines | 884 code | 252 blank | 204 comment | 199 complexity | 8eadf4bec9504b2241ba4d9f51f4030f MD5 | raw file
- /*!
- * Parsley.js
- * Version 2.3.5 - built Sun, Feb 28th 2016, 6:25 am
- * http://parsleyjs.org
- * Guillaume Potier - <guillaume@wisembly.com>
- * Marc-Andre Lafortune - <petroselinum@marc-andre.ca>
- * MIT Licensed
- */
- // The source code below is generated by babel as
- // Parsley is written in ECMAScript 6
- //
- var _slice = Array.prototype.slice;
- function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }
- (function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery')) : typeof define === 'function' && define.amd ? define(['jquery'], factory) : global.parsley = factory(global.jQuery);
- })(this, function ($) {
- 'use strict';
- var globalID = 1;
- var pastWarnings = {};
- var ParsleyUtils__ParsleyUtils = {
- // Parsley DOM-API
- // returns object from dom attributes and values
- attr: function attr($element, namespace, obj) {
- var i;
- var attribute;
- var attributes;
- var regex = new RegExp('^' + namespace, 'i');
- if ('undefined' === typeof obj) obj = {};else {
- // Clear all own properties. This won't affect prototype's values
- for (i in obj) {
- if (obj.hasOwnProperty(i)) delete obj[i];
- }
- }
- if ('undefined' === typeof $element || 'undefined' === typeof $element[0]) return obj;
- attributes = $element[0].attributes;
- for (i = attributes.length; i--;) {
- attribute = attributes[i];
- if (attribute && attribute.specified && regex.test(attribute.name)) {
- obj[this.camelize(attribute.name.slice(namespace.length))] = this.deserializeValue(attribute.value);
- }
- }
- return obj;
- },
- checkAttr: function checkAttr($element, namespace, _checkAttr) {
- return $element.is('[' + namespace + _checkAttr + ']');
- },
- setAttr: function setAttr($element, namespace, attr, value) {
- $element[0].setAttribute(this.dasherize(namespace + attr), String(value));
- },
- generateID: function generateID() {
- return '' + globalID++;
- },
- /** Third party functions **/
- // Zepto deserialize function
- deserializeValue: function deserializeValue(value) {
- var num;
- try {
- return value ? value == "true" || (value == "false" ? false : value == "null" ? null : !isNaN(num = Number(value)) ? num : /^[\[\{]/.test(value) ? $.parseJSON(value) : value) : value;
- } catch (e) {
- return value;
- }
- },
- // Zepto camelize function
- camelize: function camelize(str) {
- return str.replace(/-+(.)?/g, function (match, chr) {
- return chr ? chr.toUpperCase() : '';
- });
- },
- // Zepto dasherize function
- dasherize: function dasherize(str) {
- return str.replace(/::/g, '/').replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2').replace(/([a-z\d])([A-Z])/g, '$1_$2').replace(/_/g, '-').toLowerCase();
- },
- warn: function warn() {
- var _window$console;
- if (window.console && 'function' === typeof window.console.warn) (_window$console = window.console).warn.apply(_window$console, arguments);
- },
- warnOnce: function warnOnce(msg) {
- if (!pastWarnings[msg]) {
- pastWarnings[msg] = true;
- this.warn.apply(this, arguments);
- }
- },
- _resetWarnings: function _resetWarnings() {
- pastWarnings = {};
- },
- trimString: function trimString(string) {
- return string.replace(/^\s+|\s+$/g, '');
- },
- namespaceEvents: function namespaceEvents(events, namespace) {
- events = this.trimString(events || '').split(/\s+/);
- if (!events[0]) return '';
- return $.map(events, function (evt) {
- return evt + '.' + namespace;
- }).join(' ');
- },
- // Object.create polyfill, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Polyfill
- objectCreate: Object.create || (function () {
- var Object = function Object() {};
- return function (prototype) {
- if (arguments.length > 1) {
- throw Error('Second argument not supported');
- }
- if (typeof prototype != 'object') {
- throw TypeError('Argument must be an object');
- }
- Object.prototype = prototype;
- var result = new Object();
- Object.prototype = null;
- return result;
- };
- })()
- };
- var ParsleyUtils__default = ParsleyUtils__ParsleyUtils;
- // All these options could be overriden and specified directly in DOM using
- // `data-parsley-` default DOM-API
- // eg: `inputs` can be set in DOM using `data-parsley-inputs="input, textarea"`
- // eg: `data-parsley-stop-on-first-failing-constraint="false"`
- var ParsleyDefaults = {
- // ### General
- // Default data-namespace for DOM API
- namespace: 'data-parsley-',
- // Supported inputs by default
- inputs: 'input, textarea, select',
- // Excluded inputs by default
- excluded: 'input[type=button], input[type=submit], input[type=reset], input[type=hidden]',
- // Stop validating field on highest priority failing constraint
- priorityEnabled: true,
- // ### Field only
- // identifier used to group together inputs (e.g. radio buttons...)
- multiple: null,
- // identifier (or array of identifiers) used to validate only a select group of inputs
- group: null,
- // ### UI
- // Enable\Disable error messages
- uiEnabled: true,
- // Key events threshold before validation
- validationThreshold: 3,
- // Focused field on form validation error. 'first'|'last'|'none'
- focus: 'first',
- // event(s) that will trigger validation before first failure. eg: `input`...
- trigger: false,
- // event(s) that will trigger validation after first failure.
- triggerAfterFailure: 'input',
- // Class that would be added on every failing validation Parsley field
- errorClass: 'parsley-error',
- // Same for success validation
- successClass: 'parsley-success',
- // Return the `$element` that will receive these above success or error classes
- // Could also be (and given directly from DOM) a valid selector like `'#div'`
- classHandler: function classHandler(ParsleyField) {},
- // Return the `$element` where errors will be appended
- // Could also be (and given directly from DOM) a valid selector like `'#div'`
- errorsContainer: function errorsContainer(ParsleyField) {},
- // ul elem that would receive errors' list
- errorsWrapper: '<ul class="parsley-errors-list"></ul>',
- // li elem that would receive error message
- errorTemplate: '<li></li>'
- };
- var ParsleyAbstract = function ParsleyAbstract() {};
- ParsleyAbstract.prototype = {
- asyncSupport: true, // Deprecated
- actualizeOptions: function actualizeOptions() {
- ParsleyUtils__default.attr(this.$element, this.options.namespace, this.domOptions);
- if (this.parent && this.parent.actualizeOptions) this.parent.actualizeOptions();
- return this;
- },
- _resetOptions: function _resetOptions(initOptions) {
- this.domOptions = ParsleyUtils__default.objectCreate(this.parent.options);
- this.options = ParsleyUtils__default.objectCreate(this.domOptions);
- // Shallow copy of ownProperties of initOptions:
- for (var i in initOptions) {
- if (initOptions.hasOwnProperty(i)) this.options[i] = initOptions[i];
- }
- this.actualizeOptions();
- },
- _listeners: null,
- // Register a callback for the given event name
- // Callback is called with context as the first argument and the `this`
- // The context is the current parsley instance, or window.Parsley if global
- // A return value of `false` will interrupt the calls
- on: function on(name, fn) {
- this._listeners = this._listeners || {};
- var queue = this._listeners[name] = this._listeners[name] || [];
- queue.push(fn);
- return this;
- },
- // Deprecated. Use `on` instead
- subscribe: function subscribe(name, fn) {
- $.listenTo(this, name.toLowerCase(), fn);
- },
- // Unregister a callback (or all if none is given) for the given event name
- off: function off(name, fn) {
- var queue = this._listeners && this._listeners[name];
- if (queue) {
- if (!fn) {
- delete this._listeners[name];
- } else {
- for (var i = queue.length; i--;) if (queue[i] === fn) queue.splice(i, 1);
- }
- }
- return this;
- },
- // Deprecated. Use `off`
- unsubscribe: function unsubscribe(name, fn) {
- $.unsubscribeTo(this, name.toLowerCase());
- },
- // Trigger an event of the given name
- // A return value of `false` interrupts the callback chain
- // Returns false if execution was interrupted
- trigger: function trigger(name, target, extraArg) {
- target = target || this;
- var queue = this._listeners && this._listeners[name];
- var result;
- var parentResult;
- if (queue) {
- for (var i = queue.length; i--;) {
- result = queue[i].call(target, target, extraArg);
- if (result === false) return result;
- }
- }
- if (this.parent) {
- return this.parent.trigger(name, target, extraArg);
- }
- return true;
- },
- // Reset UI
- reset: function reset() {
- // Field case: just emit a reset event for UI
- if ('ParsleyForm' !== this.__class__) {
- this._resetUI();
- return this._trigger('reset');
- }
- // Form case: emit a reset event for each field
- for (var i = 0; i < this.fields.length; i++) this.fields[i].reset();
- this._trigger('reset');
- },
- // Destroy Parsley instance (+ UI)
- destroy: function destroy() {
- // Field case: emit destroy event to clean UI and then destroy stored instance
- this._destroyUI();
- if ('ParsleyForm' !== this.__class__) {
- this.$element.removeData('Parsley');
- this.$element.removeData('ParsleyFieldMultiple');
- this._trigger('destroy');
- return;
- }
- // Form case: destroy all its fields and then destroy stored instance
- for (var i = 0; i < this.fields.length; i++) this.fields[i].destroy();
- this.$element.removeData('Parsley');
- this._trigger('destroy');
- },
- asyncIsValid: function asyncIsValid(group, force) {
- ParsleyUtils__default.warnOnce("asyncIsValid is deprecated; please use whenValid instead");
- return this.whenValid({ group: group, force: force });
- },
- _findRelated: function _findRelated() {
- return this.options.multiple ? this.parent.$element.find('[' + this.options.namespace + 'multiple="' + this.options.multiple + '"]') : this.$element;
- }
- };
- var requirementConverters = {
- string: function string(_string) {
- return _string;
- },
- integer: function integer(string) {
- if (isNaN(string)) throw 'Requirement is not an integer: "' + string + '"';
- return parseInt(string, 10);
- },
- number: function number(string) {
- if (isNaN(string)) throw 'Requirement is not a number: "' + string + '"';
- return parseFloat(string);
- },
- reference: function reference(string) {
- // Unused for now
- var result = $(string);
- if (result.length === 0) throw 'No such reference: "' + string + '"';
- return result;
- },
- boolean: function boolean(string) {
- return string !== 'false';
- },
- object: function object(string) {
- return ParsleyUtils__default.deserializeValue(string);
- },
- regexp: function regexp(_regexp) {
- var flags = '';
- // Test if RegExp is literal, if not, nothing to be done, otherwise, we need to isolate flags and pattern
- if (/^\/.*\/(?:[gimy]*)$/.test(_regexp)) {
- // Replace the regexp literal string with the first match group: ([gimy]*)
- // If no flag is present, this will be a blank string
- flags = _regexp.replace(/.*\/([gimy]*)$/, '$1');
- // Again, replace the regexp literal string with the first match group:
- // everything excluding the opening and closing slashes and the flags
- _regexp = _regexp.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1');
- } else {
- // Anchor regexp:
- _regexp = '^' + _regexp + '$';
- }
- return new RegExp(_regexp, flags);
- }
- };
- var convertArrayRequirement = function convertArrayRequirement(string, length) {
- var m = string.match(/^\s*\[(.*)\]\s*$/);
- if (!m) throw 'Requirement is not an array: "' + string + '"';
- var values = m[1].split(',').map(ParsleyUtils__default.trimString);
- if (values.length !== length) throw 'Requirement has ' + values.length + ' values when ' + length + ' are needed';
- return values;
- };
- var convertRequirement = function convertRequirement(requirementType, string) {
- var converter = requirementConverters[requirementType || 'string'];
- if (!converter) throw 'Unknown requirement specification: "' + requirementType + '"';
- return converter(string);
- };
- var convertExtraOptionRequirement = function convertExtraOptionRequirement(requirementSpec, string, extraOptionReader) {
- var main = null;
- var extra = {};
- for (var key in requirementSpec) {
- if (key) {
- var value = extraOptionReader(key);
- if ('string' === typeof value) value = convertRequirement(requirementSpec[key], value);
- extra[key] = value;
- } else {
- main = convertRequirement(requirementSpec[key], string);
- }
- }
- return [main, extra];
- };
- // A Validator needs to implement the methods `validate` and `parseRequirements`
- var ParsleyValidator = function ParsleyValidator(spec) {
- $.extend(true, this, spec);
- };
- ParsleyValidator.prototype = {
- // Returns `true` iff the given `value` is valid according the given requirements.
- validate: function validate(value, requirementFirstArg) {
- if (this.fn) {
- // Legacy style validator
- if (arguments.length > 3) // If more args then value, requirement, instance...
- requirementFirstArg = [].slice.call(arguments, 1, -1); // Skip first arg (value) and last (instance), combining the rest
- return this.fn.call(this, value, requirementFirstArg);
- }
- if ($.isArray(value)) {
- if (!this.validateMultiple) throw 'Validator `' + this.name + '` does not handle multiple values';
- return this.validateMultiple.apply(this, arguments);
- } else {
- if (this.validateNumber) {
- if (isNaN(value)) return false;
- arguments[0] = parseFloat(arguments[0]);
- return this.validateNumber.apply(this, arguments);
- }
- if (this.validateString) {
- return this.validateString.apply(this, arguments);
- }
- throw 'Validator `' + this.name + '` only handles multiple values';
- }
- },
- // Parses `requirements` into an array of arguments,
- // according to `this.requirementType`
- parseRequirements: function parseRequirements(requirements, extraOptionReader) {
- if ('string' !== typeof requirements) {
- // Assume requirement already parsed
- // but make sure we return an array
- return $.isArray(requirements) ? requirements : [requirements];
- }
- var type = this.requirementType;
- if ($.isArray(type)) {
- var values = convertArrayRequirement(requirements, type.length);
- for (var i = 0; i < values.length; i++) values[i] = convertRequirement(type[i], values[i]);
- return values;
- } else if ($.isPlainObject(type)) {
- return convertExtraOptionRequirement(type, requirements, extraOptionReader);
- } else {
- return [convertRequirement(type, requirements)];
- }
- },
- // Defaults:
- requirementType: 'string',
- priority: 2
- };
- var ParsleyValidatorRegistry = function ParsleyValidatorRegistry(validators, catalog) {
- this.__class__ = 'ParsleyValidatorRegistry';
- // Default Parsley locale is en
- this.locale = 'en';
- this.init(validators || {}, catalog || {});
- };
- var typeRegexes = {
- email: /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,
- // Follow https://www.w3.org/TR/html5/infrastructure.html#floating-point-numbers
- number: /^-?(\d*\.)?\d+(e[-+]?\d+)?$/i,
- integer: /^-?\d+$/,
- digits: /^\d+$/,
- alphanum: /^\w+$/i,
- url: new RegExp("^" +
- // protocol identifier
- "(?:(?:https?|ftp)://)?" + // ** mod: make scheme optional
- // user:pass authentication
- "(?:\\S+(?::\\S*)?@)?" + "(?:" +
- // IP address exclusion
- // private & local networks
- // "(?!(?:10|127)(?:\\.\\d{1,3}){3})" + // ** mod: allow local networks
- // "(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})" + // ** mod: allow local networks
- // "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" + // ** mod: allow local networks
- // IP address dotted notation octets
- // excludes loopback network 0.0.0.0
- // excludes reserved space >= 224.0.0.0
- // excludes network & broacast addresses
- // (first & last IP address of each class)
- "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" + "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" + "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" + "|" +
- // host name
- '(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)' +
- // domain name
- '(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*' +
- // TLD identifier
- '(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))' + ")" +
- // port number
- "(?::\\d{2,5})?" +
- // resource path
- "(?:/\\S*)?" + "$", 'i')
- };
- typeRegexes.range = typeRegexes.number;
- // See http://stackoverflow.com/a/10454560/8279
- var decimalPlaces = function decimalPlaces(num) {
- var match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
- if (!match) {
- return 0;
- }
- return Math.max(0,
- // Number of digits right of decimal point.
- (match[1] ? match[1].length : 0) - (
- // Adjust for scientific notation.
- match[2] ? +match[2] : 0));
- };
- ParsleyValidatorRegistry.prototype = {
- init: function init(validators, catalog) {
- this.catalog = catalog;
- // Copy prototype's validators:
- this.validators = $.extend({}, this.validators);
- for (var name in validators) this.addValidator(name, validators[name].fn, validators[name].priority);
- window.Parsley.trigger('parsley:validator:init');
- },
- // Set new messages locale if we have dictionary loaded in ParsleyConfig.i18n
- setLocale: function setLocale(locale) {
- if ('undefined' === typeof this.catalog[locale]) throw new Error(locale + ' is not available in the catalog');
- this.locale = locale;
- return this;
- },
- // Add a new messages catalog for a given locale. Set locale for this catalog if set === `true`
- addCatalog: function addCatalog(locale, messages, set) {
- if ('object' === typeof messages) this.catalog[locale] = messages;
- if (true === set) return this.setLocale(locale);
- return this;
- },
- // Add a specific message for a given constraint in a given locale
- addMessage: function addMessage(locale, name, message) {
- if ('undefined' === typeof this.catalog[locale]) this.catalog[locale] = {};
- this.catalog[locale][name] = message;
- return this;
- },
- // Add messages for a given locale
- addMessages: function addMessages(locale, nameMessageObject) {
- for (var name in nameMessageObject) this.addMessage(locale, name, nameMessageObject[name]);
- return this;
- },
- // Add a new validator
- //
- // addValidator('custom', {
- // requirementType: ['integer', 'integer'],
- // validateString: function(value, from, to) {},
- // priority: 22,
- // messages: {
- // en: "Hey, that's no good",
- // fr: "Aye aye, pas bon du tout",
- // }
- // })
- //
- // Old API was addValidator(name, function, priority)
- //
- addValidator: function addValidator(name, arg1, arg2) {
- if (this.validators[name]) ParsleyUtils__default.warn('Validator "' + name + '" is already defined.');else if (ParsleyDefaults.hasOwnProperty(name)) {
- ParsleyUtils__default.warn('"' + name + '" is a restricted keyword and is not a valid validator name.');
- return;
- }
- return this._setValidator.apply(this, arguments);
- },
- updateValidator: function updateValidator(name, arg1, arg2) {
- if (!this.validators[name]) {
- ParsleyUtils__default.warn('Validator "' + name + '" is not already defined.');
- return this.addValidator.apply(this, arguments);
- }
- return this._setValidator(this, arguments);
- },
- removeValidator: function removeValidator(name) {
- if (!this.validators[name]) ParsleyUtils__default.warn('Validator "' + name + '" is not defined.');
- delete this.validators[name];
- return this;
- },
- _setValidator: function _setValidator(name, validator, priority) {
- if ('object' !== typeof validator) {
- // Old style validator, with `fn` and `priority`
- validator = {
- fn: validator,
- priority: priority
- };
- }
- if (!validator.validate) {
- validator = new ParsleyValidator(validator);
- }
- this.validators[name] = validator;
- for (var locale in validator.messages || {}) this.addMessage(locale, name, validator.messages[locale]);
- return this;
- },
- getErrorMessage: function getErrorMessage(constraint) {
- var message;
- // Type constraints are a bit different, we have to match their requirements too to find right error message
- if ('type' === constraint.name) {
- var typeMessages = this.catalog[this.locale][constraint.name] || {};
- message = typeMessages[constraint.requirements];
- } else message = this.formatMessage(this.catalog[this.locale][constraint.name], constraint.requirements);
- return message || this.catalog[this.locale].defaultMessage || this.catalog.en.defaultMessage;
- },
- // Kind of light `sprintf()` implementation
- formatMessage: function formatMessage(string, parameters) {
- if ('object' === typeof parameters) {
- for (var i in parameters) string = this.formatMessage(string, parameters[i]);
- return string;
- }
- return 'string' === typeof string ? string.replace(/%s/i, parameters) : '';
- },
- // Here is the Parsley default validators list.
- // A validator is an object with the following key values:
- // - priority: an integer
- // - requirement: 'string' (default), 'integer', 'number', 'regexp' or an Array of these
- // - validateString, validateMultiple, validateNumber: functions returning `true`, `false` or a promise
- // Alternatively, a validator can be a function that returns such an object
- //
- validators: {
- notblank: {
- validateString: function validateString(value) {
- return (/\S/.test(value)
- );
- },
- priority: 2
- },
- required: {
- validateMultiple: function validateMultiple(values) {
- return values.length > 0;
- },
- validateString: function validateString(value) {
- return (/\S/.test(value)
- );
- },
- priority: 512
- },
- type: {
- validateString: function validateString(value, type) {
- var _ref = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
- var _ref$step = _ref.step;
- var step = _ref$step === undefined ? '1' : _ref$step;
- var _ref$base = _ref.base;
- var base = _ref$base === undefined ? 0 : _ref$base;
- var regex = typeRegexes[type];
- if (!regex) {
- throw new Error('validator type `' + type + '` is not supported');
- }
- if (!regex.test(value)) return false;
- if ('number' === type) {
- if (!/^any$/i.test(step || '')) {
- var nb = Number(value);
- var decimals = Math.max(decimalPlaces(step), decimalPlaces(base));
- if (decimalPlaces(nb) > decimals) // Value can't have too many decimals
- return false;
- // Be careful of rounding errors by using integers.
- var toInt = function toInt(f) {
- return Math.round(f * Math.pow(10, decimals));
- };
- if ((toInt(nb) - toInt(base)) % toInt(step) != 0) return false;
- }
- }
- return true;
- },
- requirementType: {
- '': 'string',
- step: 'string',
- base: 'number'
- },
- priority: 256
- },
- pattern: {
- validateString: function validateString(value, regexp) {
- return regexp.test(value);
- },
- requirementType: 'regexp',
- priority: 64
- },
- minlength: {
- validateString: function validateString(value, requirement) {
- return value.length >= requirement;
- },
- requirementType: 'integer',
- priority: 30
- },
- maxlength: {
- validateString: function validateString(value, requirement) {
- return value.length <= requirement;
- },
- requirementType: 'integer',
- priority: 30
- },
- length: {
- validateString: function validateString(value, min, max) {
- return value.length >= min && value.length <= max;
- },
- requirementType: ['integer', 'integer'],
- priority: 30
- },
- mincheck: {
- validateMultiple: function validateMultiple(values, requirement) {
- return values.length >= requirement;
- },
- requirementType: 'integer',
- priority: 30
- },
- maxcheck: {
- validateMultiple: function validateMultiple(values, requirement) {
- return values.length <= requirement;
- },
- requirementType: 'integer',
- priority: 30
- },
- check: {
- validateMultiple: function validateMultiple(values, min, max) {
- return values.length >= min && values.length <= max;
- },
- requirementType: ['integer', 'integer'],
- priority: 30
- },
- min: {
- validateNumber: function validateNumber(value, requirement) {
- return value >= requirement;
- },
- requirementType: 'number',
- priority: 30
- },
- max: {
- validateNumber: function validateNumber(value, requirement) {
- return value <= requirement;
- },
- requirementType: 'number',
- priority: 30
- },
- range: {
- validateNumber: function validateNumber(value, min, max) {
- return value >= min && value <= max;
- },
- requirementType: ['number', 'number'],
- priority: 30
- },
- equalto: {
- validateString: function validateString(value, refOrValue) {
- var $reference = $(refOrValue);
- if ($reference.length) return value === $reference.val();else return value === refOrValue;
- },
- priority: 256
- }
- }
- };
- var ParsleyUI = {};
- var diffResults = function diffResults(newResult, oldResult, deep) {
- var added = [];
- var kept = [];
- for (var i = 0; i < newResult.length; i++) {
- var found = false;
- for (var j = 0; j < oldResult.length; j++) if (newResult[i].assert.name === oldResult[j].assert.name) {
- found = true;
- break;
- }
- if (found) kept.push(newResult[i]);else added.push(newResult[i]);
- }
- return {
- kept: kept,
- added: added,
- removed: !deep ? diffResults(oldResult, newResult, true).added : []
- };
- };
- ParsleyUI.Form = {
- _actualizeTriggers: function _actualizeTriggers() {
- var _this = this;
- this.$element.on('submit.Parsley', function (evt) {
- _this.onSubmitValidate(evt);
- });
- this.$element.on('click.Parsley', 'input[type="submit"], button[type="submit"]', function (evt) {
- _this.onSubmitButton(evt);
- });
- // UI could be disabled
- if (false === this.options.uiEnabled) return;
- this.$element.attr('novalidate', '');
- },
- focus: function focus() {
- this._focusedField = null;
- if (true === this.validationResult || 'none' === this.options.focus) return null;
- for (var i = 0; i < this.fields.length; i++) {
- var field = this.fields[i];
- if (true !== field.validationResult && field.validationResult.length > 0 && 'undefined' === typeof field.options.noFocus) {
- this._focusedField = field.$element;
- if ('first' === this.options.focus) break;
- }
- }
- if (null === this._focusedField) return null;
- return this._focusedField.focus();
- },
- _destroyUI: function _destroyUI() {
- // Reset all event listeners
- this.$element.off('.Parsley');
- }
- };
- ParsleyUI.Field = {
- _reflowUI: function _reflowUI() {
- this._buildUI();
- // If this field doesn't have an active UI don't bother doing something
- if (!this._ui) return;
- // Diff between two validation results
- var diff = diffResults(this.validationResult, this._ui.lastValidationResult);
- // Then store current validation result for next reflow
- this._ui.lastValidationResult = this.validationResult;
- // Handle valid / invalid / none field class
- this._manageStatusClass();
- // Add, remove, updated errors messages
- this._manageErrorsMessages(diff);
- // Triggers impl
- this._actualizeTriggers();
- // If field is not valid for the first time, bind keyup trigger to ease UX and quickly inform user
- if ((diff.kept.length || diff.added.length) && !this._failedOnce) {
- this._failedOnce = true;
- this._actualizeTriggers();
- }
- },
- // Returns an array of field's error message(s)
- getErrorsMessages: function getErrorsMessages() {
- // No error message, field is valid
- if (true === this.validationResult) return [];
- var messages = [];
- for (var i = 0; i < this.validationResult.length; i++) messages.push(this.validationResult[i].errorMessage || this._getErrorMessage(this.validationResult[i].assert));
- return messages;
- },
- // It's a goal of Parsley that this method is no longer required [#1073]
- addError: function addError(name) {
- var _ref2 = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
- var message = _ref2.message;
- var assert = _ref2.assert;
- var _ref2$updateClass = _ref2.updateClass;
- var updateClass = _ref2$updateClass === undefined ? true : _ref2$updateClass;
- this._buildUI();
- this._addError(name, { message: message, assert: assert });
- if (updateClass) this._errorClass();
- },
- // It's a goal of Parsley that this method is no longer required [#1073]
- updateError: function updateError(name) {
- var _ref3 = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
- var message = _ref3.message;
- var assert = _ref3.assert;
- var _ref3$updateClass = _ref3.updateClass;
- var updateClass = _ref3$updateClass === undefined ? true : _ref3$updateClass;
- this._buildUI();
- this._updateError(name, { message: message, assert: assert });
- if (updateClass) this._errorClass();
- },
- // It's a goal of Parsley that this method is no longer required [#1073]
- removeError: function removeError(name) {
- var _ref4 = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
- var _ref4$updateClass = _ref4.updateClass;
- var updateClass = _ref4$updateClass === undefined ? true : _ref4$updateClass;
- this._buildUI();
- this._removeError(name);
- // edge case possible here: remove a standard Parsley error that is still failing in this.validationResult
- // but highly improbable cuz' manually removing a well Parsley handled error makes no sense.
- if (updateClass) this._manageStatusClass();
- },
- _manageStatusClass: function _manageStatusClass() {
- if (this.hasConstraints() && this.needsValidation() && true === this.validationResult) this._successClass();else if (this.validationResult.length > 0) this._errorClass();else this._resetClass();
- },
- _manageErrorsMessages: function _manageErrorsMessages(diff) {
- if ('undefined' !== typeof this.options.errorsMessagesDisabled) return;
- // Case where we have errorMessage option that configure an unique field error message, regardless failing validators
- if ('undefined' !== typeof this.options.errorMessage) {
- if (diff.added.length || diff.kept.length) {
- this._insertErrorWrapper();
- if (0 === this._ui.$errorsWrapper.find('.parsley-custom-error-message').length) this._ui.$errorsWrapper.append($(this.options.errorTemplate).addClass('parsley-custom-error-message'));
- return this._ui.$errorsWrapper.addClass('filled').find('.parsley-custom-error-message').html(this.options.errorMessage);
- }
- return this._ui.$errorsWrapper.removeClass('filled').find('.parsley-custom-error-message').remove();
- }
- // Show, hide, update failing constraints messages
- for (var i = 0; i < diff.removed.length; i++) this._removeError(diff.removed[i].assert.name);
- for (i = 0; i < diff.added.length; i++) this._addError(diff.added[i].assert.name, { message: diff.added[i].errorMessage, assert: diff.added[i].assert });
- for (i = 0; i < diff.kept.length; i++) this._updateError(diff.kept[i].assert.name, { message: diff.kept[i].errorMessage, assert: diff.kept[i].assert });
- },
- _addError: function _addError(name, _ref5) {
- var message = _ref5.message;
- var assert = _ref5.assert;
- this._insertErrorWrapper();
- this._ui.$errorsWrapper.addClass('filled').append($(this.options.errorTemplate).addClass('parsley-' + name).html(message || this._getErrorMessage(assert)));
- },
- _updateError: function _updateError(name, _ref6) {
- var message = _ref6.message;
- var assert = _ref6.assert;
- this._ui.$errorsWrapper.addClass('filled').find('.parsley-' + name).html(message || this._getErrorMessage(assert));
- },
- _removeError: function _removeError(name) {
- this._ui.$errorsWrapper.removeClass('filled').find('.parsley-' + name).remove();
- },
- _getErrorMessage: function _getErrorMessage(constraint) {
- var customConstraintErrorMessage = constraint.name + 'Message';
- if ('undefined' !== typeof this.options[customConstraintErrorMessage]) return window.Parsley.formatMessage(this.options[customConstraintErrorMessage], constraint.requirements);
- return window.Parsley.getErrorMessage(constraint);
- },
- _buildUI: function _buildUI() {
- // UI could be already built or disabled
- if (this._ui || false === this.options.uiEnabled) return;
- var _ui = {};
- // Give field its Parsley id in DOM
- this.$element.attr(this.options.namespace + 'id', this.__id__);
- /** Generate important UI elements and store them in this **/
- // $errorClassHandler is the $element that woul have parsley-error and parsley-success classes
- _ui.$errorClassHandler = this._manageClassHandler();
- // $errorsWrapper is a div that would contain the various field errors, it will be appended into $errorsContainer
- _ui.errorsWrapperId = 'parsley-id-' + (this.options.multiple ? 'multiple-' + this.options.multiple : this.__id__);
- _ui.$errorsWrapper = $(this.options.errorsWrapper).attr('id', _ui.errorsWrapperId);
- // ValidationResult UI storage to detect what have changed bwt two validations, and update DOM accordingly
- _ui.lastValidationResult = [];
- _ui.validationInformationVisible = false;
- // Store it in this for later
- this._ui = _ui;
- },
- // Determine which element will have `parsley-error` and `parsley-success` classes
- _manageClassHandler: function _manageClassHandler() {
- // An element selector could be passed through DOM with `data-parsley-class-handler=#foo`
- if ('string' === typeof this.options.classHandler && $(this.options.classHandler).length) return $(this.options.classHandler);
- // Class handled could also be determined by function given in Parsley options
- var $handler = this.options.classHandler.call(this, this);
- // If this function returned a valid existing DOM element, go for it
- if ('undefined' !== typeof $handler && $handler.length) return $handler;
- // Otherwise, if simple element (input, texatrea, select...) it will perfectly host the classes
- if (!this.options.multiple || this.$element.is('select')) return this.$element;
- // But if multiple element (radio, checkbox), that would be their parent
- return this.$element.parent();
- },
- _insertErrorWrapper: function _insertErrorWrapper() {
- var $errorsContainer;
- // Nothing to do if already inserted
- if (0 !== this._ui.$errorsWrapper.parent().length) return this._ui.$errorsWrapper.parent();
- if ('string' === typeof this.options.errorsContainer) {
- if ($(this.options.errorsContainer).length) return $(this.options.errorsContainer).append(this._ui.$errorsWrapper);else ParsleyUtils__default.warn('The errors container `' + this.options.errorsContainer + '` does not exist in DOM');
- } else if ('function' === typeof this.options.errorsContainer) $errorsContainer = this.options.errorsContainer.call(this, this);
- if ('undefined' !== typeof $errorsContainer && $errorsContainer.length) return $errorsContainer.append(this._ui.$errorsWrapper);
- var $from = this.$element;
- if (this.options.multiple) $from = $from.parent();
- return $from.after(this._ui.$errorsWrapper);
- },
- _actualizeTriggers: function _actualizeTriggers() {
- var _this2 = this;
- var $toBind = this._findRelated();
- // Remove Parsley events already bound on this field
- $toBind.off('.Parsley');
- if (this._failedOnce) $toBind.on(ParsleyUtils__default.namespaceEvents(this.options.triggerAfterFailure, 'Parsley'), function () {
- _this2.validate();
- });else {
- $toBind.on(ParsleyUtils__default.namespaceEvents(this.options.trigger, 'Parsley'), function (event) {
- _this2._eventValidate(event);
- });
- }
- },
- _eventValidate: function _eventValidate(event) {
- // For keyup, keypress, keydown, input... events that could be a little bit obstrusive
- // do not validate if val length < min threshold on first validation. Once field have been validated once and info
- // about success or failure have been displayed, always validate with this trigger to reflect every yalidation change.
- if (/key|input/.test(event.type)) if (!(this._ui && this._ui.validationInformationVisible) && this.getValue().length <= this.options.validationThreshold) return;
- this.validate();
- },
- _resetUI: function _resetUI() {
- // Reset all event listeners
- this._failedOnce = false;
- this._actualizeTriggers();
- // Nothing to do if UI never initialized for this field
- if ('undefined' === typeof this._ui) return;
- // Reset all errors' li
- this._ui.$errorsWrapper.removeClass('filled').children().remove();
- // Reset validation class
- this._resetClass();
- // Reset validation flags and last validation result
- this._ui.lastValidationResult = [];
- this._ui.validationInformationVisible = false;
- },
- _destroyUI: function _destroyUI() {
- this._resetUI();
- if ('undefined' !== typeof this._ui) this._ui.$errorsWrapper.remove();
- delete this._ui;
- },
- _successClass: function _successClass() {
- this._ui.validationInformationVisible = true;
- this._ui.$errorClassHandler.removeClass(this.options.errorClass).addClass(this.options.successClass);
- },
- _errorClass: function _errorClass() {
- this._ui.validationInformationVisible = true;
- this._ui.$errorClassHandler.removeClass(this.options.successClass).addClass(this.options.errorClass);
- },
- _resetClass: function _resetClass() {
- this._ui.$errorClassHandler.removeClass(this.options.successClass).removeClass(this.options.errorClass);
- }
- };
- var ParsleyForm = function ParsleyForm(element, domOptions, options) {
- this.__class__ = 'ParsleyForm';
- this.__id__ = ParsleyUtils__default.generateID();
- this.$element = $(element);
- this.domOptions = domOptions;
- this.options = options;
- this.parent = window.Parsley;
- this.fields = [];
- this.validationResult = null;
- };
- var ParsleyForm__statusMapping = { pending: null, resolved: true, rejected: false };
- ParsleyForm.prototype = {
- onSubmitValidate: function onSubmitValidate(event) {
- var _this3 = this;
- // This is a Parsley generated submit event, do not validate, do not prevent, simply exit and keep normal behavior
- if (true === event.parsley) return;
- // If we didn't come here through a submit button, use the first one in the form
- var $submitSource = this._$submitSource || this.$element.find('input[type="submit"], button[type="submit"]').first();
- this._$submitSource = null;
- this.$element.find('.parsley-synthetic-submit-button').prop('disabled', true);
- if ($submitSource.is('[formnovalidate]')) return;
- var promise = this.whenValidate({ event: event });
- if ('resolved' === promise.state() && false !== this._trigger('submit')) {
- // All good, let event go through. We make this distinction because browsers
- // differ in their handling of `submit` being called from inside a submit event [#1047]
- } else {
- // Rejected or pending: cancel this submit
- event.stopImmediatePropagation();
- event.preventDefault();
- if ('pending' === promise.state()) promise.done(function () {
- _this3._submit($submitSource);
- });
- }
- },
- onSubmitButton: function onSubmitButton(event) {
- this._$submitSource = $(event.target);
- },
- // internal
- // _submit submits the form, this time without going through the validations.
- // Care must be taken to "fake" the actual submit button being clicked.
- _submit: function _submit($submitSource) {
- if (false === this._trigger('submit')) return;
- // Add submit button's data
- if ($submitSource) {
- var $synthetic = this.$element.find('.parsley-synthetic-submit-button').prop('disabled', false);
- if (0 === $synthetic.length) $synthetic = $('<input class="parsley-synthetic-submit-button" type="hidden">').appendTo(this.$element);
- $synthetic.attr({
- name: $submitSource.attr('name'),
- value: $submitSource.attr('value')
- });
- }
- this.$element.trigger($.extend($.Event('submit'), { parsley: true }));
- },
- // Performs validation on fields while triggering events.
- // @returns `true` if all validations succeeds, `false`
- // if a failure is immediately detected, or `null`
- // if dependant on a promise.
- // Consider using `whenValidate` instead.
- validate: function validate(options) {
- if (arguments.length >= 1 && !$.isPlainObject(options)) {
- ParsleyUtils__default.warnOnce('Calling validate on a parsley form without passing arguments as an object is deprecated.');
- var _arguments = _slice.call(arguments);
- var group = _arguments[0];
- var force = _arguments[1];
- var event = _arguments[2];
- options = { group: group, force: force, event: event };
- }
- return ParsleyForm__statusMapping[this.whenValidate(options).state()];
- },
- whenValidate: function whenValidate() {
- var _this4 = this;
- var _ref7 = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
- var group = _ref7.group;
- var force = _ref7.force;
- var event = _ref7.event;
- this.submitEvent = event;
- if (event) {
- this.submitEvent = $.extend({}, event, { preventDefault: function preventDefault() {
- ParsleyUtils__default.warnOnce("Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`");
- _this4.validationResult = false;
- } });
- }
- this.validationResult = true;
- // fire validate event to eventually modify things before very validation
- this._trigger('validate');
- // Refresh form DOM options and form's fields that could have changed
- this._refreshFields();
- var promises = this._withoutReactualizingFormOptions(function () {
- return $.map(_this4.fields, function (field) {
- return field.whenValidate({ force: force, group: group });
- });
- });
- var promiseBasedOnValidationResult = function promiseBasedOnValidationResult() {
- var r = $.Deferred();
- if (false === _this4.validationResult) r.reject();
- return r.resolve().promise();
- };
- return $.when.apply($, _toConsumableArray(promises)).done(function () {
- _this4._trigger('success');
- }).fail(function () {
- _this4.validationResult = false;
- _this4.focus();
- _this4._trigger('error');
- }).always(function () {
- _this4._trigger('validated');
- }).pipe(promiseBasedOnValidationResult, promiseBasedOnValidationResult);
- },
- // Iterate over refreshed fields, and stop on first failure.
- // Returns `true` if all fields are valid, `false` if a failure is detected
- // or `null` if the result depends on an unresolved promise.
- // Prefer using `whenValid` instead.
- isValid: function isValid(options) {
- if (arguments.length >= 1 && !$.isPlainObject(options)) {
- ParsleyUtils__default.warnOnce('Calling isValid on a parsley form without passing arguments as an object is deprecated.');
- var _arguments2 = _slice.call(arguments);
- var group = _arguments2[0];
- var force = _arguments2[1];
- options = { group: group, force: force };
- }
- return ParsleyForm__statusMapping[this.whenValid(options).state()];
- },
- // Iterate over refreshed fields and validate them.
- // Returns a promise.
- // A validation that immediately fails will interrupt the validations.
- whenValid: function whenValid() {
- var _this5 = this;
- var _ref8 = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
- var group = _ref8.group;
- var force = _ref8.force;
- this._refreshFields();
- var promises = this._withoutReactualizingFormOptions(function () {
- return $.map(_this5.fields, function (field) {
- return field.whenValid({ group: group, force: force });
- });
- });
- return $.when.apply($, _toConsumableArray(promises));
- },
- _refreshFields: function _refreshFields() {
- return this.actualizeOptions()._bindFields();
- },
- _bindFields: function _bindFields() {
- var _this6 = this;
- var oldFields = this.fields;
- this.fields = [];
- this.fieldsMappedById = {};
- this._withoutReactualizingFormOptions(function () {
- _this6.$element.find(_this6.options.inputs).not(_this6.options.excluded).each(function (_, element) {
- var fieldInstance = new window.Parsley.Factory(element, {}, _this6);
- // Only add valid and not excluded `ParsleyField` and `ParsleyFieldMultiple` children
- if (('ParsleyField' === fieldInstance.__class__ || 'ParsleyFieldMultiple' === fieldInstance.__class__) && true !== fieldInstance.options.excluded) if ('undefined' === typeof _this6.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__]) {
- _this6.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__] = fieldInstance;
- _this6.fields.push(fieldInstance);
- }
- });
- $(oldFields).not(_this6.fields).each(function (_, field) {
- field._trigger('reset');
- });
- });
- return this;
- },
- // Internal only.
- // Looping on a form's fields to do validation or similar
- // will trigger reactualizing options on all of them, which
- // in turn will reactualize the form's options.
- // To avoid calling actualizeOptions so many times on the form
- // for nothing, _withoutReactualizingFormOptions temporarily disables
- // the method actualizeOptions on this form while `fn` is called.
- _withoutReactualizingFormOptions: function _withoutReactualizingFormOptions(fn) {
- var oldActualizeOptions = this.actualizeOptions;
- this.actualizeOptions = function () {
- return this;
- };
- var result = fn();
- this.actualizeOptions = oldActualizeOptions;
- return result;
- },
- // Internal only.
- // Shortcut to trigger an event
- // Returns true iff event is not interrupted and default not prevented.
- _trigger: function _trigger(eventName) {
- return this.trigger('form:' + eventName);