You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

jquery.validate.js 67KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660
  1. /*!
  2. * jQuery Validation Plugin v1.19.3
  3. *
  4. * https://jqueryvalidation.org/
  5. *
  6. * Copyright (c) 2021 Jörn Zaefferer
  7. * Released under the MIT license
  8. */
  9. (function (factory) {
  10. if (typeof define === "function" && define.amd) {
  11. define(["jquery"], factory);
  12. } else if (typeof module === "object" && module.exports) {
  13. module.exports = factory(require("jquery"));
  14. } else {
  15. factory(jQuery);
  16. }
  17. }(function ($) {
  18. $.extend($.fn, {
  19. // https://jqueryvalidation.org/validate/
  20. validate: function (options) {
  21. // If nothing is selected, return nothing; can't chain anyway
  22. if (!this.length) {
  23. if (options && options.debug && window.console) {
  24. console.warn("Nothing selected, can't validate, returning nothing.");
  25. }
  26. return;
  27. }
  28. // Check if a validator for this form was already created
  29. var validator = $.data(this[0], "validator");
  30. if (validator) {
  31. return validator;
  32. }
  33. // Add novalidate tag if HTML5.
  34. this.attr("novalidate", "novalidate");
  35. validator = new $.validator(options, this[0]);
  36. $.data(this[0], "validator", validator);
  37. if (validator.settings.onsubmit) {
  38. this.on("click.validate", ":submit", function (event) {
  39. // Track the used submit button to properly handle scripted
  40. // submits later.
  41. validator.submitButton = event.currentTarget;
  42. // Allow suppressing validation by adding a cancel class to the submit button
  43. if ($(this).hasClass("cancel")) {
  44. validator.cancelSubmit = true;
  45. }
  46. // Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
  47. if ($(this).attr("formnovalidate") !== undefined) {
  48. validator.cancelSubmit = true;
  49. }
  50. });
  51. // Validate the form on submit
  52. this.on("submit.validate", function (event) {
  53. if (validator.settings.debug) {
  54. // Prevent form submit to be able to see console output
  55. event.preventDefault();
  56. }
  57. function handle() {
  58. var hidden, result;
  59. // Insert a hidden input as a replacement for the missing submit button
  60. // The hidden input is inserted in two cases:
  61. // - A user defined a `submitHandler`
  62. // - There was a pending request due to `remote` method and `stopRequest()`
  63. // was called to submit the form in case it's valid
  64. if (validator.submitButton && (validator.settings.submitHandler || validator.formSubmitted)) {
  65. hidden = $("<input type='hidden'/>")
  66. .attr("name", validator.submitButton.name)
  67. .val($(validator.submitButton).val())
  68. .appendTo(validator.currentForm);
  69. }
  70. if (validator.settings.submitHandler && !validator.settings.debug) {
  71. result = validator.settings.submitHandler.call(validator, validator.currentForm, event);
  72. if (hidden) {
  73. // And clean up afterwards; thanks to no-block-scope, hidden can be referenced
  74. hidden.remove();
  75. }
  76. if (result !== undefined) {
  77. return result;
  78. }
  79. return false;
  80. }
  81. return true;
  82. }
  83. // Prevent submit for invalid forms or custom submit handlers
  84. if (validator.cancelSubmit) {
  85. validator.cancelSubmit = false;
  86. return handle();
  87. }
  88. if (validator.form()) {
  89. if (validator.pendingRequest) {
  90. validator.formSubmitted = true;
  91. return false;
  92. }
  93. return handle();
  94. } else {
  95. validator.focusInvalid();
  96. return false;
  97. }
  98. });
  99. }
  100. return validator;
  101. },
  102. // https://jqueryvalidation.org/valid/
  103. valid: function () {
  104. var valid, validator, errorList;
  105. if ($(this[0]).is("form")) {
  106. valid = this.validate().form();
  107. } else {
  108. errorList = [];
  109. valid = true;
  110. validator = $(this[0].form).validate();
  111. this.each(function () {
  112. valid = validator.element(this) && valid;
  113. if (!valid) {
  114. errorList = errorList.concat(validator.errorList);
  115. }
  116. });
  117. validator.errorList = errorList;
  118. }
  119. return valid;
  120. },
  121. // https://jqueryvalidation.org/rules/
  122. rules: function (command, argument) {
  123. var element = this[0],
  124. isContentEditable = typeof this.attr("contenteditable") !== "undefined" && this.attr("contenteditable") !== "false",
  125. settings, staticRules, existingRules, data, param, filtered;
  126. // If nothing is selected, return empty object; can't chain anyway
  127. if (element == null) {
  128. return;
  129. }
  130. if (!element.form && isContentEditable) {
  131. element.form = this.closest("form")[0];
  132. element.name = this.attr("name");
  133. }
  134. if (element.form == null) {
  135. return;
  136. }
  137. if (command) {
  138. settings = $.data(element.form, "validator").settings;
  139. staticRules = settings.rules;
  140. existingRules = $.validator.staticRules(element);
  141. switch (command) {
  142. case "add":
  143. $.extend(existingRules, $.validator.normalizeRule(argument));
  144. // Remove messages from rules, but allow them to be set separately
  145. delete existingRules.messages;
  146. staticRules[element.name] = existingRules;
  147. if (argument.messages) {
  148. settings.messages[element.name] = $.extend(settings.messages[element.name], argument.messages);
  149. }
  150. break;
  151. case "remove":
  152. if (!argument) {
  153. delete staticRules[element.name];
  154. return existingRules;
  155. }
  156. filtered = {};
  157. $.each(argument.split(/\s/), function (index, method) {
  158. filtered[method] = existingRules[method];
  159. delete existingRules[method];
  160. });
  161. return filtered;
  162. }
  163. }
  164. data = $.validator.normalizeRules(
  165. $.extend(
  166. {},
  167. $.validator.classRules(element),
  168. $.validator.attributeRules(element),
  169. $.validator.dataRules(element),
  170. $.validator.staticRules(element)
  171. ), element);
  172. // Make sure required is at front
  173. if (data.required) {
  174. param = data.required;
  175. delete data.required;
  176. data = $.extend({required: param}, data);
  177. }
  178. // Make sure remote is at back
  179. if (data.remote) {
  180. param = data.remote;
  181. delete data.remote;
  182. data = $.extend(data, {remote: param});
  183. }
  184. return data;
  185. }
  186. });
  187. // JQuery trim is deprecated, provide a trim method based on String.prototype.trim
  188. var trim = function (str) {
  189. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim#Polyfill
  190. return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "");
  191. };
  192. // Custom selectors
  193. $.extend($.expr.pseudos || $.expr[":"], { // '|| $.expr[ ":" ]' here enables backwards compatibility to jQuery 1.7. Can be removed when dropping jQ 1.7.x support
  194. // https://jqueryvalidation.org/blank-selector/
  195. blank: function (a) {
  196. return !trim("" + $(a).val());
  197. },
  198. // https://jqueryvalidation.org/filled-selector/
  199. filled: function (a) {
  200. var val = $(a).val();
  201. return val !== null && !!trim("" + val);
  202. },
  203. // https://jqueryvalidation.org/unchecked-selector/
  204. unchecked: function (a) {
  205. return !$(a).prop("checked");
  206. }
  207. });
  208. // Constructor for validator
  209. $.validator = function (options, form) {
  210. this.settings = $.extend(true, {}, $.validator.defaults, options);
  211. this.currentForm = form;
  212. this.init();
  213. };
  214. // https://jqueryvalidation.org/jQuery.validator.format/
  215. $.validator.format = function (source, params) {
  216. if (arguments.length === 1) {
  217. return function () {
  218. var args = $.makeArray(arguments);
  219. args.unshift(source);
  220. return $.validator.format.apply(this, args);
  221. };
  222. }
  223. if (params === undefined) {
  224. return source;
  225. }
  226. if (arguments.length > 2 && params.constructor !== Array) {
  227. params = $.makeArray(arguments).slice(1);
  228. }
  229. if (params.constructor !== Array) {
  230. params = [params];
  231. }
  232. $.each(params, function (i, n) {
  233. source = source.replace(new RegExp("\\{" + i + "\\}", "g"), function () {
  234. return n;
  235. });
  236. });
  237. return source;
  238. };
  239. $.extend($.validator, {
  240. defaults: {
  241. messages: {},
  242. groups: {},
  243. rules: {},
  244. errorClass: "error",
  245. pendingClass: "pending",
  246. validClass: "valid",
  247. errorElement: "label",
  248. focusCleanup: false,
  249. focusInvalid: true,
  250. errorContainer: $([]),
  251. errorLabelContainer: $([]),
  252. onsubmit: true,
  253. ignore: ":hidden",
  254. ignoreTitle: false,
  255. onfocusin: function (element) {
  256. this.lastActive = element;
  257. // Hide error label and remove error class on focus if enabled
  258. if (this.settings.focusCleanup) {
  259. if (this.settings.unhighlight) {
  260. this.settings.unhighlight.call(this, element, this.settings.errorClass, this.settings.validClass);
  261. }
  262. this.hideThese(this.errorsFor(element));
  263. }
  264. },
  265. onfocusout: function (element) {
  266. if (!this.checkable(element) && (element.name in this.submitted || !this.optional(element))) {
  267. this.element(element);
  268. }
  269. },
  270. onkeyup: function (element, event) {
  271. // Avoid revalidate the field when pressing one of the following keys
  272. // Shift => 16
  273. // Ctrl => 17
  274. // Alt => 18
  275. // Caps lock => 20
  276. // End => 35
  277. // Home => 36
  278. // Left arrow => 37
  279. // Up arrow => 38
  280. // Right arrow => 39
  281. // Down arrow => 40
  282. // Insert => 45
  283. // Num lock => 144
  284. // AltGr key => 225
  285. var excludedKeys = [
  286. 16, 17, 18, 20, 35, 36, 37,
  287. 38, 39, 40, 45, 144, 225
  288. ];
  289. if (event.which === 9 && this.elementValue(element) === "" || $.inArray(event.keyCode, excludedKeys) !== -1) {
  290. } else if (element.name in this.submitted || element.name in this.invalid) {
  291. this.element(element);
  292. }
  293. },
  294. onclick: function (element) {
  295. // Click on selects, radiobuttons and checkboxes
  296. if (element.name in this.submitted) {
  297. this.element(element);
  298. // Or option elements, check parent select in that case
  299. } else if (element.parentNode.name in this.submitted) {
  300. this.element(element.parentNode);
  301. }
  302. },
  303. highlight: function (element, errorClass, validClass) {
  304. if (element.type === "radio") {
  305. this.findByName(element.name).addClass(errorClass).removeClass(validClass);
  306. } else {
  307. $(element).addClass(errorClass).removeClass(validClass);
  308. }
  309. },
  310. unhighlight: function (element, errorClass, validClass) {
  311. if (element.type === "radio") {
  312. this.findByName(element.name).removeClass(errorClass).addClass(validClass);
  313. } else {
  314. $(element).removeClass(errorClass).addClass(validClass);
  315. }
  316. }
  317. },
  318. // https://jqueryvalidation.org/jQuery.validator.setDefaults/
  319. setDefaults: function (settings) {
  320. $.extend($.validator.defaults, settings);
  321. },
  322. messages: {
  323. required: "This field is required.",
  324. remote: "Please fix this field.",
  325. email: "Please enter a valid email address.",
  326. url: "Please enter a valid URL.",
  327. date: "Please enter a valid date.",
  328. dateISO: "Please enter a valid date (ISO).",
  329. number: "Please enter a valid number.",
  330. digits: "Please enter only digits.",
  331. equalTo: "Please enter the same value again.",
  332. maxlength: $.validator.format("Please enter no more than {0} characters."),
  333. minlength: $.validator.format("Please enter at least {0} characters."),
  334. rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
  335. range: $.validator.format("Please enter a value between {0} and {1}."),
  336. max: $.validator.format("Please enter a value less than or equal to {0}."),
  337. min: $.validator.format("Please enter a value greater than or equal to {0}."),
  338. step: $.validator.format("Please enter a multiple of {0}.")
  339. },
  340. autoCreateRanges: false,
  341. prototype: {
  342. init: function () {
  343. this.labelContainer = $(this.settings.errorLabelContainer);
  344. this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
  345. this.containers = $(this.settings.errorContainer).add(this.settings.errorLabelContainer);
  346. this.submitted = {};
  347. this.valueCache = {};
  348. this.pendingRequest = 0;
  349. this.pending = {};
  350. this.invalid = {};
  351. this.reset();
  352. var currentForm = this.currentForm,
  353. groups = (this.groups = {}),
  354. rules;
  355. $.each(this.settings.groups, function (key, value) {
  356. if (typeof value === "string") {
  357. value = value.split(/\s/);
  358. }
  359. $.each(value, function (index, name) {
  360. groups[name] = key;
  361. });
  362. });
  363. rules = this.settings.rules;
  364. $.each(rules, function (key, value) {
  365. rules[key] = $.validator.normalizeRule(value);
  366. });
  367. function delegate(event) {
  368. var isContentEditable = typeof $(this).attr("contenteditable") !== "undefined" && $(this).attr("contenteditable") !== "false";
  369. // Set form expando on contenteditable
  370. if (!this.form && isContentEditable) {
  371. this.form = $(this).closest("form")[0];
  372. this.name = $(this).attr("name");
  373. }
  374. // Ignore the element if it belongs to another form. This will happen mainly
  375. // when setting the `form` attribute of an input to the id of another form.
  376. if (currentForm !== this.form) {
  377. return;
  378. }
  379. var validator = $.data(this.form, "validator"),
  380. eventType = "on" + event.type.replace(/^validate/, ""),
  381. settings = validator.settings;
  382. if (settings[eventType] && !$(this).is(settings.ignore)) {
  383. settings[eventType].call(validator, this, event);
  384. }
  385. }
  386. $(this.currentForm)
  387. .on("focusin.validate focusout.validate keyup.validate",
  388. ":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], " +
  389. "[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], " +
  390. "[type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], " +
  391. "[type='radio'], [type='checkbox'], [contenteditable], [type='button']", delegate)
  392. // Support: Chrome, oldIE
  393. // "select" is provided as event.target when clicking a option
  394. .on("click.validate", "select, option, [type='radio'], [type='checkbox']", delegate);
  395. if (this.settings.invalidHandler) {
  396. $(this.currentForm).on("invalid-form.validate", this.settings.invalidHandler);
  397. }
  398. },
  399. // https://jqueryvalidation.org/Validator.form/
  400. form: function () {
  401. this.checkForm();
  402. $.extend(this.submitted, this.errorMap);
  403. this.invalid = $.extend({}, this.errorMap);
  404. if (!this.valid()) {
  405. $(this.currentForm).triggerHandler("invalid-form", [this]);
  406. }
  407. this.showErrors();
  408. return this.valid();
  409. },
  410. checkForm: function () {
  411. this.prepareForm();
  412. for (var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++) {
  413. this.check(elements[i]);
  414. }
  415. return this.valid();
  416. },
  417. // https://jqueryvalidation.org/Validator.element/
  418. element: function (element) {
  419. var cleanElement = this.clean(element),
  420. checkElement = this.validationTargetFor(cleanElement),
  421. v = this,
  422. result = true,
  423. rs, group;
  424. if (checkElement === undefined) {
  425. delete this.invalid[cleanElement.name];
  426. } else {
  427. this.prepareElement(checkElement);
  428. this.currentElements = $(checkElement);
  429. // If this element is grouped, then validate all group elements already
  430. // containing a value
  431. group = this.groups[checkElement.name];
  432. if (group) {
  433. $.each(this.groups, function (name, testgroup) {
  434. if (testgroup === group && name !== checkElement.name) {
  435. cleanElement = v.validationTargetFor(v.clean(v.findByName(name)));
  436. if (cleanElement && cleanElement.name in v.invalid) {
  437. v.currentElements.push(cleanElement);
  438. result = v.check(cleanElement) && result;
  439. }
  440. }
  441. });
  442. }
  443. rs = this.check(checkElement) !== false;
  444. result = result && rs;
  445. if (rs) {
  446. this.invalid[checkElement.name] = false;
  447. } else {
  448. this.invalid[checkElement.name] = true;
  449. }
  450. if (!this.numberOfInvalids()) {
  451. // Hide error containers on last error
  452. this.toHide = this.toHide.add(this.containers);
  453. }
  454. this.showErrors();
  455. // Add aria-invalid status for screen readers
  456. $(element).attr("aria-invalid", !rs);
  457. }
  458. return result;
  459. },
  460. // https://jqueryvalidation.org/Validator.showErrors/
  461. showErrors: function (errors) {
  462. if (errors) {
  463. var validator = this;
  464. // Add items to error list and map
  465. $.extend(this.errorMap, errors);
  466. this.errorList = $.map(this.errorMap, function (message, name) {
  467. return {
  468. message: message,
  469. element: validator.findByName(name)[0]
  470. };
  471. });
  472. // Remove items from success list
  473. this.successList = $.grep(this.successList, function (element) {
  474. return !(element.name in errors);
  475. });
  476. }
  477. if (this.settings.showErrors) {
  478. this.settings.showErrors.call(this, this.errorMap, this.errorList);
  479. } else {
  480. this.defaultShowErrors();
  481. }
  482. },
  483. // https://jqueryvalidation.org/Validator.resetForm/
  484. resetForm: function () {
  485. if ($.fn.resetForm) {
  486. $(this.currentForm).resetForm();
  487. }
  488. this.invalid = {};
  489. this.submitted = {};
  490. this.prepareForm();
  491. this.hideErrors();
  492. var elements = this.elements()
  493. .removeData("previousValue")
  494. .removeAttr("aria-invalid");
  495. this.resetElements(elements);
  496. },
  497. resetElements: function (elements) {
  498. var i;
  499. if (this.settings.unhighlight) {
  500. for (i = 0; elements[i]; i++) {
  501. this.settings.unhighlight.call(this, elements[i],
  502. this.settings.errorClass, "");
  503. this.findByName(elements[i].name).removeClass(this.settings.validClass);
  504. }
  505. } else {
  506. elements
  507. .removeClass(this.settings.errorClass)
  508. .removeClass(this.settings.validClass);
  509. }
  510. },
  511. numberOfInvalids: function () {
  512. return this.objectLength(this.invalid);
  513. },
  514. objectLength: function (obj) {
  515. /* jshint unused: false */
  516. var count = 0,
  517. i;
  518. for (i in obj) {
  519. // This check allows counting elements with empty error
  520. // message as invalid elements
  521. if (obj[i] !== undefined && obj[i] !== null && obj[i] !== false) {
  522. count++;
  523. }
  524. }
  525. return count;
  526. },
  527. hideErrors: function () {
  528. this.hideThese(this.toHide);
  529. },
  530. hideThese: function (errors) {
  531. errors.not(this.containers).text("");
  532. this.addWrapper(errors).hide();
  533. },
  534. valid: function () {
  535. return this.size() === 0;
  536. },
  537. size: function () {
  538. return this.errorList.length;
  539. },
  540. focusInvalid: function () {
  541. if (this.settings.focusInvalid) {
  542. try {
  543. $(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
  544. .filter(":visible")
  545. .trigger("focus")
  546. // Manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
  547. .trigger("focusin");
  548. } catch (e) {
  549. // Ignore IE throwing errors when focusing hidden elements
  550. }
  551. }
  552. },
  553. findLastActive: function () {
  554. var lastActive = this.lastActive;
  555. return lastActive && $.grep(this.errorList, function (n) {
  556. return n.element.name === lastActive.name;
  557. }).length === 1 && lastActive;
  558. },
  559. elements: function () {
  560. var validator = this,
  561. rulesCache = {};
  562. // Select all valid inputs inside the form (no submit or reset buttons)
  563. return $(this.currentForm)
  564. .find("input, select, textarea, [contenteditable]")
  565. .not(":submit, :reset, :image, :disabled")
  566. .not(this.settings.ignore)
  567. .filter(function () {
  568. var name = this.name || $(this).attr("name"); // For contenteditable
  569. var isContentEditable = typeof $(this).attr("contenteditable") !== "undefined" && $(this).attr("contenteditable") !== "false";
  570. if (!name && validator.settings.debug && window.console) {
  571. console.error("%o has no name assigned", this);
  572. }
  573. // Set form expando on contenteditable
  574. if (isContentEditable) {
  575. this.form = $(this).closest("form")[0];
  576. this.name = name;
  577. }
  578. // Ignore elements that belong to other/nested forms
  579. if (this.form !== validator.currentForm) {
  580. return false;
  581. }
  582. // Select only the first element for each name, and only those with rules specified
  583. if (name in rulesCache || !validator.objectLength($(this).rules())) {
  584. return false;
  585. }
  586. rulesCache[name] = true;
  587. return true;
  588. });
  589. },
  590. clean: function (selector) {
  591. return $(selector)[0];
  592. },
  593. errors: function () {
  594. var errorClass = this.settings.errorClass.split(" ").join(".");
  595. return $(this.settings.errorElement + "." + errorClass, this.errorContext);
  596. },
  597. resetInternals: function () {
  598. this.successList = [];
  599. this.errorList = [];
  600. this.errorMap = {};
  601. this.toShow = $([]);
  602. this.toHide = $([]);
  603. },
  604. reset: function () {
  605. this.resetInternals();
  606. this.currentElements = $([]);
  607. },
  608. prepareForm: function () {
  609. this.reset();
  610. this.toHide = this.errors().add(this.containers);
  611. },
  612. prepareElement: function (element) {
  613. this.reset();
  614. this.toHide = this.errorsFor(element);
  615. },
  616. elementValue: function (element) {
  617. var $element = $(element),
  618. type = element.type,
  619. isContentEditable = typeof $element.attr("contenteditable") !== "undefined" && $element.attr("contenteditable") !== "false",
  620. val, idx;
  621. if (type === "radio" || type === "checkbox") {
  622. return this.findByName(element.name).filter(":checked").val();
  623. } else if (type === "number" && typeof element.validity !== "undefined") {
  624. return element.validity.badInput ? "NaN" : $element.val();
  625. }
  626. if (isContentEditable) {
  627. val = $element.text();
  628. } else {
  629. val = $element.val();
  630. }
  631. if (type === "file") {
  632. // Modern browser (chrome & safari)
  633. if (val.substr(0, 12) === "C:\\fakepath\\") {
  634. return val.substr(12);
  635. }
  636. // Legacy browsers
  637. // Unix-based path
  638. idx = val.lastIndexOf("/");
  639. if (idx >= 0) {
  640. return val.substr(idx + 1);
  641. }
  642. // Windows-based path
  643. idx = val.lastIndexOf("\\");
  644. if (idx >= 0) {
  645. return val.substr(idx + 1);
  646. }
  647. // Just the file name
  648. return val;
  649. }
  650. if (typeof val === "string") {
  651. return val.replace(/\r/g, "");
  652. }
  653. return val;
  654. },
  655. check: function (element) {
  656. element = this.validationTargetFor(this.clean(element));
  657. var rules = $(element).rules(),
  658. rulesCount = $.map(rules, function (n, i) {
  659. return i;
  660. }).length,
  661. dependencyMismatch = false,
  662. val = this.elementValue(element),
  663. result, method, rule, normalizer;
  664. // Prioritize the local normalizer defined for this element over the global one
  665. // if the former exists, otherwise user the global one in case it exists.
  666. if (typeof rules.normalizer === "function") {
  667. normalizer = rules.normalizer;
  668. } else if (typeof this.settings.normalizer === "function") {
  669. normalizer = this.settings.normalizer;
  670. }
  671. // If normalizer is defined, then call it to retreive the changed value instead
  672. // of using the real one.
  673. // Note that `this` in the normalizer is `element`.
  674. if (normalizer) {
  675. val = normalizer.call(element, val);
  676. // Delete the normalizer from rules to avoid treating it as a pre-defined method.
  677. delete rules.normalizer;
  678. }
  679. for (method in rules) {
  680. rule = {method: method, parameters: rules[method]};
  681. try {
  682. result = $.validator.methods[method].call(this, val, element, rule.parameters);
  683. // If a method indicates that the field is optional and therefore valid,
  684. // don't mark it as valid when there are no other rules
  685. if (result === "dependency-mismatch" && rulesCount === 1) {
  686. dependencyMismatch = true;
  687. continue;
  688. }
  689. dependencyMismatch = false;
  690. if (result === "pending") {
  691. this.toHide = this.toHide.not(this.errorsFor(element));
  692. return;
  693. }
  694. if (!result) {
  695. this.formatAndAdd(element, rule);
  696. return false;
  697. }
  698. } catch (e) {
  699. if (this.settings.debug && window.console) {
  700. console.log("Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e);
  701. }
  702. if (e instanceof TypeError) {
  703. e.message += ". Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.";
  704. }
  705. throw e;
  706. }
  707. }
  708. if (dependencyMismatch) {
  709. return;
  710. }
  711. if (this.objectLength(rules)) {
  712. this.successList.push(element);
  713. }
  714. return true;
  715. },
  716. // Return the custom message for the given element and validation method
  717. // specified in the element's HTML5 data attribute
  718. // return the generic message if present and no method specific message is present
  719. customDataMessage: function (element, method) {
  720. return $(element).data("msg" + method.charAt(0).toUpperCase() +
  721. method.substring(1).toLowerCase()) || $(element).data("msg");
  722. },
  723. // Return the custom message for the given element name and validation method
  724. customMessage: function (name, method) {
  725. var m = this.settings.messages[name];
  726. return m && (m.constructor === String ? m : m[method]);
  727. },
  728. // Return the first defined argument, allowing empty strings
  729. findDefined: function () {
  730. for (var i = 0; i < arguments.length; i++) {
  731. if (arguments[i] !== undefined) {
  732. return arguments[i];
  733. }
  734. }
  735. return undefined;
  736. },
  737. // The second parameter 'rule' used to be a string, and extended to an object literal
  738. // of the following form:
  739. // rule = {
  740. // method: "method name",
  741. // parameters: "the given method parameters"
  742. // }
  743. //
  744. // The old behavior still supported, kept to maintain backward compatibility with
  745. // old code, and will be removed in the next major release.
  746. defaultMessage: function (element, rule) {
  747. if (typeof rule === "string") {
  748. rule = {method: rule};
  749. }
  750. var message = this.findDefined(
  751. this.customMessage(element.name, rule.method),
  752. this.customDataMessage(element, rule.method),
  753. // 'title' is never undefined, so handle empty string as undefined
  754. !this.settings.ignoreTitle && element.title || undefined,
  755. $.validator.messages[rule.method],
  756. "<strong>Warning: No message defined for " + element.name + "</strong>"
  757. ),
  758. theregex = /\$?\{(\d+)\}/g;
  759. if (typeof message === "function") {
  760. message = message.call(this, rule.parameters, element);
  761. } else if (theregex.test(message)) {
  762. message = $.validator.format(message.replace(theregex, "{$1}"), rule.parameters);
  763. }
  764. return message;
  765. },
  766. formatAndAdd: function (element, rule) {
  767. var message = this.defaultMessage(element, rule);
  768. this.errorList.push({
  769. message: message,
  770. element: element,
  771. method: rule.method
  772. });
  773. this.errorMap[element.name] = message;
  774. this.submitted[element.name] = message;
  775. },
  776. addWrapper: function (toToggle) {
  777. if (this.settings.wrapper) {
  778. toToggle = toToggle.add(toToggle.parent(this.settings.wrapper));
  779. }
  780. return toToggle;
  781. },
  782. defaultShowErrors: function () {
  783. var i, elements, error;
  784. for (i = 0; this.errorList[i]; i++) {
  785. error = this.errorList[i];
  786. if (this.settings.highlight) {
  787. this.settings.highlight.call(this, error.element, this.settings.errorClass, this.settings.validClass);
  788. }
  789. this.showLabel(error.element, error.message);
  790. }
  791. if (this.errorList.length) {
  792. this.toShow = this.toShow.add(this.containers);
  793. }
  794. if (this.settings.success) {
  795. for (i = 0; this.successList[i]; i++) {
  796. this.showLabel(this.successList[i]);
  797. }
  798. }
  799. if (this.settings.unhighlight) {
  800. for (i = 0, elements = this.validElements(); elements[i]; i++) {
  801. this.settings.unhighlight.call(this, elements[i], this.settings.errorClass, this.settings.validClass);
  802. }
  803. }
  804. this.toHide = this.toHide.not(this.toShow);
  805. this.hideErrors();
  806. this.addWrapper(this.toShow).show();
  807. },
  808. validElements: function () {
  809. return this.currentElements.not(this.invalidElements());
  810. },
  811. invalidElements: function () {
  812. return $(this.errorList).map(function () {
  813. return this.element;
  814. });
  815. },
  816. showLabel: function (element, message) {
  817. var place, group, errorID, v,
  818. error = this.errorsFor(element),
  819. elementID = this.idOrName(element),
  820. describedBy = $(element).attr("aria-describedby");
  821. if (error.length) {
  822. // Refresh error/success class
  823. error.removeClass(this.settings.validClass).addClass(this.settings.errorClass);
  824. // Replace message on existing label
  825. error.html(message);
  826. } else {
  827. // Create error element
  828. error = $("<" + this.settings.errorElement + ">")
  829. .attr("id", elementID + "-error")
  830. .addClass(this.settings.errorClass)
  831. .html(message || "");
  832. // Maintain reference to the element to be placed into the DOM
  833. place = error;
  834. if (this.settings.wrapper) {
  835. // Make sure the element is visible, even in IE
  836. // actually showing the wrapped element is handled elsewhere
  837. place = error.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
  838. }
  839. if (this.labelContainer.length) {
  840. this.labelContainer.append(place);
  841. } else if (this.settings.errorPlacement) {
  842. this.settings.errorPlacement.call(this, place, $(element));
  843. } else {
  844. place.insertAfter(element);
  845. }
  846. // Link error back to the element
  847. if (error.is("label")) {
  848. // If the error is a label, then associate using 'for'
  849. error.attr("for", elementID);
  850. // If the element is not a child of an associated label, then it's necessary
  851. // to explicitly apply aria-describedby
  852. } else if (error.parents("label[for='" + this.escapeCssMeta(elementID) + "']").length === 0) {
  853. errorID = error.attr("id");
  854. // Respect existing non-error aria-describedby
  855. if (!describedBy) {
  856. describedBy = errorID;
  857. } else if (!describedBy.match(new RegExp("\\b" + this.escapeCssMeta(errorID) + "\\b"))) {
  858. // Add to end of list if not already present
  859. describedBy += " " + errorID;
  860. }
  861. $(element).attr("aria-describedby", describedBy);
  862. // If this element is grouped, then assign to all elements in the same group
  863. group = this.groups[element.name];
  864. if (group) {
  865. v = this;
  866. $.each(v.groups, function (name, testgroup) {
  867. if (testgroup === group) {
  868. $("[name='" + v.escapeCssMeta(name) + "']", v.currentForm)
  869. .attr("aria-describedby", error.attr("id"));
  870. }
  871. });
  872. }
  873. }
  874. }
  875. if (!message && this.settings.success) {
  876. error.text("");
  877. if (typeof this.settings.success === "string") {
  878. error.addClass(this.settings.success);
  879. } else {
  880. this.settings.success(error, element);
  881. }
  882. }
  883. this.toShow = this.toShow.add(error);
  884. },
  885. errorsFor: function (element) {
  886. var name = this.escapeCssMeta(this.idOrName(element)),
  887. describer = $(element).attr("aria-describedby"),
  888. selector = "label[for='" + name + "'], label[for='" + name + "'] *";
  889. // 'aria-describedby' should directly reference the error element
  890. if (describer) {
  891. selector = selector + ", #" + this.escapeCssMeta(describer)
  892. .replace(/\s+/g, ", #");
  893. }
  894. return this
  895. .errors()
  896. .filter(selector);
  897. },
  898. // See https://api.jquery.com/category/selectors/, for CSS
  899. // meta-characters that should be escaped in order to be used with JQuery
  900. // as a literal part of a name/id or any selector.
  901. escapeCssMeta: function (string) {
  902. return string.replace(/([\\!"#$%&'()*+,./:;<=>?@\[\]^`{|}~])/g, "\\$1");
  903. },
  904. idOrName: function (element) {
  905. return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
  906. },
  907. validationTargetFor: function (element) {
  908. // If radio/checkbox, validate first element in group instead
  909. if (this.checkable(element)) {
  910. element = this.findByName(element.name);
  911. }
  912. // Always apply ignore filter
  913. return $(element).not(this.settings.ignore)[0];
  914. },
  915. checkable: function (element) {
  916. return (/radio|checkbox/i).test(element.type);
  917. },
  918. findByName: function (name) {
  919. return $(this.currentForm).find("[name='" + this.escapeCssMeta(name) + "']");
  920. },
  921. getLength: function (value, element) {
  922. switch (element.nodeName.toLowerCase()) {
  923. case "select":
  924. return $("option:selected", element).length;
  925. case "input":
  926. if (this.checkable(element)) {
  927. return this.findByName(element.name).filter(":checked").length;
  928. }
  929. }
  930. return value.length;
  931. },
  932. depend: function (param, element) {
  933. return this.dependTypes[typeof param] ? this.dependTypes[typeof param](param, element) : true;
  934. },
  935. dependTypes: {
  936. "boolean": function (param) {
  937. return param;
  938. },
  939. "string": function (param, element) {
  940. return !!$(param, element.form).length;
  941. },
  942. "function": function (param, element) {
  943. return param(element);
  944. }
  945. },
  946. optional: function (element) {
  947. var val = this.elementValue(element);
  948. return !$.validator.methods.required.call(this, val, element) && "dependency-mismatch";
  949. },
  950. startRequest: function (element) {
  951. if (!this.pending[element.name]) {
  952. this.pendingRequest++;
  953. $(element).addClass(this.settings.pendingClass);
  954. this.pending[element.name] = true;
  955. }
  956. },
  957. stopRequest: function (element, valid) {
  958. this.pendingRequest--;
  959. // Sometimes synchronization fails, make sure pendingRequest is never < 0
  960. if (this.pendingRequest < 0) {
  961. this.pendingRequest = 0;
  962. }
  963. delete this.pending[element.name];
  964. $(element).removeClass(this.settings.pendingClass);
  965. if (valid && this.pendingRequest === 0 && this.formSubmitted && this.form()) {
  966. $(this.currentForm).submit();
  967. // Remove the hidden input that was used as a replacement for the
  968. // missing submit button. The hidden input is added by `handle()`
  969. // to ensure that the value of the used submit button is passed on
  970. // for scripted submits triggered by this method
  971. if (this.submitButton) {
  972. $("input:hidden[name='" + this.submitButton.name + "']", this.currentForm).remove();
  973. }
  974. this.formSubmitted = false;
  975. } else if (!valid && this.pendingRequest === 0 && this.formSubmitted) {
  976. $(this.currentForm).triggerHandler("invalid-form", [this]);
  977. this.formSubmitted = false;
  978. }
  979. },
  980. previousValue: function (element, method) {
  981. method = typeof method === "string" && method || "remote";
  982. return $.data(element, "previousValue") || $.data(element, "previousValue", {
  983. old: null,
  984. valid: true,
  985. message: this.defaultMessage(element, {method: method})
  986. });
  987. },
  988. // Cleans up all forms and elements, removes validator-specific events
  989. destroy: function () {
  990. this.resetForm();
  991. $(this.currentForm)
  992. .off(".validate")
  993. .removeData("validator")
  994. .find(".validate-equalTo-blur")
  995. .off(".validate-equalTo")
  996. .removeClass("validate-equalTo-blur")
  997. .find(".validate-lessThan-blur")
  998. .off(".validate-lessThan")
  999. .removeClass("validate-lessThan-blur")
  1000. .find(".validate-lessThanEqual-blur")
  1001. .off(".validate-lessThanEqual")
  1002. .removeClass("validate-lessThanEqual-blur")
  1003. .find(".validate-greaterThanEqual-blur")
  1004. .off(".validate-greaterThanEqual")
  1005. .removeClass("validate-greaterThanEqual-blur")
  1006. .find(".validate-greaterThan-blur")
  1007. .off(".validate-greaterThan")
  1008. .removeClass("validate-greaterThan-blur");
  1009. }
  1010. },
  1011. classRuleSettings: {
  1012. required: {required: true},
  1013. email: {email: true},
  1014. url: {url: true},
  1015. date: {date: true},
  1016. dateISO: {dateISO: true},
  1017. number: {number: true},
  1018. digits: {digits: true},
  1019. creditcard: {creditcard: true}
  1020. },
  1021. addClassRules: function (className, rules) {
  1022. if (className.constructor === String) {
  1023. this.classRuleSettings[className] = rules;
  1024. } else {
  1025. $.extend(this.classRuleSettings, className);
  1026. }
  1027. },
  1028. classRules: function (element) {
  1029. var rules = {},
  1030. classes = $(element).attr("class");
  1031. if (classes) {
  1032. $.each(classes.split(" "), function () {
  1033. if (this in $.validator.classRuleSettings) {
  1034. $.extend(rules, $.validator.classRuleSettings[this]);
  1035. }
  1036. });
  1037. }
  1038. return rules;
  1039. },
  1040. normalizeAttributeRule: function (rules, type, method, value) {
  1041. // Convert the value to a number for number inputs, and for text for backwards compability
  1042. // allows type="date" and others to be compared as strings
  1043. if (/min|max|step/.test(method) && (type === null || /number|range|text/.test(type))) {
  1044. value = Number(value);
  1045. // Support Opera Mini, which returns NaN for undefined minlength
  1046. if (isNaN(value)) {
  1047. value = undefined;
  1048. }
  1049. }
  1050. if (value || value === 0) {
  1051. rules[method] = value;
  1052. } else if (type === method && type !== "range") {
  1053. // Exception: the jquery validate 'range' method
  1054. // does not test for the html5 'range' type
  1055. rules[method] = true;
  1056. }
  1057. },
  1058. attributeRules: function (element) {
  1059. var rules = {},
  1060. $element = $(element),
  1061. type = element.getAttribute("type"),
  1062. method, value;
  1063. for (method in $.validator.methods) {
  1064. // Support for <input required> in both html5 and older browsers
  1065. if (method === "required") {
  1066. value = element.getAttribute(method);
  1067. // Some browsers return an empty string for the required attribute
  1068. // and non-HTML5 browsers might have required="" markup
  1069. if (value === "") {
  1070. value = true;
  1071. }
  1072. // Force non-HTML5 browsers to return bool
  1073. value = !!value;
  1074. } else {
  1075. value = $element.attr(method);
  1076. }
  1077. this.normalizeAttributeRule(rules, type, method, value);
  1078. }
  1079. // 'maxlength' may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs
  1080. if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {
  1081. delete rules.maxlength;
  1082. }
  1083. return rules;
  1084. },
  1085. dataRules: function (element) {
  1086. var rules = {},
  1087. $element = $(element),
  1088. type = element.getAttribute("type"),
  1089. method, value;
  1090. for (method in $.validator.methods) {
  1091. value = $element.data("rule" + method.charAt(0).toUpperCase() + method.substring(1).toLowerCase());
  1092. // Cast empty attributes like `data-rule-required` to `true`
  1093. if (value === "") {
  1094. value = true;
  1095. }
  1096. this.normalizeAttributeRule(rules, type, method, value);
  1097. }
  1098. return rules;
  1099. },
  1100. staticRules: function (element) {
  1101. var rules = {},
  1102. validator = $.data(element.form, "validator");
  1103. if (validator.settings.rules) {
  1104. rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
  1105. }
  1106. return rules;
  1107. },
  1108. normalizeRules: function (rules, element) {
  1109. // Handle dependency check
  1110. $.each(rules, function (prop, val) {
  1111. // Ignore rule when param is explicitly false, eg. required:false
  1112. if (val === false) {
  1113. delete rules[prop];
  1114. return;
  1115. }
  1116. if (val.param || val.depends) {
  1117. var keepRule = true;
  1118. switch (typeof val.depends) {
  1119. case "string":
  1120. keepRule = !!$(val.depends, element.form).length;
  1121. break;
  1122. case "function":
  1123. keepRule = val.depends.call(element, element);
  1124. break;
  1125. }
  1126. if (keepRule) {
  1127. rules[prop] = val.param !== undefined ? val.param : true;
  1128. } else {
  1129. $.data(element.form, "validator").resetElements($(element));
  1130. delete rules[prop];
  1131. }
  1132. }
  1133. });
  1134. // Evaluate parameters
  1135. $.each(rules, function (rule, parameter) {
  1136. rules[rule] = typeof parameter === "function" && rule !== "normalizer" ? parameter(element) : parameter;
  1137. });
  1138. // Clean number parameters
  1139. $.each(["minlength", "maxlength"], function () {
  1140. if (rules[this]) {
  1141. rules[this] = Number(rules[this]);
  1142. }
  1143. });
  1144. $.each(["rangelength", "range"], function () {
  1145. var parts;
  1146. if (rules[this]) {
  1147. if (Array.isArray(rules[this])) {
  1148. rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
  1149. } else if (typeof rules[this] === "string") {
  1150. parts = rules[this].replace(/[\[\]]/g, "").split(/[\s,]+/);
  1151. rules[this] = [Number(parts[0]), Number(parts[1])];
  1152. }
  1153. }
  1154. });
  1155. if ($.validator.autoCreateRanges) {
  1156. // Auto-create ranges
  1157. if (rules.min != null && rules.max != null) {
  1158. rules.range = [rules.min, rules.max];
  1159. delete rules.min;
  1160. delete rules.max;
  1161. }
  1162. if (rules.minlength != null && rules.maxlength != null) {
  1163. rules.rangelength = [rules.minlength, rules.maxlength];
  1164. delete rules.minlength;
  1165. delete rules.maxlength;
  1166. }
  1167. }
  1168. return rules;
  1169. },
  1170. // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
  1171. normalizeRule: function (data) {
  1172. if (typeof data === "string") {
  1173. var transformed = {};
  1174. $.each(data.split(/\s/), function () {
  1175. transformed[this] = true;
  1176. });
  1177. data = transformed;
  1178. }
  1179. return data;
  1180. },
  1181. // https://jqueryvalidation.org/jQuery.validator.addMethod/
  1182. addMethod: function (name, method, message) {
  1183. $.validator.methods[name] = method;
  1184. $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name];
  1185. if (method.length < 3) {
  1186. $.validator.addClassRules(name, $.validator.normalizeRule(name));
  1187. }
  1188. },
  1189. // https://jqueryvalidation.org/jQuery.validator.methods/
  1190. methods: {
  1191. // https://jqueryvalidation.org/required-method/
  1192. required: function (value, element, param) {
  1193. // Check if dependency is met
  1194. if (!this.depend(param, element)) {
  1195. return "dependency-mismatch";
  1196. }
  1197. if (element.nodeName.toLowerCase() === "select") {
  1198. // Could be an array for select-multiple or a string, both are fine this way
  1199. var val = $(element).val();
  1200. return val && val.length > 0;
  1201. }
  1202. if (this.checkable(element)) {
  1203. return this.getLength(value, element) > 0;
  1204. }
  1205. return value !== undefined && value !== null && value.length > 0;
  1206. },
  1207. // https://jqueryvalidation.org/email-method/
  1208. email: function (value, element) {
  1209. // From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address
  1210. // Retrieved 2014-01-14
  1211. // If you have a problem with this implementation, report a bug against the above spec
  1212. // Or use custom methods to implement your own email validation
  1213. return this.optional(element) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(value);
  1214. },
  1215. // https://jqueryvalidation.org/url-method/
  1216. url: function (value, element) {
  1217. // Copyright (c) 2010-2013 Diego Perini, MIT licensed
  1218. // https://gist.github.com/dperini/729294
  1219. // see also https://mathiasbynens.be/demo/url-regex
  1220. // modified to allow protocol-relative URLs
  1221. return this.optional(element) || /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[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]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(value);
  1222. },
  1223. // https://jqueryvalidation.org/date-method/
  1224. date: (function () {
  1225. var called = false;
  1226. return function (value, element) {
  1227. if (!called) {
  1228. called = true;
  1229. if (this.settings.debug && window.console) {
  1230. console.warn(
  1231. "The `date` method is deprecated and will be removed in version '2.0.0'.\n" +
  1232. "Please don't use it, since it relies on the Date constructor, which\n" +
  1233. "behaves very differently across browsers and locales. Use `dateISO`\n" +
  1234. "instead or one of the locale specific methods in `localizations/`\n" +
  1235. "and `additional-methods.js`."
  1236. );
  1237. }
  1238. }
  1239. return this.optional(element) || !/Invalid|NaN/.test(new Date(value).toString());
  1240. };
  1241. }()),
  1242. // https://jqueryvalidation.org/dateISO-method/
  1243. dateISO: function (value, element) {
  1244. return this.optional(element) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value);
  1245. },
  1246. // https://jqueryvalidation.org/number-method/
  1247. number: function (value, element) {
  1248. return this.optional(element) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value);
  1249. },
  1250. // https://jqueryvalidation.org/digits-method/
  1251. digits: function (value, element) {
  1252. return this.optional(element) || /^\d+$/.test(value);
  1253. },
  1254. // https://jqueryvalidation.org/minlength-method/
  1255. minlength: function (value, element, param) {
  1256. var length = Array.isArray(value) ? value.length : this.getLength(value, element);
  1257. return this.optional(element) || length >= param;
  1258. },
  1259. // https://jqueryvalidation.org/maxlength-method/
  1260. maxlength: function (value, element, param) {
  1261. var length = Array.isArray(value) ? value.length : this.getLength(value, element);
  1262. return this.optional(element) || length <= param;
  1263. },
  1264. // https://jqueryvalidation.org/rangelength-method/
  1265. rangelength: function (value, element, param) {
  1266. var length = Array.isArray(value) ? value.length : this.getLength(value, element);
  1267. return this.optional(element) || (length >= param[0] && length <= param[1]);
  1268. },
  1269. // https://jqueryvalidation.org/min-method/
  1270. min: function (value, element, param) {
  1271. return this.optional(element) || value >= param;
  1272. },
  1273. // https://jqueryvalidation.org/max-method/
  1274. max: function (value, element, param) {
  1275. return this.optional(element) || value <= param;
  1276. },
  1277. // https://jqueryvalidation.org/range-method/
  1278. range: function (value, element, param) {
  1279. return this.optional(element) || (value >= param[0] && value <= param[1]);
  1280. },
  1281. // https://jqueryvalidation.org/step-method/
  1282. step: function (value, element, param) {
  1283. var type = $(element).attr("type"),
  1284. errorMessage = "Step attribute on input type " + type + " is not supported.",
  1285. supportedTypes = ["text", "number", "range"],
  1286. re = new RegExp("\\b" + type + "\\b"),
  1287. notSupported = type && !re.test(supportedTypes.join()),
  1288. decimalPlaces = function (num) {
  1289. var match = ("" + num).match(/(?:\.(\d+))?$/);
  1290. if (!match) {
  1291. return 0;
  1292. }
  1293. // Number of digits right of decimal point.
  1294. return match[1] ? match[1].length : 0;
  1295. },
  1296. toInt = function (num) {
  1297. return Math.round(num * Math.pow(10, decimals));
  1298. },
  1299. valid = true,
  1300. decimals;
  1301. // Works only for text, number and range input types
  1302. // TODO find a way to support input types date, datetime, datetime-local, month, time and week
  1303. if (notSupported) {
  1304. throw new Error(errorMessage);
  1305. }
  1306. decimals = decimalPlaces(param);
  1307. // Value can't have too many decimals
  1308. if (decimalPlaces(value) > decimals || toInt(value) % toInt(param) !== 0) {
  1309. valid = false;
  1310. }
  1311. return this.optional(element) || valid;
  1312. },
  1313. // https://jqueryvalidation.org/equalTo-method/
  1314. equalTo: function (value, element, param) {
  1315. // Bind to the blur event of the target in order to revalidate whenever the target field is updated
  1316. var target = $(param);
  1317. if (this.settings.onfocusout && target.not(".validate-equalTo-blur").length) {
  1318. target.addClass("validate-equalTo-blur").on("blur.validate-equalTo", function () {
  1319. $(element).valid();
  1320. });
  1321. }
  1322. return value === target.val();
  1323. },
  1324. // https://jqueryvalidation.org/remote-method/
  1325. remote: function (value, element, param, method) {
  1326. if (this.optional(element)) {
  1327. return "dependency-mismatch";
  1328. }
  1329. method = typeof method === "string" && method || "remote";
  1330. var previous = this.previousValue(element, method),
  1331. validator, data, optionDataString;
  1332. if (!this.settings.messages[element.name]) {
  1333. this.settings.messages[element.name] = {};
  1334. }
  1335. previous.originalMessage = previous.originalMessage || this.settings.messages[element.name][method];
  1336. this.settings.messages[element.name][method] = previous.message;
  1337. param = typeof param === "string" && {url: param} || param;
  1338. optionDataString = $.param($.extend({data: value}, param.data));
  1339. if (previous.old === optionDataString) {
  1340. return previous.valid;
  1341. }
  1342. previous.old = optionDataString;
  1343. validator = this;
  1344. this.startRequest(element);
  1345. data = {};
  1346. data[element.name] = value;
  1347. $.ajax($.extend(true, {
  1348. mode: "abort",
  1349. port: "validate" + element.name,
  1350. dataType: "json",
  1351. data: data,
  1352. context: validator.currentForm,
  1353. success: function (response) {
  1354. var valid = response === true || response === "true",
  1355. errors, message, submitted;
  1356. validator.settings.messages[element.name][method] = previous.originalMessage;
  1357. if (valid) {
  1358. submitted = validator.formSubmitted;
  1359. validator.resetInternals();
  1360. validator.toHide = validator.errorsFor(element);
  1361. validator.formSubmitted = submitted;
  1362. validator.successList.push(element);
  1363. validator.invalid[element.name] = false;
  1364. validator.showErrors();
  1365. } else {
  1366. errors = {};
  1367. message = response || validator.defaultMessage(element, {
  1368. method: method,
  1369. parameters: value
  1370. });
  1371. errors[element.name] = previous.message = message;
  1372. validator.invalid[element.name] = true;
  1373. validator.showErrors(errors);
  1374. }
  1375. previous.valid = valid;
  1376. validator.stopRequest(element, valid);
  1377. }
  1378. }, param));
  1379. return "pending";
  1380. }
  1381. }
  1382. });
  1383. // Ajax mode: abort
  1384. // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
  1385. // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
  1386. var pendingRequests = {},
  1387. ajax;
  1388. // Use a prefilter if available (1.5+)
  1389. if ($.ajaxPrefilter) {
  1390. $.ajaxPrefilter(function (settings, _, xhr) {
  1391. var port = settings.port;
  1392. if (settings.mode === "abort") {
  1393. if (pendingRequests[port]) {
  1394. pendingRequests[port].abort();
  1395. }
  1396. pendingRequests[port] = xhr;
  1397. }
  1398. });
  1399. } else {
  1400. // Proxy ajax
  1401. ajax = $.ajax;
  1402. $.ajax = function (settings) {
  1403. var mode = ("mode" in settings ? settings : $.ajaxSettings).mode,
  1404. port = ("port" in settings ? settings : $.ajaxSettings).port;
  1405. if (mode === "abort") {
  1406. if (pendingRequests[port]) {
  1407. pendingRequests[port].abort();
  1408. }
  1409. pendingRequests[port] = ajax.apply(this, arguments);
  1410. return pendingRequests[port];
  1411. }
  1412. return ajax.apply(this, arguments);
  1413. };
  1414. }
  1415. return $;
  1416. }));