weaver 0.8.10 → 0.8.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/exe/weaver +7 -6
  3. data/lib/weaver/element_types/code.rb +2 -2
  4. data/lib/weaver/element_types/dynamic_table.rb +1 -1
  5. data/lib/weaver/element_types/form_elements.rb +6 -2
  6. data/lib/weaver/element_types/panel.rb +1 -1
  7. data/lib/weaver/elements.rb +8 -5
  8. data/lib/weaver/page_types/page.rb +3 -1
  9. data/lib/weaver/version.rb +1 -1
  10. data/weaver.gemspec +2 -2
  11. metadata +16 -82
  12. data/data/weaver/js/plugins/skeuocard/Gruntfile.coffee +0 -74
  13. data/data/weaver/js/plugins/skeuocard/LICENSE +0 -21
  14. data/data/weaver/js/plugins/skeuocard/README.md +0 -393
  15. data/data/weaver/js/plugins/skeuocard/bower.json +0 -40
  16. data/data/weaver/js/plugins/skeuocard/fonts/ocra-webfont.eot +0 -0
  17. data/data/weaver/js/plugins/skeuocard/fonts/ocra-webfont.svg +0 -138
  18. data/data/weaver/js/plugins/skeuocard/fonts/ocra-webfont.ttf +0 -0
  19. data/data/weaver/js/plugins/skeuocard/fonts/ocra-webfont.woff +0 -0
  20. data/data/weaver/js/plugins/skeuocard/images/card-flip-arrow.png +0 -0
  21. data/data/weaver/js/plugins/skeuocard/images/card-front-background.png +0 -0
  22. data/data/weaver/js/plugins/skeuocard/images/card-invalid-indicator.png +0 -0
  23. data/data/weaver/js/plugins/skeuocard/images/card-valid-anim.gif +0 -0
  24. data/data/weaver/js/plugins/skeuocard/images/card-valid-indicator.png +0 -0
  25. data/data/weaver/js/plugins/skeuocard/images/error-pointer.png +0 -0
  26. data/data/weaver/js/plugins/skeuocard/images/issuers/visa-chase-sapphire.png +0 -0
  27. data/data/weaver/js/plugins/skeuocard/images/issuers/visa-simple-front.png +0 -0
  28. data/data/weaver/js/plugins/skeuocard/images/products/amex-front.png +0 -0
  29. data/data/weaver/js/plugins/skeuocard/images/products/dinersclubintl-front.png +0 -0
  30. data/data/weaver/js/plugins/skeuocard/images/products/discover-front.png +0 -0
  31. data/data/weaver/js/plugins/skeuocard/images/products/generic-back.png +0 -0
  32. data/data/weaver/js/plugins/skeuocard/images/products/generic-front.png +0 -0
  33. data/data/weaver/js/plugins/skeuocard/images/products/jcb-front.png +0 -0
  34. data/data/weaver/js/plugins/skeuocard/images/products/maestro-front.png +0 -0
  35. data/data/weaver/js/plugins/skeuocard/images/products/mastercard-front.png +0 -0
  36. data/data/weaver/js/plugins/skeuocard/images/products/unionpay-front.png +0 -0
  37. data/data/weaver/js/plugins/skeuocard/images/products/visa-back.png +0 -0
  38. data/data/weaver/js/plugins/skeuocard/images/products/visa-front.png +0 -0
  39. data/data/weaver/js/plugins/skeuocard/images/src/card-front-background.fw.png +0 -0
  40. data/data/weaver/js/plugins/skeuocard/images/src/error-pointer.png +0 -0
  41. data/data/weaver/js/plugins/skeuocard/images/src/product-amex-front.fw.png +0 -0
  42. data/data/weaver/js/plugins/skeuocard/images/src/product-dinersclub-front.fw.png +0 -0
  43. data/data/weaver/js/plugins/skeuocard/images/src/product-discover-front.fw.png +0 -0
  44. data/data/weaver/js/plugins/skeuocard/images/src/product-generic-front.fw.png +0 -0
  45. data/data/weaver/js/plugins/skeuocard/images/src/product-jcb-front.fw.png +0 -0
  46. data/data/weaver/js/plugins/skeuocard/images/src/product-maestro-front.fw.png +0 -0
  47. data/data/weaver/js/plugins/skeuocard/images/src/product-mastercard-front.fw.png +0 -0
  48. data/data/weaver/js/plugins/skeuocard/images/src/product-unionpay-front.fw.png +0 -0
  49. data/data/weaver/js/plugins/skeuocard/images/src/product-visa-front.fw.png +0 -0
  50. data/data/weaver/js/plugins/skeuocard/index.html +0 -124
  51. data/data/weaver/js/plugins/skeuocard/javascripts/skeuocard.js +0 -1748
  52. data/data/weaver/js/plugins/skeuocard/javascripts/skeuocard.min.js +0 -2
  53. data/data/weaver/js/plugins/skeuocard/javascripts/src/CardProduct.coffee +0 -284
  54. data/data/weaver/js/plugins/skeuocard/javascripts/src/ExpirationInputView.coffee +0 -206
  55. data/data/weaver/js/plugins/skeuocard/javascripts/src/FlipTabView.coffee +0 -67
  56. data/data/weaver/js/plugins/skeuocard/javascripts/src/SegmentedCardNumberInputView.coffee +0 -284
  57. data/data/weaver/js/plugins/skeuocard/javascripts/src/Skeuocard.coffee +0 -439
  58. data/data/weaver/js/plugins/skeuocard/javascripts/src/TextInputView.coffee +0 -42
  59. data/data/weaver/js/plugins/skeuocard/javascripts/vendor/cssua.min.js +0 -7
  60. data/data/weaver/js/plugins/skeuocard/javascripts/vendor/demo.fix.js +0 -17
  61. data/data/weaver/js/plugins/skeuocard/javascripts/vendor/jquery-2.0.3.min.js +0 -5
  62. data/data/weaver/js/plugins/skeuocard/package-lock.json +0 -760
  63. data/data/weaver/js/plugins/skeuocard/package.json +0 -19
  64. data/data/weaver/js/plugins/skeuocard/screenshot.png +0 -0
  65. data/data/weaver/js/plugins/skeuocard/styles/demo.css +0 -2
  66. data/data/weaver/js/plugins/skeuocard/styles/demo.css.map +0 -7
  67. data/data/weaver/js/plugins/skeuocard/styles/skeuocard.css +0 -2
  68. data/data/weaver/js/plugins/skeuocard/styles/skeuocard.css.map +0 -7
  69. data/data/weaver/js/plugins/skeuocard/styles/skeuocard.reset.css +0 -2
  70. data/data/weaver/js/plugins/skeuocard/styles/skeuocard.reset.css.map +0 -7
  71. data/data/weaver/js/plugins/skeuocard/styles/src/_browser_hacks.scss +0 -52
  72. data/data/weaver/js/plugins/skeuocard/styles/src/_cards.scss +0 -516
  73. data/data/weaver/js/plugins/skeuocard/styles/src/_util.scss +0 -15
  74. data/data/weaver/js/plugins/skeuocard/styles/src/demo.scss +0 -265
  75. data/data/weaver/js/plugins/skeuocard/styles/src/skeuocard.reset.scss +0 -60
  76. data/data/weaver/js/plugins/skeuocard/styles/src/skeuocard.scss +0 -190
