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