plugin_validate.js 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244
  1. /**
  2. * jQuery Validation Plugin 1.9.0
  3. *
  4. * http://bassistance.de/jquery-plugins/jquery-plugin-validation/
  5. * http://docs.jquery.com/Plugins/Validation
  6. *
  7. * Copyright (c) 2006 - 2011 Jörn Zaefferer
  8. *
  9. * Dual licensed under the MIT and GPL licenses:
  10. * http://www.opensource.org/licenses/mit-license.php
  11. * http://www.gnu.org/licenses/gpl.html
  12. */
  13. (function($) {
  14. $.extend($.fn, {
  15. // http://docs.jquery.com/Plugins/Validation/validate
  16. validate: function( options ) {
  17. // if nothing is selected, return nothing; can't chain anyway
  18. if (!this.length) {
  19. options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" );
  20. return;
  21. }
  22. // check if a validator for this form was already created
  23. var validator = $.data(this[0], 'validator');
  24. if ( validator ) {
  25. return validator;
  26. }
  27. // Add novalidate tag if HTML5.
  28. this.attr('novalidate', 'novalidate');
  29. validator = new $.validator( options, this[0] );
  30. $.data(this[0], 'validator', validator);
  31. if ( validator.settings.onsubmit ) {
  32. var inputsAndButtons = this.find("input, button");
  33. // allow suppresing validation by adding a cancel class to the submit button
  34. inputsAndButtons.filter(".cancel").click(function () {
  35. validator.cancelSubmit = true;
  36. });
  37. // when a submitHandler is used, capture the submitting button
  38. if (validator.settings.submitHandler) {
  39. inputsAndButtons.filter(":submit").click(function () {
  40. validator.submitButton = this;
  41. });
  42. }
  43. // validate the form on submit
  44. this.submit( function( event ) {
  45. if ( validator.settings.debug )
  46. // prevent form submit to be able to see console output
  47. event.preventDefault();
  48. function handle() {
  49. if ( validator.settings.submitHandler ) {
  50. if (validator.submitButton) {
  51. // insert a hidden input as a replacement for the missing submit button
  52. var hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);
  53. }
  54. validator.settings.submitHandler.call( validator, validator.currentForm );
  55. if (validator.submitButton) {
  56. // and clean up afterwards; thanks to no-block-scope, hidden can be referenced
  57. hidden.remove();
  58. }
  59. return false;
  60. }
  61. return true;
  62. }
  63. // prevent submit for invalid forms or custom submit handlers
  64. if ( validator.cancelSubmit ) {
  65. validator.cancelSubmit = false;
  66. return handle();
  67. }
  68. if ( validator.form() ) {
  69. if ( validator.pendingRequest ) {
  70. validator.formSubmitted = true;
  71. return false;
  72. }
  73. return handle();
  74. } else {
  75. validator.focusInvalid();
  76. return false;
  77. }
  78. });
  79. }
  80. return validator;
  81. },
  82. // http://docs.jquery.com/Plugins/Validation/valid
  83. valid: function() {
  84. if ( $(this[0]).is('form')) {
  85. return this.validate().form();
  86. } else {
  87. var valid = true;
  88. var validator = $(this[0].form).validate();
  89. this.each(function() {
  90. valid &= validator.element(this);
  91. });
  92. return valid;
  93. }
  94. },
  95. // attributes: space seperated list of attributes to retrieve and remove
  96. removeAttrs: function(attributes) {
  97. var result = {},
  98. $element = this;
  99. $.each(attributes.split(/\s/), function(index, value) {
  100. result[value] = $element.attr(value);
  101. $element.removeAttr(value);
  102. });
  103. return result;
  104. },
  105. // http://docs.jquery.com/Plugins/Validation/rules
  106. rules: function(command, argument) {
  107. var element = this[0];
  108. if (command) {
  109. var settings = $.data(element.form, 'validator').settings;
  110. var staticRules = settings.rules;
  111. var existingRules = $.validator.staticRules(element);
  112. switch(command) {
  113. case "add":
  114. $.extend(existingRules, $.validator.normalizeRule(argument));
  115. staticRules[element.name] = existingRules;
  116. if (argument.messages)
  117. settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
  118. break;
  119. case "remove":
  120. if (!argument) {
  121. delete staticRules[element.name];
  122. return existingRules;
  123. }
  124. var filtered = {};
  125. $.each(argument.split(/\s/), function(index, method) {
  126. filtered[method] = existingRules[method];
  127. delete existingRules[method];
  128. });
  129. return filtered;
  130. }
  131. }
  132. var data = $.validator.normalizeRules(
  133. $.extend(
  134. {},
  135. $.validator.metadataRules(element),
  136. $.validator.classRules(element),
  137. $.validator.attributeRules(element),
  138. $.validator.staticRules(element)
  139. ), element);
  140. // make sure required is at front
  141. if (data.required) {
  142. var param = data.required;
  143. delete data.required;
  144. data = $.extend({
  145. required: param
  146. }, data);
  147. }
  148. return data;
  149. }
  150. });
  151. // Custom selectors
  152. $.extend($.expr[":"], {
  153. // http://docs.jquery.com/Plugins/Validation/blank
  154. blank: function(a) {
  155. return !$.trim("" + a.value);
  156. },
  157. // http://docs.jquery.com/Plugins/Validation/filled
  158. filled: function(a) {
  159. return !!$.trim("" + a.value);
  160. },
  161. // http://docs.jquery.com/Plugins/Validation/unchecked
  162. unchecked: function(a) {
  163. return !a.checked;
  164. }
  165. });
  166. // constructor for validator
  167. $.validator = function( options, form ) {
  168. this.settings = $.extend( true, {}, $.validator.defaults, options );
  169. this.currentForm = form;
  170. this.init();
  171. };
  172. $.validator.format = function(source, params) {
  173. if ( arguments.length == 1 )
  174. return function() {
  175. var args = $.makeArray(arguments);
  176. args.unshift(source);
  177. return $.validator.format.apply( this, args );
  178. };
  179. if ( arguments.length > 2 && params.constructor != Array ) {
  180. params = $.makeArray(arguments).slice(1);
  181. }
  182. if ( params.constructor != Array ) {
  183. params = [ params ];
  184. }
  185. $.each(params, function(i, n) {
  186. source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
  187. });
  188. return source;
  189. };
  190. $.extend($.validator, {
  191. defaults: {
  192. messages: {},
  193. groups: {},
  194. rules: {},
  195. errorClass: "error",
  196. validClass: "valid",
  197. errorElement: "label",
  198. focusInvalid: true,
  199. errorContainer: $( [] ),
  200. errorLabelContainer: $( [] ),
  201. onsubmit: true,
  202. ignore: ":hidden",
  203. ignoreTitle: false,
  204. onfocusin: function(element, event) {
  205. this.lastActive = element;
  206. // hide error label and remove error class on focus if enabled
  207. if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
  208. this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
  209. this.addWrapper(this.errorsFor(element)).hide();
  210. }
  211. },
  212. onfocusout: function(element, event) {
  213. if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
  214. this.element(element);
  215. }
  216. },
  217. onkeyup: function(element, event) {
  218. if ( element.name in this.submitted || element == this.lastElement ) {
  219. this.element(element);
  220. }
  221. },
  222. onclick: function(element, event) {
  223. // click on selects, radiobuttons and checkboxes
  224. if ( element.name in this.submitted )
  225. this.element(element);
  226. // or option elements, check parent select in that case
  227. else if (element.parentNode.name in this.submitted)
  228. this.element(element.parentNode);
  229. },
  230. highlight: function(element, errorClass, validClass) {
  231. if (element.type === 'radio') {
  232. this.findByName(element.name).addClass(errorClass).removeClass(validClass);
  233. } else {
  234. $(element).addClass(errorClass).removeClass(validClass);
  235. }
  236. },
  237. unhighlight: function(element, errorClass, validClass) {
  238. if (element.type === 'radio') {
  239. this.findByName(element.name).removeClass(errorClass).addClass(validClass);
  240. } else {
  241. $(element).removeClass(errorClass).addClass(validClass);
  242. }
  243. }
  244. },
  245. // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
  246. setDefaults: function(settings) {
  247. $.extend( $.validator.defaults, settings );
  248. },
  249. messages: {
  250. /* required: "This field is required.",
  251. remote: "Please fix this field.",
  252. email: "Please enter a valid email address.",
  253. url: "Please enter a valid URL.",
  254. date: "Please enter a valid date.",
  255. dateISO: "Please enter a valid date (ISO).",
  256. number: "Please enter a valid number.",
  257. digits: "Please enter only digits.",
  258. creditcard: "Please enter a valid credit card number.",
  259. equalTo: "Please enter the same value again.",
  260. accept: "Please enter a value with a valid extension.",
  261. maxlength: $.validator.format("Please enter no more than {0} characters."),
  262. minlength: $.validator.format("Please enter at least {0} characters."),
  263. rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
  264. range: $.validator.format("Please enter a value between {0} and {1}."),
  265. max: $.validator.format("Please enter a value less than or equal to {0}."),
  266. min: $.validator.format("Please enter a value greater than or equal to {0}.")*/
  267. required: "Ce champ est requis.",
  268. remote: "Corriger ce champ.",
  269. email: "Inscrire une adresse de courriel valide",
  270. url: "Inscrire une adresse URL valide.",
  271. date: "Incrire une date valide.",
  272. dateISO: "Inscrire une date valide au format ISO.",
  273. number: "Inscrire un nombre valide.",
  274. digits: "Inscrire seulement des chiffres.",
  275. creditcard: "Inscrire un numéro de carte de crédit valide.",
  276. equalTo: "Inscire la même valeur.",
  277. accept: "Please enter a value with a valid extension.",
  278. maxlength: $.validator.format("Ne pas inscrire plus de {0} caractères."),
  279. minlength: $.validator.format("Inscrire au minimum {0} caractères."),
  280. rangelength: $.validator.format("Inscrire une valeur entre {0} et {1} caractères de long."),
  281. range: $.validator.format("Inscrire une valeur entre {0} et {1}."),
  282. max: $.validator.format("Inscrire une valeur plus petite ou égale à {0}."),
  283. min: $.validator.format("Inscrire une valeur plus grande ou égale à {0}.")
  284. },
  285. autoCreateRanges: false,
  286. prototype: {
  287. init: function() {
  288. this.labelContainer = $(this.settings.errorLabelContainer);
  289. this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
  290. this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
  291. this.submitted = {};
  292. this.valueCache = {};
  293. this.pendingRequest = 0;
  294. this.pending = {};
  295. this.invalid = {};
  296. this.reset();
  297. var groups = (this.groups = {});
  298. $.each(this.settings.groups, function(key, value) {
  299. $.each(value.split(/\s/), function(index, name) {
  300. groups[name] = key;
  301. });
  302. });
  303. var rules = this.settings.rules;
  304. $.each(rules, function(key, value) {
  305. rules[key] = $.validator.normalizeRule(value);
  306. });
  307. function delegate(event) {
  308. var validator = $.data(this[0].form, "validator"),
  309. eventType = "on" + event.type.replace(/^validate/, "");
  310. validator.settings[eventType] && validator.settings[eventType].call(validator, this[0], event);
  311. }
  312. $(this.currentForm)
  313. .validateDelegate("[type='text'], [type='password'], [type='file'], select, textarea, " +
  314. "[type='number'], [type='search'] ,[type='tel'], [type='url'], " +
  315. "[type='email'], [type='datetime'], [type='date'], [type='month'], " +
  316. "[type='week'], [type='time'], [type='datetime-local'], " +
  317. "[type='range'], [type='color'] ",
  318. "focusin focusout keyup", delegate)
  319. .validateDelegate("[type='radio'], [type='checkbox'], select, option", "click", delegate);
  320. if (this.settings.invalidHandler)
  321. $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
  322. },
  323. // http://docs.jquery.com/Plugins/Validation/Validator/form
  324. form: function() {
  325. this.checkForm();
  326. $.extend(this.submitted, this.errorMap);
  327. this.invalid = $.extend({}, this.errorMap);
  328. if (!this.valid())
  329. $(this.currentForm).triggerHandler("invalid-form", [this]);
  330. this.showErrors();
  331. return this.valid();
  332. },
  333. checkForm: function() {
  334. this.prepareForm();
  335. for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
  336. this.check( elements[i] );
  337. }
  338. return this.valid();
  339. },
  340. // http://docs.jquery.com/Plugins/Validation/Validator/element
  341. element: function( element ) {
  342. element = this.validationTargetFor( this.clean( element ) );
  343. this.lastElement = element;
  344. this.prepareElement( element );
  345. this.currentElements = $(element);
  346. var result = this.check( element );
  347. if ( result ) {
  348. delete this.invalid[element.name];
  349. } else {
  350. this.invalid[element.name] = true;
  351. }
  352. if ( !this.numberOfInvalids() ) {
  353. // Hide error containers on last error
  354. this.toHide = this.toHide.add( this.containers );
  355. }
  356. this.showErrors();
  357. return result;
  358. },
  359. // http://docs.jquery.com/Plugins/Validation/Validator/showErrors
  360. showErrors: function(errors) {
  361. if(errors) {
  362. // add items to error list and map
  363. $.extend( this.errorMap, errors );
  364. this.errorList = [];
  365. for ( var name in errors ) {
  366. this.errorList.push({
  367. message: errors[name],
  368. element: this.findByName(name)[0]
  369. });
  370. }
  371. // remove items from success list
  372. this.successList = $.grep( this.successList, function(element) {
  373. return !(element.name in errors);
  374. });
  375. }
  376. this.settings.showErrors
  377. ? this.settings.showErrors.call( this, this.errorMap, this.errorList )
  378. : this.defaultShowErrors();
  379. },
  380. // http://docs.jquery.com/Plugins/Validation/Validator/resetForm
  381. resetForm: function() {
  382. if ( $.fn.resetForm )
  383. $( this.currentForm ).resetForm();
  384. this.submitted = {};
  385. this.lastElement = null;
  386. this.prepareForm();
  387. this.hideErrors();
  388. this.elements().removeClass( this.settings.errorClass );
  389. },
  390. numberOfInvalids: function() {
  391. return this.objectLength(this.invalid);
  392. },
  393. objectLength: function( obj ) {
  394. var count = 0;
  395. for ( var i in obj )
  396. count++;
  397. return count;
  398. },
  399. hideErrors: function() {
  400. this.addWrapper( this.toHide ).hide();
  401. },
  402. valid: function() {
  403. return this.size() == 0;
  404. },
  405. size: function() {
  406. return this.errorList.length;
  407. },
  408. focusInvalid: function() {
  409. if( this.settings.focusInvalid ) {
  410. try {
  411. $(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
  412. .filter(":visible")
  413. .focus()
  414. // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
  415. .trigger("focusin");
  416. } catch(e) {
  417. // ignore IE throwing errors when focusing hidden elements
  418. }
  419. }
  420. },
  421. findLastActive: function() {
  422. var lastActive = this.lastActive;
  423. return lastActive && $.grep(this.errorList, function(n) {
  424. return n.element.name == lastActive.name;
  425. }).length == 1 && lastActive;
  426. },
  427. elements: function() {
  428. var validator = this,
  429. rulesCache = {};
  430. // select all valid inputs inside the form (no submit or reset buttons)
  431. return $(this.currentForm)
  432. .find("input, select, textarea")
  433. .not(":submit, :reset, :image, [disabled]")
  434. .not( this.settings.ignore )
  435. .filter(function() {
  436. !this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this);
  437. // select only the first element for each name, and only those with rules specified
  438. if ( this.name in rulesCache || !validator.objectLength($(this).rules()) )
  439. return false;
  440. rulesCache[this.name] = true;
  441. return true;
  442. });
  443. },
  444. clean: function( selector ) {
  445. return $( selector )[0];
  446. },
  447. errors: function() {
  448. return $( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext );
  449. },
  450. reset: function() {
  451. this.successList = [];
  452. this.errorList = [];
  453. this.errorMap = {};
  454. this.toShow = $([]);
  455. this.toHide = $([]);
  456. this.currentElements = $([]);
  457. },
  458. prepareForm: function() {
  459. this.reset();
  460. this.toHide = this.errors().add( this.containers );
  461. },
  462. prepareElement: function( element ) {
  463. this.reset();
  464. this.toHide = this.errorsFor(element);
  465. },
  466. check: function( element ) {
  467. element = this.validationTargetFor( this.clean( element ) );
  468. var rules = $(element).rules();
  469. var dependencyMismatch = false;
  470. for (var method in rules ) {
  471. var rule = {
  472. method: method,
  473. parameters: rules[method]
  474. };
  475. try {
  476. var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), element, rule.parameters );
  477. // if a method indicates that the field is optional and therefore valid,
  478. // don't mark it as valid when there are no other rules
  479. if ( result == "dependency-mismatch" ) {
  480. dependencyMismatch = true;
  481. continue;
  482. }
  483. dependencyMismatch = false;
  484. if ( result == "pending" ) {
  485. this.toHide = this.toHide.not( this.errorsFor(element) );
  486. return;
  487. }
  488. if( !result ) {
  489. this.formatAndAdd( element, rule );
  490. return false;
  491. }
  492. } catch(e) {
  493. this.settings.debug && window.console && console.log("exception occured when checking element " + element.id
  494. + ", check the '" + rule.method + "' method", e);
  495. throw e;
  496. }
  497. }
  498. if (dependencyMismatch)
  499. return;
  500. if ( this.objectLength(rules) )
  501. this.successList.push(element);
  502. return true;
  503. },
  504. // return the custom message for the given element and validation method
  505. // specified in the element's "messages" metadata
  506. customMetaMessage: function(element, method) {
  507. if (!$.metadata)
  508. return;
  509. var meta = this.settings.meta
  510. ? $(element).metadata()[this.settings.meta]
  511. : $(element).metadata();
  512. return meta && meta.messages && meta.messages[method];
  513. },
  514. // return the custom message for the given element name and validation method
  515. customMessage: function( name, method ) {
  516. var m = this.settings.messages[name];
  517. return m && (m.constructor == String
  518. ? m
  519. : m[method]);
  520. },
  521. // return the first defined argument, allowing empty strings
  522. findDefined: function() {
  523. for(var i = 0; i < arguments.length; i++) {
  524. if (arguments[i] !== undefined)
  525. return arguments[i];
  526. }
  527. return undefined;
  528. },
  529. defaultMessage: function( element, method) {
  530. return this.findDefined(
  531. this.customMessage( element.name, method ),
  532. this.customMetaMessage( element, method ),
  533. // title is never undefined, so handle empty string as undefined
  534. !this.settings.ignoreTitle && element.title || undefined,
  535. $.validator.messages[method],
  536. "<strong>Warning: No message defined for " + element.name + "</strong>"
  537. );
  538. },
  539. formatAndAdd: function( element, rule ) {
  540. var message = this.defaultMessage( element, rule.method ),
  541. theregex = /\$?\{(\d+)\}/g;
  542. if ( typeof message == "function" ) {
  543. message = message.call(this, rule.parameters, element);
  544. } else if (theregex.test(message)) {
  545. message = jQuery.format(message.replace(theregex, '{$1}'), rule.parameters);
  546. }
  547. this.errorList.push({
  548. message: message,
  549. element: element
  550. });
  551. this.errorMap[element.name] = message;
  552. this.submitted[element.name] = message;
  553. },
  554. addWrapper: function(toToggle) {
  555. if ( this.settings.wrapper )
  556. toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
  557. return toToggle;
  558. },
  559. defaultShowErrors: function() {
  560. for ( var i = 0; this.errorList[i]; i++ ) {
  561. var error = this.errorList[i];
  562. this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
  563. this.showLabel( error.element, error.message );
  564. }
  565. if( this.errorList.length ) {
  566. this.toShow = this.toShow.add( this.containers );
  567. }
  568. if (this.settings.success) {
  569. for ( var i = 0; this.successList[i]; i++ ) {
  570. this.showLabel( this.successList[i] );
  571. }
  572. }
  573. if (this.settings.unhighlight) {
  574. for ( var i = 0, elements = this.validElements(); elements[i]; i++ ) {
  575. this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
  576. }
  577. }
  578. this.toHide = this.toHide.not( this.toShow );
  579. this.hideErrors();
  580. this.addWrapper( this.toShow ).show();
  581. },
  582. validElements: function() {
  583. return this.currentElements.not(this.invalidElements());
  584. },
  585. invalidElements: function() {
  586. return $(this.errorList).map(function() {
  587. return this.element;
  588. });
  589. },
  590. showLabel: function(element, message) {
  591. var label = this.errorsFor( element );
  592. if ( label.length ) {
  593. // refresh error/success class
  594. label.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
  595. // check if we have a generated label, replace the message then
  596. label.attr("generated") && label.html(message);
  597. } else {
  598. // create label
  599. label = $("<" + this.settings.errorElement + "/>")
  600. .attr({
  601. "for": this.idOrName(element),
  602. generated: true
  603. })
  604. .addClass(this.settings.errorClass)
  605. .html(message || "");
  606. if ( this.settings.wrapper ) {
  607. // make sure the element is visible, even in IE
  608. // actually showing the wrapped element is handled elsewhere
  609. label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
  610. }
  611. if ( !this.labelContainer.append(label).length )
  612. this.settings.errorPlacement
  613. ? this.settings.errorPlacement(label, $(element) )
  614. : label.insertAfter(element);
  615. }
  616. if ( !message && this.settings.success ) {
  617. label.text("");
  618. typeof this.settings.success == "string"
  619. ? label.addClass( this.settings.success )
  620. : this.settings.success( label );
  621. }
  622. this.toShow = this.toShow.add(label);
  623. },
  624. errorsFor: function(element) {
  625. var name = this.idOrName(element);
  626. return this.errors().filter(function() {
  627. return $(this).attr('for') == name;
  628. });
  629. },
  630. idOrName: function(element) {
  631. return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
  632. },
  633. validationTargetFor: function(element) {
  634. // if radio/checkbox, validate first element in group instead
  635. if (this.checkable(element)) {
  636. element = this.findByName( element.name ).not(this.settings.ignore)[0];
  637. }
  638. return element;
  639. },
  640. checkable: function( element ) {
  641. return /radio|checkbox/i.test(element.type);
  642. },
  643. findByName: function( name ) {
  644. // select by name and filter by form for performance over form.find("[name=...]")
  645. var form = this.currentForm;
  646. return $(document.getElementsByName(name)).map(function(index, element) {
  647. return element.form == form && element.name == name && element || null;
  648. });
  649. },
  650. getLength: function(value, element) {
  651. switch( element.nodeName.toLowerCase() ) {
  652. case 'select':
  653. return $("option:selected", element).length;
  654. case 'input':
  655. if( this.checkable( element) )
  656. return this.findByName(element.name).filter(':checked').length;
  657. }
  658. return value.length;
  659. },
  660. depend: function(param, element) {
  661. return this.dependTypes[typeof param]
  662. ? this.dependTypes[typeof param](param, element)
  663. : true;
  664. },
  665. dependTypes: {
  666. "boolean": function(param, element) {
  667. return param;
  668. },
  669. "string": function(param, element) {
  670. return !!$(param, element.form).length;
  671. },
  672. "function": function(param, element) {
  673. return param(element);
  674. }
  675. },
  676. optional: function(element) {
  677. return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch";
  678. },
  679. startRequest: function(element) {
  680. if (!this.pending[element.name]) {
  681. this.pendingRequest++;
  682. this.pending[element.name] = true;
  683. }
  684. },
  685. stopRequest: function(element, valid) {
  686. this.pendingRequest--;
  687. // sometimes synchronization fails, make sure pendingRequest is never < 0
  688. if (this.pendingRequest < 0)
  689. this.pendingRequest = 0;
  690. delete this.pending[element.name];
  691. if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) {
  692. $(this.currentForm).submit();
  693. this.formSubmitted = false;
  694. } else if (!valid && this.pendingRequest == 0 && this.formSubmitted) {
  695. $(this.currentForm).triggerHandler("invalid-form", [this]);
  696. this.formSubmitted = false;
  697. }
  698. },
  699. previousValue: function(element) {
  700. return $.data(element, "previousValue") || $.data(element, "previousValue", {
  701. old: null,
  702. valid: true,
  703. message: this.defaultMessage( element, "remote" )
  704. });
  705. }
  706. },
  707. classRuleSettings: {
  708. required: {
  709. required: true
  710. },
  711. email: {
  712. email: true
  713. },
  714. url: {
  715. url: true
  716. },
  717. date: {
  718. date: true
  719. },
  720. dateISO: {
  721. dateISO: true
  722. },
  723. dateDE: {
  724. dateDE: true
  725. },
  726. number: {
  727. number: true
  728. },
  729. numberDE: {
  730. numberDE: true
  731. },
  732. digits: {
  733. digits: true
  734. },
  735. creditcard: {
  736. creditcard: true
  737. }
  738. },
  739. addClassRules: function(className, rules) {
  740. className.constructor == String ?
  741. this.classRuleSettings[className] = rules :
  742. $.extend(this.classRuleSettings, className);
  743. },
  744. classRules: function(element) {
  745. var rules = {};
  746. var classes = $(element).attr('class');
  747. classes && $.each(classes.split(' '), function() {
  748. if (this in $.validator.classRuleSettings) {
  749. $.extend(rules, $.validator.classRuleSettings[this]);
  750. }
  751. });
  752. return rules;
  753. },
  754. attributeRules: function(element) {
  755. var rules = {};
  756. var $element = $(element);
  757. for (var method in $.validator.methods) {
  758. var value;
  759. // If .prop exists (jQuery >= 1.6), use it to get true/false for required
  760. if (method === 'required' && typeof $.fn.prop === 'function') {
  761. value = $element.prop(method);
  762. } else {
  763. value = $element.attr(method);
  764. }
  765. if (value) {
  766. rules[method] = value;
  767. } else if ($element[0].getAttribute("type") === method) {
  768. rules[method] = true;
  769. }
  770. }
  771. // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
  772. if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {
  773. delete rules.maxlength;
  774. }
  775. return rules;
  776. },
  777. metadataRules: function(element) {
  778. if (!$.metadata) return {};
  779. var meta = $.data(element.form, 'validator').settings.meta;
  780. return meta ?
  781. $(element).metadata()[meta] :
  782. $(element).metadata();
  783. },
  784. staticRules: function(element) {
  785. var rules = {};
  786. var validator = $.data(element.form, 'validator');
  787. if (validator.settings.rules) {
  788. rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
  789. }
  790. return rules;
  791. },
  792. normalizeRules: function(rules, element) {
  793. // handle dependency check
  794. $.each(rules, function(prop, val) {
  795. // ignore rule when param is explicitly false, eg. required:false
  796. if (val === false) {
  797. delete rules[prop];
  798. return;
  799. }
  800. if (val.param || val.depends) {
  801. var keepRule = true;
  802. switch (typeof val.depends) {
  803. case "string":
  804. keepRule = !!$(val.depends, element.form).length;
  805. break;
  806. case "function":
  807. keepRule = val.depends.call(element, element);
  808. break;
  809. }
  810. if (keepRule) {
  811. rules[prop] = val.param !== undefined ? val.param : true;
  812. } else {
  813. delete rules[prop];
  814. }
  815. }
  816. });
  817. // evaluate parameters
  818. $.each(rules, function(rule, parameter) {
  819. rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
  820. });
  821. // clean number parameters
  822. $.each(['minlength', 'maxlength', 'min', 'max'], function() {
  823. if (rules[this]) {
  824. rules[this] = Number(rules[this]);
  825. }
  826. });
  827. $.each(['rangelength', 'range'], function() {
  828. if (rules[this]) {
  829. rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
  830. }
  831. });
  832. if ($.validator.autoCreateRanges) {
  833. // auto-create ranges
  834. if (rules.min && rules.max) {
  835. rules.range = [rules.min, rules.max];
  836. delete rules.min;
  837. delete rules.max;
  838. }
  839. if (rules.minlength && rules.maxlength) {
  840. rules.rangelength = [rules.minlength, rules.maxlength];
  841. delete rules.minlength;
  842. delete rules.maxlength;
  843. }
  844. }
  845. // To support custom messages in metadata ignore rule methods titled "messages"
  846. if (rules.messages) {
  847. delete rules.messages;
  848. }
  849. return rules;
  850. },
  851. // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
  852. normalizeRule: function(data) {
  853. if( typeof data == "string" ) {
  854. var transformed = {};
  855. $.each(data.split(/\s/), function() {
  856. transformed[this] = true;
  857. });
  858. data = transformed;
  859. }
  860. return data;
  861. },
  862. // http://docs.jquery.com/Plugins/Validation/Validator/addMethod
  863. addMethod: function(name, method, message) {
  864. $.validator.methods[name] = method;
  865. $.validator.messages[name] = message != undefined ? message : $.validator.messages[name];
  866. if (method.length < 3) {
  867. $.validator.addClassRules(name, $.validator.normalizeRule(name));
  868. }
  869. },
  870. methods: {
  871. // http://docs.jquery.com/Plugins/Validation/Methods/required
  872. required: function(value, element, param) {
  873. // check if dependency is met
  874. if ( !this.depend(param, element) )
  875. return "dependency-mismatch";
  876. switch( element.nodeName.toLowerCase() ) {
  877. case 'select':
  878. // could be an array for select-multiple or a string, both are fine this way
  879. var val = $(element).val();
  880. return val && val.length > 0;
  881. case 'input':
  882. if ( this.checkable(element) )
  883. return this.getLength(value, element) > 0;
  884. default:
  885. return $.trim(value).length > 0;
  886. }
  887. },
  888. // http://docs.jquery.com/Plugins/Validation/Methods/remote
  889. remote: function(value, element, param) {
  890. if ( this.optional(element) )
  891. return "dependency-mismatch";
  892. var previous = this.previousValue(element);
  893. if (!this.settings.messages[element.name] )
  894. this.settings.messages[element.name] = {};
  895. previous.originalMessage = this.settings.messages[element.name].remote;
  896. this.settings.messages[element.name].remote = previous.message;
  897. param = typeof param == "string" && {
  898. url:param
  899. } || param;
  900. if ( this.pending[element.name] ) {
  901. return "pending";
  902. }
  903. if ( previous.old === value ) {
  904. return previous.valid;
  905. }
  906. previous.old = value;
  907. var validator = this;
  908. this.startRequest(element);
  909. var data = {};
  910. data[element.name] = value;
  911. $.ajax($.extend(true, {
  912. url: param,
  913. mode: "abort",
  914. port: "validate" + element.name,
  915. dataType: "json",
  916. data: data,
  917. success: function(response) {
  918. validator.settings.messages[element.name].remote = previous.originalMessage;
  919. var valid = response === true;
  920. if ( valid ) {
  921. var submitted = validator.formSubmitted;
  922. validator.prepareElement(element);
  923. validator.formSubmitted = submitted;
  924. validator.successList.push(element);
  925. validator.showErrors();
  926. } else {
  927. var errors = {};
  928. var message = response || validator.defaultMessage( element, "remote" );
  929. errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
  930. validator.showErrors(errors);
  931. }
  932. previous.valid = valid;
  933. validator.stopRequest(element, valid);
  934. }
  935. }, param));
  936. return "pending";
  937. },
  938. // http://docs.jquery.com/Plugins/Validation/Methods/minlength
  939. minlength: function(value, element, param) {
  940. return this.optional(element) || this.getLength($.trim(value), element) >= param;
  941. },
  942. // http://docs.jquery.com/Plugins/Validation/Methods/maxlength
  943. maxlength: function(value, element, param) {
  944. return this.optional(element) || this.getLength($.trim(value), element) <= param;
  945. },
  946. // http://docs.jquery.com/Plugins/Validation/Methods/rangelength
  947. rangelength: function(value, element, param) {
  948. var length = this.getLength($.trim(value), element);
  949. return this.optional(element) || ( length >= param[0] && length <= param[1] );
  950. },
  951. // http://docs.jquery.com/Plugins/Validation/Methods/min
  952. min: function( value, element, param ) {
  953. return this.optional(element) || value >= param;
  954. },
  955. // http://docs.jquery.com/Plugins/Validation/Methods/max
  956. max: function( value, element, param ) {
  957. return this.optional(element) || value <= param;
  958. },
  959. // http://docs.jquery.com/Plugins/Validation/Methods/range
  960. range: function( value, element, param ) {
  961. return this.optional(element) || ( value >= param[0] && value <= param[1] );
  962. },
  963. // http://docs.jquery.com/Plugins/Validation/Methods/email
  964. email: function(value, element) {
  965. // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
  966. return this.optional(element) || /^((([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.test(value);
  967. },
  968. // http://docs.jquery.com/Plugins/Validation/Methods/url
  969. url: function(value, element) {
  970. // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
  971. return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([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])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
  972. },
  973. // http://docs.jquery.com/Plugins/Validation/Methods/date
  974. date: function(value, element) {
  975. return this.optional(element) || !/Invalid|NaN/.test(new Date(value));
  976. },
  977. // http://docs.jquery.com/Plugins/Validation/Methods/dateISO
  978. dateISO: function(value, element) {
  979. return this.optional(element) || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value);
  980. },
  981. // http://docs.jquery.com/Plugins/Validation/Methods/number
  982. number: function(value, element) {
  983. return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value);
  984. },
  985. // http://docs.jquery.com/Plugins/Validation/Methods/digits
  986. digits: function(value, element) {
  987. return this.optional(element) || /^\d+$/.test(value);
  988. },
  989. // http://docs.jquery.com/Plugins/Validation/Methods/creditcard
  990. // based on http://en.wikipedia.org/wiki/Luhn
  991. creditcard: function(value, element) {
  992. if ( this.optional(element) )
  993. return "dependency-mismatch";
  994. // accept only spaces, digits and dashes
  995. if (/[^0-9 -]+/.test(value))
  996. return false;
  997. var nCheck = 0,
  998. nDigit = 0,
  999. bEven = false;
  1000. value = value.replace(/\D/g, "");
  1001. for (var n = value.length - 1; n >= 0; n--) {
  1002. var cDigit = value.charAt(n);
  1003. var nDigit = parseInt(cDigit, 10);
  1004. if (bEven) {
  1005. if ((nDigit *= 2) > 9)
  1006. nDigit -= 9;
  1007. }
  1008. nCheck += nDigit;
  1009. bEven = !bEven;
  1010. }
  1011. return (nCheck % 10) == 0;
  1012. },
  1013. // http://docs.jquery.com/Plugins/Validation/Methods/accept
  1014. accept: function(value, element, param) {
  1015. param = typeof param == "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif";
  1016. return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i"));
  1017. },
  1018. // http://docs.jquery.com/Plugins/Validation/Methods/equalTo
  1019. equalTo: function(value, element, param) {
  1020. // bind to the blur event of the target in order to revalidate whenever the target field is updated
  1021. // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
  1022. var target = $(param).unbind(".validate-equalTo").bind("blur.validate-equalTo", function() {
  1023. $(element).valid();
  1024. });
  1025. return value == target.val();
  1026. }
  1027. }
  1028. });
  1029. // deprecated, use $.validator.format instead
  1030. $.format = $.validator.format;
  1031. })(jQuery);
  1032. // ajax mode: abort
  1033. // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
  1034. // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
  1035. ;
  1036. (function($) {
  1037. var pendingRequests = {};
  1038. // Use a prefilter if available (1.5+)
  1039. if ( $.ajaxPrefilter ) {
  1040. $.ajaxPrefilter(function(settings, _, xhr) {
  1041. var port = settings.port;
  1042. if (settings.mode == "abort") {
  1043. if ( pendingRequests[port] ) {
  1044. pendingRequests[port].abort();
  1045. }
  1046. pendingRequests[port] = xhr;
  1047. }
  1048. });
  1049. } else {
  1050. // Proxy ajax
  1051. var ajax = $.ajax;
  1052. $.ajax = function(settings) {
  1053. var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
  1054. port = ( "port" in settings ? settings : $.ajaxSettings ).port;
  1055. if (mode == "abort") {
  1056. if ( pendingRequests[port] ) {
  1057. pendingRequests[port].abort();
  1058. }
  1059. return (pendingRequests[port] = ajax.apply(this, arguments));
  1060. }
  1061. return ajax.apply(this, arguments);
  1062. };
  1063. }
  1064. })(jQuery);
  1065. // provides cross-browser focusin and focusout events
  1066. // IE has native support, in other browsers, use event caputuring (neither bubbles)
  1067. // provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
  1068. // handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target
  1069. ;
  1070. (function($) {
  1071. // only implement if not provided by jQuery core (since 1.4)
  1072. // TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs
  1073. if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) {
  1074. $.each({
  1075. focus: 'focusin',
  1076. blur: 'focusout'
  1077. }, function( original, fix ){
  1078. $.event.special[fix] = {
  1079. setup:function() {
  1080. this.addEventListener( original, handler, true );
  1081. },
  1082. teardown:function() {
  1083. this.removeEventListener( original, handler, true );
  1084. },
  1085. handler: function(e) {
  1086. arguments[0] = $.event.fix(e);
  1087. arguments[0].type = fix;
  1088. return $.event.handle.apply(this, arguments);
  1089. }
  1090. };
  1091. function handler(e) {
  1092. e = $.event.fix(e);
  1093. e.type = fix;
  1094. return $.event.handle.call(this, e);
  1095. }
  1096. });
  1097. };
  1098. $.extend($.fn, {
  1099. validateDelegate: function(delegate, type, handler) {
  1100. return this.bind(type, function(event) {
  1101. var target = $(event.target);
  1102. if (target.is(delegate)) {
  1103. return handler.apply(target, arguments);
  1104. }
  1105. });
  1106. }
  1107. });
  1108. })(jQuery);