jquery.validate.js
上传用户:stephen_wu
上传日期:2008-07-05
资源大小:1757k
文件大小:33k
源码类别:

网络

开发平台:

Unix_Linux

  1. /*
  2.  * jQuery validation plug-in v1.2.1
  3.  *
  4.  * http://bassistance.de/jquery-plugins/jquery-plugin-validation/
  5.  * http://docs.jquery.com/Plugins/Validation
  6.  *
  7.  * Copyright (c) 2006 - 2008 Jörn Zaefferer
  8.  *
  9.  * $Id: jquery.validate.js 4708 2008-02-10 16:04:08Z joern.zaefferer $
  10.  *
  11.  * Dual licensed under the MIT and GPL licenses:
  12.  *   http://www.opensource.org/licenses/mit-license.php
  13.  *   http://www.gnu.org/licenses/gpl.html
  14.  */
  15. jQuery.extend(jQuery.fn, {
  16. // http://docs.jquery.com/Plugins/Validation/validate
  17. validate: function( options ) {
  18. // if nothing is selected, return nothing; can't chain anyway
  19. if (!this.length) {
  20. options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" );
  21. return;
  22. }
  23. // check if a validator for this form was already created
  24. var validator = jQuery.data(this[0], 'validator');
  25. if ( validator ) {
  26. return validator;
  27. }
  28. validator = new jQuery.validator( options, this[0] );
  29. jQuery.data(this[0], 'validator', validator); 
  30. if ( validator.settings.onsubmit ) {
  31. // allow suppresing validation by adding a cancel class to the submit button
  32. this.find("input.cancel:submit").click(function() {
  33. validator.cancelSubmit = true;
  34. });
  35. // validate the form on submit
  36. this.submit( function( event ) {
  37. if ( validator.settings.debug )
  38. // prevent form submit to be able to see console output
  39. event.preventDefault();
  40. function handle() {
  41. if ( validator.settings.submitHandler ) {
  42. validator.settings.submitHandler.call( validator, validator.currentForm );
  43. return false;
  44. }
  45. return true;
  46. }
  47. // prevent submit for invalid forms or custom submit handlers
  48. if ( validator.cancelSubmit ) {
  49. validator.cancelSubmit = false;
  50. return handle();
  51. }
  52. if ( validator.form() ) {
  53. if ( validator.pendingRequest ) {
  54. validator.formSubmitted = true;
  55. return false;
  56. }
  57. return handle();
  58. } else {
  59. validator.focusInvalid();
  60. return false;
  61. }
  62. });
  63. }
  64. return validator;
  65. },
  66. // http://docs.jquery.com/Plugins/Validation/valid
  67. valid: function() {
  68.         if ( jQuery(this[0]).is('form')) {
  69.             return this.validate().form();
  70.         } else {
  71.             var valid = true;
  72.             var validator = jQuery(this[0].form).validate();
  73.             this.each(function() {
  74.                 valid = validator.element(this) && valid;
  75.             });
  76.             return valid;
  77.         }
  78.     },
  79. // http://docs.jquery.com/Plugins/Validation/rules
  80. rules: function() {
  81. var element = this[0];
  82. var data = jQuery.validator.normalizeRules(
  83. jQuery.extend(
  84. {},
  85. jQuery.validator.metadataRules(element),
  86. jQuery.validator.classRules(element),
  87. jQuery.validator.attributeRules(element),
  88. jQuery.validator.staticRules(element)
  89. ), element);
  90. // convert from object to array
  91. var rules = [];
  92. // make sure required is at front
  93. if (data.required) {
  94. rules.push({method:'required', parameters: data.required});
  95. delete data.required;
  96. }
  97. jQuery.each(data, function(method, value) {
  98. rules.push({
  99. method: method,
  100. parameters: value
  101. });
  102. });
  103. return rules;
  104. },
  105. // destructive add
  106. push: function( t ) {
  107. return this.setArray( this.add(t).get() );
  108. }
  109. });
  110. // Custom selectors
  111. jQuery.extend(jQuery.expr[":"], {
  112. // http://docs.jquery.com/Plugins/Validation/blank
  113. blank: "!jQuery.trim(a.value)",
  114. // http://docs.jquery.com/Plugins/Validation/filled
  115. filled: "!!jQuery.trim(a.value)",
  116. // http://docs.jquery.com/Plugins/Validation/unchecked
  117. unchecked: "!a.checked"
  118. });
  119. jQuery.format = function(source, params) {
  120. if ( arguments.length == 1 ) 
  121. return function() {
  122. var args = jQuery.makeArray(arguments);
  123. args.unshift(source);
  124. return jQuery.format.apply( this, args );
  125. };
  126. if ( arguments.length > 2 && params.constructor != Array  ) {
  127. params = jQuery.makeArray(arguments).slice(1);
  128. }
  129. if ( params.constructor != Array ) {
  130. params = [ params ];
  131. }
  132. jQuery.each(params, function(i, n) {
  133. source = source.replace(new RegExp("\{" + i + "\}", "g"), n);
  134. });
  135. return source;
  136. };
  137. // constructor for validator
  138. jQuery.validator = function( options, form ) {
  139. this.settings = jQuery.extend( {}, jQuery.validator.defaults, options );
  140. this.currentForm = form;
  141. this.init();
  142. };
  143. jQuery.extend(jQuery.validator, {
  144. defaults: {
  145. messages: {},
  146. errorClass: "error",
  147. errorElement: "label",
  148. focusInvalid: true,
  149. errorContainer: jQuery( [] ),
  150. errorLabelContainer: jQuery( [] ),
  151. onsubmit: true,
  152. ignore: [],
  153. onfocusin: function(element) {
  154. this.lastActive = element;
  155. // hide error label and remove error class on focus if enabled
  156. if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
  157. this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass );
  158. this.errorsFor(element).hide();
  159. }
  160. },
  161. onfocusout: function(element) {
  162. if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
  163. this.element(element);
  164. }
  165. },
  166. onkeyup: function(element) {
  167. if ( element.name in this.submitted || element == this.lastElement ) {
  168. this.element(element);
  169. }
  170. },
  171. onclick: function(element) {
  172. if ( element.name in this.submitted )
  173. this.element(element);
  174. },
  175. highlight: function( element, errorClass ) {
  176. jQuery( element ).addClass( errorClass );
  177. },
  178. unhighlight: function( element, errorClass ) {
  179. jQuery( element ).removeClass( errorClass );
  180. }
  181. },
  182. // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
  183. setDefaults: function(settings) {
  184. jQuery.extend( jQuery.validator.defaults, settings );
  185. },
  186. messages: {
  187. required: "This field is required.",
  188. remote: "Please fix this field.",
  189. email: "Please enter a valid email address.",
  190. url: "Please enter a valid URL.",
  191. date: "Please enter a valid date.",
  192. dateISO: "Please enter a valid date (ISO).",
  193. dateDE: "Bitte geben Sie ein gültiges Datum ein.",
  194. number: "Please enter a valid number.",
  195. numberDE: "Bitte geben Sie eine Nummer ein.",
  196. digits: "Please enter only digits",
  197. creditcard: "Please enter a valid credit card.",
  198. equalTo: "Please enter the same value again.",
  199. accept: "Please enter a value with a valid extension.",
  200. maxlength: jQuery.format("Please enter no more than {0} characters."),
  201. maxLength: jQuery.format("Please enter no more than {0} characters."),
  202. minlength: jQuery.format("Please enter at least {0} characters."),
  203. minLength: jQuery.format("Please enter at least {0} characters."),
  204. rangelength: jQuery.format("Please enter a value between {0} and {1} characters long."),
  205. rangeLength: jQuery.format("Please enter a value between {0} and {1} characters long."),
  206. rangeValue: jQuery.format("Please enter a value between {0} and {1}."),
  207. range: jQuery.format("Please enter a value between {0} and {1}."),
  208. maxValue: jQuery.format("Please enter a value less than or equal to {0}."),
  209. max: jQuery.format("Please enter a value less than or equal to {0}."),
  210. minValue: jQuery.format("Please enter a value greater than or equal to {0}."),
  211. min: jQuery.format("Please enter a value greater than or equal to {0}.")
  212. },
  213. autoCreateRanges: false,
  214. prototype: {
  215. init: function() {
  216. this.labelContainer = jQuery(this.settings.errorLabelContainer);
  217. this.errorContext = this.labelContainer.length && this.labelContainer || jQuery(this.currentForm);
  218. this.containers = jQuery(this.settings.errorContainer).add( this.settings.errorLabelContainer );
  219. this.submitted = {};
  220. this.valueCache = {};
  221. this.pendingRequest = 0;
  222. this.pending = {};
  223. this.invalid = {};
  224. this.reset();
  225. function delegate(event) {
  226. var validator = jQuery.data(this[0].form, "validator");
  227. validator.settings["on" + event.type] && validator.settings["on" + event.type].call(validator, this[0] );
  228. }
  229. jQuery(this.currentForm)
  230. .delegate("focusin focusout keyup", ":text, :password, :file, select, textarea", delegate)
  231. .delegate("click", ":radio, :checkbox", delegate);
  232. },
  233. // http://docs.jquery.com/Plugins/Validation/Validator/form
  234. form: function() {
  235. this.prepareForm();
  236. var elements = this.elements();
  237. for ( var i = 0; elements[i]; i++ ) {
  238. this.check( elements[i] );
  239. }
  240. jQuery.extend(this.submitted, this.errorMap);
  241. this.invalid = jQuery.extend({}, this.errorMap);
  242. jQuery(this.currentForm).triggerHandler("invalid-form.validate", [this]);
  243. this.showErrors();
  244. return this.valid();
  245. },
  246. // http://docs.jquery.com/Plugins/Validation/Validator/element
  247. element: function( element ) {
  248. element = this.clean( element );
  249. this.lastElement = element;
  250. this.prepareElement( element );
  251. var result = this.check( element );
  252. if ( result ) {
  253. delete this.invalid[element.name];
  254. } else {
  255. this.invalid[element.name] = true;
  256. }
  257. if ( !this.numberOfInvalids() ) {
  258. // Hide error containers on last error
  259. this.toHide.push( this.containers );
  260. }
  261. this.showErrors();
  262. return result;
  263. },
  264. // http://docs.jquery.com/Plugins/Validation/Validator/showErrors
  265. showErrors: function(errors) {
  266. if(errors) {
  267. // add items to error list and map
  268. jQuery.extend( this.errorMap, errors );
  269. this.errorList = [];
  270. for ( var name in errors ) {
  271. this.errorList.push({
  272. message: errors[name],
  273. element: this.findByName(name)[0]
  274. });
  275. }
  276. // remove items from success list
  277. this.successList = jQuery.grep( this.successList, function(element) {
  278. return !(element.name in errors);
  279. });
  280. }
  281. this.settings.showErrors
  282. ? this.settings.showErrors.call( this, this.errorMap, this.errorList )
  283. : this.defaultShowErrors();
  284. },
  285. // http://docs.jquery.com/Plugins/Validation/Validator/resetForm
  286. resetForm: function() {
  287. if ( jQuery.fn.resetForm )
  288. jQuery( this.currentForm ).resetForm();
  289. this.prepareForm();
  290. this.hideErrors();
  291. this.elements().removeClass( this.settings.errorClass );
  292. },
  293. numberOfInvalids: function() {
  294. var count = 0;
  295. for ( var i in this.invalid )
  296. count++;
  297. return count;
  298. },
  299. hideErrors: function() {
  300. this.addWrapper( this.toHide ).hide();
  301. },
  302. valid: function() {
  303. return this.size() == 0;
  304. },
  305. size: function() {
  306. return this.errorList.length;
  307. },
  308. focusInvalid: function() {
  309. if( this.settings.focusInvalid ) {
  310. try {
  311. jQuery(this.findLastActive() || this.errorList.length && this.errorList[0].element || []).filter(":visible").focus();
  312. } catch(e) { /* ignore IE throwing errors when focusing hidden elements */ }
  313. }
  314. },
  315. findLastActive: function() {
  316. var lastActive = this.lastActive;
  317. return lastActive && jQuery.grep(this.errorList, function(n) {
  318. return n.element.name == lastActive.name;
  319. }).length == 1 && lastActive;
  320. },
  321. elements: function() {
  322. var validator = this;
  323. var rulesCache = {};
  324. // select all valid inputs inside the form (no submit or reset buttons)
  325. // workaround with jQuery([]).add until http://dev.jquery.com/ticket/2114 is solved
  326. return jQuery([]).add(this.currentForm.elements)
  327. .filter("input, select, textarea")
  328. .not(":submit, :reset, [disabled]")
  329. .not( this.settings.ignore )
  330. .filter(function() {
  331. !this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this);
  332. // select only the first element for each name, and only those with rules specified
  333. if ( this.name in rulesCache || !jQuery(this).rules().length )
  334. return false;
  335. rulesCache[this.name] = true;
  336. return true;
  337. });
  338. },
  339. clean: function( selector ) {
  340. return jQuery( selector )[0];
  341. },
  342. errors: function() {
  343. return jQuery( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext );
  344. },
  345. reset: function() {
  346. this.successList = [];
  347. this.errorList = [];
  348. this.errorMap = {};
  349. this.toShow = jQuery( [] );
  350. this.toHide = jQuery( [] );
  351. this.formSubmitted = false;
  352. },
  353. prepareForm: function() {
  354. this.reset();
  355. this.toHide = this.errors().push( this.containers );
  356. },
  357. prepareElement: function( element ) {
  358. this.reset();
  359. this.toHide = this.errorsFor( this.clean(element) );
  360. },
  361. check: function( element ) {
  362. element = this.clean( element );
  363. this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass );
  364. var rules = jQuery(element).rules();
  365. for( var i = 0; rules[i]; i++) {
  366. var rule = rules[i];
  367. try {
  368. var result = jQuery.validator.methods[rule.method].call( this, jQuery.trim(element.value), element, rule.parameters );
  369. if ( result == "dependency-mismatch" )
  370. return;
  371. if ( result == "pending" ) {
  372. this.toHide = this.toHide.not( this.errorsFor(element) );
  373. return;
  374. }
  375. if( !result ) {
  376. this.formatAndAdd( element, rule );
  377. return false;
  378. }
  379. } catch(e) {
  380. this.settings.debug && window.console && console.warn("exception occured when checking element " + element.id
  381.  + ", check the '" + rule.method + "' method");
  382. throw e;
  383. }
  384. }
  385. if ( rules.length )
  386. this.successList.push(element);
  387. return true;
  388. },
  389. // return the custom message for the given element name and validation method
  390. customMessage: function( name, method ) {
  391. var m = this.settings.messages[name];
  392. return m && (m.constructor == String
  393. ? m
  394. : m[method]);
  395. },
  396. // return the first defined argument, allowing empty strings
  397. findDefined: function() {
  398. for(var i = 0; i < arguments.length; i++) {
  399. if (arguments[i] !== undefined)
  400. return arguments[i];
  401. }
  402. return undefined;
  403. },
  404. defaultMessage: function( element, method) {
  405. return this.findDefined(
  406. this.customMessage( element.name, method ),
  407. // title is never undefined, so handle empty string as undefined
  408. element.title || undefined,
  409. jQuery.validator.messages[method],
  410. "<strong>Warning: No message defined for " + element.name + "</strong>"
  411. );
  412. },
  413. formatAndAdd: function( element, rule ) {
  414. var message = this.defaultMessage( element, rule.method );
  415. if ( typeof message == "function" ) 
  416. message = message.call(this, rule.parameters, element);
  417. this.errorList.push({
  418. message: message,
  419. element: element
  420. });
  421. this.errorMap[element.name] = message;
  422. this.submitted[element.name] = message;
  423. },
  424. addWrapper: function(toToggle) {
  425. if ( this.settings.wrapper )
  426. toToggle.push( toToggle.parents( this.settings.wrapper ) );
  427. return toToggle;
  428. },
  429. defaultShowErrors: function() {
  430. for ( var i = 0; this.errorList[i]; i++ ) {
  431. var error = this.errorList[i];
  432. this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass );
  433. this.showLabel( error.element, error.message );
  434. }
  435. if( this.errorList.length ) {
  436. this.toShow.push( this.containers );
  437. }
  438. if (this.settings.success) {
  439. for ( var i = 0; this.successList[i]; i++ ) {
  440. this.showLabel( this.successList[i] );
  441. }
  442. }
  443. this.toHide = this.toHide.not( this.toShow );
  444. this.hideErrors();
  445. this.addWrapper( this.toShow ).show();
  446. },
  447. showLabel: function(element, message) {
  448. var label = this.errorsFor( element );
  449. if ( label.length ) {
  450. // refresh error/success class
  451. label.removeClass().addClass( this.settings.errorClass );
  452. // check if we have a generated label, replace the message then
  453. label.attr("generated") && label.html(message);
  454. } else {
  455. // create label
  456. label = jQuery("<" + this.settings.errorElement + "/>")
  457. .attr({"for":  this.idOrName(element), generated: true})
  458. .addClass(this.settings.errorClass)
  459. .html(message || "");
  460. if ( this.settings.wrapper ) {
  461. // make sure the element is visible, even in IE
  462. // actually showing the wrapped element is handled elsewhere
  463. label = label.hide().show().wrap("<" + this.settings.wrapper + ">").parent();
  464. }
  465. if ( !this.labelContainer.append(label).length )
  466. this.settings.errorPlacement
  467. ? this.settings.errorPlacement(label, jQuery(element) )
  468. : label.insertAfter(element);
  469. }
  470. if ( !message && this.settings.success ) {
  471. label.text("");
  472. typeof this.settings.success == "string"
  473. ? label.addClass( this.settings.success )
  474. : this.settings.success( label );
  475. }
  476. this.toShow.push(label);
  477. },
  478. errorsFor: function(element) {
  479. return this.errors().filter("[@for='" + this.idOrName(element) + "']");
  480. },
  481. idOrName: function(element) {
  482. return this.checkable(element) ? element.name : element.id || element.name;
  483. },
  484. rules: function( element ) {
  485. return jQuery(element).rules();
  486. },
  487. checkable: function( element ) {
  488. return /radio|checkbox/i.test(element.type);
  489. },
  490. findByName: function( name ) {
  491. // select by name and filter by form for performance over form.find("[name=...]")
  492. var form = this.currentForm;
  493. return jQuery(document.getElementsByName(name)).map(function(index, element) {
  494. return element.form == form && element || null;
  495. //  && element.name == name
  496. });
  497. },
  498. getLength: function(value, element) {
  499. switch( element.nodeName.toLowerCase() ) {
  500. case 'select':
  501. return jQuery("option:selected", element).length;
  502. case 'input':
  503. if( this.checkable( element) )
  504. return this.findByName(element.name).filter(':checked').length;
  505. }
  506. return value.length;
  507. },
  508. depend: function(param, element) {
  509. return this.dependTypes[typeof param]
  510. ? this.dependTypes[typeof param](param, element)
  511. : true;
  512. },
  513. dependTypes: {
  514. "boolean": function(param, element) {
  515. return param;
  516. },
  517. "string": function(param, element) {
  518. return !!jQuery(param, element.form).length;
  519. },
  520. "function": function(param, element) {
  521. return param(element);
  522. }
  523. },
  524. optional: function(element) {
  525. return !jQuery.validator.methods.required.call(this, jQuery.trim(element.value), element) && "dependency-mismatch";
  526. },
  527. startRequest: function(element) {
  528. if (!this.pending[element.name]) {
  529. this.pendingRequest++;
  530. this.pending[element.name] = true;
  531. }
  532. },
  533. stopRequest: function(element, valid) {
  534. this.pendingRequest--;
  535. // sometimes synchronization fails, make pendingRequest is never < 0
  536. if (this.pendingRequest < 0)
  537. this.pendingRequest = 0;
  538. delete this.pending[element.name];
  539. if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) {
  540. jQuery(this.currentForm).submit();
  541. }
  542. },
  543. previousValue: function(element) {
  544. return jQuery.data(element, "previousValue") || jQuery.data(element, "previousValue", previous = {
  545. old: null,
  546. valid: true,
  547. message: this.defaultMessage( element, "remote" )
  548. });
  549. }
  550. },
  551. classRuleSettings: {
  552. required: {required: true},
  553. email: {email: true},
  554. url: {url: true},
  555. date: {date: true},
  556. dateISO: {dateISO: true},
  557. dateDE: {dateDE: true},
  558. number: {number: true},
  559. numberDE: {numberDE: true},
  560. digits: {digits: true},
  561. creditcard: {creditcard: true}
  562. },
  563. addClassRules: function(className, rules) {
  564. className.constructor == String ?
  565. this.classRuleSettings[className] = rules :
  566. jQuery.extend(this.classRuleSettings, className);
  567. },
  568. classRules: function(element) {
  569. var rules = {};
  570. var classes = jQuery(element).attr('class');
  571. classes && jQuery.each(classes.split(' '), function() {
  572. if (this in jQuery.validator.classRuleSettings) {
  573. jQuery.extend(rules, jQuery.validator.classRuleSettings[this]);
  574. }
  575. });
  576. return rules;
  577. },
  578. attributeRules: function(element) {
  579. var rules = {};
  580. var $element = jQuery(element);
  581. for (method in jQuery.validator.methods) {
  582. var value = $element.attr(method);
  583. // allow 0 but neither undefined nor empty string
  584. if (value !== undefined && value !== '') {
  585. rules[method] = value;
  586. }
  587. }
  588. // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
  589. if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {
  590. delete rules.maxlength;
  591. // deprecated
  592. delete rules.maxLength;
  593. }
  594. return rules;
  595. },
  596. metadataRules: function(element) {
  597. if (!jQuery.metadata) return {};
  598. var meta = jQuery.data(element.form, 'validator').settings.meta;
  599. return meta ?
  600. jQuery(element).metadata()[meta] :
  601. jQuery(element).metadata();
  602. },
  603. staticRules: function(element) {
  604. var rules = {};
  605. var validator = jQuery.data(element.form, 'validator');
  606. if (validator.settings.rules) {
  607. rules = jQuery.validator.normalizeRule(validator.settings.rules[element.name]) || {};
  608. }
  609. return rules;
  610. },
  611. normalizeRules: function(rules, element) {
  612. // convert deprecated rules
  613. jQuery.each({
  614. minLength: 'minlength',
  615. maxLength: 'maxlength',
  616. rangeLength: 'rangelength',
  617. minValue: 'min',
  618. maxValue: 'max',
  619. rangeValue: 'range'
  620. }, function(dep, curr) {
  621. if (rules[dep]) {
  622. rules[curr] = rules[dep];
  623. delete rules[dep];
  624. }
  625. });
  626. // evaluate parameters
  627. jQuery.each(rules, function(rule, parameter) {
  628. rules[rule] = jQuery.isFunction(parameter) ? parameter(element) : parameter;
  629. });
  630. // clean number parameters
  631. jQuery.each(['minlength', 'maxlength', 'min', 'max'], function() {
  632. if (rules[this]) {
  633. rules[this] = Number(rules[this]);
  634. }
  635. });
  636. jQuery.each(['rangelength', 'range'], function() {
  637. if (rules[this]) {
  638. rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
  639. }
  640. });
  641. if (jQuery.validator.autoCreateRanges) {
  642. // auto-create ranges
  643. if (rules.min && rules.max) {
  644. rules.range = [rules.min, rules.max];
  645. delete rules.min;
  646. delete rules.max;
  647. }
  648. if (rules.minlength && rules.maxlength) {
  649. rules.rangelength = [rules.minlength, rules.maxlength];
  650. delete rules.minlength;
  651. delete rules.maxlength;
  652. }
  653. }
  654. return rules;
  655. },
  656. // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
  657. normalizeRule: function(data) {
  658. if( typeof data == "string" ) {
  659. var transformed = {};
  660. transformed[data] = true;
  661. data = transformed;
  662. }
  663. return data;
  664. },
  665. // http://docs.jquery.com/Plugins/Validation/Validator/addMethod
  666. addMethod: function(name, method, message) {
  667. jQuery.validator.methods[name] = method;
  668. jQuery.validator.messages[name] = message;
  669. if (method.length < 3) {
  670. jQuery.validator.addClassRules(name, jQuery.validator.normalizeRule(name));
  671. }
  672. },
  673. methods: {
  674. // http://docs.jquery.com/Plugins/Validation/Methods/required
  675. required: function(value, element, param) {
  676. // check if dependency is met
  677. if ( !this.depend(param, element) )
  678. return "dependency-mismatch";
  679. switch( element.nodeName.toLowerCase() ) {
  680. case 'select':
  681. var options = jQuery("option:selected", element);
  682. return options.length > 0 && ( element.type == "select-multiple" || (jQuery.browser.msie && !(options[0].attributes['value'].specified) ? options[0].text : options[0].value).length > 0);
  683. case 'input':
  684. if ( this.checkable(element) )
  685. return this.getLength(value, element) > 0;
  686. default:
  687. return value.length > 0;
  688. }
  689. },
  690. // http://docs.jquery.com/Plugins/Validation/Methods/remote
  691. remote: function(value, element, param) {
  692. if ( this.optional(element) )
  693. return "dependency-mismatch";
  694. var previous = this.previousValue(element);
  695. if (!this.settings.messages[element.name] )
  696. this.settings.messages[element.name] = {};
  697. this.settings.messages[element.name].remote = typeof previous.message == "function" ? previous.message(value) : previous.message;
  698. if ( previous.old !== value ) {
  699. previous.old = value;
  700. var validator = this;
  701. this.startRequest(element);
  702. var data = {};
  703. data[element.name] = value;
  704. jQuery.ajax({
  705. url: param,
  706. mode: "abort",
  707. port: "validate" + element.name,
  708. dataType: "json",
  709. data: data,
  710. success: function(response) {
  711. if ( !response ) {
  712. var errors = {};
  713. errors[element.name] =  response || validator.defaultMessage( element, "remote" );
  714. validator.showErrors(errors);
  715. } else {
  716. var submitted = validator.formSubmitted;
  717. validator.prepareElement(element);
  718. validator.formSubmitted = submitted;
  719. validator.successList.push(element);
  720. validator.showErrors();
  721. }
  722. previous.valid = response;
  723. validator.stopRequest(element, response);
  724. }
  725. });
  726. return "pending";
  727. } else if( this.pending[element.name] ) {
  728. return "pending";
  729. }
  730. return previous.valid;
  731. },
  732. // http://docs.jquery.com/Plugins/Validation/Methods/minlength
  733. minlength: function(value, element, param) {
  734. return this.optional(element) || this.getLength(value, element) >= param;
  735. },
  736. // deprecated, to be removed in 1.3
  737. minLength: function(value, element, param) {
  738. return jQuery.validator.methods.minlength.apply(this, arguments);
  739. },
  740. // http://docs.jquery.com/Plugins/Validation/Methods/maxlength
  741. maxlength: function(value, element, param) {
  742. return this.optional(element) || this.getLength(value, element) <= param;
  743. },
  744. // deprecated, to be removed in 1.3
  745. maxLength: function(value, element, param) {
  746. return jQuery.validator.methods.maxlength.apply(this, arguments);
  747. },
  748. // http://docs.jquery.com/Plugins/Validation/Methods/rangelength
  749. rangelength: function(value, element, param) {
  750. var length = this.getLength(value, element);
  751. return this.optional(element) || ( length >= param[0] && length <= param[1] );
  752. },
  753. // deprecated, to be removed in 1.3
  754. rangeLength: function(value, element, param) {
  755. return jQuery.validator.methods.rangelength.apply(this, arguments);
  756. },
  757. // http://docs.jquery.com/Plugins/Validation/Methods/min
  758. min: function( value, element, param ) {
  759. return this.optional(element) || value >= param;
  760. },
  761. // deprecated, to be removed in 1.3
  762. minValue: function() {
  763. return jQuery.validator.methods.min.apply(this, arguments);
  764. },
  765. // http://docs.jquery.com/Plugins/Validation/Methods/max
  766. max: function( value, element, param ) {
  767. return this.optional(element) || value <= param;
  768. },
  769. // deprecated, to be removed in 1.3
  770. maxValue: function() {
  771. return jQuery.validator.methods.max.apply(this, arguments);
  772. },
  773. // http://docs.jquery.com/Plugins/Validation/Methods/range
  774. range: function( value, element, param ) {
  775. return this.optional(element) || ( value >= param[0] && value <= param[1] );
  776. },
  777. // deprecated, to be removed in 1.3
  778. rangeValue: function() {
  779. return jQuery.validator.methods.range.apply(this, arguments);
  780. },
  781. // http://docs.jquery.com/Plugins/Validation/Methods/email
  782. email: function(value, element) {
  783. // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
  784. return this.optional(element) || /^((([a-z]|d|[!#$%&'*+-/=?^_`{|}~]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])+(.([a-z]|d|[!#$%&'*+-/=?^_`{|}~]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])+)*)|((x22)((((x20|x09)*(x0dx0a))?(x20|x09)+)?(([x01-x08x0bx0cx0e-x1fx7f]|x21|[x23-x5b]|[x5d-x7e]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(\([x01-x09x0bx0cx0d-x7f]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF]))))*(((x20|x09)*(x0dx0a))?(x20|x09)+)?(x22)))@((([a-z]|d|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(([a-z]|d|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])*([a-z]|d|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF]))).)+(([a-z]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(([a-z]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])*([a-z]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF]))).?$/i.test(value);
  785. },
  786. // http://docs.jquery.com/Plugins/Validation/Methods/url
  787. url: function(value, element) {
  788. // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
  789. return this.optional(element) || /^(https?|ftp)://(((([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(%[da-f]{2})|[!$&'()*+,;=]|:)*@)?(((d|[1-9]d|1dd|2[0-4]d|25[0-5]).(d|[1-9]d|1dd|2[0-4]d|25[0-5]).(d|[1-9]d|1dd|2[0-4]d|25[0-5]).(d|[1-9]d|1dd|2[0-4]d|25[0-5]))|((([a-z]|d|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(([a-z]|d|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])*([a-z]|d|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF]))).)+(([a-z]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(([a-z]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])*([a-z]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF]))).?)(:d*)?)(/((([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(%[da-f]{2})|[!$&'()*+,;=]|:|@)+(/(([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(%[da-f]{2})|[!$&'()*+,;=]|:|@)*)*)?)?(?((([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(%[da-f]{2})|[!$&'()*+,;=]|:|@)|[uE000-uF8FF]|/|?)*)?(#((([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(%[da-f]{2})|[!$&'()*+,;=]|:|@)|/|?)*)?$/i.test(value);
  790. },
  791.         
  792. // http://docs.jquery.com/Plugins/Validation/Methods/date
  793. date: function(value, element) {
  794. return this.optional(element) || !/Invalid|NaN/.test(new Date(value));
  795. },
  796. // http://docs.jquery.com/Plugins/Validation/Methods/dateISO
  797. dateISO: function(value, element) {
  798. return this.optional(element) || /^d{4}[/-]d{1,2}[/-]d{1,2}$/.test(value);
  799. },
  800. // http://docs.jquery.com/Plugins/Validation/Methods/dateDE
  801. dateDE: function(value, element) {
  802. return this.optional(element) || /^dd?.dd?.ddd?d?$/.test(value);
  803. },
  804. // http://docs.jquery.com/Plugins/Validation/Methods/number
  805. number: function(value, element) {
  806. return this.optional(element) || /^-?(?:d+|d{1,3}(?:,d{3})+)(?:.d+)?$/.test(value);
  807. },
  808. // http://docs.jquery.com/Plugins/Validation/Methods/numberDE
  809. numberDE: function(value, element) {
  810. return this.optional(element) || /^-?(?:d+|d{1,3}(?:.d{3})+)(?:,d+)?$/.test(value);
  811. },
  812. // http://docs.jquery.com/Plugins/Validation/Methods/digits
  813. digits: function(value, element) {
  814. return this.optional(element) || /^d+$/.test(value);
  815. },
  816. // http://docs.jquery.com/Plugins/Validation/Methods/creditcard
  817. // based on http://en.wikipedia.org/wiki/Luhn
  818. creditcard: function(value, element) {
  819. if ( this.optional(element) )
  820. return "dependency-mismatch";
  821. var nCheck = 0,
  822. nDigit = 0,
  823. bEven = false;
  824. value = value.replace(/D/g, "");
  825. for (n = value.length - 1; n >= 0; n--) {
  826. var cDigit = value.charAt(n);
  827. var nDigit = parseInt(cDigit, 10);
  828. if (bEven) {
  829. if ((nDigit *= 2) > 9)
  830. nDigit -= 9;
  831. }
  832. nCheck += nDigit;
  833. bEven = !bEven;
  834. }
  835. return (nCheck % 10) == 0;
  836. },
  837. // http://docs.jquery.com/Plugins/Validation/Methods/accept
  838. accept: function(value, element, param) {
  839. param = typeof param == "string" ? param : "png|jpe?g|gif";
  840. return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i")); 
  841. },
  842. // http://docs.jquery.com/Plugins/Validation/Methods/equalTo
  843. equalTo: function(value, element, param) {
  844. return value == jQuery(param).val();
  845. }
  846. }
  847. });
  848. // ajax mode: abort
  849. // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
  850. // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() 
  851. ;(function($) {
  852. var ajax = $.ajax;
  853. var pendingRequests = {};
  854. $.ajax = function(settings) {
  855. // create settings for compatibility with ajaxSetup
  856. settings = jQuery.extend(settings, jQuery.extend({}, jQuery.ajaxSettings, settings));
  857. var port = settings.port;
  858. if (settings.mode == "abort") {
  859. if ( pendingRequests[port] ) {
  860. pendingRequests[port].abort();
  861. }
  862. return pendingRequests[port] = ajax.apply(this, arguments);
  863. }
  864. return ajax.apply(this, arguments);
  865. };
  866. })(jQuery);
  867. // provides cross-browser focusin and focusout events
  868. // IE has native support, in other browsers, use event caputuring (neither bubbles)
  869. // provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
  870. // handler is only called when $(event.target).is(delegate), in the scope of the jQuery-object for event.target 
  871. // provides triggerEvent(type: String, target: Element) to trigger delegated events
  872. ;(function($) {
  873. $.extend($.event.special, {
  874. focusin: {
  875. setup: function() {
  876. if ($.browser.msie)
  877. return false;
  878. this.addEventListener("focus", $.event.special.focusin.handler, true);
  879. },
  880. teardown: function() {
  881. if ($.browser.msie)
  882. return false;
  883. this.removeEventListener("focus", $.event.special.focusin.handler, true);
  884. },
  885. handler: function(event) {
  886. var args = Array.prototype.slice.call( arguments, 1 );
  887. args.unshift($.extend($.event.fix(event), { type: "focusin" }));
  888. return $.event.handle.apply(this, args);
  889. }
  890. },
  891. focusout: {
  892. setup: function() {
  893. if ($.browser.msie)
  894. return false;
  895. this.addEventListener("blur", $.event.special.focusout.handler, true);
  896. },
  897. teardown: function() {
  898. if ($.browser.msie)
  899. return false;
  900. this.removeEventListener("blur", $.event.special.focusout.handler, true);
  901. },
  902. handler: function(event) {
  903. var args = Array.prototype.slice.call( arguments, 1 );
  904. args.unshift($.extend($.event.fix(event), { type: "focusout" }));
  905. return $.event.handle.apply(this, args);
  906. }
  907. }
  908. });
  909. $.extend($.fn, {
  910. delegate: function(type, delegate, handler) {
  911. return this.bind(type, function(event) {
  912. var target = $(event.target);
  913. if (target.is(delegate)) {
  914. return handler.apply(target, arguments);
  915. }
  916. });
  917. },
  918. triggerEvent: function(type, target) {
  919. return this.triggerHandler(type, [jQuery.event.fix({ type: type, target: target })]);
  920. }
  921. })
  922. })(jQuery);