UNPKG

node-red-contrib-knx-ultimate

Version:

Control your KNX and KNX Secure intallation via Node-Red! A bunch of KNX nodes, with integrated Philips HUE control and ETS group address importer. Easy to use and highly configurable.

1,315 lines (1,067 loc) 93.3 kB
/*! * Parsley.js * Version 2.8.1 - built Sat, Feb 3rd 2018, 2:27 pm * 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; var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })(); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 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 Utils = { // 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 (!element) return obj; attributes = element.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.hasAttribute(namespace + _checkAttr); }, setAttr: function setAttr(element, namespace, attr, value) { element.setAttribute(this.dasherize(namespace + attr), String(value)); }, getType: function getType(element) { return element.getAttribute('type') || 'text'; }, generateID: function generateID() { return '' + globalID++; }, /** Third party functions **/ deserializeValue: function deserializeValue(value) { var num; try { return value ? value == "true" || (value == "false" ? false : value == "null" ? null : !isNaN(num = Number(value)) ? num : /^[\[\{]/.test(value) ? JSON.parse(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, ''); }, parse: { date: function date(string) { var parsed = string.match(/^(\d{4,})-(\d\d)-(\d\d)$/); if (!parsed) return null; var _parsed$map = parsed.map(function (x) { return parseInt(x, 10); }); var _parsed$map2 = _slicedToArray(_parsed$map, 4); var _ = _parsed$map2[0]; var year = _parsed$map2[1]; var month = _parsed$map2[2]; var day = _parsed$map2[3]; var date = new Date(year, month - 1, day); if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) return null; return date; }, string: function string(_string) { return _string; }, integer: function integer(string) { if (isNaN(string)) return null; return parseInt(string, 10); }, number: function number(string) { if (isNaN(string)) throw null; return parseFloat(string); }, 'boolean': function _boolean(string) { return !/^\s*false\s*$/i.test(string); }, object: function object(string) { return Utils.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); } }, parseRequirement: function parseRequirement(requirementType, string) { var converter = this.parse[requirementType || 'string']; if (!converter) throw 'Unknown requirement specification: "' + requirementType + '"'; var converted = converter(string); if (converted === null) throw 'Requirement is not a ' + requirementType + ': "' + string + '"'; return converted; }, namespaceEvents: function namespaceEvents(events, namespace) { events = this.trimString(events || '').split(/\s+/); if (!events[0]) return ''; return $.map(events, function (evt) { return evt + '.' + namespace; }).join(' '); }, difference: function difference(array, remove) { // This is O(N^2), should be optimized var result = []; $.each(array, function (_, elem) { if (remove.indexOf(elem) == -1) result.push(elem); }); return result; }, // Alter-ego to native Promise.all, but for jQuery all: function all(promises) { // jQuery treats $.when() and $.when(singlePromise) differently; let's avoid that and add spurious elements return $.when.apply($, _toConsumableArray(promises).concat([42, 42])); }, // 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; }; })(), _SubmitSelector: 'input[type="submit"], button:submit' }; // 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 Defaults = { // ### 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(Field) {}, // Return the `$element` where errors will be appended // Could also be (and given directly from DOM) a valid selector like `'#div'` errorsContainer: function errorsContainer(Field) {}, // 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 Base = function Base() { this.__id__ = Utils.generateID(); }; Base.prototype = { asyncSupport: true, // Deprecated _pipeAccordingToValidationResult: function _pipeAccordingToValidationResult() { var _this = this; var pipe = function pipe() { var r = $.Deferred(); if (true !== _this.validationResult) r.reject(); return r.resolve().promise(); }; return [pipe, pipe]; }, actualizeOptions: function actualizeOptions() { Utils.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 = Utils.objectCreate(this.parent.options); this.options = Utils.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; }, asyncIsValid: function asyncIsValid(group, force) { Utils.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.querySelectorAll('[' + this.options.namespace + 'multiple="' + this.options.multiple + '"]')) : this.$element; } }; 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(Utils.trimString); if (values.length !== length) throw 'Requirement has ' + values.length + ' values when ' + length + ' are needed'; return values; }; 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 = Utils.parseRequirement(requirementSpec[key], value); extra[key] = value; } else { main = Utils.parseRequirement(requirementSpec[key], string); } } return [main, extra]; }; // A Validator needs to implement the methods `validate` and `parseRequirements` var Validator = function Validator(spec) { $.extend(true, this, spec); }; Validator.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(value, requirementFirstArg); } if (Array.isArray(value)) { if (!this.validateMultiple) throw 'Validator `' + this.name + '` does not handle multiple values'; return this.validateMultiple.apply(this, arguments); } else { var instance = arguments[arguments.length - 1]; if (this.validateDate && instance._isDateInput()) { arguments[0] = Utils.parse.date(arguments[0]); if (arguments[0] === null) return false; return this.validateDate.apply(this, arguments); } 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 Array.isArray(requirements) ? requirements : [requirements]; } var type = this.requirementType; if (Array.isArray(type)) { var values = convertArrayRequirement(requirements, type.length); for (var i = 0; i < values.length; i++) values[i] = Utils.parseRequirement(type[i], values[i]); return values; } else if ($.isPlainObject(type)) { return convertExtraOptionRequirement(type, requirements, extraOptionReader); } else { return [Utils.parseRequirement(type, requirements)]; } }, // Defaults: requirementType: 'string', priority: 2 }; var ValidatorRegistry = function ValidatorRegistry(validators, catalog) { this.__class__ = 'ValidatorRegistry'; // Default Parsley locale is en this.locale = 'en'; this.init(validators || {}, catalog || {}); }; var typeTesters = { email: /^((([a-zA-Z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-zA-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-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/, // 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, date: { test: function test(value) { return Utils.parse.date(value) !== null; } }, 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-zA-Z\\u00a1-\\uffff0-9]-*)*[a-zA-Z\\u00a1-\\uffff0-9]+)' + // domain name '(?:\\.(?:[a-zA-Z\\u00a1-\\uffff0-9]-*)*[a-zA-Z\\u00a1-\\uffff0-9]+)*' + // TLD identifier '(?:\\.(?:[a-zA-Z\\u00a1-\\uffff]{2,}))' + ")" + // port number "(?::\\d{2,5})?" + // resource path "(?:/\\S*)?" + "$") }; typeTesters.range = typeTesters.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)); }; // parseArguments('number', ['1', '2']) => [1, 2] var ValidatorRegistry__parseArguments = function ValidatorRegistry__parseArguments(type, args) { return args.map(Utils.parse[type]); }; // operatorToValidator returns a validating function for an operator function, applied to the given type var ValidatorRegistry__operatorToValidator = function ValidatorRegistry__operatorToValidator(type, operator) { return function (value) { for (var _len = arguments.length, requirementsAndInput = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { requirementsAndInput[_key - 1] = arguments[_key]; } requirementsAndInput.pop(); // Get rid of `input` argument return operator.apply(undefined, [value].concat(_toConsumableArray(ValidatorRegistry__parseArguments(type, requirementsAndInput)))); }; }; var ValidatorRegistry__comparisonOperator = function ValidatorRegistry__comparisonOperator(operator) { return { validateDate: ValidatorRegistry__operatorToValidator('date', operator), validateNumber: ValidatorRegistry__operatorToValidator('number', operator), requirementType: operator.length <= 2 ? 'string' : ['string', 'string'], // Support operators with a 1 or 2 requirement(s) priority: 30 }; }; ValidatorRegistry.prototype = { init: function init(validators, catalog) { this.catalog = catalog; // Copy prototype's validators: this.validators = _extends({}, 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]) Utils.warn('Validator "' + name + '" is already defined.');else if (Defaults.hasOwnProperty(name)) { Utils.warn('"' + name + '" is a restricted keyword and is not a valid validator name.'); return; } return this._setValidator.apply(this, arguments); }, hasValidator: function hasValidator(name) { return !!this.validators[name]; }, updateValidator: function updateValidator(name, arg1, arg2) { if (!this.validators[name]) { Utils.warn('Validator "' + name + '" is not already defined.'); return this.addValidator.apply(this, arguments); } return this._setValidator.apply(this, arguments); }, removeValidator: function removeValidator(name) { if (!this.validators[name]) Utils.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 Validator(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 ? 'any' : _ref$step; var _ref$base = _ref.base; var base = _ref$base === undefined ? 0 : _ref$base; var tester = typeTesters[type]; if (!tester) { throw new Error('validator type `' + type + '` is not supported'); } if (!tester.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: ValidatorRegistry__comparisonOperator(function (value, requirement) { return value >= requirement; }), max: ValidatorRegistry__comparisonOperator(function (value, requirement) { return value <= requirement; }), range: ValidatorRegistry__comparisonOperator(function (value, min, max) { return value >= min && value <= max; }), equalto: { validateString: function validateString(value, refOrValue) { var $reference = $(refOrValue); if ($reference.length) return value === $reference.val();else return value === refOrValue; }, priority: 256 } } }; var UI = {}; 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 : [] }; }; UI.Form = { _actualizeTriggers: function _actualizeTriggers() { var _this2 = this; this.$element.on('submit.Parsley', function (evt) { _this2.onSubmitValidate(evt); }); this.$element.on('click.Parsley', Utils._SubmitSelector, function (evt) { _this2.onSubmitButton(evt); }); // UI could be disabled if (false === this.options.uiEnabled) return; this.element.setAttribute('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'); } }; UI.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.$errorClassHandler.attr('aria-describedby', this._ui.errorsWrapperId); 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.$errorClassHandler.removeAttr('aria-describedby'); 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.setAttribute(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() { // Class handled could also be determined by function given in Parsley options 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 $handlerFunction = this.options.classHandler; // It might also be the function name of a global function if ('string' === typeof this.options.classHandler && 'function' === typeof window[this.options.classHandler]) $handlerFunction = window[this.options.classHandler]; if ('function' === typeof $handlerFunction) { var $handler = $handlerFunction.call(this, this); // If this function returned a valid existing DOM element, go for it if ('undefined' !== typeof $handler && $handler.length) return $handler; } else if ('object' === typeof $handlerFunction && $handlerFunction instanceof jQuery && $handlerFunction.length) { return $handlerFunction; } else if ($handlerFunction) { Utils.warn('The class handler `' + $handlerFunction + '` does not exist in DOM nor as a global JS function'); } return this._inputHolder(); }, _inputHolder: function _inputHolder() { // if simple element (input, texatrea, select...) it will perfectly host the classes and precede the error container if (!this.options.multiple || this.element.nodeName === 'SELECT') return this.$element; // But if multiple element (radio, checkbox), that would be their parent return this.$element.parent(); }, _insertErrorWrapper: function _insertErrorWrapper() { var $errorsContainer = this.options.errorsContainer; // Nothing to do if already inserted if (0 !== this._ui.$errorsWrapper.parent().length) return this._ui.$errorsWrapper.parent(); if ('string' === typeof $errorsContainer) { if ($($errorsContainer).length) return $($errorsContainer).append(this._ui.$errorsWrapper);else if ('function' === typeof window[$errorsContainer]) $errorsContainer = window[$errorsContainer];else Utils.warn('The errors container `' + $errorsContainer + '` does not exist in DOM nor as a global JS function'); } if ('function' === typeof $errorsContainer) $errorsContainer = $errorsContainer.call(this, this); if ('object' === typeof $errorsContainer && $errorsContainer.length) return $errorsContainer.append(this._ui.$errorsWrapper); return this._inputHolder().after(this._ui.$errorsWrapper); }, _actualizeTriggers: function _actualizeTriggers() { var _this3 = this; var $toBind = this._findRelated(); var trigger; // Remove Parsley events already bound on this field $toBind.off('.Parsley'); if (this._failedOnce) $toBind.on(Utils.namespaceEvents(this.options.triggerAfterFailure, 'Parsley'), function () { _this3._validateIfNeeded(); });else if (trigger = Utils.namespaceEvents(this.options.trigger, 'Parsley')) { $toBind.on(trigger, function (event) { _this3._validateIfNeeded(event); }); } }, _validateIfNeeded: function _validateIfNeeded(event) { var _this4 = this; // 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 (event && /key|input/.test(event.type)) if (!(this._ui && this._ui.validationInformationVisible) && this.getValue().length <= this.options.validationThreshold) return; if (this.options.debounce) { window.clearTimeout(this._debounced); this._debounced = window.setTimeout(function () { return _this4.validate(); }, this.options.debounce); } else 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 Form = function Form(element, domOptions, options) { this.__class__ = 'Form'; this.element = element; this.$element = $(element); this.domOptions = domOptions; this.options = options; this.parent = window.Parsley; this.fields = []; this.validationResult = null; }; var Form__statusMapping = { pending: null, resolved: true, rejected: false }; Form.prototype = { onSubmitValidate: function onSubmitValidate(event) { var _this5 = 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(Utils._SubmitSelector)[0]; this._submitSource = null; this.$element.find('.parsley-synthetic-submit-button').prop('disabled', true); if (submitSource && null !== submitSource.getAttribute('formnovalidate')) return; window.Parsley._remoteCache = {}; 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 () { _this5._submit(submitSource); }); } }, onSubmitButton: function onSubmitButton(event) { this._submitSource = event.currentTarget; }, // 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.getAttribute('name'), value: submitSource.getAttribute('value') }); } this.$element.trigger(_extends($.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)) { Utils.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 Form__statusMapping[this.whenValidate(options).state()]; }, whenValidate: function whenValidate() { var _Utils$all$done$fail$always, _this6 = 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 = _extends({}, event, { preventDefault: function preventDefault() { Utils.warnOnce("Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`"); _this6.validationResult = false; } }); } this.validationResult = true; // fire validate event to eventually modify things before every 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(_this6.fields, function (field) { return field.whenValidate({ force: force, group: group }); }); }); return (_Utils$all$done$fail$always = Utils.all(promises).done(function () { _this6._trigger('success'); }).fail(function () { _this6.validationResult = false; _this6.focus(); _this6._trigger('error'); }).always(function () { _this6._trigger('validated'); })).pipe.apply(_Utils$all$done$fail$always, _toConsumableArray(t