PluginProbe ʕ •ᴥ•ʔ
Strong Testimonials / 2.33
Strong Testimonials v2.33
3.3.6 3.3.5 3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.0.1 2.30.9 2.31.10 2.32 2.32.1 2.32.2 2.32.3 2.32.4 2.33 2.34 2.35 2.36 2.37 2.38 2.38.1 2.39 2.39.1 2.39.2 2.39.3 2.40.0 2.40.1 2.40.2 2.40.3 2.40.4 2.40.5 2.40.6 2.40.7 2.41.0 2.41.1 2.50.0 2.50.1 2.50.2 2.50.3 2.50.4 2.51.0 2.51.1 2.51.2 2.51.3 2.51.4 2.51.5 2.51.6 2.51.7 2.51.8 2.51.9 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 3.1.19 3.1.2 3.1.20 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.10 3.2.11 3.2.12 3.2.13 3.2.14 3.2.15 3.2.16 3.2.17 3.2.18 3.2.19 3.2.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0
strong-testimonials / public / js / lib / validate / additional-methods.js
strong-testimonials / public / js / lib / validate Last commit date
localization 9 years ago additional-methods.js 9 years ago additional-methods.min.js 9 years ago jquery.validate.js 9 years ago jquery.validate.min.js 9 years ago
additional-methods.js
1122 lines
1 /*!
2 * jQuery Validation Plugin v1.16.0
3 *
4 * http://jqueryvalidation.org/
5 *
6 * Copyright (c) 2016 Jörn Zaefferer
7 * Released under the MIT license
8 */
9 (function( factory ) {
10 if ( typeof define === "function" && define.amd ) {
11 define( ["jquery", "./jquery.validate"], factory );
12 } else if (typeof module === "object" && module.exports) {
13 module.exports = factory( require( "jquery" ) );
14 } else {
15 factory( jQuery );
16 }
17 }(function( $ ) {
18
19 ( function() {
20
21 function stripHtml( value ) {
22
23 // Remove html tags and space chars
24 return value.replace( /<.[^<>]*?>/g, " " ).replace( /&nbsp;|&#160;/gi, " " )
25
26 // Remove punctuation
27 .replace( /[.(),;:!?%#$'\"_+=\/\-“”’]*/g, "" );
28 }
29
30 $.validator.addMethod( "maxWords", function( value, element, params ) {
31 return this.optional( element ) || stripHtml( value ).match( /\b\w+\b/g ).length <= params;
32 }, $.validator.format( "Please enter {0} words or less." ) );
33
34 $.validator.addMethod( "minWords", function( value, element, params ) {
35 return this.optional( element ) || stripHtml( value ).match( /\b\w+\b/g ).length >= params;
36 }, $.validator.format( "Please enter at least {0} words." ) );
37
38 $.validator.addMethod( "rangeWords", function( value, element, params ) {
39 var valueStripped = stripHtml( value ),
40 regex = /\b\w+\b/g;
41 return this.optional( element ) || valueStripped.match( regex ).length >= params[ 0 ] && valueStripped.match( regex ).length <= params[ 1 ];
42 }, $.validator.format( "Please enter between {0} and {1} words." ) );
43
44 }() );
45
46 // Accept a value from a file input based on a required mimetype
47 $.validator.addMethod( "accept", function( value, element, param ) {
48
49 // Split mime on commas in case we have multiple types we can accept
50 var typeParam = typeof param === "string" ? param.replace( /\s/g, "" ) : "image/*",
51 optionalValue = this.optional( element ),
52 i, file, regex;
53
54 // Element is optional
55 if ( optionalValue ) {
56 return optionalValue;
57 }
58
59 if ( $( element ).attr( "type" ) === "file" ) {
60
61 // Escape string to be used in the regex
62 // see: http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
63 // Escape also "/*" as "/.*" as a wildcard
64 typeParam = typeParam
65 .replace( /[\-\[\]\/\{\}\(\)\+\?\.\\\^\$\|]/g, "\\$&" )
66 .replace( /,/g, "|" )
67 .replace( /\/\*/g, "/.*" );
68
69 // Check if the element has a FileList before checking each file
70 if ( element.files && element.files.length ) {
71 regex = new RegExp( ".?(" + typeParam + ")$", "i" );
72 for ( i = 0; i < element.files.length; i++ ) {
73 file = element.files[ i ];
74
75 // Grab the mimetype from the loaded file, verify it matches
76 if ( !file.type.match( regex ) ) {
77 return false;
78 }
79 }
80 }
81 }
82
83 // Either return true because we've validated each file, or because the
84 // browser does not support element.files and the FileList feature
85 return true;
86 }, $.validator.format( "Please enter a value with a valid mimetype." ) );
87
88 $.validator.addMethod( "alphanumeric", function( value, element ) {
89 return this.optional( element ) || /^\w+$/i.test( value );
90 }, "Letters, numbers, and underscores only please" );
91
92 /*
93 * Dutch bank account numbers (not 'giro' numbers) have 9 digits
94 * and pass the '11 check'.
95 * We accept the notation with spaces, as that is common.
96 * acceptable: 123456789 or 12 34 56 789
97 */
98 $.validator.addMethod( "bankaccountNL", function( value, element ) {
99 if ( this.optional( element ) ) {
100 return true;
101 }
102 if ( !( /^[0-9]{9}|([0-9]{2} ){3}[0-9]{3}$/.test( value ) ) ) {
103 return false;
104 }
105
106 // Now '11 check'
107 var account = value.replace( / /g, "" ), // Remove spaces
108 sum = 0,
109 len = account.length,
110 pos, factor, digit;
111 for ( pos = 0; pos < len; pos++ ) {
112 factor = len - pos;
113 digit = account.substring( pos, pos + 1 );
114 sum = sum + factor * digit;
115 }
116 return sum % 11 === 0;
117 }, "Please specify a valid bank account number" );
118
119 $.validator.addMethod( "bankorgiroaccountNL", function( value, element ) {
120 return this.optional( element ) ||
121 ( $.validator.methods.bankaccountNL.call( this, value, element ) ) ||
122 ( $.validator.methods.giroaccountNL.call( this, value, element ) );
123 }, "Please specify a valid bank or giro account number" );
124
125 /**
126 * BIC is the business identifier code (ISO 9362). This BIC check is not a guarantee for authenticity.
127 *
128 * BIC pattern: BBBBCCLLbbb (8 or 11 characters long; bbb is optional)
129 *
130 * Validation is case-insensitive. Please make sure to normalize input yourself.
131 *
132 * BIC definition in detail:
133 * - First 4 characters - bank code (only letters)
134 * - Next 2 characters - ISO 3166-1 alpha-2 country code (only letters)
135 * - Next 2 characters - location code (letters and digits)
136 * a. shall not start with '0' or '1'
137 * b. second character must be a letter ('O' is not allowed) or digit ('0' for test (therefore not allowed), '1' denoting passive participant, '2' typically reverse-billing)
138 * - Last 3 characters - branch code, optional (shall not start with 'X' except in case of 'XXX' for primary office) (letters and digits)
139 */
140 $.validator.addMethod( "bic", function( value, element ) {
141 return this.optional( element ) || /^([A-Z]{6}[A-Z2-9][A-NP-Z1-9])(X{3}|[A-WY-Z0-9][A-Z0-9]{2})?$/.test( value.toUpperCase() );
142 }, "Please specify a valid BIC code" );
143
144 /*
145 * Código de identificación fiscal ( CIF ) is the tax identification code for Spanish legal entities
146 * Further rules can be found in Spanish on http://es.wikipedia.org/wiki/C%C3%B3digo_de_identificaci%C3%B3n_fiscal
147 *
148 * Spanish CIF structure:
149 *
150 * [ T ][ P ][ P ][ N ][ N ][ N ][ N ][ N ][ C ]
151 *
152 * Where:
153 *
154 * T: 1 character. Kind of Organization Letter: [ABCDEFGHJKLMNPQRSUVW]
155 * P: 2 characters. Province.
156 * N: 5 characters. Secuencial Number within the province.
157 * C: 1 character. Control Digit: [0-9A-J].
158 *
159 * [ T ]: Kind of Organizations. Possible values:
160 *
161 * A. Corporations
162 * B. LLCs
163 * C. General partnerships
164 * D. Companies limited partnerships
165 * E. Communities of goods
166 * F. Cooperative Societies
167 * G. Associations
168 * H. Communities of homeowners in horizontal property regime
169 * J. Civil Societies
170 * K. Old format
171 * L. Old format
172 * M. Old format
173 * N. Nonresident entities
174 * P. Local authorities
175 * Q. Autonomous bodies, state or not, and the like, and congregations and religious institutions
176 * R. Congregations and religious institutions (since 2008 ORDER EHA/451/2008)
177 * S. Organs of State Administration and regions
178 * V. Agrarian Transformation
179 * W. Permanent establishments of non-resident in Spain
180 *
181 * [ C ]: Control Digit. It can be a number or a letter depending on T value:
182 * [ T ] --> [ C ]
183 * ------ ----------
184 * A Number
185 * B Number
186 * E Number
187 * H Number
188 * K Letter
189 * P Letter
190 * Q Letter
191 * S Letter
192 *
193 */
194 $.validator.addMethod( "cifES", function( value ) {
195 "use strict";
196
197 var cifRegEx = new RegExp( /^([ABCDEFGHJKLMNPQRSUVW])(\d{7})([0-9A-J])$/gi );
198 var letter = value.substring( 0, 1 ), // [ T ]
199 number = value.substring( 1, 8 ), // [ P ][ P ][ N ][ N ][ N ][ N ][ N ]
200 control = value.substring( 8, 9 ), // [ C ]
201 all_sum = 0,
202 even_sum = 0,
203 odd_sum = 0,
204 i, n,
205 control_digit,
206 control_letter;
207
208 function isOdd( n ) {
209 return n % 2 === 0;
210 }
211
212 // Quick format test
213 if ( value.length !== 9 || !cifRegEx.test( value ) ) {
214 return false;
215 }
216
217 for ( i = 0; i < number.length; i++ ) {
218 n = parseInt( number[ i ], 10 );
219
220 // Odd positions
221 if ( isOdd( i ) ) {
222
223 // Odd positions are multiplied first.
224 n *= 2;
225
226 // If the multiplication is bigger than 10 we need to adjust
227 odd_sum += n < 10 ? n : n - 9;
228
229 // Even positions
230 // Just sum them
231 } else {
232 even_sum += n;
233 }
234 }
235
236 all_sum = even_sum + odd_sum;
237 control_digit = ( 10 - ( all_sum ).toString().substr( -1 ) ).toString();
238 control_digit = parseInt( control_digit, 10 ) > 9 ? "0" : control_digit;
239 control_letter = "JABCDEFGHI".substr( control_digit, 1 ).toString();
240
241 // Control must be a digit
242 if ( letter.match( /[ABEH]/ ) ) {
243 return control === control_digit;
244
245 // Control must be a letter
246 } else if ( letter.match( /[KPQS]/ ) ) {
247 return control === control_letter;
248
249 // Can be either
250 } else {
251 return control === control_digit || control === control_letter;
252 }
253
254 return false;
255
256 }, "Please specify a valid CIF number." );
257
258 /*
259 * Brazillian CPF number (Cadastrado de Pessoas Físicas) is the equivalent of a Brazilian tax registration number.
260 * CPF numbers have 11 digits in total: 9 numbers followed by 2 check numbers that are being used for validation.
261 */
262 $.validator.addMethod( "cpfBR", function( value ) {
263
264 // Removing special characters from value
265 value = value.replace( /([~!@#$%^&*()_+=`{}\[\]\-|\\:;'<>,.\/? ])+/g, "" );
266
267 // Checking value to have 11 digits only
268 if ( value.length !== 11 ) {
269 return false;
270 }
271
272 var sum = 0,
273 firstCN, secondCN, checkResult, i;
274
275 firstCN = parseInt( value.substring( 9, 10 ), 10 );
276 secondCN = parseInt( value.substring( 10, 11 ), 10 );
277
278 checkResult = function( sum, cn ) {
279 var result = ( sum * 10 ) % 11;
280 if ( ( result === 10 ) || ( result === 11 ) ) {
281 result = 0;
282 }
283 return ( result === cn );
284 };
285
286 // Checking for dump data
287 if ( value === "" ||
288 value === "00000000000" ||
289 value === "11111111111" ||
290 value === "22222222222" ||
291 value === "33333333333" ||
292 value === "44444444444" ||
293 value === "55555555555" ||
294 value === "66666666666" ||
295 value === "77777777777" ||
296 value === "88888888888" ||
297 value === "99999999999"
298 ) {
299 return false;
300 }
301
302 // Step 1 - using first Check Number:
303 for ( i = 1; i <= 9; i++ ) {
304 sum = sum + parseInt( value.substring( i - 1, i ), 10 ) * ( 11 - i );
305 }
306
307 // If first Check Number (CN) is valid, move to Step 2 - using second Check Number:
308 if ( checkResult( sum, firstCN ) ) {
309 sum = 0;
310 for ( i = 1; i <= 10; i++ ) {
311 sum = sum + parseInt( value.substring( i - 1, i ), 10 ) * ( 12 - i );
312 }
313 return checkResult( sum, secondCN );
314 }
315 return false;
316
317 }, "Please specify a valid CPF number" );
318
319 // http://jqueryvalidation.org/creditcard-method/
320 // based on http://en.wikipedia.org/wiki/Luhn_algorithm
321 $.validator.addMethod( "creditcard", function( value, element ) {
322 if ( this.optional( element ) ) {
323 return "dependency-mismatch";
324 }
325
326 // Accept only spaces, digits and dashes
327 if ( /[^0-9 \-]+/.test( value ) ) {
328 return false;
329 }
330
331 var nCheck = 0,
332 nDigit = 0,
333 bEven = false,
334 n, cDigit;
335
336 value = value.replace( /\D/g, "" );
337
338 // Basing min and max length on
339 // http://developer.ean.com/general_info/Valid_Credit_Card_Types
340 if ( value.length < 13 || value.length > 19 ) {
341 return false;
342 }
343
344 for ( n = value.length - 1; n >= 0; n-- ) {
345 cDigit = value.charAt( n );
346 nDigit = parseInt( cDigit, 10 );
347 if ( bEven ) {
348 if ( ( nDigit *= 2 ) > 9 ) {
349 nDigit -= 9;
350 }
351 }
352
353 nCheck += nDigit;
354 bEven = !bEven;
355 }
356
357 return ( nCheck % 10 ) === 0;
358 }, "Please enter a valid credit card number." );
359
360 /* NOTICE: Modified version of Castle.Components.Validator.CreditCardValidator
361 * Redistributed under the the Apache License 2.0 at http://www.apache.org/licenses/LICENSE-2.0
362 * Valid Types: mastercard, visa, amex, dinersclub, enroute, discover, jcb, unknown, all (overrides all other settings)
363 */
364 $.validator.addMethod( "creditcardtypes", function( value, element, param ) {
365 if ( /[^0-9\-]+/.test( value ) ) {
366 return false;
367 }
368
369 value = value.replace( /\D/g, "" );
370
371 var validTypes = 0x0000;
372
373 if ( param.mastercard ) {
374 validTypes |= 0x0001;
375 }
376 if ( param.visa ) {
377 validTypes |= 0x0002;
378 }
379 if ( param.amex ) {
380 validTypes |= 0x0004;
381 }
382 if ( param.dinersclub ) {
383 validTypes |= 0x0008;
384 }
385 if ( param.enroute ) {
386 validTypes |= 0x0010;
387 }
388 if ( param.discover ) {
389 validTypes |= 0x0020;
390 }
391 if ( param.jcb ) {
392 validTypes |= 0x0040;
393 }
394 if ( param.unknown ) {
395 validTypes |= 0x0080;
396 }
397 if ( param.all ) {
398 validTypes = 0x0001 | 0x0002 | 0x0004 | 0x0008 | 0x0010 | 0x0020 | 0x0040 | 0x0080;
399 }
400 if ( validTypes & 0x0001 && /^(5[12345])/.test( value ) ) { // Mastercard
401 return value.length === 16;
402 }
403 if ( validTypes & 0x0002 && /^(4)/.test( value ) ) { // Visa
404 return value.length === 16;
405 }
406 if ( validTypes & 0x0004 && /^(3[47])/.test( value ) ) { // Amex
407 return value.length === 15;
408 }
409 if ( validTypes & 0x0008 && /^(3(0[012345]|[68]))/.test( value ) ) { // Dinersclub
410 return value.length === 14;
411 }
412 if ( validTypes & 0x0010 && /^(2(014|149))/.test( value ) ) { // Enroute
413 return value.length === 15;
414 }
415 if ( validTypes & 0x0020 && /^(6011)/.test( value ) ) { // Discover
416 return value.length === 16;
417 }
418 if ( validTypes & 0x0040 && /^(3)/.test( value ) ) { // Jcb
419 return value.length === 16;
420 }
421 if ( validTypes & 0x0040 && /^(2131|1800)/.test( value ) ) { // Jcb
422 return value.length === 15;
423 }
424 if ( validTypes & 0x0080 ) { // Unknown
425 return true;
426 }
427 return false;
428 }, "Please enter a valid credit card number." );
429
430 /**
431 * Validates currencies with any given symbols by @jameslouiz
432 * Symbols can be optional or required. Symbols required by default
433 *
434 * Usage examples:
435 * currency: ["£", false] - Use false for soft currency validation
436 * currency: ["$", false]
437 * currency: ["RM", false] - also works with text based symbols such as "RM" - Malaysia Ringgit etc
438 *
439 * <input class="currencyInput" name="currencyInput">
440 *
441 * Soft symbol checking
442 * currencyInput: {
443 * currency: ["$", false]
444 * }
445 *
446 * Strict symbol checking (default)
447 * currencyInput: {
448 * currency: "$"
449 * //OR
450 * currency: ["$", true]
451 * }
452 *
453 * Multiple Symbols
454 * currencyInput: {
455 * currency: "$,£,¢"
456 * }
457 */
458 $.validator.addMethod( "currency", function( value, element, param ) {
459 var isParamString = typeof param === "string",
460 symbol = isParamString ? param : param[ 0 ],
461 soft = isParamString ? true : param[ 1 ],
462 regex;
463
464 symbol = symbol.replace( /,/g, "" );
465 symbol = soft ? symbol + "]" : symbol + "]?";
466 regex = "^[" + symbol + "([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)$";
467 regex = new RegExp( regex );
468 return this.optional( element ) || regex.test( value );
469
470 }, "Please specify a valid currency" );
471
472 $.validator.addMethod( "dateFA", function( value, element ) {
473 return this.optional( element ) || /^[1-4]\d{3}\/((0?[1-6]\/((3[0-1])|([1-2][0-9])|(0?[1-9])))|((1[0-2]|(0?[7-9]))\/(30|([1-2][0-9])|(0?[1-9]))))$/.test( value );
474 }, $.validator.messages.date );
475
476 /**
477 * Return true, if the value is a valid date, also making this formal check dd/mm/yyyy.
478 *
479 * @example $.validator.methods.date("01/01/1900")
480 * @result true
481 *
482 * @example $.validator.methods.date("01/13/1990")
483 * @result false
484 *
485 * @example $.validator.methods.date("01.01.1900")
486 * @result false
487 *
488 * @example <input name="pippo" class="{dateITA:true}" />
489 * @desc Declares an optional input element whose value must be a valid date.
490 *
491 * @name $.validator.methods.dateITA
492 * @type Boolean
493 * @cat Plugins/Validate/Methods
494 */
495 $.validator.addMethod( "dateITA", function( value, element ) {
496 var check = false,
497 re = /^\d{1,2}\/\d{1,2}\/\d{4}$/,
498 adata, gg, mm, aaaa, xdata;
499 if ( re.test( value ) ) {
500 adata = value.split( "/" );
501 gg = parseInt( adata[ 0 ], 10 );
502 mm = parseInt( adata[ 1 ], 10 );
503 aaaa = parseInt( adata[ 2 ], 10 );
504 xdata = new Date( Date.UTC( aaaa, mm - 1, gg, 12, 0, 0, 0 ) );
505 if ( ( xdata.getUTCFullYear() === aaaa ) && ( xdata.getUTCMonth() === mm - 1 ) && ( xdata.getUTCDate() === gg ) ) {
506 check = true;
507 } else {
508 check = false;
509 }
510 } else {
511 check = false;
512 }
513 return this.optional( element ) || check;
514 }, $.validator.messages.date );
515
516 $.validator.addMethod( "dateNL", function( value, element ) {
517 return this.optional( element ) || /^(0?[1-9]|[12]\d|3[01])[\.\/\-](0?[1-9]|1[012])[\.\/\-]([12]\d)?(\d\d)$/.test( value );
518 }, $.validator.messages.date );
519
520 // Older "accept" file extension method. Old docs: http://docs.jquery.com/Plugins/Validation/Methods/accept
521 $.validator.addMethod( "extension", function( value, element, param ) {
522 param = typeof param === "string" ? param.replace( /,/g, "|" ) : "png|jpe?g|gif";
523 return this.optional( element ) || value.match( new RegExp( "\\.(" + param + ")$", "i" ) );
524 }, $.validator.format( "Please enter a value with a valid extension." ) );
525
526 /**
527 * Dutch giro account numbers (not bank numbers) have max 7 digits
528 */
529 $.validator.addMethod( "giroaccountNL", function( value, element ) {
530 return this.optional( element ) || /^[0-9]{1,7}$/.test( value );
531 }, "Please specify a valid giro account number" );
532
533 /**
534 * IBAN is the international bank account number.
535 * It has a country - specific format, that is checked here too
536 *
537 * Validation is case-insensitive. Please make sure to normalize input yourself.
538 */
539 $.validator.addMethod( "iban", function( value, element ) {
540
541 // Some quick simple tests to prevent needless work
542 if ( this.optional( element ) ) {
543 return true;
544 }
545
546 // Remove spaces and to upper case
547 var iban = value.replace( / /g, "" ).toUpperCase(),
548 ibancheckdigits = "",
549 leadingZeroes = true,
550 cRest = "",
551 cOperator = "",
552 countrycode, ibancheck, charAt, cChar, bbanpattern, bbancountrypatterns, ibanregexp, i, p;
553
554 // Check for IBAN code length.
555 // It contains:
556 // country code ISO 3166-1 - two letters,
557 // two check digits,
558 // Basic Bank Account Number (BBAN) - up to 30 chars
559 var minimalIBANlength = 5;
560 if ( iban.length < minimalIBANlength ) {
561 return false;
562 }
563
564 // Check the country code and find the country specific format
565 countrycode = iban.substring( 0, 2 );
566 bbancountrypatterns = {
567 "AL": "\\d{8}[\\dA-Z]{16}",
568 "AD": "\\d{8}[\\dA-Z]{12}",
569 "AT": "\\d{16}",
570 "AZ": "[\\dA-Z]{4}\\d{20}",
571 "BE": "\\d{12}",
572 "BH": "[A-Z]{4}[\\dA-Z]{14}",
573 "BA": "\\d{16}",
574 "BR": "\\d{23}[A-Z][\\dA-Z]",
575 "BG": "[A-Z]{4}\\d{6}[\\dA-Z]{8}",
576 "CR": "\\d{17}",
577 "HR": "\\d{17}",
578 "CY": "\\d{8}[\\dA-Z]{16}",
579 "CZ": "\\d{20}",
580 "DK": "\\d{14}",
581 "DO": "[A-Z]{4}\\d{20}",
582 "EE": "\\d{16}",
583 "FO": "\\d{14}",
584 "FI": "\\d{14}",
585 "FR": "\\d{10}[\\dA-Z]{11}\\d{2}",
586 "GE": "[\\dA-Z]{2}\\d{16}",
587 "DE": "\\d{18}",
588 "GI": "[A-Z]{4}[\\dA-Z]{15}",
589 "GR": "\\d{7}[\\dA-Z]{16}",
590 "GL": "\\d{14}",
591 "GT": "[\\dA-Z]{4}[\\dA-Z]{20}",
592 "HU": "\\d{24}",
593 "IS": "\\d{22}",
594 "IE": "[\\dA-Z]{4}\\d{14}",
595 "IL": "\\d{19}",
596 "IT": "[A-Z]\\d{10}[\\dA-Z]{12}",
597 "KZ": "\\d{3}[\\dA-Z]{13}",
598 "KW": "[A-Z]{4}[\\dA-Z]{22}",
599 "LV": "[A-Z]{4}[\\dA-Z]{13}",
600 "LB": "\\d{4}[\\dA-Z]{20}",
601 "LI": "\\d{5}[\\dA-Z]{12}",
602 "LT": "\\d{16}",
603 "LU": "\\d{3}[\\dA-Z]{13}",
604 "MK": "\\d{3}[\\dA-Z]{10}\\d{2}",
605 "MT": "[A-Z]{4}\\d{5}[\\dA-Z]{18}",
606 "MR": "\\d{23}",
607 "MU": "[A-Z]{4}\\d{19}[A-Z]{3}",
608 "MC": "\\d{10}[\\dA-Z]{11}\\d{2}",
609 "MD": "[\\dA-Z]{2}\\d{18}",
610 "ME": "\\d{18}",
611 "NL": "[A-Z]{4}\\d{10}",
612 "NO": "\\d{11}",
613 "PK": "[\\dA-Z]{4}\\d{16}",
614 "PS": "[\\dA-Z]{4}\\d{21}",
615 "PL": "\\d{24}",
616 "PT": "\\d{21}",
617 "RO": "[A-Z]{4}[\\dA-Z]{16}",
618 "SM": "[A-Z]\\d{10}[\\dA-Z]{12}",
619 "SA": "\\d{2}[\\dA-Z]{18}",
620 "RS": "\\d{18}",
621 "SK": "\\d{20}",
622 "SI": "\\d{15}",
623 "ES": "\\d{20}",
624 "SE": "\\d{20}",
625 "CH": "\\d{5}[\\dA-Z]{12}",
626 "TN": "\\d{20}",
627 "TR": "\\d{5}[\\dA-Z]{17}",
628 "AE": "\\d{3}\\d{16}",
629 "GB": "[A-Z]{4}\\d{14}",
630 "VG": "[\\dA-Z]{4}\\d{16}"
631 };
632
633 bbanpattern = bbancountrypatterns[ countrycode ];
634
635 // As new countries will start using IBAN in the
636 // future, we only check if the countrycode is known.
637 // This prevents false negatives, while almost all
638 // false positives introduced by this, will be caught
639 // by the checksum validation below anyway.
640 // Strict checking should return FALSE for unknown
641 // countries.
642 if ( typeof bbanpattern !== "undefined" ) {
643 ibanregexp = new RegExp( "^[A-Z]{2}\\d{2}" + bbanpattern + "$", "" );
644 if ( !( ibanregexp.test( iban ) ) ) {
645 return false; // Invalid country specific format
646 }
647 }
648
649 // Now check the checksum, first convert to digits
650 ibancheck = iban.substring( 4, iban.length ) + iban.substring( 0, 4 );
651 for ( i = 0; i < ibancheck.length; i++ ) {
652 charAt = ibancheck.charAt( i );
653 if ( charAt !== "0" ) {
654 leadingZeroes = false;
655 }
656 if ( !leadingZeroes ) {
657 ibancheckdigits += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf( charAt );
658 }
659 }
660
661 // Calculate the result of: ibancheckdigits % 97
662 for ( p = 0; p < ibancheckdigits.length; p++ ) {
663 cChar = ibancheckdigits.charAt( p );
664 cOperator = "" + cRest + "" + cChar;
665 cRest = cOperator % 97;
666 }
667 return cRest === 1;
668 }, "Please specify a valid IBAN" );
669
670 $.validator.addMethod( "integer", function( value, element ) {
671 return this.optional( element ) || /^-?\d+$/.test( value );
672 }, "A positive or negative non-decimal number please" );
673
674 $.validator.addMethod( "ipv4", function( value, element ) {
675 return this.optional( element ) || /^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/i.test( value );
676 }, "Please enter a valid IP v4 address." );
677
678 $.validator.addMethod( "ipv6", function( value, element ) {
679 return this.optional( element ) || /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i.test( value );
680 }, "Please enter a valid IP v6 address." );
681
682 $.validator.addMethod( "lettersonly", function( value, element ) {
683 return this.optional( element ) || /^[a-z]+$/i.test( value );
684 }, "Letters only please" );
685
686 $.validator.addMethod( "letterswithbasicpunc", function( value, element ) {
687 return this.optional( element ) || /^[a-z\-.,()'"\s]+$/i.test( value );
688 }, "Letters or punctuation only please" );
689
690 $.validator.addMethod( "mobileNL", function( value, element ) {
691 return this.optional( element ) || /^((\+|00(\s|\s?\-\s?)?)31(\s|\s?\-\s?)?(\(0\)[\-\s]?)?|0)6((\s|\s?\-\s?)?[0-9]){8}$/.test( value );
692 }, "Please specify a valid mobile number" );
693
694 /* For UK phone functions, do the following server side processing:
695 * Compare original input with this RegEx pattern:
696 * ^\(?(?:(?:00\)?[\s\-]?\(?|\+)(44)\)?[\s\-]?\(?(?:0\)?[\s\-]?\(?)?|0)([1-9]\d{1,4}\)?[\s\d\-]+)$
697 * Extract $1 and set $prefix to '+44<space>' if $1 is '44', otherwise set $prefix to '0'
698 * Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2.
699 * A number of very detailed GB telephone number RegEx patterns can also be found at:
700 * http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers
701 */
702 $.validator.addMethod( "mobileUK", function( phone_number, element ) {
703 phone_number = phone_number.replace( /\(|\)|\s+|-/g, "" );
704 return this.optional( element ) || phone_number.length > 9 &&
705 phone_number.match( /^(?:(?:(?:00\s?|\+)44\s?|0)7(?:[1345789]\d{2}|624)\s?\d{3}\s?\d{3})$/ );
706 }, "Please specify a valid mobile number" );
707
708 /*
709 * The NIE (Número de Identificación de Extranjero) is a Spanish tax identification number assigned by the Spanish
710 * authorities to any foreigner.
711 *
712 * The NIE is the equivalent of a Spaniards Número de Identificación Fiscal (NIF) which serves as a fiscal
713 * identification number. The CIF number (Certificado de Identificación Fiscal) is equivalent to the NIF, but applies to
714 * companies rather than individuals. The NIE consists of an 'X' or 'Y' followed by 7 or 8 digits then another letter.
715 */
716 $.validator.addMethod( "nieES", function( value ) {
717 "use strict";
718
719 var nieRegEx = new RegExp( /^[MXYZ]{1}[0-9]{7,8}[TRWAGMYFPDXBNJZSQVHLCKET]{1}$/gi );
720 var validChars = "TRWAGMYFPDXBNJZSQVHLCKET",
721 letter = value.substr( value.length - 1 ).toUpperCase(),
722 number;
723
724 value = value.toString().toUpperCase();
725
726 // Quick format test
727 if ( value.length > 10 || value.length < 9 || !nieRegEx.test( value ) ) {
728 return false;
729 }
730
731 // X means same number
732 // Y means number + 10000000
733 // Z means number + 20000000
734 value = value.replace( /^[X]/, "0" )
735 .replace( /^[Y]/, "1" )
736 .replace( /^[Z]/, "2" );
737
738 number = value.length === 9 ? value.substr( 0, 8 ) : value.substr( 0, 9 );
739
740 return validChars.charAt( parseInt( number, 10 ) % 23 ) === letter;
741
742 }, "Please specify a valid NIE number." );
743
744 /*
745 * The Número de Identificación Fiscal ( NIF ) is the way tax identification used in Spain for individuals
746 */
747 $.validator.addMethod( "nifES", function( value ) {
748 "use strict";
749
750 value = value.toUpperCase();
751
752 // Basic format test
753 if ( !value.match( "((^[A-Z]{1}[0-9]{7}[A-Z0-9]{1}$|^[T]{1}[A-Z0-9]{8}$)|^[0-9]{8}[A-Z]{1}$)" ) ) {
754 return false;
755 }
756
757 // Test NIF
758 if ( /^[0-9]{8}[A-Z]{1}$/.test( value ) ) {
759 return ( "TRWAGMYFPDXBNJZSQVHLCKE".charAt( value.substring( 8, 0 ) % 23 ) === value.charAt( 8 ) );
760 }
761
762 // Test specials NIF (starts with K, L or M)
763 if ( /^[KLM]{1}/.test( value ) ) {
764 return ( value[ 8 ] === String.fromCharCode( 64 ) );
765 }
766
767 return false;
768
769 }, "Please specify a valid NIF number." );
770
771 $.validator.addMethod( "notEqualTo", function( value, element, param ) {
772 return this.optional( element ) || !$.validator.methods.equalTo.call( this, value, element, param );
773 }, "Please enter a different value, values must not be the same." );
774
775 $.validator.addMethod( "nowhitespace", function( value, element ) {
776 return this.optional( element ) || /^\S+$/i.test( value );
777 }, "No white space please" );
778
779 /**
780 * Return true if the field value matches the given format RegExp
781 *
782 * @example $.validator.methods.pattern("AR1004",element,/^AR\d{4}$/)
783 * @result true
784 *
785 * @example $.validator.methods.pattern("BR1004",element,/^AR\d{4}$/)
786 * @result false
787 *
788 * @name $.validator.methods.pattern
789 * @type Boolean
790 * @cat Plugins/Validate/Methods
791 */
792 $.validator.addMethod( "pattern", function( value, element, param ) {
793 if ( this.optional( element ) ) {
794 return true;
795 }
796 if ( typeof param === "string" ) {
797 param = new RegExp( "^(?:" + param + ")$" );
798 }
799 return param.test( value );
800 }, "Invalid format." );
801
802 /**
803 * Dutch phone numbers have 10 digits (or 11 and start with +31).
804 */
805 $.validator.addMethod( "phoneNL", function( value, element ) {
806 return this.optional( element ) || /^((\+|00(\s|\s?\-\s?)?)31(\s|\s?\-\s?)?(\(0\)[\-\s]?)?|0)[1-9]((\s|\s?\-\s?)?[0-9]){8}$/.test( value );
807 }, "Please specify a valid phone number." );
808
809 /* For UK phone functions, do the following server side processing:
810 * Compare original input with this RegEx pattern:
811 * ^\(?(?:(?:00\)?[\s\-]?\(?|\+)(44)\)?[\s\-]?\(?(?:0\)?[\s\-]?\(?)?|0)([1-9]\d{1,4}\)?[\s\d\-]+)$
812 * Extract $1 and set $prefix to '+44<space>' if $1 is '44', otherwise set $prefix to '0'
813 * Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2.
814 * A number of very detailed GB telephone number RegEx patterns can also be found at:
815 * http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers
816 */
817
818 // Matches UK landline + mobile, accepting only 01-3 for landline or 07 for mobile to exclude many premium numbers
819 $.validator.addMethod( "phonesUK", function( phone_number, element ) {
820 phone_number = phone_number.replace( /\(|\)|\s+|-/g, "" );
821 return this.optional( element ) || phone_number.length > 9 &&
822 phone_number.match( /^(?:(?:(?:00\s?|\+)44\s?|0)(?:1\d{8,9}|[23]\d{9}|7(?:[1345789]\d{8}|624\d{6})))$/ );
823 }, "Please specify a valid uk phone number" );
824
825 /* For UK phone functions, do the following server side processing:
826 * Compare original input with this RegEx pattern:
827 * ^\(?(?:(?:00\)?[\s\-]?\(?|\+)(44)\)?[\s\-]?\(?(?:0\)?[\s\-]?\(?)?|0)([1-9]\d{1,4}\)?[\s\d\-]+)$
828 * Extract $1 and set $prefix to '+44<space>' if $1 is '44', otherwise set $prefix to '0'
829 * Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2.
830 * A number of very detailed GB telephone number RegEx patterns can also be found at:
831 * http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers
832 */
833 $.validator.addMethod( "phoneUK", function( phone_number, element ) {
834 phone_number = phone_number.replace( /\(|\)|\s+|-/g, "" );
835 return this.optional( element ) || phone_number.length > 9 &&
836 phone_number.match( /^(?:(?:(?:00\s?|\+)44\s?)|(?:\(?0))(?:\d{2}\)?\s?\d{4}\s?\d{4}|\d{3}\)?\s?\d{3}\s?\d{3,4}|\d{4}\)?\s?(?:\d{5}|\d{3}\s?\d{3})|\d{5}\)?\s?\d{4,5})$/ );
837 }, "Please specify a valid phone number" );
838
839 /**
840 * Matches US phone number format
841 *
842 * where the area code may not start with 1 and the prefix may not start with 1
843 * allows '-' or ' ' as a separator and allows parens around area code
844 * some people may want to put a '1' in front of their number
845 *
846 * 1(212)-999-2345 or
847 * 212 999 2344 or
848 * 212-999-0983
849 *
850 * but not
851 * 111-123-5434
852 * and not
853 * 212 123 4567
854 */
855 $.validator.addMethod( "phoneUS", function( phone_number, element ) {
856 phone_number = phone_number.replace( /\s+/g, "" );
857 return this.optional( element ) || phone_number.length > 9 &&
858 phone_number.match( /^(\+?1-?)?(\([2-9]([02-9]\d|1[02-9])\)|[2-9]([02-9]\d|1[02-9]))-?[2-9]([02-9]\d|1[02-9])-?\d{4}$/ );
859 }, "Please specify a valid phone number" );
860
861 /*
862 * Valida CEPs do brasileiros:
863 *
864 * Formatos aceitos:
865 * 99999-999
866 * 99.999-999
867 * 99999999
868 */
869 $.validator.addMethod( "postalcodeBR", function( cep_value, element ) {
870 return this.optional( element ) || /^\d{2}.\d{3}-\d{3}?$|^\d{5}-?\d{3}?$/.test( cep_value );
871 }, "Informe um CEP válido." );
872
873 /**
874 * Matches a valid Canadian Postal Code
875 *
876 * @example jQuery.validator.methods.postalCodeCA( "H0H 0H0", element )
877 * @result true
878 *
879 * @example jQuery.validator.methods.postalCodeCA( "H0H0H0", element )
880 * @result false
881 *
882 * @name jQuery.validator.methods.postalCodeCA
883 * @type Boolean
884 * @cat Plugins/Validate/Methods
885 */
886 $.validator.addMethod( "postalCodeCA", function( value, element ) {
887 return this.optional( element ) || /^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ] *\d[ABCEGHJKLMNPRSTVWXYZ]\d$/i.test( value );
888 }, "Please specify a valid postal code" );
889
890 /* Matches Italian postcode (CAP) */
891 $.validator.addMethod( "postalcodeIT", function( value, element ) {
892 return this.optional( element ) || /^\d{5}$/.test( value );
893 }, "Please specify a valid postal code" );
894
895 $.validator.addMethod( "postalcodeNL", function( value, element ) {
896 return this.optional( element ) || /^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/.test( value );
897 }, "Please specify a valid postal code" );
898
899 // Matches UK postcode. Does not match to UK Channel Islands that have their own postcodes (non standard UK)
900 $.validator.addMethod( "postcodeUK", function( value, element ) {
901 return this.optional( element ) || /^((([A-PR-UWYZ][0-9])|([A-PR-UWYZ][0-9][0-9])|([A-PR-UWYZ][A-HK-Y][0-9])|([A-PR-UWYZ][A-HK-Y][0-9][0-9])|([A-PR-UWYZ][0-9][A-HJKSTUW])|([A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRVWXY]))\s?([0-9][ABD-HJLNP-UW-Z]{2})|(GIR)\s?(0AA))$/i.test( value );
902 }, "Please specify a valid UK postcode" );
903
904 /*
905 * Lets you say "at least X inputs that match selector Y must be filled."
906 *
907 * The end result is that neither of these inputs:
908 *
909 * <input class="productinfo" name="partnumber">
910 * <input class="productinfo" name="description">
911 *
912 * ...will validate unless at least one of them is filled.
913 *
914 * partnumber: {require_from_group: [1,".productinfo"]},
915 * description: {require_from_group: [1,".productinfo"]}
916 *
917 * options[0]: number of fields that must be filled in the group
918 * options[1]: CSS selector that defines the group of conditionally required fields
919 */
920 $.validator.addMethod( "require_from_group", function( value, element, options ) {
921 var $fields = $( options[ 1 ], element.form ),
922 $fieldsFirst = $fields.eq( 0 ),
923 validator = $fieldsFirst.data( "valid_req_grp" ) ? $fieldsFirst.data( "valid_req_grp" ) : $.extend( {}, this ),
924 isValid = $fields.filter( function() {
925 return validator.elementValue( this );
926 } ).length >= options[ 0 ];
927
928 // Store the cloned validator for future validation
929 $fieldsFirst.data( "valid_req_grp", validator );
930
931 // If element isn't being validated, run each require_from_group field's validation rules
932 if ( !$( element ).data( "being_validated" ) ) {
933 $fields.data( "being_validated", true );
934 $fields.each( function() {
935 validator.element( this );
936 } );
937 $fields.data( "being_validated", false );
938 }
939 return isValid;
940 }, $.validator.format( "Please fill at least {0} of these fields." ) );
941
942 /*
943 * Lets you say "either at least X inputs that match selector Y must be filled,
944 * OR they must all be skipped (left blank)."
945 *
946 * The end result, is that none of these inputs:
947 *
948 * <input class="productinfo" name="partnumber">
949 * <input class="productinfo" name="description">
950 * <input class="productinfo" name="color">
951 *
952 * ...will validate unless either at least two of them are filled,
953 * OR none of them are.
954 *
955 * partnumber: {skip_or_fill_minimum: [2,".productinfo"]},
956 * description: {skip_or_fill_minimum: [2,".productinfo"]},
957 * color: {skip_or_fill_minimum: [2,".productinfo"]}
958 *
959 * options[0]: number of fields that must be filled in the group
960 * options[1]: CSS selector that defines the group of conditionally required fields
961 *
962 */
963 $.validator.addMethod( "skip_or_fill_minimum", function( value, element, options ) {
964 var $fields = $( options[ 1 ], element.form ),
965 $fieldsFirst = $fields.eq( 0 ),
966 validator = $fieldsFirst.data( "valid_skip" ) ? $fieldsFirst.data( "valid_skip" ) : $.extend( {}, this ),
967 numberFilled = $fields.filter( function() {
968 return validator.elementValue( this );
969 } ).length,
970 isValid = numberFilled === 0 || numberFilled >= options[ 0 ];
971
972 // Store the cloned validator for future validation
973 $fieldsFirst.data( "valid_skip", validator );
974
975 // If element isn't being validated, run each skip_or_fill_minimum field's validation rules
976 if ( !$( element ).data( "being_validated" ) ) {
977 $fields.data( "being_validated", true );
978 $fields.each( function() {
979 validator.element( this );
980 } );
981 $fields.data( "being_validated", false );
982 }
983 return isValid;
984 }, $.validator.format( "Please either skip these fields or fill at least {0} of them." ) );
985
986 /* Validates US States and/or Territories by @jdforsythe
987 * Can be case insensitive or require capitalization - default is case insensitive
988 * Can include US Territories or not - default does not
989 * Can include US Military postal abbreviations (AA, AE, AP) - default does not
990 *
991 * Note: "States" always includes DC (District of Colombia)
992 *
993 * Usage examples:
994 *
995 * This is the default - case insensitive, no territories, no military zones
996 * stateInput: {
997 * caseSensitive: false,
998 * includeTerritories: false,
999 * includeMilitary: false
1000 * }
1001 *
1002 * Only allow capital letters, no territories, no military zones
1003 * stateInput: {
1004 * caseSensitive: false
1005 * }
1006 *
1007 * Case insensitive, include territories but not military zones
1008 * stateInput: {
1009 * includeTerritories: true
1010 * }
1011 *
1012 * Only allow capital letters, include territories and military zones
1013 * stateInput: {
1014 * caseSensitive: true,
1015 * includeTerritories: true,
1016 * includeMilitary: true
1017 * }
1018 *
1019 */
1020 $.validator.addMethod( "stateUS", function( value, element, options ) {
1021 var isDefault = typeof options === "undefined",
1022 caseSensitive = ( isDefault || typeof options.caseSensitive === "undefined" ) ? false : options.caseSensitive,
1023 includeTerritories = ( isDefault || typeof options.includeTerritories === "undefined" ) ? false : options.includeTerritories,
1024 includeMilitary = ( isDefault || typeof options.includeMilitary === "undefined" ) ? false : options.includeMilitary,
1025 regex;
1026
1027 if ( !includeTerritories && !includeMilitary ) {
1028 regex = "^(A[KLRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$";
1029 } else if ( includeTerritories && includeMilitary ) {
1030 regex = "^(A[AEKLPRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$";
1031 } else if ( includeTerritories ) {
1032 regex = "^(A[KLRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$";
1033 } else {
1034 regex = "^(A[AEKLPRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$";
1035 }
1036
1037 regex = caseSensitive ? new RegExp( regex ) : new RegExp( regex, "i" );
1038 return this.optional( element ) || regex.test( value );
1039 }, "Please specify a valid state" );
1040
1041 // TODO check if value starts with <, otherwise don't try stripping anything
1042 $.validator.addMethod( "strippedminlength", function( value, element, param ) {
1043 return $( value ).text().length >= param;
1044 }, $.validator.format( "Please enter at least {0} characters" ) );
1045
1046 $.validator.addMethod( "time", function( value, element ) {
1047 return this.optional( element ) || /^([01]\d|2[0-3]|[0-9])(:[0-5]\d){1,2}$/.test( value );
1048 }, "Please enter a valid time, between 00:00 and 23:59" );
1049
1050 $.validator.addMethod( "time12h", function( value, element ) {
1051 return this.optional( element ) || /^((0?[1-9]|1[012])(:[0-5]\d){1,2}(\ ?[AP]M))$/i.test( value );
1052 }, "Please enter a valid time in 12-hour am/pm format" );
1053
1054 // Same as url, but TLD is optional
1055 $.validator.addMethod( "url2", function( value, element ) {
1056 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 );
1057 }, $.validator.messages.url );
1058
1059 /**
1060 * Return true, if the value is a valid vehicle identification number (VIN).
1061 *
1062 * Works with all kind of text inputs.
1063 *
1064 * @example <input type="text" size="20" name="VehicleID" class="{required:true,vinUS:true}" />
1065 * @desc Declares a required input element whose value must be a valid vehicle identification number.
1066 *
1067 * @name $.validator.methods.vinUS
1068 * @type Boolean
1069 * @cat Plugins/Validate/Methods
1070 */
1071 $.validator.addMethod( "vinUS", function( v ) {
1072 if ( v.length !== 17 ) {
1073 return false;
1074 }
1075
1076 var LL = [ "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" ],
1077 VL = [ 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 7, 9, 2, 3, 4, 5, 6, 7, 8, 9 ],
1078 FL = [ 8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2 ],
1079 rs = 0,
1080 i, n, d, f, cd, cdv;
1081
1082 for ( i = 0; i < 17; i++ ) {
1083 f = FL[ i ];
1084 d = v.slice( i, i + 1 );
1085 if ( i === 8 ) {
1086 cdv = d;
1087 }
1088 if ( !isNaN( d ) ) {
1089 d *= f;
1090 } else {
1091 for ( n = 0; n < LL.length; n++ ) {
1092 if ( d.toUpperCase() === LL[ n ] ) {
1093 d = VL[ n ];
1094 d *= f;
1095 if ( isNaN( cdv ) && n === 8 ) {
1096 cdv = LL[ n ];
1097 }
1098 break;
1099 }
1100 }
1101 }
1102 rs += d;
1103 }
1104 cd = rs % 11;
1105 if ( cd === 10 ) {
1106 cd = "X";
1107 }
1108 if ( cd === cdv ) {
1109 return true;
1110 }
1111 return false;
1112 }, "The specified vehicle identification number (VIN) is invalid." );
1113
1114 $.validator.addMethod( "zipcodeUS", function( value, element ) {
1115 return this.optional( element ) || /^\d{5}(-\d{4})?$/.test( value );
1116 }, "The specified US ZIP Code is invalid" );
1117
1118 $.validator.addMethod( "ziprange", function( value, element ) {
1119 return this.optional( element ) || /^90[2-5]\d\{2\}-\d{4}$/.test( value );
1120 }, "Your ZIP-code must be in the range 902xx-xxxx to 905xx-xxxx" );
1121 return $;
1122 }));