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