@@ -1,1748 +0,0 @@
1
- /*
2
- "Skeuocard" -- A Skeuomorphic Credit-Card Input Enhancement
3
- @description Skeuocard is a skeuomorphic credit card input plugin, supporting
4
- progressive enhancement. It renders a credit-card input which
5
- behaves similarly to a physical credit card.
6
- @author Ken Keiter <ken@kenkeiter.com>
7
- @updated 2013-07-25
8
- @website http://kenkeiter.com/
9
- @exports [window.Skeuocard]
10
- */
11
-
12
-
13
- (function() {
14
- var $, Skeuocard, visaProduct,
15
- __slice = [].slice,
16
- __hasProp = {}.hasOwnProperty,
17
- __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; };
18
-
19
- $ = jQuery;
20
-
21
- Skeuocard = (function() {
22
- Skeuocard.currentDate = new Date();
23
-
24
- function Skeuocard(el, opts) {
25
- var optDefaults;
26
- if (opts == null) {
27
- opts = {};
28
- }
29
- this.el = {
30
- container: $(el),
31
- underlyingFields: {}
32
- };
33
- this._inputViews = {};
34
- this._inputViewsByFace = {
35
- front: [],
36
- back: []
37
- };
38
- this._tabViews = {};
39
- this._state = {};
40
- this.product = null;
41
- this.visibleFace = 'front';
42
- optDefaults = {
43
- debug: false,
44
- dontFocus: false,
45
- acceptedCardProducts: null,
46
- cardNumberPlaceholderChar: 'X',
47
- genericPlaceholder: "XXXX XXXX XXXX XXXX",
48
- typeInputSelector: '[name="cc_type"]',
49
- numberInputSelector: '[name="cc_number"]',
50
- expMonthInputSelector: '[name="cc_exp_month"]',
51
- expYearInputSelector: '[name="cc_exp_year"]',
52
- nameInputSelector: '[name="cc_name"]',
53
- cvcInputSelector: '[name="cc_cvc"]',
54
- initialValues: {},
55
- validationState: {},
56
- strings: {
57
- hiddenFaceFillPrompt: "<strong>Click here</strong> to <br>fill in the other side.",
58
- hiddenFaceErrorWarning: "There's a problem on the other side.",
59
- hiddenFaceSwitchPrompt: "Forget something?<br> Flip the card over."
60
- }
61
- };
62
- this.options = $.extend(optDefaults, opts);
63
- this._conformDOM();
64
- this._bindInputEvents();
65
- this._importImplicitOptions();
66
- this.render();
67
- }
68
-
69
- Skeuocard.prototype._log = function() {
70
- var msg;
71
- msg = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
72
- if ((typeof console !== "undefined" && console !== null ? console.log : void 0) && !!this.options.debug) {
73
- if (this.options.debug != null) {
74
- return console.log.apply(console, ["[skeuocard]"].concat(__slice.call(msg)));
75
- }
76
- }
77
- };
78
-
79
- Skeuocard.prototype.trigger = function() {
80
- var args, _ref;
81
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
82
- return (_ref = this.el.container).trigger.apply(_ref, args);
83
- };
84
-
85
- Skeuocard.prototype.bind = function() {
86
- var args, _ref;
87
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
88
- return (_ref = this.el.container).bind.apply(_ref, args);
89
- };
90
-
91
- /*
92
- Transform the elements within the container, conforming the DOM so that it
93
- becomes styleable, and that the underlying inputs are hidden.
94
- */
95
-
96
-
97
- Skeuocard.prototype._conformDOM = function() {
98
- var elem, name, _ref, _ref1;
99
- this.el.container.removeClass('no-js');
100
- this.el.container.addClass("skeuocard js");
101
- this.el.underlyingFields = {
102
- type: this.el.container.find(this.options.typeInputSelector),
103
- number: this.el.container.find(this.options.numberInputSelector),
104
- expMonth: this.el.container.find(this.options.expMonthInputSelector),
105
- expYear: this.el.container.find(this.options.expYearInputSelector),
106
- name: this.el.container.find(this.options.nameInputSelector),
107
- cvc: this.el.container.find(this.options.cvcInputSelector)
108
- };
109
- _ref = this.el.underlyingFields;
110
- for (name in _ref) {
111
- if (!__hasProp.call(_ref, name)) continue;
112
- elem = _ref[name];
113
- $(elem).detach();
114
- }
115
- this.el.container.find("> :not(input,select,textarea)").remove();
116
- _ref1 = this.el.underlyingFields;
117
- for (name in _ref1) {
118
- if (!__hasProp.call(_ref1, name)) continue;
119
- elem = _ref1[name];
120
- $(elem).appendTo(this.el.container);
121
- }
122
- this.el.container.find("> input,select,textarea").hide();
123
- this.el.front = $("<div>").attr({
124
- "class": "face front"
125
- });
126
- this.el.back = $("<div>").attr({
127
- "class": "face back"
128
- });
129
- this.el.cardBody = $("<div>").attr({
130
- "class": "card-body"
131
- });
132
- this.el.front.appendTo(this.el.cardBody);
133
- this.el.back.appendTo(this.el.cardBody);
134
- this.el.cardBody.appendTo(this.el.container);
135
- this._tabViews.front = new Skeuocard.prototype.FlipTabView(this, 'front', {
136
- strings: this.options.strings
137
- });
138
- this._tabViews.back = new Skeuocard.prototype.FlipTabView(this, 'back', {
139
- strings: this.options.strings
140
- });
141
- this.el.front.prepend(this._tabViews.front.el);
142
- this.el.back.prepend(this._tabViews.back.el);
143
- this._tabViews.front.hide();
144
- this._tabViews.back.hide();
145
- this._inputViews = {
146
- number: new this.SegmentedCardNumberInputView(),
147
- exp: new this.ExpirationInputView({
148
- currentDate: this.options.currentDate
149
- }),
150
- name: new this.TextInputView({
151
- "class": "cc-name",
152
- placeholder: "YOUR NAME"
153
- }),
154
- cvc: new this.TextInputView({
155
- "class": "cc-cvc",
156
- placeholder: "XXX",
157
- requireMaxLength: true
158
- })
159
- };
160
- this._inputViews.number.el.addClass('cc-number');
161
- this._inputViews.number.el.appendTo(this.el.front);
162
- this._inputViews.name.el.appendTo(this.el.front);
163
- this._inputViews.exp.el.addClass('cc-exp');
164
- this._inputViews.exp.el.appendTo(this.el.front);
165
- this._inputViews.cvc.el.appendTo(this.el.back);
166
- return this.el.container;
167
- };
168
-
169
- /*
170
- Import implicit initialization options from the DOM. Brings in things like
171
- the accepted card type, initial validation state, existing values, etc.
172
- */
173
-
174
-
175
- Skeuocard.prototype._importImplicitOptions = function() {
176
- var fieldEl, fieldName, _initialExp, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6,
177
- _this = this;
178
- _ref = this.el.underlyingFields;
179
- for (fieldName in _ref) {
180
- fieldEl = _ref[fieldName];
181
- if (this.options.initialValues[fieldName] == null) {
182
- this.options.initialValues[fieldName] = fieldEl.val();
183
- } else {
184
- this.options.initialValues[fieldName] = this.options.initialValues[fieldName].toString();
185
- this._setUnderlyingValue(fieldName, this.options.initialValues[fieldName]);
186
- }
187
- if (((_ref1 = this.options.initialValues[fieldName]) != null ? _ref1.length : void 0) > 0) {
188
- this._state['initiallyFilled'] = true;
189
- }
190
- if (this.options.validationState[fieldName] == null) {
191
- this.options.validationState[fieldName] = !fieldEl.hasClass('invalid');
192
- }
193
- }
194
- if (this.options.acceptedCardProducts == null) {
195
- this.options.acceptedCardProducts = [];
196
- this.el.underlyingFields.type.find('option').each(function(i, _el) {
197
- var el, shortname;
198
- el = $(_el);
199
- shortname = el.attr('data-sc-type') || el.attr('value');
200
- return _this.options.acceptedCardProducts.push(shortname);
201
- });
202
- }
203
- if (((_ref2 = this.options.initialValues.number) != null ? _ref2.length : void 0) > 0) {
204
- this.set('number', this.options.initialValues.number);
205
- }
206
- if (((_ref3 = this.options.initialValues.name) != null ? _ref3.length : void 0) > 0) {
207
- this.set('name', this.options.initialValues.name);
208
- }
209
- if (((_ref4 = this.options.initialValues.cvc) != null ? _ref4.length : void 0) > 0) {
210
- this.set('cvc', this.options.initialValues.cvc);
211
- }
212
- if (((_ref5 = this.options.initialValues.expYear) != null ? _ref5.length : void 0) > 0 && ((_ref6 = this.options.initialValues.expMonth) != null ? _ref6.length : void 0) > 0) {
213
- _initialExp = new Date(parseInt(this.options.initialValues.expYear), parseInt(this.options.initialValues.expMonth) - 1, 1);
214
- this.set('exp', _initialExp);
215
- }
216
- this._updateValidationForFace('front');
217
- return this._updateValidationForFace('back');
218
- };
219
-
220
- Skeuocard.prototype.set = function(field, newValue) {
221
- this._inputViews[field].setValue(newValue);
222
- return this._inputViews[field].trigger('valueChanged', this._inputViews[field]);
223
- };
224
-
225
- /*
226
- Bind interaction events to their appropriate handlers.
227
- */
228
-
229
-
230
- Skeuocard.prototype._bindInputEvents = function() {
231
- var _expirationChange,
232
- _this = this;
233
- this.el.underlyingFields.number.bind("change", function(e) {
234
- _this._inputViews.number.setValue(_this._getUnderlyingValue('number'));
235
- return _this.render();
236
- });
237
- _expirationChange = function(e) {
238
- var month, year;
239
- month = parseInt(_this._getUnderlyingValue('expMonth'));
240
- year = parseInt(_this._getUnderlyingValue('expYear'));
241
- _this._inputViews.exp.setValue(new Date(year, month - 1));
242
- return _this.render();
243
- };
244
- this.el.underlyingFields.expMonth.bind("change", _expirationChange);
245
- this.el.underlyingFields.expYear.bind("change", _expirationChange);
246
- this.el.underlyingFields.name.bind("change", function(e) {
247
- _this._inputViews.exp.setValue(_this._getUnderlyingValue('name'));
248
- return _this.render();
249
- });
250
- this.el.underlyingFields.cvc.bind("change", function(e) {
251
- _this._inputViews.exp.setValue(_this._getUnderlyingValue('cvc'));
252
- return _this.render();
253
- });
254
- this._inputViews.number.bind("change valueChanged", function(e, input) {
255
- var cardNumber, matchedProduct, number, previousProduct, _ref, _ref1;
256
- cardNumber = input.getValue();
257
- _this._setUnderlyingValue('number', cardNumber);
258
- _this._updateValidation('number', cardNumber);
259
- number = _this._getUnderlyingValue('number');
260
- matchedProduct = Skeuocard.prototype.CardProduct.firstMatchingNumber(number);
261
- if (!((_ref = _this.product) != null ? _ref.eql(matchedProduct) : void 0)) {
262
- _this._log("Product will change:", _this.product, "=>", matchedProduct);
263
- if (_ref1 = matchedProduct != null ? matchedProduct.attrs.companyShortname : void 0, __indexOf.call(_this.options.acceptedCardProducts, _ref1) >= 0) {
264
- _this.trigger('productWillChange.skeuocard', [_this, _this.product, matchedProduct]);
265
- previousProduct = _this.product;
266
- _this.el.container.removeClass('unaccepted');
267
- _this._renderProduct(matchedProduct);
268
- _this.product = matchedProduct;
269
- } else if (matchedProduct != null) {
270
- _this.trigger('productWillChange.skeuocard', [_this, _this.product, null]);
271
- _this.el.container.addClass('unaccepted');
272
- _this._renderProduct(null);
273
- _this.product = null;
274
- } else {
275
- _this.trigger('productWillChange.skeuocard', [_this, _this.product, null]);
276
- _this.el.container.removeClass('unaccepted');
277
- _this._renderProduct(null);
278
- _this.product = null;
279
- }
280
- return _this.trigger('productDidChange.skeuocard', [_this, previousProduct, _this.product]);
281
- }
282
- });
283
- this._inputViews.exp.bind("keyup valueChanged", function(e, input) {
284
- var newDate;
285
- newDate = input.getValue();
286
- _this._updateValidation('exp', newDate);
287
- if (newDate != null) {
288
- _this._setUnderlyingValue('expMonth', newDate.getMonth() + 1);
289
- return _this._setUnderlyingValue('expYear', newDate.getFullYear());
290
- }
291
- });
292
- this._inputViews.name.bind("keyup valueChanged", function(e, input) {
293
- var value;
294
- value = input.getValue();
295
- _this._setUnderlyingValue('name', value);
296
- return _this._updateValidation('name', value);
297
- });
298
- this._inputViews.cvc.bind("keyup valueChanged", function(e, input) {
299
- var value;
300
- value = input.getValue();
301
- _this._setUnderlyingValue('cvc', value);
302
- return _this._updateValidation('cvc', value);
303
- });
304
- this.el.container.delegate("input", "keyup keydown", this._handleFieldTab.bind(this));
305
- this._tabViews.front.el.click(function() {
306
- return _this.flip();
307
- });
308
- return this._tabViews.back.el.click(function() {
309
- return _this.flip();
310
- });
311
- };
312
-
313
- Skeuocard.prototype._handleFieldTab = function(e) {
314
- var backFieldEls, currentFieldEl, frontFieldEls, _currentFace, _oppositeFace;
315
- if (e.which === 9) {
316
- currentFieldEl = $(e.currentTarget);
317
- _oppositeFace = this.visibleFace === 'front' ? 'back' : 'front';
318
- _currentFace = this.visibleFace === 'front' ? 'front' : 'back';
319
- backFieldEls = this.el[_oppositeFace].find('input');
320
- frontFieldEls = this.el[_currentFace].find('input');
321
- if (this.visibleFace === 'front' && this.el.front.hasClass('filled') && backFieldEls.length > 0 && frontFieldEls.index(currentFieldEl) === frontFieldEls.length - 1 && !e.shiftKey) {
322
- this.flip();
323
- backFieldEls.first().focus();
324
- e.preventDefault();
325
- }
326
- if (this.visibleFace === 'back' && e.shiftKey) {
327
- this.flip();
328
- backFieldEls.last().focus();
329
- e.preventDefault();
330
- }
331
- }
332
- return true;
333
- };
334
-
335
- Skeuocard.prototype._updateValidation = function(fieldName, newValue) {
336
- var fillStateChanged, isFilled, isFixed, isValid, needsFix, validationStateChanged;
337
- if (this.product == null) {
338
- return false;
339
- }
340
- isFilled = this.product[fieldName].isFilled(newValue);
341
- needsFix = (this.options.validationState[fieldName] != null) === false;
342
- isFixed = (this.options.initialValues[fieldName] != null) && newValue !== this.options.initialValues[fieldName];
343
- isValid = this.product[fieldName].isValid(newValue) && ((needsFix && isFixed) || true);
344
- fillStateChanged = this._state["" + fieldName + "Filled"] !== isFilled;
345
- validationStateChanged = this._state["" + fieldName + "Valid"] !== isValid;
346
- if (fillStateChanged) {
347
- this.trigger("fieldFillStateWillChange.skeuocard", [this, fieldName, isFilled]);
348
- this._inputViews[fieldName].el.toggleClass('filled', isFilled);
349
- this._state["" + fieldName + "Filled"] = isFilled;
350
- this.trigger("fieldFillStateDidChange.skeuocard", [this, fieldName, isFilled]);
351
- }
352
- if (validationStateChanged) {
353
- this.trigger("fieldValidationStateWillChange.skeuocard", [this, fieldName, isValid]);
354
- this._inputViews[fieldName].el.toggleClass('valid', isValid);
355
- this._inputViews[fieldName].el.toggleClass('invalid', !isValid);
356
- this._state["" + fieldName + "Valid"] = isValid;
357
- this.trigger("fieldValidationStateDidChange.skeuocard", [this, fieldName, isValid]);
358
- }
359
- this._updateValidationForFace('front');
360
- return this._updateValidationForFace('back');
361
- };
362
-
363
- Skeuocard.prototype._updateValidationForFace = function(face) {
364
- var fieldsFilled, fieldsValid, fillStateChanged, isFilled, isValid, iv, validationStateChanged;
365
- fieldsFilled = ((function() {
366
- var _i, _len, _ref, _results;
367
- _ref = this._inputViewsByFace[face];
368
- _results = [];
369
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
370
- iv = _ref[_i];
371
- _results.push(iv.el.hasClass('filled'));
372
- }
373
- return _results;
374
- }).call(this)).every(Boolean);
375
- fieldsValid = ((function() {
376
- var _i, _len, _ref, _results;
377
- _ref = this._inputViewsByFace[face];
378
- _results = [];
379
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
380
- iv = _ref[_i];
381
- _results.push(iv.el.hasClass('valid'));
382
- }
383
- return _results;
384
- }).call(this)).every(Boolean);
385
- isFilled = (fieldsFilled && (this.product != null)) || (this._state['initiallyFilled'] || false);
386
- isValid = fieldsValid && (this.product != null);
387
- fillStateChanged = this._state["" + face + "Filled"] !== isFilled;
388
- validationStateChanged = this._state["" + face + "Valid"] !== isValid;
389
- if (fillStateChanged) {
390
- this.trigger("faceFillStateWillChange.skeuocard", [this, face, isFilled]);
391
- this.el[face].toggleClass('filled', isFilled);
392
- this._state["" + face + "Filled"] = isFilled;
393
- this.trigger("faceFillStateDidChange.skeuocard", [this, face, isFilled]);
394
- }
395
- if (validationStateChanged) {
396
- this.trigger("faceValidationStateWillChange.skeuocard", [this, face, isValid]);
397
- this.el[face].toggleClass('valid', isValid);
398
- this.el[face].toggleClass('invalid', !isValid);
399
- this._state["" + face + "Valid"] = isValid;
400
- return this.trigger("faceValidationStateDidChange.skeuocard", [this, face, isValid]);
401
- }
402
- };
403
-
404
- /*
405
- Assert rendering changes necessary for the current product. Passing a null
406
- value instead of a product will revert the card to a generic state.
407
- */
408
-
409
-
410
- Skeuocard.prototype._renderProduct = function(product) {
411
- var destFace, fieldName, focused, view, viewEl, _ref, _ref1,
412
- _this = this;
413
- this._log("[_renderProduct]", "Rendering product:", product);
414
- this.el.container.removeClass(function(index, css) {
415
- return (css.match(/\b(product|issuer)-\S+/g) || []).join(' ');
416
- });
417
- if ((product != null ? product.attrs.companyShortname : void 0) != null) {
418
- this.el.container.addClass("product-" + product.attrs.companyShortname);
419
- }
420
- if ((product != null ? product.attrs.issuerShortname : void 0) != null) {
421
- this.el.container.addClass("issuer-" + product.attrs.issuerShortname);
422
- }
423
- this._setUnderlyingValue('type', (product != null ? product.attrs.companyShortname : void 0) || null);
424
- this._inputViews.number.setGroupings((product != null ? product.attrs.cardNumberGrouping : void 0) || [this.options.genericPlaceholder.length], this.options.dontFocus);
425
- delete this.options.dontFocus;
426
- if (product != null) {
427
- this._inputViews.exp.reconfigure({
428
- pattern: (product != null ? product.attrs.expirationFormat : void 0) || "MM/YY"
429
- });
430
- this._inputViews.cvc.attr({
431
- maxlength: product.attrs.cvcLength,
432
- placeholder: new Array(product.attrs.cvcLength + 1).join(this.options.cardNumberPlaceholderChar)
433
- });
434
- this._inputViewsByFace = {
435
- front: [],
436
- back: []
437
- };
438
- focused = $('input:focus');
439
- _ref = product.attrs.layout;
440
- for (fieldName in _ref) {
441
- destFace = _ref[fieldName];
442
- this._log("Moving", fieldName, "to", destFace);
443
- viewEl = this._inputViews[fieldName].el.detach();
444
- viewEl.appendTo(this.el[destFace]);
445
- this._inputViewsByFace[destFace].push(this._inputViews[fieldName]);
446
- this._inputViews[fieldName].show();
447
- }
448
- setTimeout(function() {
449
- var fieldEl, fieldLength;
450
- fieldEl = focused.first();
451
- if (fieldEl.length) {
452
- fieldLength = fieldEl[0].maxLength;
453
- fieldEl.focus();
454
- return fieldEl[0].setSelectionRange(fieldLength, fieldLength);
455
- }
456
- }, 10);
457
- } else {
458
- _ref1 = this._inputViews;
459
- for (fieldName in _ref1) {
460
- view = _ref1[fieldName];
461
- if (fieldName !== 'number') {
462
- view.hide();
463
- }
464
- }
465
- }
466
- return product;
467
- };
468
-
469
- Skeuocard.prototype._renderValidation = function() {
470
- var fieldName, fieldView, _ref, _results;
471
- _ref = this._inputViews;
472
- _results = [];
473
- for (fieldName in _ref) {
474
- fieldView = _ref[fieldName];
475
- _results.push(this._updateValidation(fieldName, fieldView.getValue()));
476
- }
477
- return _results;
478
- };
479
-
480
- Skeuocard.prototype.render = function() {
481
- this._renderProduct(this.product);
482
- return this._renderValidation();
483
- };
484
-
485
- Skeuocard.prototype.flip = function() {
486
- var surfaceName, targetFace;
487
- targetFace = this.visibleFace === 'front' ? 'back' : 'front';
488
- this.trigger('faceWillBecomeVisible.skeuocard', [this, targetFace]);
489
- this.visibleFace = targetFace;
490
- this.el.cardBody.toggleClass('flip');
491
- surfaceName = this.visibleFace === 'front' ? 'front' : 'back';
492
- this.el[surfaceName].find('.cc-field').not('.filled').find('input').first().focus();
493
- return this.trigger('faceDidBecomeVisible.skeuocard', [this, targetFace]);
494
- };
495
-
496
- Skeuocard.prototype._setUnderlyingValue = function(field, newValue) {
497
- var fieldEl, remapAttrKey, _newValue,
498
- _this = this;
499
- fieldEl = this.el.underlyingFields[field];
500
- _newValue = (newValue || "").toString();
501
- if (fieldEl == null) {
502
- throw "Set underlying value of unknown field: " + field + ".";
503
- }
504
- this.trigger('change.skeuocard', [this]);
505
- if (!fieldEl.is('select')) {
506
- return this.el.underlyingFields[field].val(_newValue);
507
- } else {
508
- remapAttrKey = "data-sc-" + field.toLowerCase();
509
- return fieldEl.find('option').each(function(i, _el) {
510
- var optionEl;
511
- optionEl = $(_el);
512
- if (_newValue === (optionEl.attr(remapAttrKey) || optionEl.attr('value'))) {
513
- return _this.el.underlyingFields[field].val(optionEl.attr('value'));
514
- }
515
- });
516
- }
517
- };
518
-
519
- Skeuocard.prototype._getUnderlyingValue = function(field) {
520
- var _ref;
521
- return (_ref = this.el.underlyingFields[field]) != null ? _ref.val() : void 0;
522
- };
523
-
524
- Skeuocard.prototype.isValid = function() {
525
- if (this.product) {
526
- if (this.product.faces === 'both') {
527
- return !this.el.front.hasClass('invalid') && !this.el.back.hasClass('invalid');
528
- } else if (this.product.faces === 'front') {
529
- return !this.el.front.hasClass('invalid');
530
- } else {
531
- return !this.el.back.hasClass('invalid');
532
- }
533
- } else {
534
- return false;
535
- }
536
- };
537
-
538
- return Skeuocard;
539
-
540
- })();
541
-
542
- window.Skeuocard = Skeuocard;
543
-
544
- /*
545
- Skeuocard::FlipTabView
546
- Handles rendering of the "flip button" control and its various warning and
547
- prompt states.
548
- */
549
-
550
-
551
- Skeuocard.prototype.FlipTabView = (function() {
552
- function FlipTabView(sc, face, opts) {
553
- var _this = this;
554
- if (opts == null) {
555
- opts = {};
556
- }
557
- this.card = sc;
558
- this.face = face;
559
- this.el = $("<div class=\"flip-tab " + face + "\"><p></p></div>");
560
- this.options = opts;
561
- this._state = {};
562
- this.card.bind('faceFillStateWillChange.skeuocard', this._faceStateChanged.bind(this));
563
- this.card.bind('faceValidationStateWillChange.skeuocard', this._faceValidationChanged.bind(this));
564
- this.card.bind('productWillChange.skeuocard', function(e, card, prevProduct, newProduct) {
565
- if (newProduct != null) {
566
- if (newProduct.faces === _this.face) {
567
- return _this.hide();
568
- } else {
569
- return _this.show();
570
- }
571
- } else {
572
- return _this.hide();
573
- }
574
- });
575
- }
576
-
577
- FlipTabView.prototype._faceStateChanged = function(e, card, face, isFilled) {
578
- var oppositeFace;
579
- oppositeFace = face === 'front' ? 'back' : 'front';
580
- if (isFilled === true && this.card._inputViewsByFace[oppositeFace].length > 0) {
581
- this.show();
582
- }
583
- if (face !== this.face) {
584
- this._state.opposingFaceFilled = isFilled;
585
- }
586
- if (this._state.opposingFaceFilled !== true) {
587
- return this.warn(this.options.strings.hiddenFaceFillPrompt, true);
588
- }
589
- };
590
-
591
- FlipTabView.prototype._faceValidationChanged = function(e, card, face, isValid) {
592
- if (face !== this.face) {
593
- this._state.opposingFaceValid = isValid;
594
- }
595
- if (this._state.opposingFaceValid) {
596
- return this.prompt(this.options.strings.hiddenFaceSwitchPrompt);
597
- } else {
598
- if (this._state.opposingFaceFilled) {
599
- return this.warn(this.options.strings.hiddenFaceErrorWarning);
600
- } else {
601
- return this.warn(this.options.strings.hiddenFaceFillPrompt);
602
- }
603
- }
604
- };
605
-
606
- FlipTabView.prototype._setText = function(text) {
607
- return this.el.find('p').first().html(text);
608
- };
609
-
610
- FlipTabView.prototype.warn = function(message) {
611
- this._resetClasses();
612
- this._setText(message);
613
- return this.el.addClass('warn');
614
- };
615
-
616
- FlipTabView.prototype.prompt = function(message) {
617
- this._resetClasses();
618
- this._setText(message);
619
- return this.el.addClass('prompt');
620
- };
621
-
622
- FlipTabView.prototype._resetClasses = function() {
623
- this.el.removeClass('warn');
624
- return this.el.removeClass('prompt');
625
- };
626
-
627
- FlipTabView.prototype.show = function() {
628
- return this.el.show();
629
- };
630
-
631
- FlipTabView.prototype.hide = function() {
632
- return this.el.hide();
633
- };
634
-
635
- return FlipTabView;
636
-
637
- })();
638
-
639
- /*
640
- # Skeuocard::SegmentedCardNumberInputView
641
- # Provides a reconfigurable segmented input view for credit card numbers.
642
- */
643
-
644
-
645
- Skeuocard.prototype.SegmentedCardNumberInputView = (function() {
646
- SegmentedCardNumberInputView.prototype._digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
647
-
648
- SegmentedCardNumberInputView.prototype._keys = {
649
- backspace: 8,
650
- tab: 9,
651
- enter: 13,
652
- del: 46,
653
- arrowLeft: 37,
654
- arrowUp: 38,
655
- arrowRight: 39,
656
- arrowDown: 40,
657
- arrows: [37, 38, 39, 40],
658
- command: 16,
659
- alt: 17
660
- };
661
-
662
- SegmentedCardNumberInputView.prototype._specialKeys = [8, 9, 13, 46, 37, 38, 39, 40, 16, 17];
663
-
664
- function SegmentedCardNumberInputView(opts) {
665
- if (opts == null) {
666
- opts = {};
667
- }
668
- this.optDefaults = {
669
- value: "",
670
- groupings: [19],
671
- placeholderChar: "X"
672
- };
673
- this.options = $.extend({}, this.optDefaults, opts);
674
- this._state = {
675
- selectingAll: false
676
- };
677
- this._buildDOM();
678
- this.setGroupings(this.options.groupings);
679
- }
680
-
681
- SegmentedCardNumberInputView.prototype._buildDOM = function() {
682
- var _this = this;
683
- this.el = $('<fieldset>');
684
- this.el.addClass('cc-field');
685
- this.el.delegate("input", "keypress", this._handleGroupKeyPress.bind(this));
686
- this.el.delegate("input", "keydown", this._handleGroupKeyDown.bind(this));
687
- this.el.delegate("input", "keyup", this._handleGroupKeyUp.bind(this));
688
- this.el.delegate("input", "paste", this._handleGroupPaste.bind(this));
689
- this.el.delegate("input", "change", this._handleGroupChange.bind(this));
690
- this.el.delegate("input", "focus", function(e) {
691
- return _this.el.addClass('focus');
692
- });
693
- return this.el.delegate("input", "blur", function(e) {
694
- return _this.el.removeClass('focus');
695
- });
696
- };
697
-
698
- SegmentedCardNumberInputView.prototype._handleGroupKeyDown = function(e) {
699
- var currentTarget, cursorEnd, cursorStart, inputGroupEl, inputMaxLength, nextInputEl, prevInputEl, _ref;
700
- if (e.ctrlKey || e.metaKey) {
701
- return this._handleModifiedKeyDown(e);
702
- }
703
- inputGroupEl = $(e.currentTarget);
704
- currentTarget = e.currentTarget;
705
- cursorStart = currentTarget.selectionStart;
706
- cursorEnd = currentTarget.selectionEnd;
707
- inputMaxLength = currentTarget.maxLength;
708
- prevInputEl = inputGroupEl.prevAll('input');
709
- nextInputEl = inputGroupEl.nextAll('input');
710
- switch (e.which) {
711
- case this._keys.backspace:
712
- if (prevInputEl.length > 0 && cursorEnd === 0) {
713
- this._focusField(prevInputEl.first(), 'end');
714
- }
715
- break;
716
- case this._keys.arrowUp:
717
- if (cursorEnd === inputMaxLength) {
718
- this._focusField(inputGroupEl, 'start');
719
- } else {
720
- this._focusField(inputGroupEl.prev(), 'end');
721
- }
722
- e.preventDefault();
723
- break;
724
- case this._keys.arrowDown:
725
- if (cursorEnd === inputMaxLength) {
726
- this._focusField(inputGroupEl.next(), 'start');
727
- } else {
728
- this._focusField(inputGroupEl, 'end');
729
- }
730
- e.preventDefault();
731
- break;
732
- case this._keys.arrowLeft:
733
- if (cursorEnd === 0) {
734
- this._focusField(inputGroupEl.prev(), 'end');
735
- e.preventDefault();
736
- }
737
- break;
738
- case this._keys.arrowRight:
739
- if (cursorEnd === inputMaxLength) {
740
- this._focusField(inputGroupEl.next(), 'start');
741
- e.preventDefault();
742
- }
743
- break;
744
- default:
745
- if (!(_ref = e.which, __indexOf.call(this._specialKeys, _ref) >= 0) && (cursorStart === inputMaxLength && cursorEnd === inputMaxLength) && nextInputEl.length !== 0) {
746
- this._focusField(nextInputEl.first(), 'start');
747
- }
748
- }
749
- return true;
750
- };
751
-
752
- SegmentedCardNumberInputView.prototype._handleGroupKeyPress = function(e) {
753
- var inputGroupEl, isDigit, _ref, _ref1;
754
- inputGroupEl = $(e.currentTarget);
755
- isDigit = (_ref = String.fromCharCode(e.which), __indexOf.call(this._digits, _ref) >= 0);
756
- if (e.ctrlKey || e.metaKey) {
757
- return true;
758
- }
759
- if (e.which === 0) {
760
- return true;
761
- }
762
- if ((!e.shiftKey && (_ref1 = e.which, __indexOf.call(this._specialKeys, _ref1) >= 0)) || isDigit) {
763
- return true;
764
- }
765
- e.preventDefault();
766
- return false;
767
- };
768
-
769
- SegmentedCardNumberInputView.prototype._handleGroupKeyUp = function(e) {
770
- var currentTarget, cursorEnd, cursorStart, inputGroupEl, inputMaxLength, nextInputEl, _ref, _ref1, _ref2;
771
- inputGroupEl = $(e.currentTarget);
772
- currentTarget = e.currentTarget;
773
- inputMaxLength = currentTarget.maxLength;
774
- cursorStart = currentTarget.selectionStart;
775
- cursorEnd = currentTarget.selectionEnd;
776
- nextInputEl = inputGroupEl.nextAll('input');
777
- if (e.ctrlKey || e.metaKey) {
778
- return true;
779
- }
780
- if (this._state.selectingAll && (_ref = e.which, __indexOf.call(this._specialKeys, _ref) >= 0) && e.which !== this._keys.command && e.which !== this._keys.alt) {
781
- this._endSelectAll();
782
- }
783
- if (!(_ref1 = e.which, __indexOf.call(this._specialKeys, _ref1) >= 0) && !(e.shiftKey && e.which === this._keys.tab) && (cursorStart === inputMaxLength && cursorEnd === inputMaxLength) && nextInputEl.length !== 0) {
784
- this._focusField(nextInputEl.first(), 'start');
785
- }
786
- if (!(e.shiftKey && (_ref2 = e.which, __indexOf.call(this._specialKeys, _ref2) >= 0))) {
787
- this.trigger('change', [this]);
788
- }
789
- return true;
790
- };
791
-
792
- SegmentedCardNumberInputView.prototype._handleModifiedKeyDown = function(e) {
793
- var char;
794
- char = String.fromCharCode(e.which);
795
- switch (char) {
796
- case 'a':
797
- case 'A':
798
- this._beginSelectAll();
799
- return e.preventDefault();
800
- }
801
- };
802
-
803
- SegmentedCardNumberInputView.prototype._handleGroupPaste = function(e) {
804
- var _this = this;
805
- return setTimeout(function() {
806
- var newValue;
807
- newValue = _this.getValue().replace(/[^0-9]+/g, '');
808
- if (_this._state.selectingAll) {
809
- _this._endSelectAll();
810
- }
811
- _this.setValue(newValue);
812
- return _this.trigger('change', [_this]);
813
- }, 50);
814
- };
815
-
816
- SegmentedCardNumberInputView.prototype._handleGroupChange = function(e) {
817
- return e.stopPropagation();
818
- };
819
-
820
- SegmentedCardNumberInputView.prototype._getFocusedField = function() {
821
- return this.el.find("input:focus");
822
- };
823
-
824
- SegmentedCardNumberInputView.prototype._beginSelectAll = function() {
825
- var fieldEl;
826
- if (!this.el.hasClass('selecting-all')) {
827
- this._state.lastGrouping = this.options.groupings;
828
- this._state.lastLength = this.getValue().length;
829
- this.setGroupings(this.optDefaults.groupings);
830
- this.el.addClass('selecting-all');
831
- fieldEl = this.el.find("input");
832
- fieldEl[0].setSelectionRange(0, fieldEl.val().length);
833
- return this._state.selectingAll = true;
834
- } else {
835
- fieldEl = this.el.find("input");
836
- return fieldEl[0].setSelectionRange(0, fieldEl.val().length);
837
- }
838
- };
839
-
840
- SegmentedCardNumberInputView.prototype._endSelectAll = function() {
841
- if (this.el.hasClass('selecting-all')) {
842
- this._state.selectingAll = false;
843
- if (this._state.lastLength === this.getValue().length) {
844
- this.setGroupings(this._state.lastGrouping);
845
- }
846
- return this.el.removeClass('selecting-all');
847
- }
848
- };
849
-
850
- SegmentedCardNumberInputView.prototype._indexInValueAtFieldSelection = function(field) {
851
- var groupingIndex, i, len, offset, _i, _len, _ref;
852
- groupingIndex = this.el.find('input').index(field);
853
- offset = 0;
854
- _ref = this.options.groupings;
855
- for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
856
- len = _ref[i];
857
- if (i < groupingIndex) {
858
- offset += len;
859
- }
860
- }
861
- return offset + field[0].selectionEnd;
862
- };
863
-
864
- SegmentedCardNumberInputView.prototype.setGroupings = function(groupings, dontFocus) {
865
- var groupEl, groupLength, _caretPosition, _currentField, _i, _len, _value;
866
- _currentField = this._getFocusedField();
867
- _value = this.getValue();
868
- _caretPosition = 0;
869
- if (_currentField.length > 0) {
870
- _caretPosition = this._indexInValueAtFieldSelection(_currentField);
871
- }
872
- this.el.empty();
873
- for (_i = 0, _len = groupings.length; _i < _len; _i++) {
874
- groupLength = groupings[_i];
875
- groupEl = $("<input>").attr({
876
- type: 'text',
877
- pattern: '[0-9]*',
878
- size: groupLength,
879
- maxlength: groupLength,
880
- "class": "group" + groupLength,
881
- placeholder: new Array(groupLength + 1).join(this.options.placeholderChar)
882
- });
883
- this.el.append(groupEl);
884
- }
885
- this.options.groupings = groupings;
886
- this.setValue(_value);
887
- _currentField = this._focusFieldForValue([_caretPosition, _caretPosition], dontFocus);
888
- if ((_currentField != null) && _currentField[0].selectionEnd === _currentField[0].maxLength) {
889
- return this._focusField(_currentField.next(), 'start');
890
- }
891
- };
892
-
893
- SegmentedCardNumberInputView.prototype._focusFieldForValue = function(place, dontFocus) {
894
- var field, fieldOffset, fieldPosition, groupIndex, groupLength, value, _i, _lastStartPos, _len, _ref;
895
- value = this.getValue();
896
- if (place === 'start') {
897
- field = this.el.find('input').first();
898
- if (!dontFocus) {
899
- this._focusField(field, place);
900
- }
901
- } else if (place === 'end') {
902
- field = this.el.find('input').last();
903
- if (!dontFocus) {
904
- this._focusField(field, place);
905
- }
906
- } else {
907
- field = null;
908
- fieldOffset = null;
909
- _lastStartPos = 0;
910
- _ref = this.options.groupings;
911
- for (groupIndex = _i = 0, _len = _ref.length; _i < _len; groupIndex = ++_i) {
912
- groupLength = _ref[groupIndex];
913
- if (place[1] > _lastStartPos && place[1] <= _lastStartPos + groupLength) {
914
- field = $(this.el.find('input')[groupIndex]);
915
- fieldPosition = place[1] - _lastStartPos;
916
- }
917
- _lastStartPos += groupLength;
918
- }
919
- if ((field != null) && (fieldPosition != null)) {
920
- if (!dontFocus) {
921
- this._focusField(field, [fieldPosition, fieldPosition]);
922
- }
923
- } else {
924
- if (!dontFocus) {
925
- this._focusField(this.el.find('input'), 'end');
926
- }
927
- }
928
- }
929
- return field;
930
- };
931
-
932
- SegmentedCardNumberInputView.prototype._focusField = function(field, place) {
933
- var fieldLen;
934
- if (field.length !== 0) {
935
- field[0].focus();
936
- if ($(field[0]).is(':visible') && field[0] === document.activeElement) {
937
- if (place === 'start') {
938
- return field[0].setSelectionRange(0, 0);
939
- } else if (place === 'end') {
940
- fieldLen = field[0].maxLength;
941
- return field[0].setSelectionRange(fieldLen, fieldLen);
942
- } else {
943
- return field[0].setSelectionRange(place[0], place[1]);
944
- }
945
- }
946
- }
947
- };
948
-
949
- SegmentedCardNumberInputView.prototype.setValue = function(newValue) {
950
- var el, groupIndex, groupLength, groupVal, _i, _lastStartPos, _len, _ref, _results;
951
- _lastStartPos = 0;
952
- _ref = this.options.groupings;
953
- _results = [];
954
- for (groupIndex = _i = 0, _len = _ref.length; _i < _len; groupIndex = ++_i) {
955
- groupLength = _ref[groupIndex];
956
- el = $(this.el.find('input').get(groupIndex));
957
- groupVal = newValue.substr(_lastStartPos, groupLength);
958
- el.val(groupVal);
959
- _results.push(_lastStartPos += groupLength);
960
- }
961
- return _results;
962
- };
963
-
964
- SegmentedCardNumberInputView.prototype.getValue = function() {
965
- var buffer, el, _i, _len, _ref;
966
- buffer = "";
967
- _ref = this.el.find('input');
968
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
969
- el = _ref[_i];
970
- buffer += $(el).val();
971
- }
972
- return buffer;
973
- };
974
-
975
- SegmentedCardNumberInputView.prototype.maxLength = function() {
976
- return this.options.groupings.reduce(function(a, b) {
977
- return a + b;
978
- });
979
- };
980
-
981
- SegmentedCardNumberInputView.prototype.bind = function() {
982
- var args, _ref;
983
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
984
- return (_ref = this.el).bind.apply(_ref, args);
985
- };
986
-
987
- SegmentedCardNumberInputView.prototype.trigger = function() {
988
- var args, _ref;
989
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
990
- return (_ref = this.el).trigger.apply(_ref, args);
991
- };
992
-
993
- SegmentedCardNumberInputView.prototype.show = function() {
994
- return this.el.show();
995
- };
996
-
997
- SegmentedCardNumberInputView.prototype.hide = function() {
998
- return this.el.hide();
999
- };
1000
-
1001
- SegmentedCardNumberInputView.prototype.addClass = function() {
1002
- var args, _ref;
1003
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1004
- return (_ref = this.el).addClass.apply(_ref, args);
1005
- };
1006
-
1007
- SegmentedCardNumberInputView.prototype.removeClass = function() {
1008
- var args, _ref;
1009
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1010
- return (_ref = this.el).removeClass.apply(_ref, args);
1011
- };
1012
-
1013
- return SegmentedCardNumberInputView;
1014
-
1015
- })();
1016
-
1017
- /*
1018
- Skeuocard::ExpirationInputView
1019
- */
1020
-
1021
-
1022
- Skeuocard.prototype.ExpirationInputView = (function() {
1023
- function ExpirationInputView(opts) {
1024
- var _this = this;
1025
- if (opts == null) {
1026
- opts = {};
1027
- }
1028
- opts.pattern || (opts.pattern = "MM/YY");
1029
- this.options = opts;
1030
- this.date = null;
1031
- this.el = $("<fieldset>");
1032
- this.el.addClass('cc-field');
1033
- this.el.delegate("input", "keydown", function(e) {
1034
- return _this._onKeyDown(e);
1035
- });
1036
- this.el.delegate("input", "keyup", function(e) {
1037
- return _this._onKeyUp(e);
1038
- });
1039
- this.el.delegate("input", "focus", function(e) {
1040
- return _this.el.addClass('focus');
1041
- });
1042
- this.el.delegate("input", "blur", function(e) {
1043
- return _this.el.removeClass('focus');
1044
- });
1045
- }
1046
-
1047
- ExpirationInputView.prototype.bind = function() {
1048
- var args, _ref;
1049
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1050
- return (_ref = this.el).bind.apply(_ref, args);
1051
- };
1052
-
1053
- ExpirationInputView.prototype.trigger = function() {
1054
- var args, _ref;
1055
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1056
- return (_ref = this.el).trigger.apply(_ref, args);
1057
- };
1058
-
1059
- ExpirationInputView.prototype._getFieldCaretPosition = function(el) {
1060
- var input, sel, selLength;
1061
- input = el.get(0);
1062
- if (input.selectionEnd != null) {
1063
- return input.selectionEnd;
1064
- } else if (document.selection) {
1065
- input.focus();
1066
- sel = document.selection.createRange();
1067
- selLength = document.selection.createRange().text.length;
1068
- sel.moveStart('character', -input.value.length);
1069
- return selLength;
1070
- }
1071
- };
1072
-
1073
- ExpirationInputView.prototype._setFieldCaretPosition = function(el, pos) {
1074
- var input, range;
1075
- input = el.get(0);
1076
- if (input.createTextRange != null) {
1077
- range = input.createTextRange();
1078
- range.move("character", pos);
1079
- return range.select();
1080
- } else if (input.selectionStart != null) {
1081
- input.focus();
1082
- return input.setSelectionRange(pos, pos);
1083
- }
1084
- };
1085
-
1086
- ExpirationInputView.prototype.setPattern = function(pattern) {
1087
- var char, groupings, i, patternParts, _currentLength, _i, _len;
1088
- groupings = [];
1089
- patternParts = pattern.split('');
1090
- _currentLength = 0;
1091
- for (i = _i = 0, _len = patternParts.length; _i < _len; i = ++_i) {
1092
- char = patternParts[i];
1093
- _currentLength++;
1094
- if (patternParts[i + 1] !== char) {
1095
- groupings.push([_currentLength, char]);
1096
- _currentLength = 0;
1097
- }
1098
- }
1099
- this.options.groupings = groupings;
1100
- return this._setGroupings(this.options.groupings);
1101
- };
1102
-
1103
- ExpirationInputView.prototype._setGroupings = function(groupings) {
1104
- var fieldChars, group, groupChar, groupLength, input, sep, _i, _len, _startLength;
1105
- fieldChars = ['D', 'M', 'Y'];
1106
- this.el.empty();
1107
- _startLength = 0;
1108
- for (_i = 0, _len = groupings.length; _i < _len; _i++) {
1109
- group = groupings[_i];
1110
- groupLength = group[0];
1111
- groupChar = group[1];
1112
- if (__indexOf.call(fieldChars, groupChar) >= 0) {
1113
- input = $('<input>').attr({
1114
- type: 'text',
1115
- pattern: '[0-9]*',
1116
- placeholder: new Array(groupLength + 1).join(groupChar),
1117
- maxlength: groupLength,
1118
- "class": 'cc-exp-field-' + groupChar.toLowerCase() + ' group' + groupLength
1119
- });
1120
- input.data('fieldtype', groupChar);
1121
- this.el.append(input);
1122
- } else {
1123
- sep = $('<span>').attr({
1124
- "class": 'separator'
1125
- });
1126
- sep.html(new Array(groupLength + 1).join(groupChar));
1127
- this.el.append(sep);
1128
- }
1129
- }
1130
- this.groupEls = this.el.find('input');
1131
- if (this.date != null) {
1132
- return this._updateFieldValues();
1133
- }
1134
- };
1135
-
1136
- ExpirationInputView.prototype._zeroPadNumber = function(num, places) {
1137
- var zero;
1138
- zero = places - num.toString().length + 1;
1139
- return Array(zero).join("0") + num;
1140
- };
1141
-
1142
- ExpirationInputView.prototype._updateFieldValues = function() {
1143
- var currentDate,
1144
- _this = this;
1145
- currentDate = this.date;
1146
- if (!this.groupEls) {
1147
- return this.setPattern(this.options.pattern);
1148
- }
1149
- return this.groupEls.each(function(i, _el) {
1150
- var el, groupLength, year;
1151
- el = $(_el);
1152
- groupLength = parseInt(el.attr('maxlength'));
1153
- switch (el.data('fieldtype')) {
1154
- case 'M':
1155
- return el.val(_this._zeroPadNumber(currentDate.getMonth() + 1, groupLength));
1156
- case 'D':
1157
- return el.val(_this._zeroPadNumber(currentDate.getDate(), groupLength));
1158
- case 'Y':
1159
- year = groupLength >= 4 ? currentDate.getFullYear() : currentDate.getFullYear().toString().substr(2, 4);
1160
- return el.val(year);
1161
- }
1162
- });
1163
- };
1164
-
1165
- ExpirationInputView.prototype.clear = function() {
1166
- this.value = "";
1167
- this.date = null;
1168
- return this.groupEls.each(function() {
1169
- return $(this).val('');
1170
- });
1171
- };
1172
-
1173
- ExpirationInputView.prototype.setValue = function(newDate) {
1174
- this.date = newDate;
1175
- return this._updateFieldValues();
1176
- };
1177
-
1178
- ExpirationInputView.prototype.getValue = function() {
1179
- return this.date;
1180
- };
1181
-
1182
- ExpirationInputView.prototype.reconfigure = function(opts) {
1183
- if (opts.pattern != null) {
1184
- this.setPattern(opts.pattern);
1185
- }
1186
- if (opts.value != null) {
1187
- return this.setValue(opts.value);
1188
- }
1189
- };
1190
-
1191
- ExpirationInputView.prototype._onKeyDown = function(e) {
1192
- var groupCaretPos, groupEl, groupMaxLength, nextInputEl, prevInputEl, _ref;
1193
- e.stopPropagation();
1194
- groupEl = $(e.currentTarget);
1195
- groupEl = $(e.currentTarget);
1196
- groupMaxLength = parseInt(groupEl.attr('maxlength'));
1197
- groupCaretPos = this._getFieldCaretPosition(groupEl);
1198
- prevInputEl = groupEl.prevAll('input').first();
1199
- nextInputEl = groupEl.nextAll('input').first();
1200
- if (e.which === 8 && groupCaretPos === 0 && !$.isEmptyObject(prevInputEl)) {
1201
- prevInputEl.focus();
1202
- }
1203
- if ((_ref = e.which) === 37 || _ref === 38 || _ref === 39 || _ref === 40) {
1204
- switch (e.which) {
1205
- case 37:
1206
- if (groupCaretPos === 0 && !$.isEmptyObject(prevInputEl)) {
1207
- return prevInputEl.focus();
1208
- }
1209
- break;
1210
- case 39:
1211
- if (groupCaretPos === groupMaxLength && !$.isEmptyObject(nextInputEl)) {
1212
- return nextInputEl.focus();
1213
- }
1214
- break;
1215
- case 38:
1216
- if (!$.isEmptyObject(groupEl.prev('input'))) {
1217
- return prevInputEl.focus();
1218
- }
1219
- break;
1220
- case 40:
1221
- if (!$.isEmptyObject(groupEl.next('input'))) {
1222
- return nextInputEl.focus();
1223
- }
1224
- }
1225
- }
1226
- };
1227
-
1228
- ExpirationInputView.prototype.getRawValue = function(fieldType) {
1229
- return parseInt(this.el.find(".cc-exp-field-" + fieldType).val());
1230
- };
1231
-
1232
- ExpirationInputView.prototype._onKeyUp = function(e) {
1233
- var arrowKeys, dateObj, day, groupCaretPos, groupEl, groupMaxLength, groupValLength, month, nextInputEl, pattern, specialKeys, year, _ref, _ref1;
1234
- e.stopPropagation();
1235
- specialKeys = [8, 9, 16, 17, 18, 19, 20, 27, 33, 34, 35, 36, 37, 38, 39, 40, 45, 46, 91, 93, 144, 145, 224];
1236
- arrowKeys = [37, 38, 39, 40];
1237
- groupEl = $(e.currentTarget);
1238
- groupMaxLength = parseInt(groupEl.attr('maxlength'));
1239
- groupCaretPos = this._getFieldCaretPosition(groupEl);
1240
- if (_ref = e.which, __indexOf.call(specialKeys, _ref) < 0) {
1241
- groupValLength = groupEl.val().length;
1242
- pattern = new RegExp('[^0-9]+', 'g');
1243
- groupEl.val(groupEl.val().replace(pattern, ''));
1244
- if (groupEl.val().length < groupValLength) {
1245
- this._setFieldCaretPosition(groupEl, groupCaretPos - 1);
1246
- } else {
1247
- this._setFieldCaretPosition(groupEl, groupCaretPos);
1248
- }
1249
- }
1250
- nextInputEl = groupEl.nextAll('input').first();
1251
- if ((_ref1 = e.which, __indexOf.call(specialKeys, _ref1) < 0) && groupEl.val().length === groupMaxLength && !$.isEmptyObject(nextInputEl) && this._getFieldCaretPosition(groupEl) === groupMaxLength) {
1252
- nextInputEl.focus();
1253
- }
1254
- day = this.getRawValue('d') || 1;
1255
- month = this.getRawValue('m');
1256
- year = this.getRawValue('y');
1257
- if (month === 0 || month > 12 || year === 0) {
1258
- this.date = new Date(1900, 0, 1);
1259
- } else {
1260
- if (year < 2000) {
1261
- year += 2000;
1262
- }
1263
- dateObj = new Date(year, month - 1, day);
1264
- this.date = dateObj;
1265
- }
1266
- this.trigger("keyup", [this]);
1267
- return false;
1268
- };
1269
-
1270
- ExpirationInputView.prototype._inputGroupEls = function() {
1271
- return this.el.find("input");
1272
- };
1273
-
1274
- ExpirationInputView.prototype.show = function() {
1275
- return this.el.show();
1276
- };
1277
-
1278
- ExpirationInputView.prototype.hide = function() {
1279
- return this.el.hide();
1280
- };
1281
-
1282
- return ExpirationInputView;
1283
-
1284
- })();
1285
-
1286
- /*
1287
- Skeuocard::TextInputView
1288
- */
1289
-
1290
-
1291
- Skeuocard.prototype.TextInputView = (function() {
1292
- function TextInputView(opts) {
1293
- var _this = this;
1294
- this.el = $('<div>');
1295
- this.inputEl = $("<input>").attr({
1296
- type: 'text',
1297
- placeholder: opts.placeholder,
1298
- "class": opts["class"]
1299
- });
1300
- this.el.append(this.inputEl);
1301
- this.el.addClass('cc-field');
1302
- this.options = opts;
1303
- this.el.delegate("input", "focus", function(e) {
1304
- return _this.el.addClass('focus');
1305
- });
1306
- this.el.delegate("input", "blur", function(e) {
1307
- return _this.el.removeClass('focus');
1308
- });
1309
- this.el.delegate("input", "keyup", function(e) {
1310
- e.stopPropagation();
1311
- return _this.trigger('keyup', [_this]);
1312
- });
1313
- }
1314
-
1315
- TextInputView.prototype.clear = function() {
1316
- return this.inputEl.val("");
1317
- };
1318
-
1319
- TextInputView.prototype.attr = function() {
1320
- var args, _ref;
1321
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1322
- return (_ref = this.inputEl).attr.apply(_ref, args);
1323
- };
1324
-
1325
- TextInputView.prototype.setValue = function(newValue) {
1326
- return this.inputEl.val(newValue);
1327
- };
1328
-
1329
- TextInputView.prototype.getValue = function() {
1330
- return this.inputEl.val();
1331
- };
1332
-
1333
- TextInputView.prototype.bind = function() {
1334
- var args, _ref;
1335
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1336
- return (_ref = this.el).bind.apply(_ref, args);
1337
- };
1338
-
1339
- TextInputView.prototype.trigger = function() {
1340
- var args, _ref;
1341
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1342
- return (_ref = this.el).trigger.apply(_ref, args);
1343
- };
1344
-
1345
- TextInputView.prototype.show = function() {
1346
- return this.el.show();
1347
- };
1348
-
1349
- TextInputView.prototype.hide = function() {
1350
- return this.el.hide();
1351
- };
1352
-
1353
- return TextInputView;
1354
-
1355
- })();
1356
-
1357
- /*
1358
- Skeuocard::CardProduct
1359
- */
1360
-
1361
-
1362
- Skeuocard.prototype.CardProduct = (function() {
1363
- CardProduct._registry = [];
1364
-
1365
- CardProduct.create = function(opts) {
1366
- return this._registry.push(new Skeuocard.prototype.CardProduct(opts));
1367
- };
1368
-
1369
- CardProduct.firstMatchingShortname = function(shortname) {
1370
- var card, _i, _len, _ref;
1371
- _ref = this._registry;
1372
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1373
- card = _ref[_i];
1374
- if (card.attrs.companyShortname === shortname) {
1375
- return card;
1376
- }
1377
- }
1378
- return null;
1379
- };
1380
-
1381
- CardProduct.firstMatchingNumber = function(number) {
1382
- var card, combinedOptions, variation, _i, _len, _ref;
1383
- _ref = this._registry;
1384
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1385
- card = _ref[_i];
1386
- if (card.pattern.test(number)) {
1387
- if ((variation = card.firstVariationMatchingNumber(number))) {
1388
- combinedOptions = $.extend({}, card.attrs, variation);
1389
- return new Skeuocard.prototype.CardProduct(combinedOptions);
1390
- }
1391
- return new Skeuocard.prototype.CardProduct(card.attrs);
1392
- }
1393
- }
1394
- return null;
1395
- };
1396
-
1397
- function CardProduct(attrs) {
1398
- var faces, k, v, _ref;
1399
- this.attrs = $.extend({}, attrs);
1400
- this.pattern = this.attrs.pattern;
1401
- this._variances = [];
1402
- this.name = {
1403
- isFilled: this._isCardNameFilled.bind(this),
1404
- isValid: this._isCardNameValid.bind(this)
1405
- };
1406
- this.number = {
1407
- isFilled: this._isCardNumberFilled.bind(this),
1408
- isValid: this._isCardNumberValid.bind(this)
1409
- };
1410
- this.exp = {
1411
- isFilled: this._isCardExpirationFilled.bind(this),
1412
- isValid: this._isCardExpirationValid.bind(this)
1413
- };
1414
- this.cvc = {
1415
- isFilled: this._isCardCVCFilled.bind(this),
1416
- isValid: this._isCardCVCValid.bind(this)
1417
- };
1418
- faces = {
1419
- front: 0,
1420
- back: 0
1421
- };
1422
- _ref = attrs.layout;
1423
- for (k in _ref) {
1424
- v = _ref[k];
1425
- faces[attrs.layout[k]] += 1;
1426
- }
1427
- if (faces.front > 0 && faces.back > 0) {
1428
- this.faces = 'both';
1429
- } else {
1430
- if (faces.front > 0) {
1431
- this.faces = 'front';
1432
- } else {
1433
- this.faces = 'back';
1434
- }
1435
- }
1436
- }
1437
-
1438
- CardProduct.prototype.createVariation = function(attrs) {
1439
- return this._variances.push(attrs);
1440
- };
1441
-
1442
- CardProduct.prototype.firstVariationMatchingNumber = function(number) {
1443
- var variance, _i, _len, _ref;
1444
- _ref = this._variances;
1445
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1446
- variance = _ref[_i];
1447
- if (variance.pattern.test(number)) {
1448
- return variance;
1449
- }
1450
- }
1451
- return null;
1452
- };
1453
-
1454
- CardProduct.prototype.fieldsForLayoutFace = function(faceName) {
1455
- var face, fieldName, _ref, _results;
1456
- _ref = this.attrs.layout;
1457
- _results = [];
1458
- for (fieldName in _ref) {
1459
- face = _ref[fieldName];
1460
- if (face === faceName) {
1461
- _results.push(fieldName);
1462
- }
1463
- }
1464
- return _results;
1465
- };
1466
-
1467
- CardProduct.prototype._id = function() {
1468
- var ident;
1469
- ident = this.attrs.companyShortname;
1470
- if (this.attrs.issuerShortname != null) {
1471
- ident += this.attrs.issuerShortname;
1472
- }
1473
- return ident;
1474
- };
1475
-
1476
- CardProduct.prototype.eql = function(otherCardProduct) {
1477
- return (otherCardProduct != null ? otherCardProduct._id() : void 0) === this._id();
1478
- };
1479
-
1480
- CardProduct.prototype._daysInMonth = function(m, y) {
1481
- switch (m) {
1482
- case 1:
1483
- if ((y % 4 === 0 && y % 100) || y % 400 === 0) {
1484
- return 29;
1485
- } else {
1486
- return 28;
1487
- }
1488
- case 3:
1489
- case 5:
1490
- case 8:
1491
- case 10:
1492
- return 30;
1493
- default:
1494
- return 31;
1495
- }
1496
- };
1497
-
1498
- CardProduct.prototype._isCardNumberFilled = function(number) {
1499
- var _ref;
1500
- if (this.attrs.cardNumberLength != null) {
1501
- return (_ref = number.length, __indexOf.call(this.attrs.cardNumberLength, _ref) >= 0);
1502
- }
1503
- };
1504
-
1505
- CardProduct.prototype._isCardExpirationFilled = function(exp) {
1506
- var currentDate, day, month, year;
1507
- currentDate = Skeuocard.currentDate;
1508
- if (!((exp != null) && (exp.getMonth != null) && (exp.getFullYear != null))) {
1509
- return false;
1510
- }
1511
- day = exp.getDate();
1512
- month = exp.getMonth();
1513
- year = exp.getFullYear();
1514
- return (day > 0 && day <= this._daysInMonth(month, year)) && (month >= 0 && month <= 11) && (year >= 1900 && year <= currentDate.getFullYear() + 10);
1515
- };
1516
-
1517
- CardProduct.prototype._isCardCVCFilled = function(cvc) {
1518
- return cvc.length === this.attrs.cvcLength;
1519
- };
1520
-
1521
- CardProduct.prototype._isCardNameFilled = function(name) {
1522
- return name.length > 0;
1523
- };
1524
-
1525
- CardProduct.prototype._isCardNumberValid = function(number) {
1526
- return /^\d+$/.test(number) && (this.attrs.validateLuhn === false || this._isValidLuhn(number)) && this._isCardNumberFilled(number);
1527
- };
1528
-
1529
- CardProduct.prototype._isCardExpirationValid = function(exp) {
1530
- var currentDate, day, isDateInFuture, month, year;
1531
- if (!((exp != null) && (exp.getMonth != null) && (exp.getFullYear != null))) {
1532
- return false;
1533
- }
1534
- currentDate = Skeuocard.currentDate;
1535
- day = exp.getDate();
1536
- month = exp.getMonth();
1537
- year = exp.getFullYear();
1538
- isDateInFuture = (year === currentDate.getFullYear() && month >= currentDate.getMonth()) || year > currentDate.getFullYear();
1539
- return isDateInFuture && this._isCardExpirationFilled(exp);
1540
- };
1541
-
1542
- CardProduct.prototype._isCardCVCValid = function(cvc) {
1543
- return this._isCardCVCFilled(cvc);
1544
- };
1545
-
1546
- CardProduct.prototype._isCardNameValid = function(name) {
1547
- return this._isCardNameFilled(name);
1548
- };
1549
-
1550
- CardProduct.prototype._isValidLuhn = function(number) {
1551
- var alt, i, num, sum, _i, _ref;
1552
- sum = 0;
1553
- alt = false;
1554
- for (i = _i = _ref = number.length - 1; _i >= 0; i = _i += -1) {
1555
- num = parseInt(number.charAt(i), 10);
1556
- if (isNaN(num)) {
1557
- return false;
1558
- }
1559
- if (alt) {
1560
- num *= 2;
1561
- if (num > 9) {
1562
- num = (num % 10) + 1;
1563
- }
1564
- }
1565
- alt = !alt;
1566
- sum += num;
1567
- }
1568
- return sum % 10 === 0;
1569
- };
1570
-
1571
- return CardProduct;
1572
-
1573
- })();
1574
-
1575
- /*
1576
- # Seed CardProducts.
1577
- */
1578
-
1579
-
1580
- Skeuocard.prototype.CardProduct.create({
1581
- pattern: /^(36|38|30[0-5])/,
1582
- companyName: "Diners Club",
1583
- companyShortname: "dinersclubintl",
1584
- cardNumberGrouping: [4, 6, 4],
1585
- cardNumberLength: [14],
1586
- expirationFormat: "MM/YY",
1587
- cvcLength: 3,
1588
- validateLuhn: true,
1589
- layout: {
1590
- number: 'front',
1591
- exp: 'front',
1592
- name: 'front',
1593
- cvc: 'back'
1594
- }
1595
- });
1596
-
1597
- Skeuocard.prototype.CardProduct.create({
1598
- pattern: /^35/,
1599
- companyName: "JCB",
1600
- companyShortname: "jcb",
1601
- cardNumberGrouping: [4, 4, 4, 4],
1602
- cardNumberLength: [16],
1603
- expirationFormat: "MM/'YY",
1604
- cvcLength: 3,
1605
- validateLuhn: true,
1606
- layout: {
1607
- number: 'front',
1608
- exp: 'front',
1609
- name: 'front',
1610
- cvc: 'back'
1611
- }
1612
- });
1613
-
1614
- Skeuocard.prototype.CardProduct.create({
1615
- pattern: /^3[47]/,
1616
- companyName: "American Express",
1617
- companyShortname: "amex",
1618
- cardNumberGrouping: [4, 6, 5],
1619
- cardNumberLength: [15],
1620
- expirationFormat: "MM/YY",
1621
- cvcLength: 4,
1622
- validateLuhn: true,
1623
- layout: {
1624
- number: 'front',
1625
- exp: 'front',
1626
- name: 'front',
1627
- cvc: 'front'
1628
- }
1629
- });
1630
-
1631
- Skeuocard.prototype.CardProduct.create({
1632
- pattern: /^(6706|6771|6709)/,
1633
- companyName: "Laser Card Services Ltd.",
1634
- companyShortname: "laser",
1635
- cardNumberGrouping: [4, 4, 4, 4],
1636
- cardNumberLength: [16, 17, 18, 19],
1637
- expirationFormat: "MM/YY",
1638
- validateLuhn: true,
1639
- cvcLength: 3,
1640
- layout: {
1641
- number: 'front',
1642
- exp: 'front',
1643
- name: 'front',
1644
- cvc: 'back'
1645
- }
1646
- });
1647
-
1648
- Skeuocard.prototype.CardProduct.create({
1649
- pattern: /^4/,
1650
- companyName: "Visa",
1651
- companyShortname: "visa",
1652
- cardNumberGrouping: [4, 4, 4, 4],
1653
- cardNumberLength: [13, 14, 15, 16],
1654
- expirationFormat: "MM/YY",
1655
- validateLuhn: true,
1656
- cvcLength: 3,
1657
- layout: {
1658
- number: 'front',
1659
- exp: 'front',
1660
- name: 'front',
1661
- cvc: 'back'
1662
- }
1663
- });
1664
-
1665
- Skeuocard.prototype.CardProduct.create({
1666
- pattern: /^(62|88)/,
1667
- companyName: "China UnionPay",
1668
- companyShortname: "unionpay",
1669
- cardNumberGrouping: [19],
1670
- cardNumberLength: [16, 17, 18, 19],
1671
- expirationFormat: "MM/YY",
1672
- validateLuhn: false,
1673
- cvcLength: 3,
1674
- layout: {
1675
- number: 'front',
1676
- exp: 'front',
1677
- name: 'front',
1678
- cvc: 'back'
1679
- }
1680
- });
1681
-
1682
- Skeuocard.prototype.CardProduct.create({
1683
- pattern: /^(5[1-5]|(222[1-9])|(22[3-9][0-9])|(2[3-6][0-9]{2})|(27[01][0-9])|2720)/,
1684
- companyName: "Mastercard",
1685
- companyShortname: "mastercard",
1686
- cardNumberGrouping: [4, 4, 4, 4],
1687
- cardNumberLength: [16],
1688
- expirationFormat: "MM/YY",
1689
- validateLuhn: true,
1690
- cvcLength: 3,
1691
- layout: {
1692
- number: 'front',
1693
- exp: 'front',
1694
- name: 'front',
1695
- cvc: 'back'
1696
- }
1697
- });
1698
-
1699
- Skeuocard.prototype.CardProduct.create({
1700
- pattern: /^(5018|5020|5038|6304|6759|676[1-3])/,
1701
- companyName: "Maestro (MasterCard)",
1702
- companyShortname: "maestro",
1703
- cardNumberGrouping: [4, 4, 4, 4],
1704
- cardNumberLength: [12, 13, 14, 15, 16, 17, 18, 19],
1705
- expirationFormat: "MM/YY",
1706
- validateLuhn: true,
1707
- cvcLength: 3,
1708
- layout: {
1709
- number: 'front',
1710
- exp: 'front',
1711
- name: 'front',
1712
- cvc: 'back'
1713
- }
1714
- });
1715
-
1716
- Skeuocard.prototype.CardProduct.create({
1717
- pattern: /^(6011|65|64[4-9]|622)/,
1718
- companyName: "Discover",
1719
- companyShortname: "discover",
1720
- cardNumberGrouping: [4, 4, 4, 4],
1721
- cardNumberLength: [16],
1722
- expirationFormat: "MM/YY",
1723
- validateLuhn: true,
1724
- cvcLength: 3,
1725
- layout: {
1726
- number: 'front',
1727
- exp: 'front',
1728
- name: 'front',
1729
- cvc: 'back'
1730
- }
1731
- });
1732
-
1733
- visaProduct = Skeuocard.prototype.CardProduct.firstMatchingShortname('visa');
1734
-
1735
- visaProduct.createVariation({
1736
- pattern: /^414720/,
1737
- issuingAuthority: "Chase",
1738
- issuerName: "Chase Sapphire Card",
1739
- issuerShortname: "chase-sapphire",
1740
- layout: {
1741
- name: 'front',
1742
- number: 'front',
1743
- exp: 'front',
1744
- cvc: 'front'
1745
- }
1746
- });
1747
-
1748
- }).call(this);