jquery_payment 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bbe943b4869a023e4fba27d4668edec3330d5e98
4
- data.tar.gz: 6f73bb991dd38e166dbe948840549d71459216eb
3
+ metadata.gz: b81c9502e1846c8f6b85fa50d22265a09997197e
4
+ data.tar.gz: 4d83fb132bdc5f814ea6aadd7d4c0e21682f0ef7
5
5
  SHA512:
6
- metadata.gz: ce56e8553f93bb46ae0028af09b8707a1cd9d9018fed95abefaae3bf733059ae8ba22024d3b5b0cb6e7da2186cdc3234da75312d1c99dfc12327b89486b4992f
7
- data.tar.gz: b2ae9ae6513af5ed06f5a9e914e32bab9959ae558d423baceb11e85b584ca501acf47a2628e153f72aec40e5f8fa83b1e1d8ab7bfa899ab304d491a915aac6d5
6
+ metadata.gz: eb6e85a22c319f8ddbe113c8dfe27fba60be259ddff8b24ed014a9b2bbf61888cd3d7a96af0f4ed8c2713464e3c0f5e48bf1273339125b209f6788f15efd69d4
7
+ data.tar.gz: bd9cf68d671d9c336751043d027e52a39a19b0872afc8330b5bae25b9ac26df140303de14453ee4e0c13d64319c10c3112737fa86cb94ad0299fa2583c2c53a0
data/README.md CHANGED
@@ -18,7 +18,9 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
+ In the **application.js** file add:
21
22
 
23
+ //= require jquery.payment
22
24
 
23
25
  ## Contributing
24
26
 
@@ -21,6 +21,4 @@ Gem::Specification.new do |spec|
21
21
  spec.add_development_dependency "bundler", "~> 1.3"
22
22
  spec.add_development_dependency "rake"
23
23
 
24
- # coffee-script
25
- spec.add_dependency "coffee-script"
26
24
  end
