1 | 1 | 'use strict'; |
2 | | |
3 | 1 | var valid = {}; |
4 | | |
5 | | // ----- Regexp checks from is_js |
6 | | // -- Modified url to include port: https://gist.github.com/dperini/729294 |
7 | | // -- Modified affirmative to include 'on' and allowed any capitalization |
8 | | // -- Added negatory |
9 | | // -- Improved creditCard regexp allows for more card types |
10 | | // - http://stackoverflow.com/a/23231321 |
11 | | // --------------------------------------- |
12 | 1 | valid._regexps = { |
13 | | affirmative: /^(?:1|t(?:rue)?|y(?:es)?|on|ok(?:ay)?)$/, |
14 | | alphabetic: /^[A-Za-z]+$/, |
15 | | alphaNumeric: /^[A-Za-z0-9]+$/, |
16 | | creditCard: { |
17 | | mastercardVisa: /^4[0-9]{12}(?:[0-9]{3})?$^5[1-5][0-9]{14}$|^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14})$/, |
18 | | amex: /^3[47][0-9]{13}$/, |
19 | | carteBlanche: /^389[0-9]{11}$|^380[0-9]{11}$/, |
20 | | dinersClub: /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/, |
21 | | discover: /^65[4-9][0-9]{13}|64[4-9][0-9]{13}|6011[0-9]{12}|(622(?:12[6-9]|1[3-9][0-9]|[2-8][0-9][0-9]|9[01][0-9]|92[0-5])[0-9]{10})$/, |
22 | | jcb: /^(?:2131|1800|35\d{3})\d{11}$/, |
23 | | lasercard: /^(6304|6706|6709|6771)[0-9]{12,15}$/, |
24 | | maestro: /^(5018|5020|5038|6304|6759|6761|6763|6799)[0-9]{8,19}$/, |
25 | | solo: /^(6334|6767)[0-9]{12}|(6334|6767)[0-9]{14}|(6334|6767)[0-9]{15}$|^(4903|4905|4911|4936|6333|6759)[0-9]{12}|(4903|4905|4911|4936|6333|6759)[0-9]{14}|(4903|4905|4911|4936|6333|6759)[0-9]{15}|564182[0-9]{10}|564182[0-9]{12}|564182[0-9]{13}|633110[0-9]{10}|633110[0-9]{12}|633110[0-9]{13}$/, |
26 | | unionpay: /^(62[0-9]{14,17})$/ |
27 | | }, |
28 | | email: /^((([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, |
29 | | negatory: /^(?:1|f(?:alse)?|n(?:o)?|off)$/, |
30 | | url: /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/i |
31 | | }; |
32 | | |
33 | | |
34 | | // --------------------------------- string methods --------------------------------- |
35 | | |
36 | | // ----- private typechecker method |
37 | | // --------------------------------------- |
38 | 1 | valid._isString = function(str) { |
39 | | |
40 | 147 | if (typeof str === 'string' || str instanceof String) { |
41 | 138 | return true; |
42 | | } |
43 | | |
44 | 9 | return false; |
45 | | |
46 | | }; |
47 | | |
48 | | // ----- private regexp test methods |
49 | | // --------------------------------------- |
50 | 1 | valid._testRegexp = function(regexp, str) { |
51 | | |
52 | 108 | if (!this._isString(str)) { |
53 | 6 | return false; |
54 | | } |
55 | | |
56 | 102 | str = str.toLowerCase(); |
57 | | |
58 | 102 | return this._regexps[regexp].test(str); |
59 | | }; |
60 | | |
61 | 1 | valid._testCardRegexp = function(regexp, n) { |
62 | 46 | return this._regexps.creditCard[regexp].test(n); |
63 | | }; |
64 | | |
65 | | |
66 | | // ----- affirmative |
67 | | // --------------------------------------- |
68 | 1 | valid.affirmative = function(str) { |
69 | | |
70 | 25 | return this._testRegexp('affirmative', str); |
71 | | |
72 | | }; |
73 | | |
74 | | |
75 | | // ----- alphanumeric |
76 | | // --------------------------------------- |
77 | 1 | valid.alphaNumeric = function(str) { |
78 | | |
79 | 15 | return this._testRegexp('alphaNumeric', str); |
80 | | |
81 | | }; |
82 | | |
83 | | |
84 | | // ----- alphabetic |
85 | | // --------------------------------------- |
86 | 1 | valid.alpha = function(str) { |
87 | | |
88 | 17 | return this._testRegexp('alphabetic', str); |
89 | | |
90 | | }; |
91 | | |
92 | | |
93 | | // ----- email |
94 | | // --------------------------------------- |
95 | 1 | valid.email = function(str) { |
96 | | |
97 | 9 | return this._testRegexp('email', str); |
98 | | |
99 | | }; |
100 | | |
101 | | |
102 | | // ----- negatory |
103 | | // --------------------------------------- |
104 | 1 | valid.negatory = function(str) { |
105 | | |
106 | 19 | return this._testRegexp('negatory', str); |
107 | | |
108 | | }; |
109 | | |
110 | | |
111 | | // ----- numeric |
112 | | // --------------------------------------- |
113 | 1 | valid.numeric = function(str) { |
114 | | |
115 | 12 | if (!this._isString(str)) { |
116 | 1 | return false; |
117 | | } |
118 | | |
119 | 11 | if (str === '') { |
120 | 1 | return false; |
121 | | } |
122 | | |
123 | 10 | return !isNaN(str); // http://stackoverflow.com/a/175787 |
124 | | |
125 | | }; |
126 | | |
127 | | |
128 | | // ----- value |
129 | | // --------------------------------------- |
130 | 1 | valid.value = function(str) { |
131 | | |
132 | 25 | if (this._isString(str)) { |
133 | | |
134 | 24 | str = str.replace(',', ''); |
135 | 24 | var numbers = ['0','1','2','3','4','5','6','7','8','9', '-']; |
136 | | |
137 | | // for $100 and #123, etc. |
138 | 24 | if (numbers.indexOf(str[0]) === -1) { |
139 | 11 | str = str.slice(1); |
140 | | } |
141 | | |
142 | | } |
143 | | |
144 | | else { |
145 | 1 | return false; |
146 | | } |
147 | | |
148 | 24 | return !isNaN(parseInt(str), 10); |
149 | | |
150 | | }; |
151 | | |
152 | | |
153 | | // ----- url |
154 | | // --------------------------------------- |
155 | 1 | valid.url = function(str) { |
156 | | |
157 | 21 | return this._testRegexp('url', str); |
158 | | |
159 | | }; |
160 | | |
161 | | |
162 | | |
163 | | |
164 | | |
165 | | // --------------------------------- number methods --------------------------------- |
166 | | |
167 | | // ----- private typechecker method |
168 | | // --------------------------------------- |
169 | 1 | valid._isNumber = function(str) { |
170 | | |
171 | 92 | if (typeof str === 'number' || str instanceof Number) { |
172 | 86 | return true; |
173 | | } |
174 | | |
175 | 6 | return false; |
176 | | |
177 | | }; |
178 | | |
179 | | |
180 | | // -------------- credit card methods -------------- |
181 | | |
182 | | // ----- credit card check constructor |
183 | | // --------------------------------------- |
184 | 1 | function CreditCard(name) { |
185 | | |
186 | 12 | return function(n) { |
187 | | |
188 | 45 | if (!valid._isNumber(n)) { |
189 | 1 | return false; |
190 | | } |
191 | | |
192 | 44 | if (!valid._testCardRegexp(name, n)) { |
193 | 12 | return false; |
194 | | } |
195 | | |
196 | 32 | return true; |
197 | | |
198 | | }; |
199 | | |
200 | | } |
201 | | |
202 | | |
203 | | // ----- specific card regexp validation |
204 | | // --------------------------------------- |
205 | 1 | valid.card = { |
206 | | mastercardVisa: new CreditCard('mastercardVisa'), |
207 | | mastercard: new CreditCard('mastercardVisa'), // alias |
208 | | visa: new CreditCard('mastercardVisa'), // alias |
209 | | amex: new CreditCard('amex'), |
210 | | maestro: new CreditCard('maestro'), |
211 | | jcb: new CreditCard('jcb'), |
212 | | unionpay: new CreditCard('unionpay'), |
213 | | discover: new CreditCard('discover'), |
214 | | solo: new CreditCard('solo'), |
215 | | carteBlanche: new CreditCard('carteBlanche'), |
216 | | dinersClub: new CreditCard('dinersClub'), |
217 | | lasercard: new CreditCard('lasercard') |
218 | | }; |
219 | | |
220 | | |
221 | | // ----- generic card validation |
222 | | // -- 1. input must be number |
223 | | // -- 2. input length must be valid |
224 | | // -- 3. return true if any specific test passes |
225 | | // -- 4. perform complex check based on number |
226 | | // --------------------------------------- |
227 | 1 | valid.creditCard = valid.card.generic = function(n) { |
228 | | |
229 | 28 | if (!valid._isNumber(n)) { |
230 | 2 | return false; |
231 | | } |
232 | | |
233 | 26 | var str = n.toString(); |
234 | | |
235 | | // must be valid card length |
236 | 26 | if (str.length < 13 || str.length > 19) { |
237 | 2 | return false; |
238 | | } |
239 | | |
240 | | // should return true if any specific regexp tests pass |
241 | 24 | for (var prop in valid._regexps.creditCard) { |
242 | | |
243 | 121 | if (valid._regexps.creditCard.hasOwnProperty(prop)) { |
244 | 121 | if (valid._regexps.creditCard[prop].test(n)) { |
245 | 22 | return true; |
246 | | } |
247 | | } |
248 | | |
249 | | } |
250 | | |
251 | | // method of testing credit cards from |
252 | | // http://ajax.aspnetcdn.com/ajax/jquery.validate/1.13.1/jquery.validate.js |
253 | 2 | var testNumber = 0; |
254 | | |
255 | 2 | for (var i = str.length - 1, current, currentInteger = 0, even = false; i>=0; i--) { |
256 | | |
257 | 32 | current = str.charAt(i); |
258 | 32 | currentInteger = parseInt(current, 10); |
259 | | |
260 | 32 | if (even && (currentInteger *= 2) > 9 ) { |
261 | 5 | currentInteger -= 9; |
262 | | } |
263 | | |
264 | 32 | testNumber += currentInteger; |
265 | 32 | even = !even; |
266 | | } |
267 | | |
268 | 2 | return (testNumber % 10) === 0; |
269 | | |
270 | | }; |
271 | | |
272 | | |
273 | | // ----- integer |
274 | | // --------------------------------------- |
275 | 1 | valid.integer = function(n) { |
276 | | |
277 | 11 | if (!this._isNumber(n)) { |
278 | 1 | return false; |
279 | | } |
280 | | |
281 | 10 | return n % 1 === 0; |
282 | | |
283 | | }; |
284 | | |
285 | | |
286 | | // ----- zip code |
287 | | // --------------------------------------- |
288 | 1 | valid.zipCode = function(n) { |
289 | | |
290 | 6 | if (!this._isNumber(n)) { |
291 | 1 | return false; |
292 | | } |
293 | | |
294 | 5 | var len = n.toString().length; |
295 | | |
296 | 5 | if (len !== 5 && len !== 9) { |
297 | 3 | return false; |
298 | | } |
299 | | |
300 | 2 | return true; |
301 | | |
302 | | }; |
303 | | |
304 | 1 | module.exports = valid; |