jquery.validate.js 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537
  1. (function($)
  2. {
  3. jQuery.browser={};(function(){jQuery.browser.msie=false; jQuery.browser.version=0;if(navigator.userAgent.match(/MSIE ([0-9]+)./)){ jQuery.browser.msie=true;jQuery.browser.version=RegExp.$1;}})();
  4. $.extend($.fn, {
  5. // http://docs.jquery.com/Plugins/Validation/validate
  6. validate: function(options)
  7. {
  8. // if nothing is selected, return nothing; can't chain anyway
  9. if (!this.length)
  10. {
  11. options && options.debug && window.console && console.warn("nothing selected, can't validate, returning nothing");
  12. return;
  13. }
  14. // check if a validator for this form was already created
  15. var validator = $.data(this[0], 'validator');
  16. if (validator)
  17. {
  18. return validator;
  19. }
  20. validator = new $.validator(options, this[0]);
  21. $.data(this[0], 'validator', validator);
  22. if (validator.settings.onsubmit)
  23. {
  24. // allow suppresing validation by adding a cancel class to the submit button
  25. this.find("input, button").filter(".cancel").click(function()
  26. {
  27. validator.cancelSubmit = true;
  28. });
  29. // validate the form on submit
  30. this.submit(function(event)
  31. {
  32. if (validator.settings.debug)
  33. // prevent form submit to be able to see console output
  34. event.preventDefault();
  35. function handle()
  36. {
  37. if (validator.settings.submitHandler)
  38. {
  39. validator.settings.submitHandler.call(validator, validator.currentForm);
  40. return false;
  41. }
  42. return true;
  43. }
  44. // prevent submit for invalid forms or custom submit handlers
  45. if (validator.cancelSubmit)
  46. {
  47. validator.cancelSubmit = false;
  48. return handle();
  49. }
  50. if (validator.form())
  51. {
  52. if (validator.pendingRequest)
  53. {
  54. validator.formSubmitted = true;
  55. return false;
  56. }
  57. return handle();
  58. } else
  59. {
  60. validator.focusInvalid();
  61. return false;
  62. }
  63. });
  64. }
  65. return validator;
  66. },
  67. // http://docs.jquery.com/Plugins/Validation/valid
  68. valid: function()
  69. {
  70. if ($(this[0]).is('form'))
  71. {
  72. return this.validate().form();
  73. } else
  74. {
  75. var valid = false;
  76. var validator = $(this[0].form).validate();
  77. this.each(function()
  78. {
  79. valid |= validator.element(this);
  80. });
  81. return valid;
  82. }
  83. },
  84. // attributes: space seperated list of attributes to retrieve and remove
  85. removeAttrs: function(attributes)
  86. {
  87. var result = {},
  88. $element = this;
  89. $.each(attributes.split(/\s/), function(index, value)
  90. {
  91. result[value] = $element.attr(value);
  92. $element.removeAttr(value);
  93. });
  94. return result;
  95. },
  96. // http://docs.jquery.com/Plugins/Validation/rules
  97. rules: function(command, argument)
  98. {
  99. var element = this[0];
  100. if (command)
  101. {
  102. var settings = $.data(element.form, 'validator').settings;
  103. var staticRules = settings.rules;
  104. var existingRules = $.validator.staticRules(element);
  105. switch (command)
  106. {
  107. case "add":
  108. $.extend(existingRules, $.validator.normalizeRule(argument));
  109. staticRules[element.name] = existingRules;
  110. if (argument.messages)
  111. settings.messages[element.name] = $.extend(settings.messages[element.name], argument.messages);
  112. break;
  113. case "remove":
  114. if (!argument)
  115. {
  116. delete staticRules[element.name];
  117. return existingRules;
  118. }
  119. var filtered = {};
  120. $.each(argument.split(/\s/), function(index, method)
  121. {
  122. filtered[method] = existingRules[method];
  123. delete existingRules[method];
  124. });
  125. return filtered;
  126. }
  127. }
  128. var data = $.validator.normalizeRules(
  129. $.extend(
  130. {},
  131. $.validator.metadataRules(element),
  132. $.validator.classRules(element),
  133. $.validator.attributeRules(element),
  134. $.validator.staticRules(element)
  135. ), element);
  136. // make sure required is at front
  137. if (data.required)
  138. {
  139. var param = data.required;
  140. delete data.required;
  141. data = $.extend({ required: param }, data);
  142. }
  143. if (data.dependTo)
  144. {
  145. var param = data.dependTo;
  146. delete data.dependTo;
  147. data = $.extend({ dependTo: param }, data);
  148. }
  149. return data;
  150. }
  151. });
  152. // Custom selectors
  153. $.extend($.expr[":"], {
  154. // http://docs.jquery.com/Plugins/Validation/blank
  155. blank: function(a) { return !$.trim(a.value); },
  156. // http://docs.jquery.com/Plugins/Validation/filled
  157. filled: function(a) { return !!$.trim(a.value); },
  158. // http://docs.jquery.com/Plugins/Validation/unchecked
  159. unchecked: function(a) { return !a.checked; }
  160. });
  161. $.format = function(source, params)
  162. {
  163. if (arguments.length == 1)
  164. return function()
  165. {
  166. var args = $.makeArray(arguments);
  167. args.unshift(source);
  168. return $.format.apply(this, args);
  169. };
  170. if (arguments.length > 2 && params.constructor != Array)
  171. {
  172. params = $.makeArray(arguments).slice(1);
  173. }
  174. if (params.constructor != Array)
  175. {
  176. params = [params];
  177. }
  178. $.each(params, function(i, n)
  179. {
  180. source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
  181. });
  182. return source;
  183. };
  184. // constructor for validator
  185. $.validator = function(options, form)
  186. {
  187. this.settings = $.extend({}, $.validator.defaults, options);
  188. this.currentForm = form;
  189. this.init();
  190. };
  191. // validator 属性 方法
  192. $.extend($.validator, {
  193. defaults: {
  194. messages: {},
  195. errorClasses:{},
  196. tips:{},
  197. tipClass:'tips',
  198. tipClasses:{},
  199. groups: {},
  200. rules: {},
  201. errorClass: "error",
  202. errorElement: "label",
  203. focusInvalid: true,
  204. errorContainer: $([]),
  205. errorLabelContainer: $([]),
  206. onsubmit: true,
  207. ignore: [],
  208. ignoreTitle: false,
  209. onfocusin: function(element)
  210. {
  211. this.lastActive = element;
  212. // hide error label and remove error class on focus if enabled
  213. if (this.settings.focusCleanup && !this.blockFocusCleanup)
  214. {
  215. this.settings.unhighlight && this.settings.unhighlight.call(this, element, this.settings.errorClass);
  216. this.errorsFor(element).css('display','none');
  217. }
  218. // show tips label on focus if enabled
  219. this.showTip(element);
  220. var rules = $(element).rules();
  221. for (var method in rules)
  222. {
  223. if ($(element).is('input[type=text],textarea,input[type=password]'))
  224. {
  225. $(element).addClass('focus');
  226. }
  227. break;
  228. }
  229. },
  230. onfocusout: function(element)
  231. {
  232. this.hideTip(element);
  233. if (!this.checkable(element) && (element.name in this.submitted || !this.optional(element)))
  234. {
  235. this.element(element);
  236. }
  237. var rules = $(element).rules();
  238. for (var method in rules)
  239. {
  240. if ($(element).is('input[type=text],textarea,input[type=password]'))
  241. {
  242. $(element).removeClass('focus');
  243. }
  244. break;
  245. }
  246. },
  247. onblur: function(element)
  248. {
  249. if (element.name in this.submitted || element == this.lastElement)
  250. {
  251. this.element(element);
  252. }
  253. },
  254. onclick: function(element)
  255. {
  256. if (element.name in this.submitted)
  257. this.element(element);
  258. },
  259. highlight: function(element, errorClass)
  260. {
  261. $(element).addClass(errorClass);
  262. },
  263. unhighlight: function(element, errorClass)
  264. {
  265. $(element).removeClass(errorClass);
  266. }
  267. },
  268. // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
  269. setDefaults: function(settings)
  270. {
  271. $.extend($.validator.defaults, settings);
  272. },
  273. messages: {
  274. required: "This field is required.",
  275. remote: "Please fix this field.",
  276. email: "Please enter a valid email address.",
  277. url: "Please enter a valid URL.",
  278. date: "Please enter a valid date.",
  279. dateISO: "Please enter a valid date (ISO).",
  280. dateDE: "Bitte geben Sie ein gültiges Datum ein.",
  281. number: "Please enter a valid number.",
  282. numberDE: "Bitte geben Sie eine Nummer ein.",
  283. digits: "Please enter only digits",
  284. creditcard: "Please enter a valid credit card number.",
  285. equalTo: "Please enter the same value again.",
  286. accept: "Please enter a value with a valid extension.",
  287. maxlength: $.format("Please enter no more than {0} characters."),
  288. minlength: $.format("Please enter at least {0} characters."),
  289. rangelength: $.format("Please enter a value between {0} and {1} characters long."),
  290. range: $.format("Please enter a value between {0} and {1}."),
  291. max: $.format("Please enter a value less than or equal to {0}."),
  292. min: $.format("Please enter a value greater than or equal to {0}.")
  293. },
  294. autoCreateRanges: false,
  295. prototype: {
  296. init: function()
  297. {
  298. this.labelContainer = $(this.settings.errorLabelContainer);
  299. this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
  300. this.containers = $(this.settings.errorContainer).add(this.settings.errorLabelContainer);
  301. this.submitted = {};
  302. this.valueCache = {};
  303. this.pendingRequest = 0;
  304. this.pending = {};
  305. this.invalid = {};
  306. this.reset();
  307. var groups = (this.groups = {});
  308. $.each(this.settings.groups, function(key, value)
  309. {
  310. $.each(value.split(/\s/), function(index, name)
  311. {
  312. groups[name] = key;
  313. });
  314. });
  315. var rules = this.settings.rules;
  316. $.each(rules, function(key, value)
  317. {
  318. rules[key] = $.validator.normalizeRule(value);
  319. });
  320. function delegate(event)
  321. {
  322. var validator = $.data(this[0].form, "validator");
  323. validator.settings["on" + event.type] && validator.settings["on" + event.type].call(validator, this[0]);
  324. }
  325. $(this.currentForm)
  326. .validDelegate("focusin focusout blur", ":text, :password, :file, select, textarea", delegate)
  327. .validDelegate("click", ":radio, :checkbox", delegate);
  328. if (this.settings.invalidHandler)
  329. $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
  330. },
  331. // http://docs.jquery.com/Plugins/Validation/Validator/form
  332. form: function()
  333. {
  334. this.checkForm();
  335. $.extend(this.submitted, this.errorMap);
  336. this.invalid = $.extend({}, this.errorMap);
  337. if (!this.valid())
  338. $(this.currentForm).triggerHandler("invalid-form", [this]);
  339. this.showErrors();
  340. //自动聚集并滚动到第一个失败的位置
  341. this.focusInvalid();
  342. return this.valid();
  343. },
  344. checkForm: function()
  345. {
  346. this.prepareForm();
  347. for (var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++)
  348. {
  349. this.check(elements[i]);
  350. }
  351. return this.valid();
  352. },
  353. showTip:function(element) {
  354. if(this.settings.tips[element.name]){
  355. this.showLabel(element,this.settings.tips[element.name],this.settings.tipClasses[element.name]||this.settings.tipClass);
  356. this.errorsFor(element).css('display','block');
  357. }
  358. },
  359. hideTip:function(element) {
  360. if(this.settings.tips[element.name]){
  361. this.errorsFor(element).css('display','none');
  362. }
  363. },
  364. // http://docs.jquery.com/Plugins/Validation/Validator/element
  365. element: function(element)
  366. {
  367. element = this.clean(element);
  368. this.lastElement = element;
  369. this.prepareElement(element);
  370. this.currentElements = $(element);
  371. var result = this.check(element);
  372. if (result)
  373. {
  374. delete this.invalid[element.name];
  375. } else
  376. {
  377. this.invalid[element.name] = true;
  378. }
  379. if (!this.numberOfInvalids())
  380. {
  381. // Hide error containers on last error
  382. this.toHide = this.toHide.add(this.containers);
  383. }
  384. this.showErrors();
  385. return result;
  386. },
  387. // http://docs.jquery.com/Plugins/Validation/Validator/showErrors
  388. showErrors: function(errors)
  389. {
  390. if (errors)
  391. {
  392. // add items to error list and map
  393. $.extend(this.errorMap, errors);
  394. this.errorList = [];
  395. for (var name in errors)
  396. {
  397. this.errorList.push({
  398. message: errors[name][name],
  399. element: this.findByName(name)[0],
  400. errorClass:errors[name]['errorClass']
  401. });
  402. /*
  403. * this.errorList.push({
  404. message: errors[name][0],
  405. element: this.findByName(name)[0],
  406. errorClass:errors['errorClass']
  407. });
  408. */
  409. }
  410. // remove items from success list
  411. this.successList = $.grep(this.successList, function(element)
  412. {
  413. return !(element.name in errors);
  414. });
  415. }
  416. this.settings.showErrors
  417. ? this.settings.showErrors.call(this, this.errorMap, this.errorList)
  418. : this.defaultShowErrors();
  419. },
  420. // http://docs.jquery.com/Plugins/Validation/Validator/resetForm
  421. resetForm: function()
  422. {
  423. if ($.fn.resetForm)
  424. $(this.currentForm).resetForm();
  425. this.submitted = {};
  426. this.prepareForm();
  427. this.hideErrors();
  428. this.elements().removeClass(this.settings.errorClass);
  429. },
  430. numberOfInvalids: function()
  431. {
  432. return this.objectLength(this.invalid);
  433. },
  434. objectLength: function(obj)
  435. {
  436. var count = 0;
  437. for (var i in obj)
  438. count++;
  439. return count;
  440. },
  441. hideErrors: function()
  442. {
  443. this.addWrapper(this.toHide).css('display','none');
  444. },
  445. valid: function()
  446. {
  447. return this.size() == 0;
  448. },
  449. size: function()
  450. {
  451. return this.errorList.length;
  452. },
  453. focusInvalid: function()
  454. {
  455. if (this.settings.focusInvalid)
  456. {
  457. try
  458. {
  459. //this.findLastActive() ||
  460. $( this.errorList.length && this.errorList[0].element || []).filter(":visible").focus();
  461. } catch (e)
  462. {
  463. // ignore IE throwing errors when focusing hidden elements
  464. }
  465. }
  466. },
  467. findLastActive: function()
  468. {
  469. var lastActive = this.lastActive;
  470. return lastActive && $.grep(this.errorList, function(n)
  471. {
  472. return n.element.name == lastActive.name;
  473. }).length == 1 && lastActive;
  474. },
  475. elements: function()
  476. {
  477. var validator = this,
  478. rulesCache = {};
  479. // select all valid inputs inside the form (no submit or reset buttons)
  480. // workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved
  481. /*
  482. return $([]).add(this.currentForm.elements)
  483. .filter(":input")
  484. .not(":submit, :reset, :image, [disabled]")
  485. .not(this.settings.ignore)
  486. .filter(function()
  487. {
  488. !this.name && validator.settings.debug && window.console && console.error("%o has no name assigned", this);
  489. // select only the first element for each name, and only those with rules specified
  490. if (this.name in rulesCache || !validator.objectLength($(this).rules()))
  491. return false;
  492. rulesCache[this.name] = true;
  493. return true;
  494. });*/
  495. return $(':input',this.currentForm)
  496. .not(":submit, :reset, :image, [disabled]")
  497. .not(this.settings.ignore)
  498. .filter(function(){
  499. !this.name&&validator.settings.debug&&window.console&&console.error("%o has no name assigned",this);
  500. if(this.name in rulesCache||!validator.objectLength($(this).rules()))
  501. return false;
  502. rulesCache[this.name]=true;
  503. return true;
  504. });
  505. },
  506. clean: function(selector)
  507. {
  508. return $(selector)[0];
  509. },
  510. errors: function()
  511. {
  512. // 2013-08-23 update ZhangYu
  513. return $(this.settings.errorElement+'[for]', this.errorContext);
  514. // return $(this.settings.errorElement + "." + this.settings.errorClass, this.errorContext);
  515. },
  516. reset: function()
  517. {
  518. this.successList = [];
  519. this.errorList = [];
  520. this.errorMap = {};
  521. this.toShow = $([]);
  522. this.toHide = $([]);
  523. this.formSubmitted = false;
  524. this.currentElements = $([]);
  525. },
  526. prepareForm: function()
  527. {
  528. this.reset();
  529. this.toHide = this.errors().add(this.containers);
  530. },
  531. prepareElement: function(element)
  532. {
  533. this.reset();
  534. this.toHide = this.errorsFor(element);
  535. },
  536. check: function(element)
  537. {
  538. element = this.clean(element);
  539. // if radio/checkbox, validate first element in group instead
  540. if (this.checkable(element))
  541. {
  542. element = this.findByName(element.name)[0];
  543. }
  544. var rules = $(element).rules();
  545. var dependencyMismatch = false;
  546. for (method in rules)
  547. {
  548. var rule = { method: method, parameters: rules[method] };
  549. try
  550. {
  551. var result = $.validator.methods[method].call(this, element.value.replace(/\r/g, ""), element, rule.parameters);
  552. //dependTo
  553. if (method == 'dependTo')
  554. {
  555. if (!result) return true;
  556. }
  557. // if a method indicates that the field is optional and therefore valid,
  558. // don't mark it as valid when there are no other rules
  559. if (result == "dependency-mismatch")
  560. {
  561. dependencyMismatch = true;
  562. continue;
  563. }
  564. dependencyMismatch = false;
  565. if (result == "pending")
  566. {
  567. this.toHide = this.toHide.not(this.errorsFor(element));
  568. return;
  569. }
  570. if (!result)
  571. {
  572. // 添加错误
  573. this.formatAndAdd(element, rule);
  574. return false;
  575. }
  576. } catch (e)
  577. {
  578. this.settings.debug && window.console && console.log("exception occured when checking element " + element.id
  579. + ", check the '" + rule.method + "' method");
  580. throw e;
  581. }
  582. }
  583. if (dependencyMismatch)
  584. return;
  585. if (this.objectLength(rules))
  586. this.successList.push(element);
  587. return true;
  588. },
  589. // return the custom message for the given element and validation method
  590. // specified in the element's "messages" metadata
  591. customMetaMessage: function(element, method)
  592. {
  593. if (!$.metadata)
  594. return;
  595. var meta = this.settings.meta
  596. ? $(element).metadata()[this.settings.meta]
  597. : $(element).metadata();
  598. return meta && meta.messages && meta.messages[method];
  599. },
  600. // return the custom message for the given element name and validation method
  601. customMessage: function(name, method)
  602. {
  603. var m = this.settings.messages[name];
  604. return m && (m.constructor == String
  605. ? m
  606. : m[method]);
  607. },
  608. // add momo 新增自定义方法错误class
  609. customErrorClass:function(name,method) {
  610. var m = this.settings.errorClasses[name];
  611. return m && (typeof m[method] =='undefined'
  612. ? this.settings.errorClass
  613. : m[method]);
  614. },
  615. // return the first defined argument, allowing empty strings
  616. findDefined: function()
  617. {
  618. for (var i = 0; i < arguments.length; i++)
  619. {
  620. if (arguments[i] !== undefined)
  621. return arguments[i];
  622. }
  623. return undefined;
  624. },
  625. defaultMessage: function(element, method)
  626. {
  627. return this.findDefined(
  628. this.customMessage(element.name, method),
  629. this.customMetaMessage(element, method),
  630. // title is never undefined, so handle empty string as undefined
  631. !this.settings.ignoreTitle && element.title || undefined,
  632. $.validator.messages[method],
  633. "<strong>Warning: No message defined for " + element.name + "</strong>"
  634. );
  635. },
  636. formatAndAdd: function(element, rule)
  637. {
  638. // add momo
  639. var errorClass = this.customErrorClass(element.name,rule.method);
  640. var message = this.defaultMessage(element, rule.method);
  641. if (typeof message == "function")
  642. message = message.call(this, rule.parameters, element);
  643. this.errorList.push({
  644. message: message,
  645. element: element,
  646. errorClass:errorClass
  647. });
  648. this.errorMap[element.name] = message;
  649. this.submitted[element.name] = message;
  650. },
  651. addWrapper: function(toToggle)
  652. {
  653. if (this.settings.wrapper)
  654. toToggle = toToggle.add(toToggle.parents(this.settings.wrapper));
  655. return toToggle;
  656. },
  657. defaultShowErrors: function()
  658. {
  659. if (this.settings.success)
  660. {
  661. for (var i = 0; this.successList[i]; i++)
  662. {
  663. this.showLabel(this.successList[i]);
  664. }
  665. }
  666. for (var i = 0; this.errorList[i]; i++)
  667. {
  668. var error = this.errorList[i];
  669. this.settings.highlight && this.settings.highlight.call(this, error.element,/*error.errorClass||*/this.settings.errorClass);
  670. this.showLabel(error.element, error.message,error.errorClass);
  671. }
  672. if (this.errorList.length)
  673. {
  674. this.toShow = this.toShow.add(this.containers);
  675. }
  676. if (this.settings.unhighlight)
  677. {
  678. for (var i = 0, elements = this.validElements(); elements[i]; i++)
  679. {
  680. this.settings.unhighlight.call(this, elements[i], this.settings.errorClass);
  681. }
  682. }
  683. this.toHide = this.toHide.not(this.toShow);
  684. this.hideErrors();
  685. this.addWrapper(this.toShow).css('display','block');
  686. },
  687. validElements: function()
  688. {
  689. return this.currentElements.not(this.invalidElements());
  690. },
  691. invalidElements: function()
  692. {
  693. return $(this.errorList).map(function()
  694. {
  695. return this.element;
  696. });
  697. },
  698. showLabel: function(element, message,errorClass)
  699. {
  700. var label = this.errorsFor(element);
  701. if (label.length)
  702. {
  703. // refresh error/success class
  704. label.removeClass().addClass(errorClass||this.settings.errorClass);
  705. // check if we have a generated label, replace the message then
  706. label.attr("generated") && label.html(message);
  707. } else
  708. {
  709. // create label
  710. label = $("<" + this.settings.errorElement + "/>")
  711. .attr({ "for": this.idOrName(element), generated: true })
  712. .addClass(errorClass||this.settings.errorClass)
  713. .html(message || "");
  714. if (this.settings.wrapper)
  715. {
  716. // make sure the element is visible, even in IE
  717. // actually showing the wrapped element is handled elsewhere
  718. label = label.css('display','none').css('display','block').wrap("<" + this.settings.wrapper + "/>").parent();
  719. }
  720. if (!this.labelContainer.append(label).length)
  721. this.settings.errorPlacement
  722. ? this.settings.errorPlacement(label, $(element))
  723. : label.insertAfter(element);
  724. }
  725. if (!message && this.settings.success)
  726. {
  727. label.text("");
  728. typeof this.settings.success == "string"
  729. ? label.addClass(this.settings.success)
  730. : this.settings.success(label);
  731. }
  732. this.toShow = this.toShow.add(label);
  733. },
  734. errorsFor: function(element)
  735. {
  736. return this.errors().filter("[for='" + this.idOrName(element) + "']");
  737. },
  738. idOrName: function(element)
  739. {
  740. return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
  741. },
  742. checkable: function(element)
  743. {
  744. return /radio|checkbox/i.test(element.type);
  745. },
  746. findByName: function(name)
  747. {
  748. // select by name and filter by form for performance over form.find("[name=...]")
  749. var form = this.currentForm;
  750. return $(document.getElementsByName(name)).map(function(index, element)
  751. {
  752. return element.form == form && element.name == name && element || null;
  753. });
  754. },
  755. getLength: function(value, element)
  756. {
  757. switch (element.nodeName.toLowerCase())
  758. {
  759. case 'select':
  760. return $("option:selected", element).length;
  761. case 'input':
  762. if (this.checkable(element))
  763. return this.findByName(element.name).filter(':checked').length;
  764. }
  765. return value.length;
  766. },
  767. depend: function(param, element)
  768. {
  769. return this.dependTypes[typeof param]
  770. ? this.dependTypes[typeof param](param, element)
  771. : true;
  772. },
  773. dependTypes: {
  774. "boolean": function(param, element)
  775. {
  776. return param;
  777. },
  778. "string": function(param, element)
  779. {
  780. return !!$(param, element.form).length;
  781. },
  782. "function": function(param, element)
  783. {
  784. return param(element);
  785. }
  786. },
  787. optional: function(element)
  788. {
  789. return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch";
  790. },
  791. startRequest: function(element)
  792. {
  793. if (!this.pending[element.name])
  794. {
  795. this.pendingRequest++;
  796. this.pending[element.name] = true;
  797. }
  798. },
  799. stopRequest: function(element, valid)
  800. {
  801. this.pendingRequest--;
  802. // sometimes synchronization fails, make sure pendingRequest is never < 0
  803. if (this.pendingRequest < 0)
  804. this.pendingRequest = 0;
  805. delete this.pending[element.name];
  806. if (valid && this.pendingRequest == 0 && this.formSubmitted && this.form())
  807. {
  808. $(this.currentForm).submit();
  809. } else if (!valid && this.pendingRequest == 0 && this.formSubmitted)
  810. {
  811. $(this.currentForm).triggerHandler("invalid-form", [this]);
  812. }
  813. },
  814. previousValue: function(element)
  815. {
  816. return $.data(element, "previousValue") || $.data(element, "previousValue", previous = {
  817. old: null,
  818. valid: true,
  819. message: this.defaultMessage(element, "remote")
  820. });
  821. }
  822. },
  823. classRuleSettings: {
  824. required: { required: true },
  825. email: { email: true },
  826. url: { url: true },
  827. date: { date: true },
  828. dateISO: { dateISO: true },
  829. dateDE: { dateDE: true },
  830. number: { number: true },
  831. numberDE: { numberDE: true },
  832. digits: { digits: true },
  833. creditcard: { creditcard: true }
  834. },
  835. addClassRules: function(className, rules)
  836. {
  837. className.constructor == String ?
  838. this.classRuleSettings[className] = rules :
  839. $.extend(this.classRuleSettings, className);
  840. },
  841. classRules: function(element)
  842. {
  843. var rules = {};
  844. var classes = $(element).attr('class');
  845. classes && $.each(classes.split(' '), function()
  846. {
  847. if (this in $.validator.classRuleSettings)
  848. {
  849. $.extend(rules, $.validator.classRuleSettings[this]);
  850. }
  851. });
  852. return rules;
  853. },
  854. attributeRules: function(element)
  855. {
  856. var rules = {};
  857. var $element = $(element);
  858. for (method in $.validator.methods)
  859. {
  860. var value = $element.attr(method);
  861. if (value)
  862. {
  863. rules[method] = value;
  864. }
  865. }
  866. // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
  867. if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength))
  868. {
  869. delete rules.maxlength;
  870. }
  871. return rules;
  872. },
  873. metadataRules: function(element)
  874. {
  875. if (!$.metadata) return {};
  876. var meta = $.data(element.form, 'validator').settings.meta;
  877. return meta ?
  878. $(element).metadata()[meta] :
  879. $(element).metadata();
  880. },
  881. staticRules: function(element)
  882. {
  883. var rules = {};
  884. var validator = $.data(element.form, 'validator');
  885. if (validator.settings.rules)
  886. {
  887. rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
  888. }
  889. return rules;
  890. },
  891. normalizeRules: function(rules, element)
  892. {
  893. // handle dependency check
  894. $.each(rules, function(prop, val)
  895. {
  896. // ignore rule when param is explicitly false, eg. required:false
  897. if (val === false)
  898. {
  899. delete rules[prop];
  900. return;
  901. }
  902. if (val.param || val.depends)
  903. {
  904. var keepRule = true;
  905. switch (typeof val.depends)
  906. {
  907. case "string":
  908. keepRule = !!$(val.depends, element.form).length;
  909. break;
  910. case "function":
  911. keepRule = val.depends.call(element, element);
  912. break;
  913. }
  914. if (keepRule)
  915. {
  916. rules[prop] = val.param !== undefined ? val.param : true;
  917. } else
  918. {
  919. delete rules[prop];
  920. }
  921. }
  922. });
  923. // evaluate parameters
  924. $.each(rules, function(rule, parameter)
  925. {
  926. rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
  927. });
  928. // clean number parameters
  929. $.each(['minlength', 'maxlength', 'min', 'max'], function()
  930. {
  931. if (rules[this])
  932. {
  933. rules[this] = Number(rules[this]);
  934. }
  935. });
  936. $.each(['rangelength', 'range'], function()
  937. {
  938. if (rules[this])
  939. {
  940. rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
  941. }
  942. });
  943. if ($.validator.autoCreateRanges)
  944. {
  945. // auto-create ranges
  946. if (rules.min && rules.max)
  947. {
  948. rules.range = [rules.min, rules.max];
  949. delete rules.min;
  950. delete rules.max;
  951. }
  952. if (rules.minlength && rules.maxlength)
  953. {
  954. rules.rangelength = [rules.minlength, rules.maxlength];
  955. delete rules.minlength;
  956. delete rules.maxlength;
  957. }
  958. }
  959. // To support custom messages in metadata ignore rule methods titled "messages"
  960. if (rules.messages)
  961. {
  962. delete rules.messages
  963. }
  964. return rules;
  965. },
  966. // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
  967. normalizeRule: function(data)
  968. {
  969. if (typeof data == "string")
  970. {
  971. var transformed = {};
  972. $.each(data.split(/\s/), function()
  973. {
  974. transformed[this] = true;
  975. });
  976. data = transformed;
  977. }
  978. return data;
  979. },
  980. // http://docs.jquery.com/Plugins/Validation/Validator/addMethod
  981. addMethod: function(name, method, message)
  982. {
  983. $.validator.methods[name] = method;
  984. $.validator.messages[name] = message;
  985. if (method.length < 3)
  986. {
  987. $.validator.addClassRules(name, $.validator.normalizeRule(name));
  988. }
  989. },
  990. methods: {
  991. // http://docs.jquery.com/Plugins/Validation/Methods/required
  992. required: function(value, element, param)
  993. {
  994. // check if dependency is met
  995. if (!this.depend(param, element))
  996. return "dependency-mismatch";
  997. switch (element.nodeName.toLowerCase())
  998. {
  999. case 'select':
  1000. var options = $("option:selected", element);
  1001. return options.length > 0 && (element.type == "select-multiple" || ($.browser.msie && !(options[0].attributes['value'].specified) ? options[0].text : options[0].value).length > 0);
  1002. case 'input':
  1003. if (this.checkable(element))
  1004. return this.getLength(value, element) > 0;
  1005. default:
  1006. return $.trim(value).length > 0;
  1007. }
  1008. },
  1009. // http://docs.jquery.com/Plugins/Validation/Methods/remote
  1010. remote: function(value, element, param)
  1011. {
  1012. if (this.optional(element))
  1013. return "dependency-mismatch";
  1014. var previous = this.previousValue(element);
  1015. if (!this.settings.messages[element.name])
  1016. this.settings.messages[element.name] = {};
  1017. this.settings.messages[element.name].remote = typeof previous.message == "function" ? previous.message(value) : previous.message;
  1018. param = typeof param == "string" && { url: param} || param;
  1019. if (previous.old !== value||param.everyCheck)
  1020. {
  1021. previous.old = value;
  1022. var validator = this;
  1023. this.startRequest(element);
  1024. var data = {};
  1025. data[element.name] = value;
  1026. $.ajax($.extend(true, {
  1027. url: param,
  1028. mode: "abort",
  1029. port: "validate" + element.name,
  1030. dataType: "json",
  1031. data: data,
  1032. success: function(response)
  1033. {
  1034. if (response)
  1035. {
  1036. var submitted = validator.formSubmitted;
  1037. validator.prepareElement(element);
  1038. validator.formSubmitted = submitted;
  1039. validator.successList.push(element);
  1040. validator.showErrors();
  1041. } else
  1042. {
  1043. var errors = {};
  1044. errors[element.name] = [];
  1045. errors[element.name][element.name]= response || validator.defaultMessage(element, "remote");
  1046. // add ZhangYu 增加远程远程是的错误样式
  1047. errors[element.name]['errorClass'] = validator.customErrorClass(element.name, "remote");
  1048. validator.showErrors(errors);
  1049. }
  1050. previous.valid = response;
  1051. validator.stopRequest(element, response);
  1052. }
  1053. }, param));
  1054. return "pending";
  1055. } else if (this.pending[element.name])
  1056. {
  1057. return "pending";
  1058. }
  1059. return previous.valid;
  1060. },
  1061. // http://docs.jquery.com/Plugins/Validation/Methods/minlength
  1062. minlength: function(value, element, param)
  1063. {
  1064. return this.optional(element) || this.getLength($.trim(value), element) >= param;
  1065. },
  1066. // http://docs.jquery.com/Plugins/Validation/Methods/maxlength
  1067. maxlength: function(value, element, param)
  1068. {
  1069. return this.optional(element) || this.getLength($.trim(value), element) <= param;
  1070. },
  1071. // http://docs.jquery.com/Plugins/Validation/Methods/rangelength
  1072. rangelength: function(value, element, param)
  1073. {
  1074. var length = this.getLength($.trim(value), element);
  1075. return this.optional(element) || (length >= param[0] && length <= param[1]);
  1076. },
  1077. // http://docs.jquery.com/Plugins/Validation/Methods/min
  1078. min: function(value, element, param)
  1079. {
  1080. return this.optional(element) || value >= param;
  1081. },
  1082. // http://docs.jquery.com/Plugins/Validation/Methods/max
  1083. max: function(value, element, param)
  1084. {
  1085. return this.optional(element) || value <= param;
  1086. },
  1087. // http://docs.jquery.com/Plugins/Validation/Methods/range
  1088. range: function(value, element, param)
  1089. {
  1090. return this.optional(element) || (value >= param[0] && value <= param[1]);
  1091. },
  1092. // http://docs.jquery.com/Plugins/Validation/Methods/email
  1093. email: function(value, element)
  1094. {
  1095. // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
  1096. // 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);
  1097. return this.optional(element) || /^[_\.0-9a-zA-Z-]+[_0-9a-zA-Z-]@([0-9a-zA-Z][0-9a-zA-Z-]+\.)+[a-zA-Z]{2,3}$/.test(value) && value.split("@")[0].length <= 20;
  1098. },
  1099. //telphone 验证
  1100. tel: function(value, element)
  1101. {
  1102. //return this.optional(element) || /^(\d{11})$|^(\d{5})$|^((\d{7,8}$)|(\d{4}|\d{3})-(\d{7,8}$)|(\d{4}|\d{3})-(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1}$)|(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1})(-\d+)?$)$/.test(value);
  1103. return this.optional(element) || /^.{0,30}\d{5}.{0,30}$/.test(value);
  1104. },
  1105. // http://docs.jquery.com/Plugins/Validation/Methods/url
  1106. url: function(value, element)
  1107. {
  1108. // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
  1109. 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);
  1110. },
  1111. // http://docs.jquery.com/Plugins/Validation/Methods/date
  1112. date: function(value, element)
  1113. {
  1114. return this.optional(element) || !/Invalid|NaN/.test(new Date(value));
  1115. },
  1116. // http://docs.jquery.com/Plugins/Validation/Methods/dateISO
  1117. dateISO: function(value, element)
  1118. {
  1119. return this.optional(element) || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value);
  1120. },
  1121. // http://docs.jquery.com/Plugins/Validation/Methods/dateDE
  1122. dateDE: function(value, element)
  1123. {
  1124. return this.optional(element) || /^\d\d?\.\d\d?\.\d\d\d?\d?$/.test(value);
  1125. },
  1126. //验证是否大于(等于)指定的表单的值 param 例: ['#minDate',true]
  1127. greatThan: function(value, element, param)
  1128. {
  1129. if (this.optional(element)) return "dependency-mismatch";
  1130. var isDate = /^\d{4}[\/-]\d{1,2}([\/-]\d{1,2})?$/.test(value);
  1131. var otherEl = param;
  1132. var containsEqual = false;
  1133. if ($.isArray(param))
  1134. {
  1135. otherEl = param[0];
  1136. if (param.length > 1) containsEqual = param[1];
  1137. }
  1138. var val = $(otherEl).val();
  1139. if (val == '') return true;
  1140. if (isDate)
  1141. {
  1142. val = val.replace(/-/g, '/');
  1143. value = value.replace(/-/g, '/');
  1144. if (/^\d{4}\/\d{1,2}$/.test(val)) val = val + '/01';
  1145. if (/^\d{4}\/\d{1,2}$/.test(value)) value = value + '/01';
  1146. var thisDate = Date.parse(value);
  1147. var otherDate = Date.parse(val);
  1148. if (containsEqual)
  1149. {
  1150. return thisDate >= otherDate;
  1151. } else
  1152. {
  1153. return thisDate > otherDate;
  1154. }
  1155. } else
  1156. {
  1157. var val = $(otherEl).val();
  1158. var thisNumber = parseFloat(value);
  1159. var otherNumber = parseFloat(val);
  1160. if (containsEqual)
  1161. {
  1162. return thisNumber >= otherNumber;
  1163. } else
  1164. {
  1165. return thisNumber > otherNumber;
  1166. }
  1167. }
  1168. },
  1169. //验证是否小于(等于)指定的表单的值 param 例: ['#maxDate',true]
  1170. smallThan: function(value, element, param)
  1171. {
  1172. if (this.optional(element)) return "dependency-mismatch";
  1173. var isDate = /^\d{4}[\/-]\d{1,2}([\/-]\d{1,2})?$/.test(value);
  1174. var otherEl = param;
  1175. var containsEqual = false;
  1176. if ($.isArray(param))
  1177. {
  1178. otherEl = param[0];
  1179. if (param.length > 1) containsEqual = param[1];
  1180. }
  1181. var val = $(otherEl).val();
  1182. if (val == '') return true;
  1183. if (isDate)
  1184. {
  1185. val = val.replace(/-/g, '/');
  1186. value = value.replace(/-/g, '/');
  1187. if (/^\d{4}\/\d{1,2}$/.test(val)) val = val + '/01';
  1188. if (/^\d{4}\/\d{1,2}$/.test(value)) value = value + '/01';
  1189. var thisDate = Date.parse(value);
  1190. var otherDate = Date.parse(val);
  1191. if (containsEqual)
  1192. {
  1193. return thisDate <= otherDate;
  1194. } else
  1195. {
  1196. return thisDate < otherDate;
  1197. }
  1198. } else
  1199. {
  1200. var val = $(otherEl).val();
  1201. var thisNumber = parseFloat(value);
  1202. var otherNumber = parseFloat(val);
  1203. if (containsEqual)
  1204. {
  1205. return thisNumber <= otherNumber;
  1206. } else
  1207. {
  1208. return thisNumber < otherNumber;
  1209. }
  1210. }
  1211. },
  1212. // http://docs.jquery.com/Plugins/Validation/Methods/number
  1213. number: function(value, element)
  1214. {
  1215. return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value);
  1216. },
  1217. // http://docs.jquery.com/Plugins/Validation/Methods/numberDE
  1218. numberDE: function(value, element)
  1219. {
  1220. return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:\.\d{3})+)(?:,\d+)?$/.test(value);
  1221. },
  1222. // http://docs.jquery.com/Plugins/Validation/Methods/digits
  1223. digits: function(value, element)
  1224. {
  1225. return this.optional(element) || /^\d+$/.test(value);
  1226. },
  1227. // http://docs.jquery.com/Plugins/Validation/Methods/creditcard
  1228. // based on http://en.wikipedia.org/wiki/Luhn
  1229. creditcard: function(value, element)
  1230. {
  1231. if (this.optional(element))
  1232. return "dependency-mismatch";
  1233. // accept only digits and dashes
  1234. if (/[^0-9-]+/.test(value))
  1235. return false;
  1236. var nCheck = 0,
  1237. nDigit = 0,
  1238. bEven = false;
  1239. value = value.replace(/\D/g, "");
  1240. for (n = value.length - 1; n >= 0; n--)
  1241. {
  1242. var cDigit = value.charAt(n);
  1243. var nDigit = parseInt(cDigit, 10);
  1244. if (bEven)
  1245. {
  1246. if ((nDigit *= 2) > 9)
  1247. nDigit -= 9;
  1248. }
  1249. nCheck += nDigit;
  1250. bEven = !bEven;
  1251. }
  1252. return (nCheck % 10) == 0;
  1253. },
  1254. // http://docs.jquery.com/Plugins/Validation/Methods/accept
  1255. accept: function(value, element, param)
  1256. {
  1257. param = typeof param == "string" ? param : "png|jpe?g|gif";
  1258. return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i"));
  1259. },
  1260. // http://docs.jquery.com/Plugins/Validation/Methods/equalTo
  1261. equalTo: function(value, element, param)
  1262. {
  1263. return value == $(param).val();
  1264. },
  1265. bigTo: function(value, element, param)
  1266. {
  1267. return value >= $(param).val();
  1268. },
  1269. //依赖于某个元素的值
  1270. dependTo: function(value, element, param)
  1271. {
  1272. var el = null;
  1273. var val = true;
  1274. var not = false; //是否取反,表示当值不等于指定的值时才验证
  1275. if ($.isArray(param))
  1276. {
  1277. if (param.length <= 0) return false;
  1278. el = param[0];
  1279. if (param.length > 1) val = param[1];
  1280. if (param.length > 2) not = (param[2] == 'not');
  1281. } else
  1282. {
  1283. var temp = param.split('|');
  1284. if (temp.length <= 0) return false;
  1285. el = temp[0];
  1286. if (temp.length > 1)
  1287. {
  1288. val = temp[1];
  1289. if (val == 'true' || val == 'True')
  1290. {
  1291. val = true;
  1292. } else if (val == 'false' || val == 'False')
  1293. {
  1294. val = false;
  1295. }
  1296. }
  1297. if (temp.length > 2) not = (temp[2] == 'not');
  1298. }
  1299. var jel = $(el);
  1300. if (jel.length > 0)
  1301. {
  1302. var e = jel[0];
  1303. if (e.type == 'checkbox' || e.type == 'radio')
  1304. {
  1305. result = jel.attr('checked') == val;
  1306. } else
  1307. {
  1308. result = jel.val() == val;
  1309. }
  1310. }
  1311. if (not) result = !result;
  1312. return result;
  1313. },
  1314. //判断是否匹配于指定的正则表达式
  1315. match: function(value, element, param)
  1316. {
  1317. if (this.optional(element)) return "dependency-mismatch";
  1318. var reg = param;
  1319. if (typeof param == 'string')
  1320. {
  1321. reg = new RegExp(param);
  1322. }
  1323. return reg.test(value);
  1324. }
  1325. }
  1326. });
  1327. })(jQuery);
  1328. // ajax mode: abort
  1329. // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
  1330. // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
  1331. ; (function($)
  1332. {
  1333. var ajax = $.ajax;
  1334. var pendingRequests = {};
  1335. $.ajax = function(settings)
  1336. {
  1337. // create settings for compatibility with ajaxSetup
  1338. settings = $.extend(settings, $.extend({}, $.ajaxSettings, settings));
  1339. var port = settings.port;
  1340. if (settings.mode == "abort")
  1341. {
  1342. if (pendingRequests[port])
  1343. {
  1344. pendingRequests[port].abort();
  1345. }
  1346. return (pendingRequests[port] = ajax.apply(this, arguments));
  1347. }
  1348. return ajax.apply(this, arguments);
  1349. };
  1350. })(jQuery);
  1351. // provides cross-browser focusin and focusout events
  1352. // IE has native support, in other browsers, use event caputuring (neither bubbles)
  1353. // provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
  1354. // handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target
  1355. // provides triggerEvent(type: String, target: Element) to trigger delegated events
  1356. ; (function($)
  1357. {
  1358. $.each({
  1359. focus: 'focusin',
  1360. blur: 'focusout'
  1361. }, function(original, fix)
  1362. {
  1363. $.event.special[fix] = {
  1364. setup: function()
  1365. {
  1366. if ($.browser.msie) return false;
  1367. this.addEventListener(original, $.event.special[fix].handler, true);
  1368. },
  1369. teardown: function()
  1370. {
  1371. if ($.browser.msie) return false;
  1372. this.removeEventListener(original,
  1373. $.event.special[fix].handler, true);
  1374. },
  1375. handler: function(e)
  1376. {
  1377. arguments[0] = $.event.fix(e);
  1378. arguments[0].type = fix;
  1379. return $.event.handle.apply(this, arguments);
  1380. }
  1381. };
  1382. });
  1383. $.extend($.fn, {
  1384. validDelegate: function(type, delegate, handler)
  1385. {
  1386. return this.bind(type, function(event)
  1387. {
  1388. var target = $(event.target);
  1389. if (target.is(delegate))
  1390. {
  1391. return handler.apply(target, arguments);
  1392. }
  1393. });
  1394. },
  1395. triggerEvent: function(type, target)
  1396. {
  1397. return this.triggerHandler(type, [$.event.fix({ type: type, target: target })]);
  1398. }
  1399. })
  1400. })(jQuery);