jquery_payment 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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(' ')