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