@@ -1,3 +1,3 @@
1
1
  module JqueryPayment
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -0,0 +1,483 @@
1
+ // Generated by CoffeeScript 1.4.0
2
+ (function() {
3
+ var $, cardFromNumber, cardFromType, cards, defaultFormat, formatBackCardNumber, formatBackExpiry, formatCardNumber, formatExpiry, formatForwardExpiry, formatForwardSlash, hasTextSelected, luhnCheck, reFormatCardNumber, restrictCVC, restrictCardNumber, restrictExpiry, restrictNumeric, setCardType,
4
+ __slice = [].slice,
5
+ __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
6
+ _this = this;
7
+
8
+ $ = jQuery;
9
+
10
+ $.payment = {};
11
+
12
+ $.payment.fn = {};
13
+
14
+ $.fn.payment = function() {
15
+ var args, method;
16
+ method = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
17
+ return $.payment.fn[method].apply(this, args);
18
+ };
19
+
20
+ defaultFormat = /(\d{1,4})/g;
21
+
22
+ cards = [
23
+ {
24
+ type: 'maestro',
25
+ pattern: /^(5018|5020|5038|6304|6759|676[1-3])/,
26
+ format: defaultFormat,
27
+ length: [12, 13, 14, 15, 16, 17, 18, 19],
28
+ cvcLength: [3],
29
+ luhn: true
30
+ }, {
31
+ type: 'dinersclub',
32
+ pattern: /^(36|38|30[0-5])/,
33
+ format: defaultFormat,
34
+ length: [14],
35
+ cvcLength: [3],
36
+ luhn: true
37
+ }, {
38
+ type: 'laser',
39
+ pattern: /^(6706|6771|6709)/,
40
+ format: defaultFormat,
41
+ length: [16, 17, 18, 19],
42
+ cvcLength: [3],
43
+ luhn: true
44
+ }, {
45
+ type: 'jcb',
46
+ pattern: /^35/,
47
+ format: defaultFormat,
48
+ length: [16],
49
+ cvcLength: [3],
50
+ luhn: true
51
+ }, {
52
+ type: 'unionpay',
53
+ pattern: /^62/,
54
+ format: defaultFormat,
55
+ length: [16, 17, 18, 19],
56
+ cvcLength: [3],
57
+ luhn: false
58
+ }, {
59
+ type: 'discover',
60
+ pattern: /^(6011|65|64[4-9]|622)/,
61
+ format: defaultFormat,
62
+ length: [16],
63
+ cvcLength: [3],
64
+ luhn: true
65
+ }, {
66
+ type: 'mastercard',
67
+ pattern: /^5[1-5]/,
68
+ format: defaultFormat,
69
+ length: [16],
70
+ cvcLength: [3],
71
+ luhn: true
72
+ }, {
73
+ type: 'amex',
74
+ pattern: /^3[47]/,
75
+ format: /(\d{1,4})(\d{1,6})?(\d{1,5})?/,
76
+ length: [15],
77
+ cvcLength: [3, 4],
78
+ luhn: true
79
+ }, {
80
+ type: 'visa',
81
+ pattern: /^4/,
82
+ format: defaultFormat,
83
+ length: [13, 14, 15, 16],
84
+ cvcLength: [3],
85
+ luhn: true
86
+ }
87
+ ];
88
+
89
+ cardFromNumber = function(num) {
90
+ var card, _i, _len;
91
+ num = (num + '').replace(/\D/g, '');
92
+ for (_i = 0, _len = cards.length; _i < _len; _i++) {
93
+ card = cards[_i];
94
+ if (card.pattern.test(num)) {
95
+ return card;
96
+ }
97
+ }
98
+ };
99
+
100
+ cardFromType = function(type) {
101
+ var card, _i, _len;
102
+ for (_i = 0, _len = cards.length; _i < _len; _i++) {
103
+ card = cards[_i];
104
+ if (card.type === type) {
105
+ return card;
106
+ }
107
+ }
108
+ };
109
+
110
+ luhnCheck = function(num) {
111
+ var digit, digits, odd, sum, _i, _len;
112
+ odd = true;
113
+ sum = 0;
114
+ digits = (num + '').split('').reverse();
115
+ for (_i = 0, _len = digits.length; _i < _len; _i++) {
116
+ digit = digits[_i];
117
+ digit = parseInt(digit, 10);
118
+ if ((odd = !odd)) {
119
+ digit *= 2;
120
+ }
121
+ if (digit > 9) {
122
+ digit -= 9;
123
+ }
124
+ sum += digit;
125
+ }
126
+ return sum % 10 === 0;
127
+ };
128
+
129
+ hasTextSelected = function($target) {
130
+ var _ref;
131
+ if (($target.prop('selectionStart') != null) && $target.prop('selectionStart') !== $target.prop('selectionEnd')) {
132
+ return true;
133
+ }
134
+ if (typeof document !== "undefined" && document !== null ? (_ref = document.selection) != null ? typeof _ref.createRange === "function" ? _ref.createRange().text : void 0 : void 0 : void 0) {
135
+ return true;
136
+ }
137
+ return false;
138
+ };
139
+
140
+ reFormatCardNumber = function(e) {
141
+ var _this = this;
142
+ return setTimeout(function() {
143
+ var $target, value;
144
+ $target = $(e.currentTarget);
145
+ value = $target.val();
146
+ value = $.payment.formatCardNumber(value);
147
+ return $target.val(value);
148
+ });
149
+ };
150
+
151
+ formatCardNumber = function(e) {
152
+ var $target, card, digit, length, re, upperLength, value;
153
+ digit = String.fromCharCode(e.which);
154
+ if (!/^\d+$/.test(digit)) {
155
+ return;
156
+ }
157
+ $target = $(e.currentTarget);
158
+ value = $target.val();
159
+ card = cardFromNumber(value + digit);
160
+ length = (value.replace(/\D/g, '') + digit).length;
161
+ upperLength = 16;
162
+ if (card) {
163
+ upperLength = card.length[card.length.length - 1];
164
+ }
165
+ if (length >= upperLength) {
166
+ return;
167
+ }
168
+ if (($target.prop('selectionStart') != null) && $target.prop('selectionStart') !== value.length) {
169
+ return;
170
+ }
171
+ if (card && card.type === 'amex') {
172
+ re = /^(\d{4}|\d{4}\s\d{6})$/;
173
+ } else {
174
+ re = /(?:^|\s)(\d{4})$/;
175
+ }
176
+ if (re.test(value)) {
177
+ e.preventDefault();
178
+ return $target.val(value + ' ' + digit);
179
+ } else if (re.test(value + digit)) {
180
+ e.preventDefault();
181
+ return $target.val(value + digit + ' ');
182
+ }
183
+ };
184
+
185
+ formatBackCardNumber = function(e) {
186
+ var $target, value;
187
+ $target = $(e.currentTarget);
188
+ value = $target.val();
189
+ if (e.meta) {
190
+ return;
191
+ }
192
+ if (($target.prop('selectionStart') != null) && $target.prop('selectionStart') !== value.length) {
193
+ return;
194
+ }
195
+ if (e.which === 8 && /\s\d?$/.test(value)) {
196
+ e.preventDefault();
197
+ return $target.val(value.replace(/\s\d?$/, ''));
198
+ }
199
+ };
200
+
201
+ formatExpiry = function(e) {
202
+ var $target, digit, val;
203
+ digit = String.fromCharCode(e.which);
204
+ if (!/^\d+$/.test(digit)) {
205
+ return;
206
+ }
207
+ $target = $(e.currentTarget);
208
+ val = $target.val() + digit;
209
+ if (/^\d$/.test(val) && (val !== '0' && val !== '1')) {
210
+ e.preventDefault();
211
+ return $target.val("0" + val + " / ");
212
+ } else if (/^\d\d$/.test(val)) {
213
+ e.preventDefault();
214
+ return $target.val("" + val + " / ");
215
+ }
216
+ };
217
+
218
+ formatForwardExpiry = function(e) {
219
+ var $target, digit, val;
220
+ digit = String.fromCharCode(e.which);
221
+ if (!/^\d+$/.test(digit)) {
222
+ return;
223
+ }
224
+ $target = $(e.currentTarget);
225
+ val = $target.val();
226
+ if (/^\d\d$/.test(val)) {
227
+ return $target.val("" + val + " / ");
228
+ }
229
+ };
230
+
231
+ formatForwardSlash = function(e) {
232
+ var $target, slash, val;
233
+ slash = String.fromCharCode(e.which);
234
+ if (slash !== '/') {
235
+ return;
236
+ }
237
+ $target = $(e.currentTarget);
238
+ val = $target.val();
239
+ if (/^\d$/.test(val) && val !== '0') {
240
+ return $target.val("0" + val + " / ");
241
+ }
242
+ };
243
+
244
+ formatBackExpiry = function(e) {
245
+ var $target, value;
246
+ if (e.meta) {
247
+ return;
248
+ }
249
+ $target = $(e.currentTarget);
250
+ value = $target.val();
251
+ if (e.which !== 8) {
252
+ return;
253
+ }
254
+ if (($target.prop('selectionStart') != null) && $target.prop('selectionStart') !== value.length) {
255
+ return;
256
+ }
257
+ if (/\s\/\s?\d?$/.test(value)) {
258
+ e.preventDefault();
259
+ return $target.val(value.replace(/\s\/\s?\d?$/, ''));
260
+ }
261
+ };
262
+
263
+ restrictNumeric = function(e) {
264
+ var input;
265
+ if (e.metaKey || e.ctrlKey) {
266
+ return true;
267
+ }
268
+ if (e.which === 32) {
269
+ return false;
270
+ }
271
+ if (e.which === 0) {
272
+ return true;
273
+ }
274
+ if (e.which < 33) {
275
+ return true;
276
+ }
277
+ input = String.fromCharCode(e.which);
278
+ return !!/[\d\s]/.test(input);
279
+ };
280
+
281
+ restrictCardNumber = function(e) {
282
+ var $target, card, digit, value;
283
+ $target = $(e.currentTarget);
284
+ digit = String.fromCharCode(e.which);
285
+ if (!/^\d+$/.test(digit)) {
286
+ return;
287
+ }
288
+ if (hasTextSelected($target)) {
289
+ return;
290
+ }
291
+ value = ($target.val() + digit).replace(/\D/g, '');
292
+ card = cardFromNumber(value);
293
+ if (card) {
294
+ return value.length <= card.length[card.length.length - 1];
295
+ } else {
296
+ return value.length <= 16;
297
+ }
298
+ };
299
+
300
+ restrictExpiry = function(e) {
301
+ var $target, digit, value;
302
+ $target = $(e.currentTarget);
303
+ digit = String.fromCharCode(e.which);
304
+ if (!/^\d+$/.test(digit)) {
305
+ return;
306
+ }
307
+ if (hasTextSelected($target)) {
308
+ return;
309
+ }
310
+ value = $target.val() + digit;
311
+ value = value.replace(/\D/g, '');
312
+ if (value.length > 6) {
313
+ return false;
314
+ }
315
+ };
316
+
317
+ restrictCVC = function(e) {
318
+ var $target, digit, val;
319
+ $target = $(e.currentTarget);
320
+ digit = String.fromCharCode(e.which);
321
+ if (!/^\d+$/.test(digit)) {
322
+ return;
323
+ }
324
+ val = $target.val() + digit;
325
+ return val.length <= 4;
326
+ };
327
+
328
+ setCardType = function(e) {
329
+ var $target, allTypes, card, cardType, val;
330
+ $target = $(e.currentTarget);
331
+ val = $target.val();
332
+ cardType = $.payment.cardType(val) || 'unknown';
333
+ if (!$target.hasClass(cardType)) {
334
+ allTypes = (function() {
335
+ var _i, _len, _results;
336
+ _results = [];
337
+ for (_i = 0, _len = cards.length; _i < _len; _i++) {
338
+ card = cards[_i];
339
+ _results.push(card.type);
340
+ }
341
+ return _results;
342
+ })();
343
+ $target.removeClass('unknown');
344
+ $target.removeClass(allTypes.join(' '));
345
+ $target.addClass(cardType);
346
+ $target.toggleClass('identified', cardType !== 'unknown');
347
+ return $target.trigger('payment.cardType', cardType);
348
+ }
349
+ };
350
+
351
+ $.payment.fn.formatCardCVC = function() {
352
+ this.payment('restrictNumeric');
353
+ this.on('keypress', restrictCVC);
354
+ return this;
355
+ };
356
+
357
+ $.payment.fn.formatCardExpiry = function() {
358
+ this.payment('restrictNumeric');
359
+ this.on('keypress', restrictExpiry);
360
+ this.on('keypress', formatExpiry);
361
+ this.on('keypress', formatForwardSlash);
362
+ this.on('keypress', formatForwardExpiry);
363
+ this.on('keydown', formatBackExpiry);
364
+ return this;
365
+ };
366
+
367
+ $.payment.fn.formatCardNumber = function() {
368
+ this.payment('restrictNumeric');
369
+ this.on('keypress', restrictCardNumber);
370
+ this.on('keypress', formatCardNumber);
371
+ this.on('keydown', formatBackCardNumber);
372
+ this.on('keyup', setCardType);
373
+ this.on('paste', reFormatCardNumber);
374
+ return this;
375
+ };
376
+
377
+ $.payment.fn.restrictNumeric = function() {
378
+ this.on('keypress', restrictNumeric);
379
+ return this;
380
+ };
381
+
382
+ $.payment.fn.cardExpiryVal = function() {
383
+ return $.payment.cardExpiryVal($(this).val());
384
+ };
385
+
386
+ $.payment.cardExpiryVal = function(value) {
387
+ var month, prefix, year, _ref;
388
+ value = value.replace(/\s/g, '');
389
+ _ref = value.split('/', 2), month = _ref[0], year = _ref[1];
390
+ if ((year != null ? year.length : void 0) === 2 && /^\d+$/.test(year)) {
391
+ prefix = (new Date).getFullYear();
392
+ prefix = prefix.toString().slice(0, 2);
393
+ year = prefix + year;
394
+ }
395
+ month = parseInt(month, 10);
396
+ year = parseInt(year, 10);
397
+ return {
398
+ month: month,
399
+ year: year
400
+ };
401
+ };
402
+
403
+ $.payment.validateCardNumber = function(num) {
404
+ var card, _ref;
405
+ num = (num + '').replace(/\s+|-/g, '');
406
+ if (!/^\d+$/.test(num)) {
407
+ return false;
408
+ }
409
+ card = cardFromNumber(num);
410
+ if (!card) {
411
+ return false;
412
+ }
413
+ return (_ref = num.length, __indexOf.call(card.length, _ref) >= 0) && (card.luhn === false || luhnCheck(num));
414
+ };
415
+
416
+ $.payment.validateCardExpiry = function(month, year) {
417
+ var currentTime, expiry, _ref;
418
+ if (typeof month === 'object' && 'month' in month) {
419
+ _ref = month, month = _ref.month, year = _ref.year;
420
+ }
421
+ if (!(month && year)) {
422
+ return false;
423
+ }
424
+ month = $.trim(month);
425
+ year = $.trim(year);
426
+ if (!/^\d+$/.test(month)) {
427
+ return false;
428
+ }
429
+ if (!/^\d+$/.test(year)) {
430
+ return false;
431
+ }
432
+ if (!(parseInt(month, 10) <= 12)) {
433
+ return false;
434
+ }
435
+ expiry = new Date(year, month);
436
+ currentTime = new Date;
437
+ expiry.setMonth(expiry.getMonth() - 1);
438
+ expiry.setMonth(expiry.getMonth() + 1, 1);
439
+ return expiry > currentTime;
440
+ };
441
+
442
+ $.payment.validateCardCVC = function(cvc, type) {
443
+ var _ref, _ref1;
444
+ cvc = $.trim(cvc);
445
+ if (!/^\d+$/.test(cvc)) {
446
+ return false;
447
+ }
448
+ if (type) {
449
+ return _ref = cvc.length, __indexOf.call((_ref1 = cardFromType(type)) != null ? _ref1.cvcLength : void 0, _ref) >= 0;
450
+ } else {
451
+ return cvc.length >= 3 && cvc.length <= 4;
452
+ }
453
+ };
454
+
455
+ $.payment.cardType = function(num) {
456
+ var _ref;
457
+ if (!num) {
458
+ return null;
459
+ }
460
+ return ((_ref = cardFromNumber(num)) != null ? _ref.type : void 0) || null;
461
+ };
462
+
463
+ $.payment.formatCardNumber = function(num) {
464
+ var card, groups, upperLength, _ref;
465
+ card = cardFromNumber(num);
466
+ if (!card) {
467
+ return num;
468
+ }
469
+ upperLength = card.length[card.length.length - 1];
470
+ num = num.replace(/\D/g, '');
471
+ num = num.slice(0, +upperLength + 1 || 9e9);
472
+ if (card.format.global) {
473
+ return (_ref = num.match(card.format)) != null ? _ref.join(' ') : void 0;
474
+ } else {
475
+ groups = card.format.exec(num);
476
+ if (groups != null) {
477
+ groups.shift();
478
+ }
479
+ return groups != null ? groups.join(' ') : void 0;
480
+ }
481
+ };
482
+
483
+ }).call(this);
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jquery_payment
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - ampvchen
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: coffee-script
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - '>='
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
41
  description: jquery.payments gem wrapper
