vendor: 94,951 bytes, lines 1-2471
1/*! 2* Parsley.js 3* Version 2.9.2 - built Tue, Dec 10th 2019, 6:18 pm 4* http://parsleyjs.org 5* Guillaume Potier - <[email protected]> 6* Marc-Andre Lafortune - <[email protected]> 7* MIT Licensed 8*/ 9 10// The source code below is generated by babel as 11// Parsley is written in ECMAScript 6 12// 13 14(function (global, factory) { 15 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery')) : 16 typeof define === 'function' && define.amd ? define(['jquery'], factory) : 17 (global = global || self, global.parsley = factory(global.jQuery)); 18}(this, (function ($) { 'use strict'; 19 20 function _typeof(obj) { 21 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { 22 _typeof = function (obj) { 23 return typeof obj; 24 }; 25 } else { 26 _typeof = function (obj) { 27 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; 28 }; 29 } 30 31 return _typeof(obj); 32 } 33 34 function _extends() { 35 _extends = Object.assign || function (target) { 36 for (var i = 1; i < arguments.length; i++) { 37 var source = arguments[i]; 38 39 for (var key in source) { 40 if (Object.prototype.hasOwnProperty.call(source, key)) { 41 target[key] = source[key]; 42 } 43 } 44 } 45 46 return target; 47 }; 48 49 return _extends.apply(this, arguments); 50 } 51 52 function _slicedToArray(arr, i) { 53 return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); 54 } 55 56 function _toConsumableArray(arr) { 57 return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); 58 } 59 60 function _arrayWithoutHoles(arr) { 61 if (Array.isArray(arr)) { 62 for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; 63 64 return arr2; 65 } 66 } 67 68 function _arrayWithHoles(arr) { 69 if (Array.isArray(arr)) return arr; 70 } 71 72 function _iterableToArray(iter) { 73 if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); 74 } 75 76 function _iterableToArrayLimit(arr, i) { 77 if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { 78 return; 79 } 80 81 var _arr = []; 82 var _n = true; 83 var _d = false; 84 var _e = undefined; 85 86 try { 87 for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { 88 _arr.push(_s.value); 89 90 if (i && _arr.length === i) break; 91 } 92 } catch (err) { 93 _d = true; 94 _e = err; 95 } finally { 96 try { 97 if (!_n && _i["return"] != null) _i["return"](); 98 } finally { 99 if (_d) throw _e; 100 } 101 } 102 103 return _arr; 104 } 105 106 function _nonIterableSpread() { 107 throw new TypeError("Invalid attempt to spread non-iterable instance"); 108 } 109 110 function _nonIterableRest() { 111 throw new TypeError("Invalid attempt to destructure non-iterable instance"); 112 } 113 114 var globalID = 1; 115 var pastWarnings = {}; 116 var Utils = { 117 // Parsley DOM-API 118 // returns object from dom attributes and values 119 attr: function attr(element, namespace, obj) { 120 var i; 121 var attribute; 122 var attributes; 123 var regex = new RegExp('^' + namespace, 'i'); 124 if ('undefined' === typeof obj) obj = {};else { 125 // Clear all own properties. This won't affect prototype's values 126 for (i in obj) { 127 if (obj.hasOwnProperty(i)) delete obj[i]; 128 } 129 } 130 if (!element) return obj; 131 attributes = element.attributes; 132 133 for (i = attributes.length; i--;) { 134 attribute = attributes[i]; 135 136 if (attribute && attribute.specified && regex.test(attribute.name)) { 137 obj[this.camelize(attribute.name.slice(namespace.length))] = this.deserializeValue(attribute.value); 138 } 139 } 140 141 return obj; 142 }, 143 checkAttr: function checkAttr(element, namespace, _checkAttr) { 144 return element.hasAttribute(namespace + _checkAttr); 145 }, 146 setAttr: function setAttr(element, namespace, attr, value) { 147 element.setAttribute(this.dasherize(namespace + attr), String(value)); 148 }, 149 getType: function getType(element) { 150 return element.getAttribute('type') || 'text'; 151 }, 152 generateID: function generateID() { 153 return '' + globalID++; 154 }, 155 156 /** Third party functions **/ 157 deserializeValue: function deserializeValue(value) { 158 var num; 159 160 try { 161 return value ? value == "true" || (value == "false" ? false : value == "null" ? null : !isNaN(num = Number(value)) ? num : /^[\[\{]/.test(value) ? JSON.parse(value) : value) : value; 162 } catch (e) { 163 return value; 164 } 165 }, 166 // Zepto camelize function 167 camelize: function camelize(str) { 168 return str.replace(/-+(.)?/g, function (match, chr) { 169 return chr ? chr.toUpperCase() : ''; 170 }); 171 }, 172 // Zepto dasherize function 173 dasherize: function dasherize(str) { 174 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(); 175 }, 176 warn: function warn() { 177 var _window$console; 178 179 if (window.console && 'function' === typeof window.console.warn) (_window$console = window.console).warn.apply(_window$console, arguments); 180 }, 181 warnOnce: function warnOnce(msg) { 182 if (!pastWarnings[msg]) { 183 pastWarnings[msg] = true; 184 this.warn.apply(this, arguments); 185 } 186 }, 187 _resetWarnings: function _resetWarnings() { 188 pastWarnings = {}; 189 }, 190 trimString: function trimString(string) { 191 return string.replace(/^\s+|\s+$/g, ''); 192 }, 193 parse: { 194 date: function date(string) { 195 var parsed = string.match(/^(\d{4,})-(\d\d)-(\d\d)$/); 196 if (!parsed) return null; 197 198 var _parsed$map = parsed.map(function (x) { 199 return parseInt(x, 10); 200 }), 201 _parsed$map2 = _slicedToArray(_parsed$map, 4), 202 _ = _parsed$map2[0], 203 year = _parsed$map2[1], 204 month = _parsed$map2[2], 205 day = _parsed$map2[3]; 206 207 var date = new Date(year, month - 1, day); 208 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) return null; 209 return date; 210 }, 211 string: function string(_string) { 212 return _string; 213 }, 214 integer: function integer(string) { 215 if (isNaN(string)) return null; 216 return parseInt(string, 10); 217 }, 218 number: function number(string) { 219 if (isNaN(string)) throw null; 220 return parseFloat(string); 221 }, 222 'boolean': function _boolean(string) { 223 return !/^\s*false\s*$/i.test(string); 224 }, 225 object: function object(string) { 226 return Utils.deserializeValue(string); 227 }, 228 regexp: function regexp(_regexp) { 229 var flags = ''; // Test if RegExp is literal, if not, nothing to be done, otherwise, we need to isolate flags and pattern 230 231 if (/^\/.*\/(?:[gimy]*)$/.test(_regexp)) { 232 // Replace the regexp literal string with the first match group: ([gimy]*) 233 // If no flag is present, this will be a blank string 234 flags = _regexp.replace(/.*\/([gimy]*)$/, '$1'); // Again, replace the regexp literal string with the first match group: 235 // everything excluding the opening and closing slashes and the flags 236 237 _regexp = _regexp.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1'); 238 } else { 239 // Anchor regexp: 240 _regexp = '^' + _regexp + '$'; 241 } 242 243 return new RegExp(_regexp, flags); 244 } 245 }, 246 parseRequirement: function parseRequirement(requirementType, string) { 247 var converter = this.parse[requirementType || 'string']; 248 if (!converter) throw 'Unknown requirement specification: "' + requirementType + '"'; 249 var converted = converter(string); 250 if (converted === null) throw "Requirement is not a ".concat(requirementType, ": \"").concat(string, "\""); 251 return converted; 252 }, 253 namespaceEvents: function namespaceEvents(events, namespace) { 254 events = this.trimString(events || '').split(/\s+/); 255 if (!events[0]) return ''; 256 return $.map(events, function (evt) { 257 return "".concat(evt, ".").concat(namespace); 258 }).join(' '); 259 }, 260 difference: function difference(array, remove) { 261 // This is O(N^2), should be optimized 262 var result = []; 263 $.each(array, function (_, elem) { 264 if (remove.indexOf(elem) == -1) result.push(elem); 265 }); 266 return result; 267 }, 268 // Alter-ego to native Promise.all, but for jQuery 269 all: function all(promises) { 270 // jQuery treats $.when() and $.when(singlePromise) differently; let's avoid that and add spurious elements 271 return $.when.apply($, _toConsumableArray(promises).concat([42, 42])); 272 }, 273 // Object.create polyfill, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Polyfill 274 objectCreate: Object.create || function () { 275 var Object = function Object() {}; 276 277 return function (prototype) { 278 if (arguments.length > 1) { 279 throw Error('Second argument not supported'); 280 } 281 282 if (_typeof(prototype) != 'object') { 283 throw TypeError('Argument must be an object'); 284 } 285 286 Object.prototype = prototype; 287 var result = new Object(); 288 Object.prototype = null; 289 return result; 290 }; 291 }(), 292 _SubmitSelector: 'input[type="submit"], button:submit' 293 }; 294 295 // All these options could be overriden and specified directly in DOM using 296 // `data-parsley-` default DOM-API 297 // eg: `inputs` can be set in DOM using `data-parsley-inputs="input, textarea"` 298 // eg: `data-parsley-stop-on-first-failing-constraint="false"` 299 var Defaults = { 300 // ### General 301 // Default data-namespace for DOM API 302 namespace: 'data-parsley-', 303 // Supported inputs by default 304 inputs: 'input, textarea, select', 305 // Excluded inputs by default 306 excluded: 'input[type=button], input[type=submit], input[type=reset], input[type=hidden]', 307 // Stop validating field on highest priority failing constraint 308 priorityEnabled: true, 309 // ### Field only 310 // identifier used to group together inputs (e.g. radio buttons...) 311 multiple: null, 312 // identifier (or array of identifiers) used to validate only a select group of inputs 313 group: null, 314 // ### UI 315 // Enable\Disable error messages 316 uiEnabled: true, 317 // Key events threshold before validation 318 validationThreshold: 3, 319 // Focused field on form validation error. 'first'|'last'|'none' 320 focus: 'first', 321 // event(s) that will trigger validation before first failure. eg: `input`... 322 trigger: false, 323 // event(s) that will trigger validation after first failure. 324 triggerAfterFailure: 'input', 325 // Class that would be added on every failing validation Parsley field 326 errorClass: 'parsley-error', 327 // Same for success validation 328 successClass: 'parsley-success', 329 // Return the `$element` that will receive these above success or error classes 330 // Could also be (and given directly from DOM) a valid selector like `'#div'` 331 classHandler: function classHandler(Field) {}, 332 // Return the `$element` where errors will be appended 333 // Could also be (and given directly from DOM) a valid selector like `'#div'` 334 errorsContainer: function errorsContainer(Field) {}, 335 // ul elem that would receive errors' list 336 errorsWrapper: '<ul class="parsley-errors-list"></ul>', 337 // li elem that would receive error message 338 errorTemplate: '<li></li>' 339 }; 340 341 var Base = function Base() { 342 this.__id__ = Utils.generateID(); 343 }; 344 345 Base.prototype = { 346 asyncSupport: true, 347 // Deprecated 348 _pipeAccordingToValidationResult: function _pipeAccordingToValidationResult() { 349 var _this = this; 350 351 var pipe = function pipe() { 352 var r = $.Deferred(); 353 if (true !== _this.validationResult) r.reject(); 354 return r.resolve().promise(); 355 }; 356 357 return [pipe, pipe]; 358 }, 359 actualizeOptions: function actualizeOptions() { 360 Utils.attr(this.element, this.options.namespace, this.domOptions); 361 if (this.parent && this.parent.actualizeOptions) this.parent.actualizeOptions(); 362 return this; 363 }, 364 _resetOptions: function _resetOptions(initOptions) { 365 this.domOptions = Utils.objectCreate(this.parent.options); 366 this.options = Utils.objectCreate(this.domOptions); // Shallow copy of ownProperties of initOptions: 367 368 for (var i in initOptions) { 369 if (initOptions.hasOwnProperty(i)) this.options[i] = initOptions[i]; 370 } 371 372 this.actualizeOptions(); 373 }, 374 _listeners: null, 375 // Register a callback for the given event name 376 // Callback is called with context as the first argument and the `this` 377 // The context is the current parsley instance, or window.Parsley if global 378 // A return value of `false` will interrupt the calls 379 on: function on(name, fn) { 380 this._listeners = this._listeners || {}; 381 var queue = this._listeners[name] = this._listeners[name] || []; 382 queue.push(fn); 383 return this; 384 }, 385 // Deprecated. Use `on` instead 386 subscribe: function subscribe(name, fn) { 387 $.listenTo(this, name.toLowerCase(), fn); 388 }, 389 // Unregister a callback (or all if none is given) for the given event name 390 off: function off(name, fn) { 391 var queue = this._listeners && this._listeners[name]; 392 393 if (queue) { 394 if (!fn) { 395 delete this._listeners[name]; 396 } else { 397 for (var i = queue.length; i--;) { 398 if (queue[i] === fn) queue.splice(i, 1); 399 } 400 } 401 } 402 403 return this; 404 }, 405 // Deprecated. Use `off` 406 unsubscribe: function unsubscribe(name, fn) { 407 $.unsubscribeTo(this, name.toLowerCase()); 408 }, 409 // Trigger an event of the given name 410 // A return value of `false` interrupts the callback chain 411 // Returns false if execution was interrupted 412 trigger: function trigger(name, target, extraArg) { 413 target = target || this; 414 var queue = this._listeners && this._listeners[name]; 415 var result; 416 417 if (queue) { 418 for (var i = queue.length; i--;) { 419 result = queue[i].call(target, target, extraArg); 420 if (result === false) return result; 421 } 422 } 423 424 if (this.parent) { 425 return this.parent.trigger(name, target, extraArg); 426 } 427 428 return true; 429 }, 430 asyncIsValid: function asyncIsValid(group, force) { 431 Utils.warnOnce("asyncIsValid is deprecated; please use whenValid instead"); 432 return this.whenValid({ 433 group: group, 434 force: force 435 }); 436 }, 437 _findRelated: function _findRelated() { 438 return this.options.multiple ? $(this.parent.element.querySelectorAll("[".concat(this.options.namespace, "multiple=\"").concat(this.options.multiple, "\"]"))) : this.$element; 439 } 440 }; 441 442 var convertArrayRequirement = function convertArrayRequirement(string, length) { 443 var m = string.match(/^\s*\[(.*)\]\s*$/); 444 if (!m) throw 'Requirement is not an array: "' + string + '"'; 445 var values = m[1].split(',').map(Utils.trimString); 446 if (values.length !== length) throw 'Requirement has ' + values.length + ' values when ' + length + ' are needed'; 447 return values; 448 }; 449 450 var convertExtraOptionRequirement = function convertExtraOptionRequirement(requirementSpec, string, extraOptionReader) { 451 var main = null; 452 var extra = {}; 453 454 for (var key in requirementSpec) { 455 if (key) { 456 var value = extraOptionReader(key); 457 if ('string' === typeof value) value = Utils.parseRequirement(requirementSpec[key], value); 458 extra[key] = value; 459 } else { 460 main = Utils.parseRequirement(requirementSpec[key], string); 461 } 462 } 463 464 return [main, extra]; 465 }; // A Validator needs to implement the methods `validate` and `parseRequirements` 466 467 468 var Validator = function Validator(spec) { 469 $.extend(true, this, spec); 470 }; 471 472 Validator.prototype = { 473 // Returns `true` iff the given `value` is valid according the given requirements. 474 validate: function validate(value, requirementFirstArg) { 475 if (this.fn) { 476 // Legacy style validator 477 if (arguments.length > 3) // If more args then value, requirement, instance... 478 requirementFirstArg = [].slice.call(arguments, 1, -1); // Skip first arg (value) and last (instance), combining the rest 479 480 return this.fn(value, requirementFirstArg); 481 } 482 483 if (Array.isArray(value)) { 484 if (!this.validateMultiple) throw 'Validator `' + this.name + '` does not handle multiple values'; 485 return this.validateMultiple.apply(this, arguments); 486 } else { 487 var instance = arguments[arguments.length - 1]; 488 489 if (this.validateDate && instance._isDateInput()) { 490 arguments[0] = Utils.parse.date(arguments[0]); 491 if (arguments[0] === null) return false; 492 return this.validateDate.apply(this, arguments); 493 } 494 495 if (this.validateNumber) { 496 if (!value) // Builtin validators all accept empty strings, except `required` of course 497 return true; 498 if (isNaN(value)) return false; 499 arguments[0] = parseFloat(arguments[0]); 500 return this.validateNumber.apply(this, arguments); 501 } 502 503 if (this.validateString) { 504 return this.validateString.apply(this, arguments); 505 } 506 507 throw 'Validator `' + this.name + '` only handles multiple values'; 508 } 509 }, 510 // Parses `requirements` into an array of arguments, 511 // according to `this.requirementType` 512 parseRequirements: function parseRequirements(requirements, extraOptionReader) { 513 if ('string' !== typeof requirements) { 514 // Assume requirement already parsed 515 // but make sure we return an array 516 return Array.isArray(requirements) ? requirements : [requirements]; 517 } 518 519 var type = this.requirementType; 520 521 if (Array.isArray(type)) { 522 var values = convertArrayRequirement(requirements, type.length); 523 524 for (var i = 0; i < values.length; i++) { 525 values[i] = Utils.parseRequirement(type[i], values[i]); 526 } 527 528 return values; 529 } else if ($.isPlainObject(type)) { 530 return convertExtraOptionRequirement(type, requirements, extraOptionReader); 531 } else { 532 return [Utils.parseRequirement(type, requirements)]; 533 } 534 }, 535 // Defaults: 536 requirementType: 'string', 537 priority: 2 538 }; 539 540 var ValidatorRegistry = function ValidatorRegistry(validators, catalog) { 541 this.__class__ = 'ValidatorRegistry'; // Default Parsley locale is en 542 543 this.locale = 'en'; 544 this.init(validators || {}, catalog || {}); 545 }; 546 547 var typeTesters = { 548 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]|\d|-|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))$/, 549 // Follow https://www.w3.org/TR/html5/infrastructure.html#floating-point-numbers 550 number: /^-?(\d*\.)?\d+(e[-+]?\d+)?$/i, 551 integer: /^-?\d+$/, 552 digits: /^\d+$/, 553 alphanum: /^\w+$/i, 554 date: { 555 test: function test(value) { 556 return Utils.parse.date(value) !== null; 557 } 558 }, 559 url: new RegExp("^" + // protocol identifier 560 "(?:(?:https?|ftp)://)?" + // ** mod: make scheme optional 561 // user:pass authentication 562 "(?:\\S+(?::\\S*)?@)?" + "(?:" + // IP address exclusion 563 // private & local networks 564 // "(?!(?:10|127)(?:\\.\\d{1,3}){3})" + // ** mod: allow local networks 565 // "(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})" + // ** mod: allow local networks 566 // "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" + // ** mod: allow local networks 567 // IP address dotted notation octets 568 // excludes loopback network 0.0.0.0 569 // excludes reserved space >= 224.0.0.0 570 // excludes network & broacast addresses 571 // (first & last IP address of each class) 572 "(?:[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 573 "(?:(?:[a-zA-Z\\u00a1-\\uffff0-9]-*)*[a-zA-Z\\u00a1-\\uffff0-9]+)" + // domain name 574 "(?:\\.(?:[a-zA-Z\\u00a1-\\uffff0-9]-*)*[a-zA-Z\\u00a1-\\uffff0-9]+)*" + // TLD identifier 575 "(?:\\.(?:[a-zA-Z\\u00a1-\\uffff]{2,}))" + ")" + // port number 576 "(?::\\d{2,5})?" + // resource path 577 "(?:/\\S*)?" + "$") 578 }; 579 typeTesters.range = typeTesters.number; // See http://stackoverflow.com/a/10454560/8279 580 581 var decimalPlaces = function decimalPlaces(num) { 582 var match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/); 583 584 if (!match) { 585 return 0; 586 } 587 588 return Math.max(0, // Number of digits right of decimal point. 589 (match[1] ? match[1].length : 0) - ( // Adjust for scientific notation. 590 match[2] ? +match[2] : 0)); 591 }; // parseArguments('number', ['1', '2']) => [1, 2] 592 593 594 var parseArguments = function parseArguments(type, args) { 595 return args.map(Utils.parse[type]); 596 }; // operatorToValidator returns a validating function for an operator function, applied to the given type 597 598 599 var operatorToValidator = function operatorToValidator(type, operator) { 600 return function (value) { 601 for (var _len = arguments.length, requirementsAndInput = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 602 requirementsAndInput[_key - 1] = arguments[_key]; 603 } 604 605 requirementsAndInput.pop(); // Get rid of `input` argument 606 607 return operator.apply(void 0, [value].concat(_toConsumableArray(parseArguments(type, requirementsAndInput)))); 608 }; 609 }; 610 611 var comparisonOperator = function comparisonOperator(operator) { 612 return { 613 validateDate: operatorToValidator('date', operator), 614 validateNumber: operatorToValidator('number', operator), 615 requirementType: operator.length <= 2 ? 'string' : ['string', 'string'], 616 // Support operators with a 1 or 2 requirement(s) 617 priority: 30 618 }; 619 }; 620 621 ValidatorRegistry.prototype = { 622 init: function init(validators, catalog) { 623 this.catalog = catalog; // Copy prototype's validators: 624 625 this.validators = _extends({}, this.validators); 626 627 for (var name in validators) { 628 this.addValidator(name, validators[name].fn, validators[name].priority); 629 } 630 631 window.Parsley.trigger('parsley:validator:init'); 632 }, 633 // Set new messages locale if we have dictionary loaded in ParsleyConfig.i18n 634 setLocale: function setLocale(locale) { 635 if ('undefined' === typeof this.catalog[locale]) throw new Error(locale + ' is not available in the catalog'); 636 this.locale = locale; 637 return this; 638 }, 639 // Add a new messages catalog for a given locale. Set locale for this catalog if set === `true` 640 addCatalog: function addCatalog(locale, messages, set) { 641 if ('object' === _typeof(messages)) this.catalog[locale] = messages; 642 if (true === set) return this.setLocale(locale); 643 return this; 644 }, 645 // Add a specific message for a given constraint in a given locale 646 addMessage: function addMessage(locale, name, message) { 647 if ('undefined' === typeof this.catalog[locale]) this.catalog[locale] = {}; 648 this.catalog[locale][name] = message; 649 return this; 650 }, 651 // Add messages for a given locale 652 addMessages: function addMessages(locale, nameMessageObject) { 653 for (var name in nameMessageObject) { 654 this.addMessage(locale, name, nameMessageObject[name]); 655 } 656 657 return this; 658 }, 659 // Add a new validator 660 // 661 // addValidator('custom', { 662 // requirementType: ['integer', 'integer'], 663 // validateString: function(value, from, to) {}, 664 // priority: 22, 665 // messages: { 666 // en: "Hey, that's no good", 667 // fr: "Aye aye, pas bon du tout", 668 // } 669 // }) 670 // 671 // Old API was addValidator(name, function, priority) 672 // 673 addValidator: function addValidator(name, arg1, arg2) { 674 if (this.validators[name]) Utils.warn('Validator "' + name + '" is already defined.');else if (Defaults.hasOwnProperty(name)) { 675 Utils.warn('"' + name + '" is a restricted keyword and is not a valid validator name.'); 676 return; 677 } 678 return this._setValidator.apply(this, arguments); 679 }, 680 hasValidator: function hasValidator(name) { 681 return !!this.validators[name]; 682 }, 683 updateValidator: function updateValidator(name, arg1, arg2) { 684 if (!this.validators[name]) { 685 Utils.warn('Validator "' + name + '" is not already defined.'); 686 return this.addValidator.apply(this, arguments); 687 } 688 689 return this._setValidator.apply(this, arguments); 690 }, 691 removeValidator: function removeValidator(name) { 692 if (!this.validators[name]) Utils.warn('Validator "' + name + '" is not defined.'); 693 delete this.validators[name]; 694 return this; 695 }, 696 _setValidator: function _setValidator(name, validator, priority) { 697 if ('object' !== _typeof(validator)) { 698 // Old style validator, with `fn` and `priority` 699 validator = { 700 fn: validator, 701 priority: priority 702 }; 703 } 704 705 if (!validator.validate) { 706 validator = new Validator(validator); 707 } 708 709 this.validators[name] = validator; 710 711 for (var locale in validator.messages || {}) { 712 this.addMessage(locale, name, validator.messages[locale]); 713 } 714 715 return this; 716 }, 717 getErrorMessage: function getErrorMessage(constraint) { 718 var message; // Type constraints are a bit different, we have to match their requirements too to find right error message 719 720 if ('type' === constraint.name) { 721 var typeMessages = this.catalog[this.locale][constraint.name] || {}; 722 message = typeMessages[constraint.requirements]; 723 } else message = this.formatMessage(this.catalog[this.locale][constraint.name], constraint.requirements); 724 725 return message || this.catalog[this.locale].defaultMessage || this.catalog.en.defaultMessage; 726 }, 727 // Kind of light `sprintf()` implementation 728 formatMessage: function formatMessage(string, parameters) { 729 if ('object' === _typeof(parameters)) { 730 for (var i in parameters) { 731 string = this.formatMessage(string, parameters[i]); 732 } 733 734 return string; 735 } 736 737 return 'string' === typeof string ? string.replace(/%s/i, parameters) : ''; 738 }, 739 // Here is the Parsley default validators list. 740 // A validator is an object with the following key values: 741 // - priority: an integer 742 // - requirement: 'string' (default), 'integer', 'number', 'regexp' or an Array of these 743 // - validateString, validateMultiple, validateNumber: functions returning `true`, `false` or a promise 744 // Alternatively, a validator can be a function that returns such an object 745 // 746 validators: { 747 notblank: { 748 validateString: function validateString(value) { 749 return /\S/.test(value); 750 }, 751 priority: 2 752 }, 753 required: { 754 validateMultiple: function validateMultiple(values) { 755 return values.length > 0; 756 }, 757 validateString: function validateString(value) { 758 return /\S/.test(value); 759 }, 760 priority: 512 761 }, 762 type: { 763 validateString: function validateString(value, type) { 764 var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, 765 _ref$step = _ref.step, 766 step = _ref$step === void 0 ? 'any' : _ref$step, 767 _ref$base = _ref.base, 768 base = _ref$base === void 0 ? 0 : _ref$base; 769 770 var tester = typeTesters[type]; 771 772 if (!tester) { 773 throw new Error('validator type `' + type + '` is not supported'); 774 } 775 776 if (!value) return true; // Builtin validators all accept empty strings, except `required` of course 777 778 if (!tester.test(value)) return false; 779 780 if ('number' === type) { 781 if (!/^any$/i.test(step || '')) { 782 var nb = Number(value); 783 var decimals = Math.max(decimalPlaces(step), decimalPlaces(base)); 784 if (decimalPlaces(nb) > decimals) // Value can't have too many decimals 785 return false; // Be careful of rounding errors by using integers. 786 787 var toInt = function toInt(f) { 788 return Math.round(f * Math.pow(10, decimals)); 789 }; 790 791 if ((toInt(nb) - toInt(base)) % toInt(step) != 0) return false; 792 } 793 } 794 795 return true; 796 }, 797 requirementType: { 798 '': 'string', 799 step: 'string', 800 base: 'number' 801 }, 802 priority: 256 803 }, 804 pattern: { 805 validateString: function validateString(value, regexp) { 806 if (!value) return true; // Builtin validators all accept empty strings, except `required` of course 807 808 return regexp.test(value); 809 }, 810 requirementType: 'regexp', 811 priority: 64 812 }, 813 minlength: { 814 validateString: function validateString(value, requirement) { 815 if (!value) return true; // Builtin validators all accept empty strings, except `required` of course 816 817 return value.length >= requirement; 818 }, 819 requirementType: 'integer', 820 priority: 30 821 }, 822 maxlength: { 823 validateString: function validateString(value, requirement) { 824 return value.length <= requirement; 825 }, 826 requirementType: 'integer', 827 priority: 30 828 }, 829 length: { 830 validateString: function validateString(value, min, max) { 831 if (!value) return true; // Builtin validators all accept empty strings, except `required` of course 832 833 return value.length >= min && value.length <= max; 834 }, 835 requirementType: ['integer', 'integer'], 836 priority: 30 837 }, 838 mincheck: { 839 validateMultiple: function validateMultiple(values, requirement) { 840 return values.length >= requirement; 841 }, 842 requirementType: 'integer', 843 priority: 30 844 }, 845 maxcheck: { 846 validateMultiple: function validateMultiple(values, requirement) { 847 return values.length <= requirement; 848 }, 849 requirementType: 'integer', 850 priority: 30 851 }, 852 check: { 853 validateMultiple: function validateMultiple(values, min, max) { 854 return values.length >= min && values.length <= max; 855 }, 856 requirementType: ['integer', 'integer'], 857 priority: 30 858 }, 859 min: comparisonOperator(function (value, requirement) { 860 return value >= requirement; 861 }), 862 max: comparisonOperator(function (value, requirement) { 863 return value <= requirement; 864 }), 865 range: comparisonOperator(function (value, min, max) { 866 return value >= min && value <= max; 867 }), 868 equalto: { 869 validateString: function validateString(value, refOrValue) { 870 if (!value) return true; // Builtin validators all accept empty strings, except `required` of course 871 872 var $reference = $(refOrValue); 873 if ($reference.length) return value === $reference.val();else return value === refOrValue; 874 }, 875 priority: 256 876 }, 877 euvatin: { 878 validateString: function validateString(value, refOrValue) { 879 if (!value) { 880 return true; // Builtin validators all accept empty strings, except `required` of course 881 } 882 883 var re = /^[A-Z][A-Z][A-Za-z0-9 -]{2,}$/; 884 return re.test(value); 885 }, 886 priority: 30 887 } 888 } 889 }; 890 891 var UI = {}; 892 893 var diffResults = function diffResults(newResult, oldResult, deep) { 894 var added = []; 895 var kept = []; 896 897 for (var i = 0; i < newResult.length; i++) { 898 var found = false; 899 900 for (var j = 0; j < oldResult.length; j++) { 901 if (newResult[i].assert.name === oldResult[j].assert.name) { 902 found = true; 903 break; 904 } 905 } 906 907 if (found) kept.push(newResult[i]);else added.push(newResult[i]); 908 } 909 910 return { 911 kept: kept, 912 added: added, 913 removed: !deep ? diffResults(oldResult, newResult, true).added : [] 914 }; 915 }; 916 917 UI.Form = { 918 _actualizeTriggers: function _actualizeTriggers() { 919 var _this = this; 920 921 this.$element.on('submit.Parsley', function (evt) { 922 _this.onSubmitValidate(evt); 923 }); 924 this.$element.on('click.Parsley', Utils._SubmitSelector, function (evt) { 925 _this.onSubmitButton(evt); 926 }); // UI could be disabled 927 928 if (false === this.options.uiEnabled) return; 929 this.element.setAttribute('novalidate', ''); 930 }, 931 focus: function focus() { 932 this._focusedField = null; 933 if (true === this.validationResult || 'none' === this.options.focus) return null; 934 935 for (var i = 0; i < this.fields.length; i++) { 936 var field = this.fields[i]; 937 938 if (true !== field.validationResult && field.validationResult.length > 0 && 'undefined' === typeof field.options.noFocus) { 939 this._focusedField = field.$element; 940 if ('first' === this.options.focus) break; 941 } 942 } 943 944 if (null === this._focusedField) return null; 945 return this._focusedField.focus(); 946 }, 947 _destroyUI: function _destroyUI() { 948 // Reset all event listeners 949 this.$element.off('.Parsley'); 950 } 951 }; 952 UI.Field = { 953 _reflowUI: function _reflowUI() { 954 this._buildUI(); // If this field doesn't have an active UI don't bother doing something 955 956 957 if (!this._ui) return; // Diff between two validation results 958 959 var diff = diffResults(this.validationResult, this._ui.lastValidationResult); // Then store current validation result for next reflow 960 961 this._ui.lastValidationResult = this.validationResult; // Handle valid / invalid / none field class 962 963 this._manageStatusClass(); // Add, remove, updated errors messages 964 965 966 this._manageErrorsMessages(diff); // Triggers impl 967 968 969 this._actualizeTriggers(); // If field is not valid for the first time, bind keyup trigger to ease UX and quickly inform user 970 971 972 if ((diff.kept.length || diff.added.length) && !this._failedOnce) { 973 this._failedOnce = true; 974 975 this._actualizeTriggers(); 976 } 977 }, 978 // Returns an array of field's error message(s) 979 getErrorsMessages: function getErrorsMessages() { 980 // No error message, field is valid 981 if (true === this.validationResult) return []; 982 var messages = []; 983 984 for (var i = 0; i < this.validationResult.length; i++) { 985 messages.push(this.validationResult[i].errorMessage || this._getErrorMessage(this.validationResult[i].assert)); 986 } 987 988 return messages; 989 }, 990 // It's a goal of Parsley that this method is no longer required [#1073] 991 addError: function addError(name) { 992 var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, 993 message = _ref.message, 994 assert = _ref.assert, 995 _ref$updateClass = _ref.updateClass, 996 updateClass = _ref$updateClass === void 0 ? true : _ref$updateClass; 997 998 this._buildUI(); 999 1000 this._addError(name, { 1001 message: message, 1002 assert: assert 1003 }); 1004 1005 if (updateClass) this._errorClass(); 1006 }, 1007 // It's a goal of Parsley that this method is no longer required [#1073] 1008 updateError: function updateError(name) { 1009 var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, 1010 message = _ref2.message, 1011 assert = _ref2.assert, 1012 _ref2$updateClass = _ref2.updateClass, 1013 updateClass = _ref2$updateClass === void 0 ? true : _ref2$updateClass; 1014 1015 this._buildUI(); 1016 1017 this._updateError(name, { 1018 message: message, 1019 assert: assert 1020 }); 1021 1022 if (updateClass) this._errorClass(); 1023 }, 1024 // It's a goal of Parsley that this method is no longer required [#1073] 1025 removeError: function removeError(name) { 1026 var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, 1027 _ref3$updateClass = _ref3.updateClass, 1028 updateClass = _ref3$updateClass === void 0 ? true : _ref3$updateClass; 1029 1030 this._buildUI(); 1031 1032 this._removeError(name); // edge case possible here: remove a standard Parsley error that is still failing in this.validationResult 1033 // but highly improbable cuz' manually removing a well Parsley handled error makes no sense. 1034 1035 1036 if (updateClass) this._manageStatusClass(); 1037 }, 1038 _manageStatusClass: function _manageStatusClass() { 1039 if (this.hasConstraints() && this.needsValidation() && true === this.validationResult) this._successClass();else if (this.validationResult.length > 0) this._errorClass();else this._resetClass(); 1040 }, 1041 _manageErrorsMessages: function _manageErrorsMessages(diff) { 1042 if ('undefined' !== typeof this.options.errorsMessagesDisabled) return; // Case where we have errorMessage option that configure an unique field error message, regardless failing validators 1043 1044 if ('undefined' !== typeof this.options.errorMessage) { 1045 if (diff.added.length || diff.kept.length) { 1046 this._insertErrorWrapper(); 1047 1048 if (0 === this._ui.$errorsWrapper.find('.parsley-custom-error-message').length) this._ui.$errorsWrapper.append($(this.options.errorTemplate).addClass('parsley-custom-error-message')); 1049 1050 this._ui.$errorClassHandler.attr('aria-describedby', this._ui.errorsWrapperId); 1051 1052 return this._ui.$errorsWrapper.addClass('filled').attr('aria-hidden', 'false').find('.parsley-custom-error-message').html(this.options.errorMessage); 1053 } 1054 1055 this._ui.$errorClassHandler.removeAttr('aria-describedby'); 1056 1057 return this._ui.$errorsWrapper.removeClass('filled').attr('aria-hidden', 'true').find('.parsley-custom-error-message').remove(); 1058 } // Show, hide, update failing constraints messages 1059 1060 1061 for (var i = 0; i < diff.removed.length; i++) { 1062 this._removeError(diff.removed[i].assert.name); 1063 } 1064 1065 for (i = 0; i < diff.added.length; i++) { 1066 this._addError(diff.added[i].assert.name, { 1067 message: diff.added[i].errorMessage, 1068 assert: diff.added[i].assert 1069 }); 1070 } 1071 1072 for (i = 0; i < diff.kept.length; i++) { 1073 this._updateError(diff.kept[i].assert.name, { 1074 message: diff.kept[i].errorMessage, 1075 assert: diff.kept[i].assert 1076 }); 1077 } 1078 }, 1079 _addError: function _addError(name, _ref4) { 1080 var message = _ref4.message, 1081 assert = _ref4.assert; 1082 1083 this._insertErrorWrapper(); 1084 1085 this._ui.$errorClassHandler.attr('aria-describedby', this._ui.errorsWrapperId); 1086 1087 this._ui.$errorsWrapper.addClass('filled').attr('aria-hidden', 'false').append($(this.options.errorTemplate).addClass('parsley-' + name).html(message || this._getErrorMessage(assert))); 1088 }, 1089 _updateError: function _updateError(name, _ref5) { 1090 var message = _ref5.message, 1091 assert = _ref5.assert; 1092 1093 this._ui.$errorsWrapper.addClass('filled').find('.parsley-' + name).html(message || this._getErrorMessage(assert)); 1094 }, 1095 _removeError: function _removeError(name) { 1096 this._ui.$errorClassHandler.removeAttr('aria-describedby'); 1097 1098 this._ui.$errorsWrapper.removeClass('filled').attr('aria-hidden', 'true').find('.parsley-' + name).remove(); 1099 }, 1100 _getErrorMessage: function _getErrorMessage(constraint) { 1101 var customConstraintErrorMessage = constraint.name + 'Message'; 1102 if ('undefined' !== typeof this.options[customConstraintErrorMessage]) return window.Parsley.formatMessage(this.options[customConstraintErrorMessage], constraint.requirements); 1103 return window.Parsley.getErrorMessage(constraint); 1104 }, 1105 _buildUI: function _buildUI() { 1106 // UI could be already built or disabled 1107 if (this._ui || false === this.options.uiEnabled) return; 1108 var _ui = {}; // Give field its Parsley id in DOM 1109 1110 this.element.setAttribute(this.options.namespace + 'id', this.__id__); 1111 /** Generate important UI elements and store them in this **/ 1112 // $errorClassHandler is the $element that woul have parsley-error and parsley-success classes 1113 1114 _ui.$errorClassHandler = this._manageClassHandler(); // $errorsWrapper is a div that would contain the various field errors, it will be appended into $errorsContainer 1115 1116 _ui.errorsWrapperId = 'parsley-id-' + (this.options.multiple ? 'multiple-' + this.options.multiple : this.__id__); 1117 _ui.$errorsWrapper = $(this.options.errorsWrapper).attr('id', _ui.errorsWrapperId); // ValidationResult UI storage to detect what have changed bwt two validations, and update DOM accordingly 1118 1119 _ui.lastValidationResult = []; 1120 _ui.validationInformationVisible = false; // Store it in this for later 1121 1122 this._ui = _ui; 1123 }, 1124 // Determine which element will have `parsley-error` and `parsley-success` classes 1125 _manageClassHandler: function _manageClassHandler() { 1126 // Class handled could also be determined by function given in Parsley options 1127 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 1128 1129 var $handlerFunction = this.options.classHandler; // It might also be the function name of a global function 1130 1131 if ('string' === typeof this.options.classHandler && 'function' === typeof window[this.options.classHandler]) $handlerFunction = window[this.options.classHandler]; 1132 1133 if ('function' === typeof $handlerFunction) { 1134 var $handler = $handlerFunction.call(this, this); // If this function returned a valid existing DOM element, go for it 1135 1136 if ('undefined' !== typeof $handler && $handler.length) return $handler; 1137 } else if ('object' === _typeof($handlerFunction) && $handlerFunction instanceof jQuery && $handlerFunction.length) { 1138 return $handlerFunction; 1139 } else if ($handlerFunction) { 1140 Utils.warn('The class handler `' + $handlerFunction + '` does not exist in DOM nor as a global JS function'); 1141 } 1142 1143 return this._inputHolder(); 1144 }, 1145 _inputHolder: function _inputHolder() { 1146 // if simple element (input, texatrea, select...) it will perfectly host the classes and precede the error container 1147 if (!this.options.multiple || this.element.nodeName === 'SELECT') return this.$element; // But if multiple element (radio, checkbox), that would be their parent 1148 1149 return this.$element.parent(); 1150 }, 1151 _insertErrorWrapper: function _insertErrorWrapper() { 1152 var $errorsContainer = this.options.errorsContainer; // Nothing to do if already inserted 1153 1154 if (0 !== this._ui.$errorsWrapper.parent().length) return this._ui.$errorsWrapper.parent(); 1155 1156 if ('string' === typeof $errorsContainer) { 1157 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'); 1158 } 1159 1160 if ('function' === typeof $errorsContainer) $errorsContainer = $errorsContainer.call(this, this); 1161 if ('object' === _typeof($errorsContainer) && $errorsContainer.length) return $errorsContainer.append(this._ui.$errorsWrapper); 1162 return this._inputHolder().after(this._ui.$errorsWrapper); 1163 }, 1164 _actualizeTriggers: function _actualizeTriggers() { 1165 var _this2 = this; 1166 1167 var $toBind = this._findRelated(); 1168 1169 var trigger; // Remove Parsley events already bound on this field 1170 1171 $toBind.off('.Parsley'); 1172 if (this._failedOnce) $toBind.on(Utils.namespaceEvents(this.options.triggerAfterFailure, 'Parsley'), function () { 1173 _this2._validateIfNeeded(); 1174 });else if (trigger = Utils.namespaceEvents(this.options.trigger, 'Parsley')) { 1175 $toBind.on(trigger, function (event) { 1176 _this2._validateIfNeeded(event); 1177 }); 1178 } 1179 }, 1180 _validateIfNeeded: function _validateIfNeeded(event) { 1181 var _this3 = this; 1182 1183 // For keyup, keypress, keydown, input... events that could be a little bit obstrusive 1184 // do not validate if val length < min threshold on first validation. Once field have been validated once and info 1185 // about success or failure have been displayed, always validate with this trigger to reflect every yalidation change. 1186 if (event && /key|input/.test(event.type)) if (!(this._ui && this._ui.validationInformationVisible) && this.getValue().length <= this.options.validationThreshold) return; 1187 1188 if (this.options.debounce) { 1189 window.clearTimeout(this._debounced); 1190 this._debounced = window.setTimeout(function () { 1191 return _this3.validate(); 1192 }, this.options.debounce); 1193 } else this.validate(); 1194 }, 1195 _resetUI: function _resetUI() { 1196 // Reset all event listeners 1197 this._failedOnce = false; 1198 1199 this._actualizeTriggers(); // Nothing to do if UI never initialized for this field 1200 1201 1202 if ('undefined' === typeof this._ui) return; // Reset all errors' li 1203 1204 this._ui.$errorsWrapper.removeClass('filled').children().remove(); // Reset validation class 1205 1206 1207 this._resetClass(); // Reset validation flags and last validation result 1208 1209 1210 this._ui.lastValidationResult = []; 1211 this._ui.validationInformationVisible = false; 1212 }, 1213 _destroyUI: function _destroyUI() { 1214 this._resetUI(); 1215 1216 if ('undefined' !== typeof this._ui) this._ui.$errorsWrapper.remove(); 1217 delete this._ui; 1218 }, 1219 _successClass: function _successClass() { 1220 this._ui.validationInformationVisible = true; 1221 1222 this._ui.$errorClassHandler.removeClass(this.options.errorClass).addClass(this.options.successClass); 1223 }, 1224 _errorClass: function _errorClass() { 1225 this._ui.validationInformationVisible = true; 1226 1227 this._ui.$errorClassHandler.removeClass(this.options.successClass).addClass(this.options.errorClass); 1228 }, 1229 _resetClass: function _resetClass() { 1230 this._ui.$errorClassHandler.removeClass(this.options.successClass).removeClass(this.options.errorClass); 1231 } 1232 }; 1233 1234 var Form = function Form(element, domOptions, options) { 1235 this.__class__ = 'Form'; 1236 this.element = element; 1237 this.$element = $(element); 1238 this.domOptions = domOptions; 1239 this.options = options; 1240 this.parent = window.Parsley; 1241 this.fields = []; 1242 this.validationResult = null; 1243 }; 1244 1245 var statusMapping = { 1246 pending: null, 1247 resolved: true, 1248 rejected: false 1249 }; 1250 Form.prototype = { 1251 onSubmitValidate: function onSubmitValidate(event) { 1252 var _this = this; 1253 1254 // This is a Parsley generated submit event, do not validate, do not prevent, simply exit and keep normal behavior 1255 if (true === event.parsley) return; // If we didn't come here through a submit button, use the first one in the form 1256 1257 var submitSource = this._submitSource || this.$element.find(Utils._SubmitSelector)[0]; 1258 this._submitSource = null; 1259 this.$element.find('.parsley-synthetic-submit-button').prop('disabled', true); 1260 if (submitSource && null !== submitSource.getAttribute('formnovalidate')) return; 1261 window.Parsley._remoteCache = {}; 1262 var promise = this.whenValidate({ 1263 event: event 1264 }); 1265 1266 if ('resolved' === promise.state() && false !== this._trigger('submit')) ; else { 1267 // Rejected or pending: cancel this submit 1268 event.stopImmediatePropagation(); 1269 event.preventDefault(); 1270 if ('pending' === promise.state()) promise.done(function () { 1271 _this._submit(submitSource); 1272 }); 1273 } 1274 }, 1275 onSubmitButton: function onSubmitButton(event) { 1276 this._submitSource = event.currentTarget; 1277 }, 1278 // internal 1279 // _submit submits the form, this time without going through the validations. 1280 // Care must be taken to "fake" the actual submit button being clicked. 1281 _submit: function _submit(submitSource) { 1282 if (false === this._trigger('submit')) return; // Add submit button's data 1283 1284 if (submitSource) { 1285 var $synthetic = this.$element.find('.parsley-synthetic-submit-button').prop('disabled', false); 1286 if (0 === $synthetic.length) $synthetic = $('<input class="parsley-synthetic-submit-button" type="hidden">').appendTo(this.$element); 1287 $synthetic.attr({ 1288 name: submitSource.getAttribute('name'), 1289 value: submitSource.getAttribute('value') 1290 }); 1291 } 1292 1293 this.$element.trigger(_extends($.Event('submit'), { 1294 parsley: true 1295 })); 1296 }, 1297 // Performs validation on fields while triggering events. 1298 // @returns `true` if all validations succeeds, `false` 1299 // if a failure is immediately detected, or `null` 1300 // if dependant on a promise. 1301 // Consider using `whenValidate` instead. 1302 validate: function validate(options) { 1303 if (arguments.length >= 1 && !$.isPlainObject(options)) { 1304 Utils.warnOnce('Calling validate on a parsley form without passing arguments as an object is deprecated.'); 1305 1306 var _arguments = Array.prototype.slice.call(arguments), 1307 group = _arguments[0], 1308 force = _arguments[1], 1309 event = _arguments[2]; 1310 1311 options = { 1312 group: group, 1313 force: force, 1314 event: event 1315 }; 1316 } 1317 1318 return statusMapping[this.whenValidate(options).state()]; 1319 }, 1320 whenValidate: function whenValidate() { 1321 var _this2 = this, 1322 _Utils$all$done$fail$; 1323 1324 var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, 1325 group = _ref.group, 1326 force = _ref.force, 1327 event = _ref.event; 1328 1329 this.submitEvent = event; 1330 1331 if (event) { 1332 this.submitEvent = _extends({}, event, { 1333 preventDefault: function preventDefault() { 1334 Utils.warnOnce("Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`"); 1335 _this2.validationResult = false; 1336 } 1337 }); 1338 } 1339 1340 this.validationResult = true; // fire validate event to eventually modify things before every validation 1341 1342 this._trigger('validate'); // Refresh form DOM options and form's fields that could have changed 1343 1344 1345 this._refreshFields(); 1346 1347 var promises = this._withoutReactualizingFormOptions(function () { 1348 return $.map(_this2.fields, function (field) { 1349 return field.whenValidate({ 1350 force: force, 1351 group: group 1352 }); 1353 }); 1354 }); 1355 1356 return (_Utils$all$done$fail$ = Utils.all(promises).done(function () { 1357 _this2._trigger('success'); 1358 }).fail(function () { 1359 _this2.validationResult = false; 1360 1361 _this2.focus(); 1362 1363 _this2._trigger('error'); 1364 }).always(function () { 1365 _this2._trigger('validated'); 1366 })).pipe.apply(_Utils$all$done$fail$, _toConsumableArray(this._pipeAccordingToValidationResult())); 1367 }, 1368 // Iterate over refreshed fields, and stop on first failure. 1369 // Returns `true` if all fields are valid, `false` if a failure is detected 1370 // or `null` if the result depends on an unresolved promise. 1371 // Prefer using `whenValid` instead. 1372 isValid: function isValid(options) { 1373 if (arguments.length >= 1 && !$.isPlainObject(options)) { 1374 Utils.warnOnce('Calling isValid on a parsley form without passing arguments as an object is deprecated.'); 1375 1376 var _arguments2 = Array.prototype.slice.call(arguments), 1377 group = _arguments2[0], 1378 force = _arguments2[1]; 1379 1380 options = { 1381 group: group, 1382 force: force 1383 }; 1384 } 1385 1386 return statusMapping[this.whenValid(options).state()]; 1387 }, 1388 // Iterate over refreshed fields and validate them. 1389 // Returns a promise. 1390 // A validation that immediately fails will interrupt the validations. 1391 whenValid: function whenValid() { 1392 var _this3 = this; 1393 1394 var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, 1395 group = _ref2.group, 1396 force = _ref2.force; 1397 1398 this._refreshFields(); 1399 1400 var promises = this._withoutReactualizingFormOptions(function () { 1401 return $.map(_this3.fields, function (field) { 1402 return field.whenValid({ 1403 group: group, 1404 force: force 1405 }); 1406 }); 1407 }); 1408 1409 return Utils.all(promises); 1410 }, 1411 refresh: function refresh() { 1412 this._refreshFields(); 1413 1414 return this; 1415 }, 1416 // Reset UI 1417 reset: function reset() { 1418 // Form case: emit a reset event for each field 1419 for (var i = 0; i < this.fields.length; i++) { 1420 this.fields[i].reset(); 1421 } 1422 1423 this._trigger('reset'); 1424 }, 1425 // Destroy Parsley instance (+ UI) 1426 destroy: function destroy() { 1427 // Field case: emit destroy event to clean UI and then destroy stored instance 1428 this._destroyUI(); // Form case: destroy all its fields and then destroy stored instance 1429 1430 1431 for (var i = 0; i < this.fields.length; i++) { 1432 this.fields[i].destroy(); 1433 } 1434 1435 this.$element.removeData('Parsley'); 1436 1437 this._trigger('destroy'); 1438 }, 1439 _refreshFields: function _refreshFields() { 1440 return this.actualizeOptions()._bindFields(); 1441 }, 1442 _bindFields: function _bindFields() { 1443 var _this4 = this; 1444 1445 var oldFields = this.fields; 1446 this.fields = []; 1447 this.fieldsMappedById = {}; 1448 1449 this._withoutReactualizingFormOptions(function () { 1450 _this4.$element.find(_this4.options.inputs).not(_this4.options.excluded).not("[".concat(_this4.options.namespace, "excluded=true]")).each(function (_, element) { 1451 var fieldInstance = new window.Parsley.Factory(element, {}, _this4); // Only add valid and not excluded `Field` and `FieldMultiple` children 1452 1453 if ('Field' === fieldInstance.__class__ || 'FieldMultiple' === fieldInstance.__class__) { 1454 var uniqueId = fieldInstance.__class__ + '-' + fieldInstance.__id__; 1455 1456 if ('undefined' === typeof _this4.fieldsMappedById[uniqueId]) { 1457 _this4.fieldsMappedById[uniqueId] = fieldInstance; 1458 1459 _this4.fields.push(fieldInstance); 1460 } 1461 } 1462 }); 1463 1464 $.each(Utils.difference(oldFields, _this4.fields), function (_, field) { 1465 field.reset(); 1466 }); 1467 }); 1468 1469 return this; 1470 }, 1471 // Internal only. 1472 // Looping on a form's fields to do validation or similar 1473 // will trigger reactualizing options on all of them, which 1474 // in turn will reactualize the form's options. 1475 // To avoid calling actualizeOptions so many times on the form 1476 // for nothing, _withoutReactualizingFormOptions temporarily disables 1477 // the method actualizeOptions on this form while `fn` is called. 1478 _withoutReactualizingFormOptions: function _withoutReactualizingFormOptions(fn) { 1479 var oldActualizeOptions = this.actualizeOptions; 1480 1481 this.actualizeOptions = function () { 1482 return this; 1483 }; 1484 1485 var result = fn(); 1486 this.actualizeOptions = oldActualizeOptions; 1487 return result; 1488 }, 1489 // Internal only. 1490 // Shortcut to trigger an event 1491 // Returns true iff event is not interrupted and default not prevented. 1492 _trigger: function _trigger(eventName) { 1493 return this.trigger('form:' + eventName); 1494 } 1495 }; 1496 1497 var Constraint = function Constraint(parsleyField, name, requirements, priority, isDomConstraint) { 1498 var validatorSpec = window.Parsley._validatorRegistry.validators[name]; 1499 var validator = new Validator(validatorSpec); 1500 priority = priority || parsleyField.options[name + 'Priority'] || validator.priority; 1501 isDomConstraint = true === isDomConstraint; 1502 1503 _extends(this, { 1504 validator: validator, 1505 name: name, 1506 requirements: requirements, 1507 priority: priority, 1508 isDomConstraint: isDomConstraint 1509 }); 1510 1511 this._parseRequirements(parsleyField.options); 1512 }; 1513 1514 var capitalize = function capitalize(str) { 1515 var cap = str[0].toUpperCase(); 1516 return cap + str.slice(1); 1517 }; 1518 1519 Constraint.prototype = { 1520 validate: function validate(value, instance) { 1521 var _this$validator; 1522 1523 return (_this$validator = this.validator).validate.apply(_this$validator, [value].concat(_toConsumableArray(this.requirementList), [instance])); 1524 }, 1525 _parseRequirements: function _parseRequirements(options) { 1526 var _this = this; 1527 1528 this.requirementList = this.validator.parseRequirements(this.requirements, function (key) { 1529 return options[_this.name + capitalize(key)]; 1530 }); 1531 } 1532 }; 1533 1534 var Field = function Field(field, domOptions, options, parsleyFormInstance) { 1535 this.__class__ = 'Field'; 1536 this.element = field; 1537 this.$element = $(field); // Set parent if we have one 1538 1539 if ('undefined' !== typeof parsleyFormInstance) { 1540 this.parent = parsleyFormInstance; 1541 } 1542 1543 this.options = options; 1544 this.domOptions = domOptions; // Initialize some properties 1545 1546 this.constraints = []; 1547 this.constraintsByName = {}; 1548 this.validationResult = true; // Bind constraints 1549 1550 this._bindConstraints(); 1551 }; 1552 1553 var statusMapping$1 = { 1554 pending: null, 1555 resolved: true, 1556 rejected: false 1557 }; 1558 Field.prototype = { 1559 // # Public API 1560 // Validate field and trigger some events for mainly `UI` 1561 // @returns `true`, an array of the validators that failed, or 1562 // `null` if validation is not finished. Prefer using whenValidate 1563 validate: function validate(options) { 1564 if (arguments.length >= 1 && !$.isPlainObject(options)) { 1565 Utils.warnOnce('Calling validate on a parsley field without passing arguments as an object is deprecated.'); 1566 options = { 1567 options: options 1568 }; 1569 } 1570 1571 var promise = this.whenValidate(options); 1572 if (!promise) // If excluded with `group` option 1573 return true; 1574 1575 switch (promise.state()) { 1576 case 'pending': 1577 return null; 1578 1579 case 'resolved': 1580 return true; 1581 1582 case 'rejected': 1583 return this.validationResult; 1584 } 1585 }, 1586 // Validate field and trigger some events for mainly `UI` 1587 // @returns a promise that succeeds only when all validations do 1588 // or `undefined` if field is not in the given `group`. 1589 whenValidate: function whenValidate() { 1590 var _this$whenValid$alway, 1591 _this = this; 1592 1593 var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, 1594 force = _ref.force, 1595 group = _ref.group; 1596 1597 // do not validate a field if not the same as given validation group 1598 this.refresh(); 1599 if (group && !this._isInGroup(group)) return; 1600 this.value = this.getValue(); // Field Validate event. `this.value` could be altered for custom needs 1601 1602 this._trigger('validate'); 1603 1604 return (_this$whenValid$alway = this.whenValid({ 1605 force: force, 1606 value: this.value, 1607 _refreshed: true 1608 }).always(function () { 1609 _this._reflowUI(); 1610 }).done(function () { 1611 _this._trigger('success'); 1612 }).fail(function () { 1613 _this._trigger('error'); 1614 }).always(function () { 1615 _this._trigger('validated'); 1616 })).pipe.apply(_this$whenValid$alway, _toConsumableArray(this._pipeAccordingToValidationResult())); 1617 }, 1618 hasConstraints: function hasConstraints() { 1619 return 0 !== this.constraints.length; 1620 }, 1621 // An empty optional field does not need validation 1622 needsValidation: function needsValidation(value) { 1623 if ('undefined' === typeof value) value = this.getValue(); // If a field is empty and not required, it is valid 1624 // Except if `data-parsley-validate-if-empty` explicitely added, useful for some custom validators 1625 1626 if (!value.length && !this._isRequired() && 'undefined' === typeof this.options.validateIfEmpty) return false; 1627 return true; 1628 }, 1629 _isInGroup: function _isInGroup(group) { 1630 if (Array.isArray(this.options.group)) return -1 !== $.inArray(group, this.options.group); 1631 return this.options.group === group; 1632 }, 1633 // Just validate field. Do not trigger any event. 1634 // Returns `true` iff all constraints pass, `false` if there are failures, 1635 // or `null` if the result can not be determined yet (depends on a promise) 1636 // See also `whenValid`. 1637 isValid: function isValid(options) { 1638 if (arguments.length >= 1 && !$.isPlainObject(options)) { 1639 Utils.warnOnce('Calling isValid on a parsley field without passing arguments as an object is deprecated.'); 1640 1641 var _arguments = Array.prototype.slice.call(arguments), 1642 force = _arguments[0], 1643 value = _arguments[1]; 1644 1645 options = { 1646 force: force, 1647 value: value 1648 }; 1649 } 1650 1651 var promise = this.whenValid(options); 1652 if (!promise) // Excluded via `group` 1653 return true; 1654 return statusMapping$1[promise.state()]; 1655 }, 1656 // Just validate field. Do not trigger any event. 1657 // @returns a promise that succeeds only when all validations do 1658 // or `undefined` if the field is not in the given `group`. 1659 // The argument `force` will force validation of empty fields. 1660 // If a `value` is given, it will be validated instead of the value of the input. 1661 whenValid: function whenValid() { 1662 var _this2 = this; 1663 1664 var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, 1665 _ref2$force = _ref2.force, 1666 force = _ref2$force === void 0 ? false : _ref2$force, 1667 value = _ref2.value, 1668 group = _ref2.group, 1669 _refreshed = _ref2._refreshed; 1670 1671 // Recompute options and rebind constraints to have latest changes 1672 if (!_refreshed) this.refresh(); // do not validate a field if not the same as given validation group 1673 1674 if (group && !this._isInGroup(group)) return; 1675 this.validationResult = true; // A field without constraint is valid 1676 1677 if (!this.hasConstraints()) return $.when(); // Value could be passed as argument, needed to add more power to 'field:validate' 1678 1679 if ('undefined' === typeof value || null === value) value = this.getValue(); 1680 if (!this.needsValidation(value) && true !== force) return $.when(); 1681 1682 var groupedConstraints = this._getGroupedConstraints(); 1683 1684 var promises = []; 1685 $.each(groupedConstraints, function (_, constraints) { 1686 // Process one group of constraints at a time, we validate the constraints 1687 // and combine the promises together. 1688 var promise = Utils.all($.map(constraints, function (constraint) { 1689 return _this2._validateConstraint(value, constraint); 1690 })); 1691 promises.push(promise); 1692 if (promise.state() === 'rejected') return false; // Interrupt processing if a group has already failed 1693 }); 1694 return Utils.all(promises); 1695 }, 1696 // @returns a promise 1697 _validateConstraint: function _validateConstraint(value, constraint) { 1698 var _this3 = this; 1699 1700 var result = constraint.validate(value, this); // Map false to a failed promise 1701 1702 if (false === result) result = $.Deferred().reject(); // Make sure we return a promise and that we record failures 1703 1704 return Utils.all([result]).fail(function (errorMessage) { 1705 if (!(_this3.validationResult instanceof Array)) _this3.validationResult = []; 1706 1707 _this3.validationResult.push({ 1708 assert: constraint, 1709 errorMessage: 'string' === typeof errorMessage && errorMessage 1710 }); 1711 }); 1712 }, 1713 // @returns Parsley field computed value that could be overrided or configured in DOM 1714 getValue: function getValue() { 1715 var value; // Value could be overriden in DOM or with explicit options 1716 1717 if ('function' === typeof this.options.value) value = this.options.value(this);else if ('undefined' !== typeof this.options.value) value = this.options.value;else value = this.$element.val(); // Handle wrong DOM or configurations 1718 1719 if ('undefined' === typeof value || null === value) return ''; 1720 return this._handleWhitespace(value); 1721 }, 1722 // Reset UI 1723 reset: function reset() { 1724 this._resetUI(); 1725 1726 return this._trigger('reset'); 1727 }, 1728 // Destroy Parsley instance (+ UI) 1729 destroy: function destroy() { 1730 // Field case: emit destroy event to clean UI and then destroy stored instance 1731 this._destroyUI(); 1732 1733 this.$element.removeData('Parsley'); 1734 this.$element.removeData('FieldMultiple'); 1735 1736 this._trigger('destroy'); 1737 }, 1738 // Actualize options and rebind constraints 1739 refresh: function refresh() { 1740 this._refreshConstraints(); 1741 1742 return this; 1743 }, 1744 _refreshConstraints: function _refreshConstraints() { 1745 return this.actualizeOptions()._bindConstraints(); 1746 }, 1747 refreshConstraints: function refreshConstraints() { 1748 Utils.warnOnce("Parsley's refreshConstraints is deprecated. Please use refresh"); 1749 return this.refresh(); 1750 }, 1751 1752 /** 1753 * Add a new constraint to a field 1754 * 1755 * @param {String} name 1756 * @param {Mixed} requirements optional 1757 * @param {Number} priority optional 1758 * @param {Boolean} isDomConstraint optional 1759 */ 1760 addConstraint: function addConstraint(name, requirements, priority, isDomConstraint) { 1761 if (window.Parsley._validatorRegistry.validators[name]) { 1762 var constraint = new Constraint(this, name, requirements, priority, isDomConstraint); // if constraint already exist, delete it and push new version 1763 1764 if ('undefined' !== this.constraintsByName[constraint.name]) this.removeConstraint(constraint.name); 1765 this.constraints.push(constraint); 1766 this.constraintsByName[constraint.name] = constraint; 1767 } 1768 1769 return this; 1770 }, 1771 // Remove a constraint 1772 removeConstraint: function removeConstraint(name) { 1773 for (var i = 0; i < this.constraints.length; i++) { 1774 if (name === this.constraints[i].name) { 1775 this.constraints.splice(i, 1); 1776 break; 1777 } 1778 } 1779 1780 delete this.constraintsByName[name]; 1781 return this; 1782 }, 1783 // Update a constraint (Remove + re-add) 1784 updateConstraint: function updateConstraint(name, parameters, priority) { 1785 return this.removeConstraint(name).addConstraint(name, parameters, priority); 1786 }, 1787 // # Internals 1788 // Internal only. 1789 // Bind constraints from config + options + DOM 1790 _bindConstraints: function _bindConstraints() { 1791 var constraints = []; 1792 var constraintsByName = {}; // clean all existing DOM constraints to only keep javascript user constraints 1793 1794 for (var i = 0; i < this.constraints.length; i++) { 1795 if (false === this.constraints[i].isDomConstraint) { 1796 constraints.push(this.constraints[i]); 1797 constraintsByName[this.constraints[i].name] = this.constraints[i]; 1798 } 1799 } 1800 1801 this.constraints = constraints; 1802 this.constraintsByName = constraintsByName; // then re-add Parsley DOM-API constraints 1803 1804 for (var name in this.options) { 1805 this.addConstraint(name, this.options[name], undefined, true); 1806 } // finally, bind special HTML5 constraints 1807 1808 1809 return this._bindHtml5Constraints(); 1810 }, 1811 // Internal only. 1812 // Bind specific HTML5 constraints to be HTML5 compliant 1813 _bindHtml5Constraints: function _bindHtml5Constraints() { 1814 // html5 required 1815 if (null !== this.element.getAttribute('required')) this.addConstraint('required', true, undefined, true); // html5 pattern 1816 1817 if (null !== this.element.getAttribute('pattern')) this.addConstraint('pattern', this.element.getAttribute('pattern'), undefined, true); // range 1818 1819 var min = this.element.getAttribute('min'); 1820 var max = this.element.getAttribute('max'); 1821 if (null !== min && null !== max) this.addConstraint('range', [min, max], undefined, true); // HTML5 min 1822 else if (null !== min) this.addConstraint('min', min, undefined, true); // HTML5 max 1823 else if (null !== max) this.addConstraint('max', max, undefined, true); // length 1824 1825 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 1826 else if (null !== this.element.getAttribute('minlength')) this.addConstraint('minlength', this.element.getAttribute('minlength'), undefined, true); // HTML5 maxlength 1827 else if (null !== this.element.getAttribute('maxlength')) this.addConstraint('maxlength', this.element.getAttribute('maxlength'), undefined, true); // html5 types 1828 1829 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 1830 1831 if ('number' === type) { 1832 return this.addConstraint('type', ['number', { 1833 step: this.element.getAttribute('step') || '1', 1834 base: min || this.element.getAttribute('value') 1835 }], undefined, true); // Regular other HTML5 supported types 1836 } else if (/^(email|url|range|date)$/i.test(type)) { 1837 return this.addConstraint('type', type, undefined, true); 1838 } 1839 1840 return this; 1841 }, 1842 // Internal only. 1843 // Field is required if have required constraint without `false` value 1844 _isRequired: function _isRequired() { 1845 if ('undefined' === typeof this.constraintsByName.required) return false; 1846 return false !== this.constraintsByName.required.requirements; 1847 }, 1848 // Internal only. 1849 // Shortcut to trigger an event 1850 _trigger: function _trigger(eventName) { 1851 return this.trigger('field:' + eventName); 1852 }, 1853 // Internal only 1854 // Handles whitespace in a value 1855 // Use `data-parsley-whitespace="squish"` to auto squish input value 1856 // Use `data-parsley-whitespace="trim"` to auto trim input value 1857 _handleWhitespace: function _handleWhitespace(value) { 1858 if (true === this.options.trimValue) Utils.warnOnce('data-parsley-trim-value="true" is deprecated, please use data-parsley-whitespace="trim"'); 1859 if ('squish' === this.options.whitespace) value = value.replace(/\s{2,}/g, ' '); 1860 if ('trim' === this.options.whitespace || 'squish' === this.options.whitespace || true === this.options.trimValue) value = Utils.trimString(value); 1861 return value; 1862 }, 1863 _isDateInput: function _isDateInput() { 1864 var c = this.constraintsByName.type; 1865 return c && c.requirements === 'date'; 1866 }, 1867 // Internal only. 1868 // Returns the constraints, grouped by descending priority. 1869 // The result is thus an array of arrays of constraints. 1870 _getGroupedConstraints: function _getGroupedConstraints() { 1871 if (false === this.options.priorityEnabled) return [this.constraints]; 1872 var groupedConstraints = []; 1873 var index = {}; // Create array unique of priorities 1874 1875 for (var i = 0; i < this.constraints.length; i++) { 1876 var p = this.constraints[i].priority; 1877 if (!index[p]) groupedConstraints.push(index[p] = []); 1878 index[p].push(this.constraints[i]); 1879 } // Sort them by priority DESC 1880 1881 1882 groupedConstraints.sort(function (a, b) { 1883 return b[0].priority - a[0].priority; 1884 }); 1885 return groupedConstraints; 1886 } 1887 }; 1888 1889 var Multiple = function Multiple() { 1890 this.__class__ = 'FieldMultiple'; 1891 }; 1892 1893 Multiple.prototype = { 1894 // Add new `$element` sibling for multiple field 1895 addElement: function addElement($element) { 1896 this.$elements.push($element); 1897 return this; 1898 }, 1899 // See `Field._refreshConstraints()` 1900 _refreshConstraints: function _refreshConstraints() { 1901 var fieldConstraints; 1902 this.constraints = []; // Select multiple special treatment 1903 1904 if (this.element.nodeName === 'SELECT') { 1905 this.actualizeOptions()._bindConstraints(); 1906 1907 return this; 1908 } // Gather all constraints for each input in the multiple group 1909 1910 1911 for (var i = 0; i < this.$elements.length; i++) { 1912 // Check if element have not been dynamically removed since last binding 1913 if (!$('html').has(this.$elements[i]).length) { 1914 this.$elements.splice(i, 1); 1915 continue; 1916 } 1917 1918 fieldConstraints = this.$elements[i].data('FieldMultiple')._refreshConstraints().constraints; 1919 1920 for (var j = 0; j < fieldConstraints.length; j++) { 1921 this.addConstraint(fieldConstraints[j].name, fieldConstraints[j].requirements, fieldConstraints[j].priority, fieldConstraints[j].isDomConstraint); 1922 } 1923 } 1924 1925 return this; 1926 }, 1927 // See `Field.getValue()` 1928 getValue: function getValue() { 1929 // Value could be overriden in DOM 1930 if ('function' === typeof this.options.value) return this.options.value(this);else if ('undefined' !== typeof this.options.value) return this.options.value; // Radio input case 1931 1932 if (this.element.nodeName === 'INPUT') { 1933 var type = Utils.getType(this.element); 1934 if (type === 'radio') return this._findRelated().filter(':checked').val() || ''; // checkbox input case 1935 1936 if (type === 'checkbox') { 1937 var values = []; 1938 1939 this._findRelated().filter(':checked').each(function () { 1940 values.push($(this).val()); 1941 }); 1942 1943 return values; 1944 } 1945 } // Select multiple case 1946 1947 1948 if (this.element.nodeName === 'SELECT' && null === this.$element.val()) return []; // Default case that should never happen 1949 1950 return this.$element.val(); 1951 }, 1952 _init: function _init() { 1953 this.$elements = [this.$element]; 1954 return this; 1955 } 1956 }; 1957 1958 var Factory = function Factory(element, options, parsleyFormInstance) { 1959 this.element = element; 1960 this.$element = $(element); // If the element has already been bound, returns its saved Parsley instance 1961 1962 var savedparsleyFormInstance = this.$element.data('Parsley'); 1963 1964 if (savedparsleyFormInstance) { 1965 // If the saved instance has been bound without a Form parent and there is one given in this call, add it 1966 if ('undefined' !== typeof parsleyFormInstance && savedparsleyFormInstance.parent === window.Parsley) { 1967 savedparsleyFormInstance.parent = parsleyFormInstance; 1968 1969 savedparsleyFormInstance._resetOptions(savedparsleyFormInstance.options); 1970 } 1971 1972 if ('object' === _typeof(options)) { 1973 _extends(savedparsleyFormInstance.options, options); 1974 } 1975 1976 return savedparsleyFormInstance; 1977 } // Parsley must be instantiated with a DOM element or jQuery $element 1978 1979 1980 if (!this.$element.length) throw new Error('You must bind Parsley on an existing element.'); 1981 if ('undefined' !== typeof parsleyFormInstance && 'Form' !== parsleyFormInstance.__class__) throw new Error('Parent instance must be a Form instance'); 1982 this.parent = parsleyFormInstance || window.Parsley; 1983 return this.init(options); 1984 }; 1985 1986 Factory.prototype = { 1987 init: function init(options) { 1988 this.__class__ = 'Parsley'; 1989 this.__version__ = '2.9.2'; 1990 this.__id__ = Utils.generateID(); // Pre-compute options 1991 1992 this._resetOptions(options); // A Form instance is obviously a `<form>` element but also every node that is not an input and has the `data-parsley-validate` attribute 1993 1994 1995 if (this.element.nodeName === 'FORM' || Utils.checkAttr(this.element, this.options.namespace, 'validate') && !this.$element.is(this.options.inputs)) return this.bind('parsleyForm'); // Every other element is bound as a `Field` or `FieldMultiple` 1996 1997 return this.isMultiple() ? this.handleMultiple() : this.bind('parsleyField'); 1998 }, 1999 isMultiple: function isMultiple() { 2000 var type = Utils.getType(this.element); 2001 return type === 'radio' || type === 'checkbox' || this.element.nodeName === 'SELECT' && null !== this.element.getAttribute('multiple'); 2002 }, 2003 // Multiples fields are a real nightmare :( 2004 // Maybe some refactoring would be appreciated here... 2005 handleMultiple: function handleMultiple() { 2006 var _this = this; 2007 2008 var name; 2009 var parsleyMultipleInstance; // Handle multiple name 2010 2011 this.options.multiple = this.options.multiple || (name = this.element.getAttribute('name')) || this.element.getAttribute('id'); // Special select multiple input 2012 2013 if (this.element.nodeName === 'SELECT' && null !== this.element.getAttribute('multiple')) { 2014 this.options.multiple = this.options.multiple || this.__id__; 2015 return this.bind('parsleyFieldMultiple'); // Else for radio / checkboxes, we need a `name` or `data-parsley-multiple` to properly bind it 2016 } else if (!this.options.multiple) { 2017 Utils.warn('To be bound by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.', this.$element); 2018 return this; 2019 } // Remove special chars 2020 2021 2022 this.options.multiple = this.options.multiple.replace(/(:|\.|\[|\]|\{|\}|\$)/g, ''); // Add proper `data-parsley-multiple` to siblings if we have a valid multiple name 2023 2024 if (name) { 2025 $('input[name="' + name + '"]').each(function (i, input) { 2026 var type = Utils.getType(input); 2027 if (type === 'radio' || type === 'checkbox') input.setAttribute(_this.options.namespace + 'multiple', _this.options.multiple); 2028 }); 2029 } // Check here if we don't already have a related multiple instance saved 2030 2031 2032 var $previouslyRelated = this._findRelated(); 2033 2034 for (var i = 0; i < $previouslyRelated.length; i++) { 2035 parsleyMultipleInstance = $($previouslyRelated.get(i)).data('Parsley'); 2036 2037 if ('undefined' !== typeof parsleyMultipleInstance) { 2038 if (!this.$element.data('FieldMultiple')) { 2039 parsleyMultipleInstance.addElement(this.$element); 2040 } 2041 2042 break; 2043 } 2044 } // Create a secret Field instance for every multiple field. It will be stored in `data('FieldMultiple')` 2045 // And will be useful later to access classic `Field` stuff while being in a `FieldMultiple` instance 2046 2047 2048 this.bind('parsleyField', true); 2049 return parsleyMultipleInstance || this.bind('parsleyFieldMultiple'); 2050 }, 2051 // Return proper `Form`, `Field` or `FieldMultiple` 2052 bind: function bind(type, doNotStore) { 2053 var parsleyInstance; 2054 2055 switch (type) { 2056 case 'parsleyForm': 2057 parsleyInstance = $.extend(new Form(this.element, this.domOptions, this.options), new Base(), window.ParsleyExtend)._bindFields(); 2058 break; 2059 2060 case 'parsleyField': 2061 parsleyInstance = $.extend(new Field(this.element, this.domOptions, this.options, this.parent), new Base(), window.ParsleyExtend); 2062 break; 2063 2064 case 'parsleyFieldMultiple': 2065 parsleyInstance = $.extend(new Field(this.element, this.domOptions, this.options, this.parent), new Multiple(), new Base(), window.ParsleyExtend)._init(); 2066 break; 2067 2068 default: 2069 throw new Error(type + 'is not a supported Parsley type'); 2070 } 2071 2072 if (this.options.multiple) Utils.setAttr(this.element, this.options.namespace, 'multiple', this.options.multiple); 2073 2074 if ('undefined' !== typeof doNotStore) { 2075 this.$element.data('FieldMultiple', parsleyInstance); 2076 return parsleyInstance; 2077 } // Store the freshly bound instance in a DOM element for later access using jQuery `data()` 2078 2079 2080 this.$element.data('Parsley', parsleyInstance); // Tell the world we have a new Form or Field instance! 2081 2082 parsleyInstance._actualizeTriggers(); 2083 2084 parsleyInstance._trigger('init'); 2085 2086 return parsleyInstance; 2087 } 2088 }; 2089 2090 var vernums = $.fn.jquery.split('.'); 2091 2092 if (parseInt(vernums[0]) <= 1 && parseInt(vernums[1]) < 8) { 2093 throw "The loaded version of jQuery is too old. Please upgrade to 1.8.x or better."; 2094 } 2095 2096 if (!vernums.forEach) { 2097 Utils.warn('Parsley requires ES5 to run properly. Please include https://github.com/es-shims/es5-shim'); 2098 } // Inherit `on`, `off` & `trigger` to Parsley: 2099 2100 2101 var Parsley = _extends(new Base(), { 2102 element: document, 2103 $element: $(document), 2104 actualizeOptions: null, 2105 _resetOptions: null, 2106 Factory: Factory, 2107 version: '2.9.2' 2108 }); // Supplement Field and Form with Base 2109 // This way, the constructors will have access to those methods 2110 2111 2112 _extends(Field.prototype, UI.Field, Base.prototype); 2113 2114 _extends(Form.prototype, UI.Form, Base.prototype); // Inherit actualizeOptions and _resetOptions: 2115 2116 2117 _extends(Factory.prototype, Base.prototype); // ### jQuery API 2118 // `$('.elem').parsley(options)` or `$('.elem').psly(options)` 2119 2120 2121 $.fn.parsley = $.fn.psly = function (options) { 2122 if (this.length > 1) { 2123 var instances = []; 2124 this.each(function () { 2125 instances.push($(this).parsley(options)); 2126 }); 2127 return instances; 2128 } // Return undefined if applied to non existing DOM element 2129 2130 2131 if (this.length == 0) { 2132 return; 2133 } 2134 2135 return new Factory(this[0], options); 2136 }; // ### Field and Form extension 2137 // Ensure the extension is now defined if it wasn't previously 2138 2139 2140 if ('undefined' === typeof window.ParsleyExtend) window.ParsleyExtend = {}; // ### Parsley config 2141 // Inherit from ParsleyDefault, and copy over any existing values 2142 2143 Parsley.options = _extends(Utils.objectCreate(Defaults), window.ParsleyConfig); 2144 window.ParsleyConfig = Parsley.options; // Old way of accessing global options 2145 // ### Globals 2146 2147 window.Parsley = window.psly = Parsley; 2148 Parsley.Utils = Utils; 2149 window.ParsleyUtils = {}; 2150 $.each(Utils, function (key, value) { 2151 if ('function' === typeof value) { 2152 window.ParsleyUtils[key] = function () { 2153 Utils.warnOnce('Accessing `window.ParsleyUtils` is deprecated. Use `window.Parsley.Utils` instead.'); 2154 return Utils[key].apply(Utils, arguments); 2155 }; 2156 } 2157 }); // ### Define methods that forward to the registry, and deprecate all access except through window.Parsley 2158 2159 var registry = window.Parsley._validatorRegistry = new ValidatorRegistry(window.ParsleyConfig.validators, window.ParsleyConfig.i18n); 2160 window.ParsleyValidator = {}; 2161 $.each('setLocale addCatalog addMessage addMessages getErrorMessage formatMessage addValidator updateValidator removeValidator hasValidator'.split(' '), function (i, method) { 2162 window.Parsley[method] = function () { 2163 return registry[method].apply(registry, arguments); 2164 }; 2165 2166 window.ParsleyValidator[method] = function () { 2167 var _window$Parsley; 2168 2169 Utils.warnOnce("Accessing the method '".concat(method, "' through Validator is deprecated. Simply call 'window.Parsley.").concat(method, "(...)'")); 2170 return (_window$Parsley = window.Parsley)[method].apply(_window$Parsley, arguments); 2171 }; 2172 }); // ### UI 2173 // Deprecated global object 2174 2175 window.Parsley.UI = UI; 2176 window.ParsleyUI = { 2177 removeError: function removeError(instance, name, doNotUpdateClass) { 2178 var updateClass = true !== doNotUpdateClass; 2179 Utils.warnOnce("Accessing UI is deprecated. Call 'removeError' on the instance directly. Please comment in issue 1073 as to your need to call this method."); 2180 return instance.removeError(name, { 2181 updateClass: updateClass 2182 }); 2183 }, 2184 getErrorsMessages: function getErrorsMessages(instance) { 2185 Utils.warnOnce("Accessing UI is deprecated. Call 'getErrorsMessages' on the instance directly."); 2186 return instance.getErrorsMessages(); 2187 } 2188 }; 2189 $.each('addError updateError'.split(' '), function (i, method) { 2190 window.ParsleyUI[method] = function (instance, name, message, assert, doNotUpdateClass) { 2191 var updateClass = true !== doNotUpdateClass; 2192 Utils.warnOnce("Accessing UI is deprecated. Call '".concat(method, "' on the instance directly. Please comment in issue 1073 as to your need to call this method.")); 2193 return instance[method](name, { 2194 message: message, 2195 assert: assert, 2196 updateClass: updateClass 2197 }); 2198 }; 2199 }); // ### PARSLEY auto-binding 2200 // Prevent it by setting `ParsleyConfig.autoBind` to `false` 2201 2202 if (false !== window.ParsleyConfig.autoBind) { 2203 $(function () { 2204 // Works only on `data-parsley-validate`. 2205 if ($('[data-parsley-validate]').length) $('[data-parsley-validate]').parsley(); 2206 }); 2207 } 2208 2209 var o = $({}); 2210 2211 var deprecated = function deprecated() { 2212 Utils.warnOnce("Parsley's pubsub module is deprecated; use the 'on' and 'off' methods on parsley instances or window.Parsley"); 2213 }; // Returns an event handler that calls `fn` with the arguments it expects 2214 2215 2216 function adapt(fn, context) { 2217 // Store to allow unbinding 2218 if (!fn.parsleyAdaptedCallback) { 2219 fn.parsleyAdaptedCallback = function () { 2220 var args = Array.prototype.slice.call(arguments, 0); 2221 args.unshift(this); 2222 fn.apply(context || o, args); 2223 }; 2224 } 2225 2226 return fn.parsleyAdaptedCallback; 2227 } 2228 2229 var eventPrefix = 'parsley:'; // Converts 'parsley:form:validate' into 'form:validate' 2230 2231 function eventName(name) { 2232 if (name.lastIndexOf(eventPrefix, 0) === 0) return name.substr(eventPrefix.length); 2233 return name; 2234 } // $.listen is deprecated. Use Parsley.on instead. 2235 2236 2237 $.listen = function (name, callback) { 2238 var context; 2239 deprecated(); 2240 2241 if ('object' === _typeof(arguments[1]) && 'function' === typeof arguments[2]) { 2242 context = arguments[1]; 2243 callback = arguments[2]; 2244 } 2245 2246 if ('function' !== typeof callback) throw new Error('Wrong parameters'); 2247 window.Parsley.on(eventName(name), adapt(callback, context)); 2248 }; 2249 2250 $.listenTo = function (instance, name, fn) { 2251 deprecated(); 2252 if (!(instance instanceof Field) && !(instance instanceof Form)) throw new Error('Must give Parsley instance'); 2253 if ('string' !== typeof name || 'function' !== typeof fn) throw new Error('Wrong parameters'); 2254 instance.on(eventName(name), adapt(fn)); 2255 }; 2256 2257 $.unsubscribe = function (name, fn) { 2258 deprecated(); 2259 if ('string' !== typeof name || 'function' !== typeof fn) throw new Error('Wrong arguments'); 2260 window.Parsley.off(eventName(name), fn.parsleyAdaptedCallback); 2261 }; 2262 2263 $.unsubscribeTo = function (instance, name) { 2264 deprecated(); 2265 if (!(instance instanceof Field) && !(instance instanceof Form)) throw new Error('Must give Parsley instance'); 2266 instance.off(eventName(name)); 2267 }; 2268 2269 $.unsubscribeAll = function (name) { 2270 deprecated(); 2271 window.Parsley.off(eventName(name)); 2272 $('form,input,textarea,select').each(function () { 2273 var instance = $(this).data('Parsley'); 2274 2275 if (instance) { 2276 instance.off(eventName(name)); 2277 } 2278 }); 2279 }; // $.emit is deprecated. Use jQuery events instead. 2280 2281 2282 $.emit = function (name, instance) { 2283 var _instance; 2284 2285 deprecated(); 2286 var instanceGiven = instance instanceof Field || instance instanceof Form; 2287 var args = Array.prototype.slice.call(arguments, instanceGiven ? 2 : 1); 2288 args.unshift(eventName(name)); 2289 2290 if (!instanceGiven) { 2291 instance = window.Parsley; 2292 } 2293 2294 (_instance = instance).trigger.apply(_instance, _toConsumableArray(args)); 2295 }; 2296 2297 $.extend(true, Parsley, { 2298 asyncValidators: { 2299 'default': { 2300 fn: function fn(xhr) { 2301 // By default, only status 2xx are deemed successful. 2302 // Note: we use status instead of state() because responses with status 200 2303 // but invalid messages (e.g. an empty body for content type set to JSON) will 2304 // result in state() === 'rejected'. 2305 return xhr.status >= 200 && xhr.status < 300; 2306 }, 2307 url: false 2308 }, 2309 reverse: { 2310 fn: function fn(xhr) { 2311 // If reverse option is set, a failing ajax request is considered successful 2312 return xhr.status < 200 || xhr.status >= 300; 2313 }, 2314 url: false 2315 } 2316 }, 2317 addAsyncValidator: function addAsyncValidator(name, fn, url, options) { 2318 Parsley.asyncValidators[name] = { 2319 fn: fn, 2320 url: url || false, 2321 options: options || {} 2322 }; 2323 return this; 2324 } 2325 }); 2326 Parsley.addValidator('remote', { 2327 requirementType: { 2328 '': 'string', 2329 'validator': 'string', 2330 'reverse': 'boolean', 2331 'options': 'object' 2332 }, 2333 validateString: function validateString(value, url, options, instance) { 2334 var data = {}; 2335 var ajaxOptions; 2336 var csr; 2337 var validator = options.validator || (true === options.reverse ? 'reverse' : 'default'); 2338 if ('undefined' === typeof Parsley.asyncValidators[validator]) throw new Error('Calling an undefined async validator: `' + validator + '`'); 2339 url = Parsley.asyncValidators[validator].url || url; // Fill current value 2340 2341 if (url.indexOf('{value}') > -1) { 2342 url = url.replace('{value}', encodeURIComponent(value)); 2343 } else { 2344 data[instance.element.getAttribute('name') || instance.element.getAttribute('id')] = value; 2345 } // Merge options passed in from the function with the ones in the attribute 2346 2347 2348 var remoteOptions = $.extend(true, options.options || {}, Parsley.asyncValidators[validator].options); // All `$.ajax(options)` could be overridden or extended directly from DOM in `data-parsley-remote-options` 2349 2350 ajaxOptions = $.extend(true, {}, { 2351 url: url, 2352 data: data, 2353 type: 'GET' 2354 }, remoteOptions); // Generate store key based on ajax options 2355 2356 instance.trigger('field:ajaxoptions', instance, ajaxOptions); 2357 csr = $.param(ajaxOptions); // Initialise querry cache 2358 2359 if ('undefined' === typeof Parsley._remoteCache) Parsley._remoteCache = {}; // Try to retrieve stored xhr 2360 2361 var xhr = Parsley._remoteCache[csr] = Parsley._remoteCache[csr] || $.ajax(ajaxOptions); 2362 2363 var handleXhr = function handleXhr() { 2364 var result = Parsley.asyncValidators[validator].fn.call(instance, xhr, url, options); 2365 if (!result) // Map falsy results to rejected promise 2366 result = $.Deferred().reject(); 2367 return $.when(result); 2368 }; 2369 2370 return xhr.then(handleXhr, handleXhr); 2371 }, 2372 priority: -1 2373 }); 2374 Parsley.on('form:submit', function () { 2375 Parsley._remoteCache = {}; 2376 }); 2377 2378 Base.prototype.addAsyncValidator = function () { 2379 Utils.warnOnce('Accessing the method `addAsyncValidator` through an instance is deprecated. Simply call `Parsley.addAsyncValidator(...)`'); 2380 return Parsley.addAsyncValidator.apply(Parsley, arguments); 2381 }; 2382 2383 // This is included with the Parsley library itself, 2384 Parsley.addMessages('en', { 2385 defaultMessage: "This value seems to be invalid.", 2386 type: { 2387 email: "This value should be a valid email.", 2388 url: "This value should be a valid url.", 2389 number: "This value should be a valid number.", 2390 integer: "This value should be a valid integer.", 2391 digits: "This value should be digits.", 2392 alphanum: "This value should be alphanumeric." 2393 }, 2394 notblank: "This value should not be blank.", 2395 required: "This value is required.", 2396 pattern: "This value seems to be invalid.", 2397 min: "This value should be greater than or equal to %s.", 2398 max: "This value should be lower than or equal to %s.", 2399 range: "This value should be between %s and %s.", 2400 minlength: "This value is too short. It should have %s characters or more.", 2401 maxlength: "This value is too long. It should have %s characters or fewer.", 2402 length: "This value length is invalid. It should be between %s and %s characters long.", 2403 mincheck: "You must select at least %s choices.", 2404 maxcheck: "You must select %s choices or fewer.", 2405 check: "You must select between %s and %s choices.", 2406 equalto: "This value should be the same.", 2407 euvatin: "It's not a valid VAT Identification Number." 2408 }); 2409 Parsley.setLocale('en'); 2410 2411 function InputEvent() { 2412 var _this = this; 2413 2414 var globals = window || global; // Slightly odd way construct our object. This way methods are force bound. 2415 // Used to test for duplicate library. 2416 2417 _extends(this, { 2418 // For browsers that do not support isTrusted, assumes event is native. 2419 isNativeEvent: function isNativeEvent(evt) { 2420 return evt.originalEvent && evt.originalEvent.isTrusted !== false; 2421 }, 2422 fakeInputEvent: function fakeInputEvent(evt) { 2423 if (_this.isNativeEvent(evt)) { 2424 $(evt.target).trigger('input'); 2425 } 2426 }, 2427 misbehaves: function misbehaves(evt) { 2428 if (_this.isNativeEvent(evt)) { 2429 _this.behavesOk(evt); 2430 2431 $(document).on('change.inputevent', evt.data.selector, _this.fakeInputEvent); 2432 2433 _this.fakeInputEvent(evt); 2434 } 2435 }, 2436 behavesOk: function behavesOk(evt) { 2437 if (_this.isNativeEvent(evt)) { 2438 $(document) // Simply unbinds the testing handler 2439 .off('input.inputevent', evt.data.selector, _this.behavesOk).off('change.inputevent', evt.data.selector, _this.misbehaves); 2440 } 2441 }, 2442 // Bind the testing handlers 2443 install: function install() { 2444 if (globals.inputEventPatched) { 2445 return; 2446 } 2447 2448 globals.inputEventPatched = '0.0.3'; 2449 2450 for (var _i = 0, _arr = ['select', 'input[type="checkbox"]', 'input[type="radio"]', 'input[type="file"]']; _i < _arr.length; _i++) { 2451 var selector = _arr[_i]; 2452 $(document).on('input.inputevent', selector, { 2453 selector: selector 2454 }, _this.behavesOk).on('change.inputevent', selector, { 2455 selector: selector 2456 }, _this.misbehaves); 2457 } 2458 }, 2459 uninstall: function uninstall() { 2460 delete globals.inputEventPatched; 2461 $(document).off('.inputevent'); 2462 } 2463 }); 2464 } 2465 var inputevent = new InputEvent(); 2466 2467 inputevent.install(); 2468 2469 return Parsley; 2470 2471})));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.