diff --git a/addons/payment/static/lib/jquery.payment/jquery.payment.js b/addons/payment/static/lib/jquery.payment/jquery.payment.js index c81c6e00d81..dcf829fbc8c 100644 --- a/addons/payment/static/lib/jquery.payment/jquery.payment.js +++ b/addons/payment/static/lib/jquery.payment/jquery.payment.js @@ -1,11 +1,10 @@ -// Generated by CoffeeScript 1.4.0 +// Generated by CoffeeScript 1.7.1 (function() { - var $, cardFromNumber, cardFromType, cards, defaultFormat, formatBackCardNumber, formatBackExpiry, formatCardNumber, formatExpiry, formatForwardExpiry, formatForwardSlash, hasTextSelected, luhnCheck, reFormatCardNumber, restrictCVC, restrictCardNumber, restrictExpiry, restrictNumeric, setCardType, + var $, cardFromNumber, cardFromType, cards, defaultFormat, formatBackCardNumber, formatBackExpiry, formatCardNumber, formatExpiry, formatForwardExpiry, formatForwardSlashAndSpace, hasTextSelected, luhnCheck, reFormatCVC, reFormatCardNumber, reFormatExpiry, reFormatNumeric, replaceFullWidthChars, restrictCVC, restrictCardNumber, restrictExpiry, restrictNumeric, safeVal, setCardType, __slice = [].slice, - __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; }, - _this = this; + __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; }; - $ = jQuery; + $ = window.jQuery || window.Zepto || window.$; $.payment = {}; @@ -19,80 +18,92 @@ defaultFormat = /(\d{1,4})/g; - cards = [ + $.payment.cards = cards = [ { type: 'maestro', - pattern: /^(5018|5020|5038|6304|6759|676[1-3])/, + patterns: [5018, 502, 503, 506, 56, 58, 639, 6220, 67], format: defaultFormat, length: [12, 13, 14, 15, 16, 17, 18, 19], cvcLength: [3], luhn: true }, { - type: 'dinersclub', - pattern: /^(36|38|30[0-5])/, - format: defaultFormat, - length: [14], - cvcLength: [3], - luhn: true - }, { - type: 'laser', - pattern: /^(6706|6771|6709)/, - format: defaultFormat, - length: [16, 17, 18, 19], - cvcLength: [3], - luhn: true - }, { - type: 'jcb', - pattern: /^35/, + type: 'forbrugsforeningen', + patterns: [600], format: defaultFormat, length: [16], cvcLength: [3], luhn: true }, { - type: 'unionpay', - pattern: /^62/, - format: defaultFormat, - length: [16, 17, 18, 19], - cvcLength: [3], - luhn: false - }, { - type: 'discover', - pattern: /^(6011|65|64[4-9]|622)/, + type: 'dankort', + patterns: [5019], format: defaultFormat, length: [16], cvcLength: [3], luhn: true + }, { + type: 'visa', + patterns: [4], + format: defaultFormat, + length: [13, 16], + cvcLength: [3], + luhn: true }, { type: 'mastercard', - pattern: /^5[1-5]/, + patterns: [51, 52, 53, 54, 55, 22, 23, 24, 25, 26, 27], format: defaultFormat, length: [16], cvcLength: [3], luhn: true }, { type: 'amex', - pattern: /^3[47]/, + patterns: [34, 37], format: /(\d{1,4})(\d{1,6})?(\d{1,5})?/, length: [15], cvcLength: [3, 4], luhn: true }, { - type: 'visa', - pattern: /^4/, + type: 'dinersclub', + patterns: [30, 36, 38, 39], + format: /(\d{1,4})(\d{1,6})?(\d{1,4})?/, + length: [14], + cvcLength: [3], + luhn: true + }, { + type: 'discover', + patterns: [60, 64, 65, 622], format: defaultFormat, - length: [13, 14, 15, 16], + length: [16], + cvcLength: [3], + luhn: true + }, { + type: 'unionpay', + patterns: [62, 88], + format: defaultFormat, + length: [16, 17, 18, 19], + cvcLength: [3], + luhn: false + }, { + type: 'jcb', + patterns: [35], + format: defaultFormat, + length: [16], cvcLength: [3], luhn: true } ]; cardFromNumber = function(num) { - var card, _i, _len; + var card, p, pattern, _i, _j, _len, _len1, _ref; num = (num + '').replace(/\D/g, ''); for (_i = 0, _len = cards.length; _i < _len; _i++) { card = cards[_i]; - if (card.pattern.test(num)) { - return card; + _ref = card.patterns; + for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { + pattern = _ref[_j]; + p = pattern + ''; + if (num.substr(0, p.length) === p) { + return card; + } } } }; @@ -131,20 +142,82 @@ if (($target.prop('selectionStart') != null) && $target.prop('selectionStart') !== $target.prop('selectionEnd')) { return true; } - if (typeof document !== "undefined" && document !== null ? (_ref = document.selection) != null ? typeof _ref.createRange === "function" ? _ref.createRange().text : void 0 : void 0 : void 0) { - return true; + if ((typeof document !== "undefined" && document !== null ? (_ref = document.selection) != null ? _ref.createRange : void 0 : void 0) != null) { + if (document.selection.createRange().text) { + return true; + } } return false; }; - reFormatCardNumber = function(e) { - var _this = this; + safeVal = function(value, $target) { + var currPair, cursor, digit, error, last, prevPair; + try { + cursor = $target.prop('selectionStart'); + } catch (_error) { + error = _error; + cursor = null; + } + last = $target.val(); + $target.val(value); + if (cursor !== null && $target.is(":focus")) { + if (cursor === last.length) { + cursor = value.length; + } + if (last !== value) { + prevPair = last.slice(cursor - 1, +cursor + 1 || 9e9); + currPair = value.slice(cursor - 1, +cursor + 1 || 9e9); + digit = value[cursor]; + if (/\d/.test(digit) && prevPair === ("" + digit + " ") && currPair === (" " + digit)) { + cursor = cursor + 1; + } + } + $target.prop('selectionStart', cursor); + return $target.prop('selectionEnd', cursor); + } + }; + + replaceFullWidthChars = function(str) { + var chars, chr, fullWidth, halfWidth, idx, value, _i, _len; + if (str == null) { + str = ''; + } + fullWidth = '\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19'; + halfWidth = '0123456789'; + value = ''; + chars = str.split(''); + for (_i = 0, _len = chars.length; _i < _len; _i++) { + chr = chars[_i]; + idx = fullWidth.indexOf(chr); + if (idx > -1) { + chr = halfWidth[idx]; + } + value += chr; + } + return value; + }; + + reFormatNumeric = function(e) { + var $target; + $target = $(e.currentTarget); return setTimeout(function() { - var $target, value; - $target = $(e.currentTarget); + var value; value = $target.val(); + value = replaceFullWidthChars(value); + value = value.replace(/\D/g, ''); + return safeVal(value, $target); + }); + }; + + reFormatCardNumber = function(e) { + var $target; + $target = $(e.currentTarget); + return setTimeout(function() { + var value; + value = $target.val(); + value = replaceFullWidthChars(value); value = $.payment.formatCardNumber(value); - return $target.val(value); + return safeVal(value, $target); }); }; @@ -175,10 +248,14 @@ } if (re.test(value)) { e.preventDefault(); - return $target.val(value + ' ' + digit); + return setTimeout(function() { + return $target.val(value + ' ' + digit); + }); } else if (re.test(value + digit)) { e.preventDefault(); - return $target.val(value + digit + ' '); + return setTimeout(function() { + return $target.val(value + digit + ' '); + }); } }; @@ -186,9 +263,6 @@ var $target, value; $target = $(e.currentTarget); value = $target.val(); - if (e.meta) { - return; - } if (e.which !== 8) { return; } @@ -197,13 +271,29 @@ } if (/\d\s$/.test(value)) { e.preventDefault(); - return $target.val(value.replace(/\d\s$/, '')); + return setTimeout(function() { + return $target.val(value.replace(/\d\s$/, '')); + }); } else if (/\s\d?$/.test(value)) { e.preventDefault(); - return $target.val(value.replace(/\s\d?$/, '')); + return setTimeout(function() { + return $target.val(value.replace(/\d$/, '')); + }); } }; + reFormatExpiry = function(e) { + var $target; + $target = $(e.currentTarget); + return setTimeout(function() { + var value; + value = $target.val(); + value = replaceFullWidthChars(value); + value = $.payment.formatExpiry(value); + return safeVal(value, $target); + }); + }; + formatExpiry = function(e) { var $target, digit, val; digit = String.fromCharCode(e.which); @@ -214,10 +304,21 @@ val = $target.val() + digit; if (/^\d$/.test(val) && (val !== '0' && val !== '1')) { e.preventDefault(); - return $target.val("0" + val + " / "); + return setTimeout(function() { + return $target.val("0" + val + " / "); + }); } else if (/^\d\d$/.test(val)) { e.preventDefault(); - return $target.val("" + val + " / "); + return setTimeout(function() { + var m1, m2; + m1 = parseInt(val[0], 10); + m2 = parseInt(val[1], 10); + if (m2 > 2 && m1 !== 0) { + return $target.val("0" + m1 + " / " + m2); + } else { + return $target.val("" + val + " / "); + } + }); } }; @@ -234,10 +335,10 @@ } }; - formatForwardSlash = function(e) { - var $target, slash, val; - slash = String.fromCharCode(e.which); - if (slash !== '/') { + formatForwardSlashAndSpace = function(e) { + var $target, val, which; + which = String.fromCharCode(e.which); + if (!(which === '/' || which === ' ')) { return; } $target = $(e.currentTarget); @@ -249,9 +350,6 @@ formatBackExpiry = function(e) { var $target, value; - if (e.meta) { - return; - } $target = $(e.currentTarget); value = $target.val(); if (e.which !== 8) { @@ -260,15 +358,26 @@ if (($target.prop('selectionStart') != null) && $target.prop('selectionStart') !== value.length) { return; } - if (/\d(\s|\/)+$/.test(value)) { + if (/\d\s\/\s$/.test(value)) { e.preventDefault(); - return $target.val(value.replace(/\d(\s|\/)*$/, '')); - } else if (/\s\/\s?\d?$/.test(value)) { - e.preventDefault(); - return $target.val(value.replace(/\s\/\s?\d?$/, '')); + return setTimeout(function() { + return $target.val(value.replace(/\d\s\/\s$/, '')); + }); } }; + reFormatCVC = function(e) { + var $target; + $target = $(e.currentTarget); + return setTimeout(function() { + var value; + value = $target.val(); + value = replaceFullWidthChars(value); + value = value.replace(/\D/g, '').slice(0, 4); + return safeVal(value, $target); + }); + }; + restrictNumeric = function(e) { var input; if (e.metaKey || e.ctrlKey) { @@ -330,6 +439,9 @@ if (!/^\d+$/.test(digit)) { return; } + if (hasTextSelected($target)) { + return; + } val = $target.val() + digit; return val.length <= 4; }; @@ -358,33 +470,44 @@ }; $.payment.fn.formatCardCVC = function() { - this.payment('restrictNumeric'); + this.on('keypress', restrictNumeric); this.on('keypress', restrictCVC); + this.on('paste', reFormatCVC); + this.on('change', reFormatCVC); + this.on('input', reFormatCVC); return this; }; $.payment.fn.formatCardExpiry = function() { - this.payment('restrictNumeric'); + this.on('keypress', restrictNumeric); this.on('keypress', restrictExpiry); this.on('keypress', formatExpiry); - this.on('keypress', formatForwardSlash); + this.on('keypress', formatForwardSlashAndSpace); this.on('keypress', formatForwardExpiry); this.on('keydown', formatBackExpiry); + this.on('change', reFormatExpiry); + this.on('input', reFormatExpiry); return this; }; $.payment.fn.formatCardNumber = function() { - this.payment('restrictNumeric'); + this.on('keypress', restrictNumeric); this.on('keypress', restrictCardNumber); this.on('keypress', formatCardNumber); this.on('keydown', formatBackCardNumber); this.on('keyup', setCardType); this.on('paste', reFormatCardNumber); + this.on('change', reFormatCardNumber); + this.on('input', reFormatCardNumber); + this.on('input', setCardType); return this; }; $.payment.fn.restrictNumeric = function() { this.on('keypress', restrictNumeric); + this.on('paste', reFormatNumeric); + this.on('change', reFormatNumeric); + this.on('input', reFormatNumeric); return this; }; @@ -394,8 +517,7 @@ $.payment.cardExpiryVal = function(value) { var month, prefix, year, _ref; - value = value.replace(/\s/g, ''); - _ref = value.split('/', 2), month = _ref[0], year = _ref[1]; + _ref = value.split(/[\s\/]+/, 2), month = _ref[0], year = _ref[1]; if ((year != null ? year.length : void 0) === 2 && /^\d+$/.test(year)) { prefix = (new Date).getFullYear(); prefix = prefix.toString().slice(0, 2); @@ -423,7 +545,7 @@ }; $.payment.validateCardExpiry = function(month, year) { - var currentTime, expiry, prefix, _ref; + var currentTime, expiry, _ref; if (typeof month === 'object' && 'month' in month) { _ref = month, month = _ref.month, year = _ref.year; } @@ -438,13 +560,18 @@ if (!/^\d+$/.test(year)) { return false; } - if (!(parseInt(month, 10) <= 12)) { + if (!((1 <= month && month <= 12))) { return false; } if (year.length === 2) { - prefix = (new Date).getFullYear(); - prefix = prefix.toString().slice(0, 2); - year = prefix + year; + if (year < 70) { + year = "20" + year; + } else { + year = "19" + year; + } + } + if (year.length !== 4) { + return false; } expiry = new Date(year, month); currentTime = new Date; @@ -454,13 +581,14 @@ }; $.payment.validateCardCVC = function(cvc, type) { - var _ref, _ref1; + var card, _ref; cvc = $.trim(cvc); if (!/^\d+$/.test(cvc)) { return false; } - if (type) { - return _ref = cvc.length, __indexOf.call((_ref1 = cardFromType(type)) != null ? _ref1.cvcLength : void 0, _ref) >= 0; + card = cardFromType(type); + if (card != null) { + return _ref = cvc.length, __indexOf.call(card.cvcLength, _ref) >= 0; } else { return cvc.length >= 3 && cvc.length <= 4; } @@ -476,22 +604,49 @@ $.payment.formatCardNumber = function(num) { var card, groups, upperLength, _ref; + num = num.replace(/\D/g, ''); card = cardFromNumber(num); if (!card) { return num; } upperLength = card.length[card.length.length - 1]; - num = num.replace(/\D/g, ''); - num = num.slice(0, +upperLength + 1 || 9e9); + num = num.slice(0, upperLength); if (card.format.global) { return (_ref = num.match(card.format)) != null ? _ref.join(' ') : void 0; } else { groups = card.format.exec(num); - if (groups != null) { - groups.shift(); + if (groups == null) { + return; } - return groups != null ? groups.join(' ') : void 0; + groups.shift(); + groups = $.grep(groups, function(n) { + return n; + }); + return groups.join(' '); } }; + $.payment.formatExpiry = function(expiry) { + var mon, parts, sep, year; + parts = expiry.match(/^\D*(\d{1,2})(\D+)?(\d{1,4})?/); + if (!parts) { + return ''; + } + mon = parts[1] || ''; + sep = parts[2] || ''; + year = parts[3] || ''; + if (year.length > 0) { + sep = ' / '; + } else if (sep === ' /') { + mon = mon.substring(0, 1); + sep = ''; + } else if (mon.length === 2 || sep.length > 0) { + sep = ' / '; + } else if (mon.length === 1 && (mon !== '0' && mon !== '1')) { + mon = "0" + mon; + sep = ' / '; + } + return mon + sep + year; + }; + }).call(this);