56
42
  email:
57
43
  - self@vchen.me
@@ -67,7 +53,7 @@ files:
67
53
  - jquery_payment.gemspec
68
54
  - lib/jquery_payment.rb
69
55
  - lib/jquery_payment/version.rb
70
- - vendor/assets/javascript/jquery.payment.coffee
56
+ - vendor/assets/javascript/jquery.payment.js
71
57
  homepage: ''
72
58
  licenses:
73
59
  - MIT
@@ -1,439 +0,0 @@
1
- $ = jQuery
2
- $.payment = {}
3
- $.payment.fn = {}
4
- $.fn.payment = (method, args...) ->
5
- $.payment.fn[method].apply(this, args)
6
-
7
- # Utils
8
-
9
- defaultFormat = /(\d{1,4})/g
10
-
11
- cards = [
12
- {
13
- type: 'maestro'
14
- pattern: /^(5018|5020|5038|6304|6759|676[1-3])/
15
- format: defaultFormat
16
- length: [12..19]
17
- cvcLength: [3]
18
- luhn: true
19
- }
20
- {
21
- type: 'dinersclub'
22
- pattern: /^(36|38|30[0-5])/
23
- format: defaultFormat
24
- length: [14]
25
- cvcLength: [3]
26
- luhn: true
27
- }
28
- {
29
- type: 'laser'
30
- pattern: /^(6706|6771|6709)/
31
- format: defaultFormat
32
- length: [16..19]
33
- cvcLength: [3]
34
- luhn: true
35
- }
36
- {
37
- type: 'jcb'
38
- pattern: /^35/
39
- format: defaultFormat
40
- length: [16]
41
- cvcLength: [3]
42
- luhn: true
43
- }
44
- {
45
- type: 'unionpay'
46
- pattern: /^62/
47
- format: defaultFormat
48
- length: [16..19]
49
- cvcLength: [3]
50
- luhn: false
51
- }
52
- {
53
- type: 'discover'
54
- pattern: /^(6011|65|64[4-9]|622)/
55
- format: defaultFormat
56
- length: [16]
57
- cvcLength: [3]
58
- luhn: true
59
- }
60
- {
61
- type: 'mastercard'
62
- pattern: /^5[1-5]/
63
- format: defaultFormat
64
- length: [16]
65
- cvcLength: [3]
66
- luhn: true
67
- }
68
- {
69
- type: 'amex'
70
- pattern: /^3[47]/
71
- format: /(\d{1,4})(\d{1,6})?(\d{1,5})?/
72
- length: [15]
73
- cvcLength: [3..4]
74
- luhn: true
75
- }
76
- {
77
- type: 'visa'
78
- pattern: /^4/
79
- format: defaultFormat
80
- length: [13..16]
81
- cvcLength: [3]
82
- luhn: true
83
- }
84
- ]
85
-
86
- cardFromNumber = (num) ->
87
- num = (num + '').replace(/\D/g, '')
88
- return card for card in cards when card.pattern.test(num)
89
-
90
- cardFromType = (type) ->
91
- return card for card in cards when card.type is type
92
-
93
- luhnCheck = (num) ->
94
- odd = true
95
- sum = 0
96
-
97
- digits = (num + '').split('').reverse()
98
-
99
- for digit in digits
100
- digit = parseInt(digit, 10)
101
- digit *= 2 if (odd = !odd)
102
- digit -= 9 if digit > 9
103
- sum += digit
104
-
105
- sum % 10 == 0
106
-
107
- hasTextSelected = ($target) ->
108
- # If some text is selected
109
- return true if $target.prop('selectionStart')? and
110
- $target.prop('selectionStart') isnt $target.prop('selectionEnd')
111
-
112
- # If some text is selected in IE
113
- return true if document?.selection?.createRange?().text
114
-
115
- false
116
-
117
- # Private
118
-
119
- # Format Card Number
120
-
121
- reFormatCardNumber = (e) ->
122
- setTimeout =>
123
- $target = $(e.currentTarget)
124
- value = $target.val()
125
- value = $.payment.formatCardNumber(value)
126
- $target.val(value)
127
-
128
- formatCardNumber = (e) ->
129
- # Only format if input is a number
130
- digit = String.fromCharCode(e.which)
131
- return unless /^\d+$/.test(digit)
132
-
133
- $target = $(e.currentTarget)
134
- value = $target.val()
135
- card = cardFromNumber(value + digit)
136
- length = (value.replace(/\D/g, '') + digit).length
137
-
138
- upperLength = 16
139
- upperLength = card.length[card.length.length - 1] if card
140
- return if length >= upperLength
141
-
142
- # Return if focus isn't at the end of the text
143
- return if $target.prop('selectionStart')? and
144
- $target.prop('selectionStart') isnt value.length
145
-
146
- if card && card.type is 'amex'
147
- # Amex cards are formatted differently
148
- re = /^(\d{4}|\d{4}\s\d{6})$/
149
- else
150
- re = /(?:^|\s)(\d{4})$/
151
-
152
- # If '4242' + 4
153
- if re.test(value)
154
- e.preventDefault()
155
- $target.val(value + ' ' + digit)
156
-
157
- # If '424' + 2
158
- else if re.test(value + digit)
159
- e.preventDefault()
160
- $target.val(value + digit + ' ')
161
-
162
- formatBackCardNumber = (e) ->
163
- $target = $(e.currentTarget)
164
- value = $target.val()
165
-
166
- return if e.meta
167
-
168
- # Return unless backspacing
169
- return unless e.which is 8
170
-
171
- # Return if focus isn't at the end of the text
172
- return if $target.prop('selectionStart')? and
173
- $target.prop('selectionStart') isnt value.length
174
-
175
- # Remove the trailing space
176
- if /\d\s$/.test(value)
177
- e.preventDefault()
178
- $target.val(value.replace(/\d\s$/, ''))
179
- else if /\s\d?$/.test(value)
180
- e.preventDefault()
181
- $target.val(value.replace(/\s\d?$/, ''))
182
-
183
- # Format Expiry
184
-
185
- formatExpiry = (e) ->
186
- # Only format if input is a number
187
- digit = String.fromCharCode(e.which)
188
- return unless /^\d+$/.test(digit)
189
-
190
- $target = $(e.currentTarget)
191
- val = $target.val() + digit
192
-
193
- if /^\d$/.test(val) and val not in ['0', '1']
194
- e.preventDefault()
195
- $target.val("0#{val} / ")
196
-
197
- else if /^\d\d$/.test(val)
198
- e.preventDefault()
199
- $target.val("#{val} / ")
200
-
201
- formatForwardExpiry = (e) ->
202
- digit = String.fromCharCode(e.which)
203
- return unless /^\d+$/.test(digit)
204
-
205
- $target = $(e.currentTarget)
206
- val = $target.val()
207
-
208
- if /^\d\d$/.test(val)
209
- $target.val("#{val} / ")
210
-
211
- formatForwardSlash = (e) ->
212
- slash = String.fromCharCode(e.which)
213
- return unless slash is '/'
214
-
215
- $target = $(e.currentTarget)
216
- val = $target.val()
217
-
218
- if /^\d$/.test(val) and val isnt '0'
219
- $target.val("0#{val} / ")
220
-
221
- formatBackExpiry = (e) ->
222
- # If shift+backspace is pressed
223
- return if e.meta
224
-
225
- $target = $(e.currentTarget)
226
- value = $target.val()
227
-
228
- # Return unless backspacing
229
- return unless e.which is 8
230
-
231
- # Return if focus isn't at the end of the text
232
- return if $target.prop('selectionStart')? and
233
- $target.prop('selectionStart') isnt value.length
234
-
235
- # Remove the trailing space
236
- if /\d(\s|\/)+$/.test(value)
237
- e.preventDefault()
238
- $target.val(value.replace(/\d(\s|\/)*$/, ''))
239
- else if /\s\/\s?\d?$/.test(value)
240
- e.preventDefault()
241
- $target.val(value.replace(/\s\/\s?\d?$/, ''))
242
-
243
- # Restrictions
244
-
245
- restrictNumeric = (e) ->
246
- # Key event is for a browser shortcut
247
- return true if e.metaKey or e.ctrlKey
248
-
249
- # If keycode is a space
250
- return false if e.which is 32
251
-
252
- # If keycode is a special char (WebKit)
253
- return true if e.which is 0
254
-
255
- # If char is a special char (Firefox)
256
- return true if e.which < 33
257
-
258
- input = String.fromCharCode(e.which)
259
-
260
- # Char is a number or a space
261
- !!/[\d\s]/.test(input)
262
-
263
- restrictCardNumber = (e) ->
264
- $target = $(e.currentTarget)
265
- digit = String.fromCharCode(e.which)
266
- return unless /^\d+$/.test(digit)
267
-
268
- return if hasTextSelected($target)
269
-
270
- # Restrict number of digits
271
- value = ($target.val() + digit).replace(/\D/g, '')
272
- card = cardFromNumber(value)
273
-
274
- if card
275
- value.length <= card.length[card.length.length - 1]
276
- else
277
- # All other cards are 16 digits long
278
- value.length <= 16
279
-
280
- restrictExpiry = (e) ->
281
- $target = $(e.currentTarget)
282
- digit = String.fromCharCode(e.which)
283
- return unless /^\d+$/.test(digit)
284
-
285
- return if hasTextSelected($target)
286
-
287
- value = $target.val() + digit
288
- value = value.replace(/\D/g, '')
289
-
290
- return false if value.length > 6
291
-
292
- restrictCVC = (e) ->
293
- $target = $(e.currentTarget)
294
- digit = String.fromCharCode(e.which)
295
- return unless /^\d+$/.test(digit)
296
-
297
- val = $target.val() + digit
298
- val.length <= 4
299
-
300
- setCardType = (e) ->
301
- $target = $(e.currentTarget)
302
- val = $target.val()
303
- cardType = $.payment.cardType(val) or 'unknown'
304
-
305
- unless $target.hasClass(cardType)
306
- allTypes = (card.type for card in cards)
307
-
308
- $target.removeClass('unknown')
309
- $target.removeClass(allTypes.join(' '))
310
-
311
- $target.addClass(cardType)
312
- $target.toggleClass('identified', cardType isnt 'unknown')
313
- $target.trigger('payment.cardType', cardType)
314
-
315
- # Public
316
-
317
- # Formatting
318
-
319
- $.payment.fn.formatCardCVC = ->
320
- @payment('restrictNumeric')
321
- @on('keypress', restrictCVC)
322
- this
323
-
324
- $.payment.fn.formatCardExpiry = ->
325
- @payment('restrictNumeric')
326
- @on('keypress', restrictExpiry)
327
- @on('keypress', formatExpiry)
328
- @on('keypress', formatForwardSlash)
329
- @on('keypress', formatForwardExpiry)
330
- @on('keydown', formatBackExpiry)
331
- this
332
-
333
- $.payment.fn.formatCardNumber = ->
334
- @payment('restrictNumeric')
335
- @on('keypress', restrictCardNumber)
336
- @on('keypress', formatCardNumber)
337
- @on('keydown', formatBackCardNumber)
338
- @on('keyup', setCardType)
339
- @on('paste', reFormatCardNumber)
340
- this
341
-
342
- # Restrictions
343
-
344
- $.payment.fn.restrictNumeric = ->
345
- @on('keypress', restrictNumeric)
346
- this
347
-
348
- # Validations
349
-
350
- $.payment.fn.cardExpiryVal = ->
351
- $.payment.cardExpiryVal($(this).val())
352
-
353
- $.payment.cardExpiryVal = (value) ->
354
- value = value.replace(/\s/g, '')
355
- [month, year] = value.split('/', 2)
356
-
357
- # Allow for year shortcut
358
- if year?.length is 2 and /^\d+$/.test(year)
359
- prefix = (new Date).getFullYear()
360
- prefix = prefix.toString()[0..1]
361
- year = prefix + year
362
-
363
- month = parseInt(month, 10)
364
- year = parseInt(year, 10)
365
-
366
- month: month, year: year
367
-
368
- $.payment.validateCardNumber = (num) ->
369
- num = (num + '').replace(/\s+|-/g, '')
370
- return false unless /^\d+$/.test(num)
371
-
372
- card = cardFromNumber(num)
373
- return false unless card
374
-
375
- num.length in card.length and
376
- (card.luhn is false or luhnCheck(num))
377
-
378
- $.payment.validateCardExpiry = (month, year) =>
379
- # Allow passing an object
380
- if typeof month is 'object' and 'month' of month
381
- {month, year} = month
382
-
383
- return false unless month and year
384
-
385
- month = $.trim(month)
386
- year = $.trim(year)
387
-
388
- return false unless /^\d+$/.test(month)
389
- return false unless /^\d+$/.test(year)
390
- return false unless parseInt(month, 10) <= 12
391
-
392
- if year.length is 2
393
- prefix = (new Date).getFullYear()
394
- prefix = prefix.toString()[0..1]
395
- year = prefix + year
396
-
397
- expiry = new Date(year, month)
398
- currentTime = new Date
399
-
400
- # Months start from 0 in JavaScript
401
- expiry.setMonth(expiry.getMonth() - 1)
402
-
403
- # The cc expires at the end of the month,
404
- # so we need to make the expiry the first day
405
- # of the month after
406
- expiry.setMonth(expiry.getMonth() + 1, 1)
407
-
408
- expiry > currentTime
409
-
410
- $.payment.validateCardCVC = (cvc, type) ->
411
- cvc = $.trim(cvc)
412
- return false unless /^\d+$/.test(cvc)
413
-
414
- if type
415
- # Check against a explicit card type
416
- cvc.length in cardFromType(type)?.cvcLength
417
- else
418
- # Check against all types
419
- cvc.length >= 3 and cvc.length <= 4
420
-
421
- $.payment.cardType = (num) ->
422
- return null unless num
423
- cardFromNumber(num)?.type or null
424
-
425
- $.payment.formatCardNumber = (num) ->
426
- card = cardFromNumber(num)
427
- return num unless card
428
-
429
- upperLength = card.length[card.length.length - 1]
430
-
431
- num = num.replace(/\D/g, '')
432
- num = num[0..upperLength]
433
-
434
- if card.format.global
435
- num.match(card.format)?.join(' ')
436
- else
437
- groups = card.format.exec(num)
438
- groups?.shift()
439
- groups?.join(' ')