mirror of
https://codeberg.org/nobody/LocalCDN.git
synced 2025-02-16 20:00:57 +01:00
Added Angular Payments v1.0.7 (#71)
This commit is contained in:
parent
7801d5bc18
commit
2553eb8536
@ -39,6 +39,9 @@ var files = {
|
||||
'resources/angular-ui-bootstrap/0.14.3/ui-bootstrap-tpls.min.jsm': true,
|
||||
'resources/angular-ui-bootstrap/0.14.3/ui-bootstrap.min.jsm': true,
|
||||
|
||||
// Angular Payments
|
||||
'resources/angular-payments/1.0.7/angular-payments.jsm': true,
|
||||
|
||||
// AngularJS
|
||||
'resources/angularjs/1.7.9/angular-animate.min.jsm': true,
|
||||
'resources/angularjs/1.7.9/angular-aria.min.jsm': true,
|
||||
|
@ -192,6 +192,7 @@ var mappings = {
|
||||
'/npm/': {
|
||||
'angular@{version}/angular.': resources.angular,
|
||||
'angular@{version}/angular.min.': resources.angular,
|
||||
'angular-payments@{version}/lib/angular-payments.js': resources.angularPayments,
|
||||
'animate.css@{version}/animate.min.css': resources.animateCSS,
|
||||
'backbone@{version}/backbone.': resources.backbone,
|
||||
'backbone@{version}/backbone-min.': resources.backbone,
|
||||
|
@ -121,6 +121,11 @@ var resources = {
|
||||
'path': 'resources/angularjs-toaster/{version}/toaster.min.jsm',
|
||||
'type': 'application/javascript'
|
||||
},
|
||||
// Angular Payments
|
||||
'angularPayments': {
|
||||
'path': 'resources/angular-payments/{version}/angular-payments.jsm',
|
||||
'type': 'application/javascript'
|
||||
},
|
||||
// Animate CSS
|
||||
'animateCSS': {
|
||||
'path': 'resources/animate.css/{version}/animate.min.css',
|
||||
|
@ -248,6 +248,8 @@ helpers.determineResourceName = function (filename) {
|
||||
return 'AngularJS Toaster (JS)';
|
||||
case 'angular-ui-router.min.jsm':
|
||||
return 'Angular UI Router';
|
||||
case 'angular-payments.jsm':
|
||||
return 'Angular Payments';
|
||||
case 'animate.min.css':
|
||||
return 'Animate CSS'
|
||||
case 'backbone-min.jsm':
|
||||
@ -457,6 +459,8 @@ helpers.setLastVersion = function (type, version) {
|
||||
version = '2.2.0';
|
||||
} else if (type.includes('/angularjs-toaster/0.')) {
|
||||
version = '0.4.18';
|
||||
} else if (type.includes('/angular-payments@1.')) {
|
||||
version = '1.0.7';
|
||||
} else if (type.includes('/angular-ui-bootstrap/0.')) {
|
||||
version = '0.14.3';
|
||||
} else if (type.includes('/angular-ui-bootstrap/1.')) {
|
||||
|
@ -37,6 +37,7 @@
|
||||
<li>Added AngularJS upgraded to v1.6.10 (Fixed <a href="https://gitlab.com/nobody42/localcdn/-/issues/72">#72</a>)</li>
|
||||
<li>Added AngularJS v1.4.14 (<a href="https://gitlab.com/nobody42/localcdn/-/issues/71">#71</a>)</li>
|
||||
<li>Fixed typo in AngularUI Bootstrap (<a href="https://gitlab.com/nobody42/localcdn/-/issues/71">#71</a>)</li>
|
||||
<li>Added Angular Payments v1.0.7 (<a href="https://gitlab.com/nobody42/localcdn/-/issues/71">#71</a>)</li>
|
||||
</ul>
|
||||
<div class="topic-label">
|
||||
Please update your uBlock/uMatrix rules
|
||||
|
881
resources/angular-payments/1.0.7/angular-payments.jsm
Normal file
881
resources/angular-payments/1.0.7/angular-payments.jsm
Normal file
@ -0,0 +1,881 @@
|
||||
angular.module('angularPayments', []);;angular.module('angularPayments')
|
||||
|
||||
.factory('Common', [function(){
|
||||
|
||||
var ret = {};
|
||||
|
||||
// expiry is a string "mm / yy[yy]"
|
||||
ret.parseExpiry = function(value){
|
||||
var month, prefix, year, _ref;
|
||||
|
||||
value = value || '';
|
||||
|
||||
value = value.replace(/\s/g, '');
|
||||
_ref = value.split('/', 2);
|
||||
month = _ref[0];
|
||||
year = _ref[1];
|
||||
|
||||
if (year && year.length === 2 && /^\d+$/.test(year)) {
|
||||
prefix = (new Date()).getFullYear();
|
||||
prefix = prefix.toString().slice(0, 2);
|
||||
year = prefix + year;
|
||||
}
|
||||
|
||||
month = parseInt(month, 10);
|
||||
year = parseInt(year, 10);
|
||||
|
||||
return {
|
||||
month: month,
|
||||
year: year
|
||||
};
|
||||
};
|
||||
|
||||
return ret;
|
||||
|
||||
}]);
|
||||
;angular.module('angularPayments')
|
||||
|
||||
.factory('Cards', [function(){
|
||||
|
||||
var defaultFormat = /(\d{1,4})/g;
|
||||
var defaultInputFormat = /(?:^|\s)(\d{4})$/;
|
||||
|
||||
var cards = [
|
||||
{
|
||||
type: 'maestro',
|
||||
pattern: /^(5018|5020|5038|6304|6759|676[1-3])/,
|
||||
format: defaultFormat,
|
||||
inputFormat: defaultInputFormat,
|
||||
length: [12, 13, 14, 15, 16, 17, 18, 19],
|
||||
cvcLength: [3],
|
||||
luhn: true
|
||||
}, {
|
||||
type: 'dinersclub',
|
||||
pattern: /^(36|38|30[0-5])/,
|
||||
format: defaultFormat,
|
||||
inputFormat: defaultInputFormat,
|
||||
length: [14],
|
||||
cvcLength: [3],
|
||||
luhn: true
|
||||
}, {
|
||||
type: 'laser',
|
||||
pattern: /^(6706|6771|6709)/,
|
||||
format: defaultFormat,
|
||||
inputFormat: defaultInputFormat,
|
||||
length: [16, 17, 18, 19],
|
||||
cvcLength: [3],
|
||||
luhn: true
|
||||
}, {
|
||||
type: 'jcb',
|
||||
pattern: /^35/,
|
||||
format: defaultFormat,
|
||||
inputFormat: defaultInputFormat,
|
||||
length: [16],
|
||||
cvcLength: [3],
|
||||
luhn: true
|
||||
}, {
|
||||
type: 'unionpay',
|
||||
pattern: /^62/,
|
||||
format: defaultFormat,
|
||||
inputFormat: defaultInputFormat,
|
||||
length: [16, 17, 18, 19],
|
||||
cvcLength: [3],
|
||||
luhn: false
|
||||
}, {
|
||||
type: 'discover',
|
||||
pattern: /^(6011|65|64[4-9]|622)/,
|
||||
format: defaultFormat,
|
||||
inputFormat: defaultInputFormat,
|
||||
length: [16],
|
||||
cvcLength: [3],
|
||||
luhn: true
|
||||
}, {
|
||||
type: 'mastercard',
|
||||
pattern: /^5[1-5]/,
|
||||
format: defaultFormat,
|
||||
inputFormat: defaultInputFormat,
|
||||
length: [16],
|
||||
cvcLength: [3],
|
||||
luhn: true
|
||||
}, {
|
||||
type: 'amex',
|
||||
pattern: /^3[47]/,
|
||||
format: /(\d{1,4})(\d{1,6})?(\d{1,5})?/,
|
||||
inputFormat: /^(\d{4}|\d{4}\s\d{6})$/,
|
||||
length: [15],
|
||||
cvcLength: [3, 4],
|
||||
luhn: true
|
||||
}, {
|
||||
type: 'visa',
|
||||
pattern: /^4/,
|
||||
format: defaultFormat,
|
||||
inputFormat: defaultInputFormat,
|
||||
length: [13, 14, 15, 16],
|
||||
cvcLength: [3],
|
||||
luhn: true
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
var _fromNumber = function(num){
|
||||
var card, i, len;
|
||||
|
||||
num = (num + '').replace(/\D/g, '');
|
||||
|
||||
for (i = 0, len = cards.length; i < len; i++) {
|
||||
|
||||
card = cards[i];
|
||||
|
||||
if (card.pattern.test(num)) {
|
||||
return card;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
var _fromType = function(type) {
|
||||
var card, i, len;
|
||||
|
||||
for (i = 0, len = cards.length; i < len; i++) {
|
||||
|
||||
card = cards[i];
|
||||
|
||||
if (card.type === type) {
|
||||
return card;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
fromNumber: function(val) { return _fromNumber(val); },
|
||||
fromType: function(val) { return _fromType(val); },
|
||||
defaultFormat: function() { return defaultFormat; },
|
||||
defaultInputFormat: function() { return defaultInputFormat; }
|
||||
};
|
||||
|
||||
}]);
|
||||
;/**
|
||||
* Format
|
||||
*/
|
||||
angular.module('angularPayments')
|
||||
|
||||
.factory('_Format', ['Cards', 'Common', '$filter', function(Cards, Common, $filter){
|
||||
|
||||
var _formats = {};
|
||||
|
||||
var _hasTextSelected = function($target) {
|
||||
var ref;
|
||||
|
||||
if (($target.prop('selectionStart') !== null) && $target.prop('selectionStart') !== $target.prop('selectionEnd')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (document.selection) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// card formatting
|
||||
|
||||
var isInvalidKey = function(e) {
|
||||
var digit = String.fromCharCode(e.which);
|
||||
return !/^\d+$/.test(digit) && !e.metaKey && e.charCode !== 0 && !e.ctrlKey;
|
||||
};
|
||||
|
||||
var _formatCardNumber = function(e) {
|
||||
var $target, card, digit, length, re, upperLength, value;
|
||||
|
||||
digit = String.fromCharCode(e.which);
|
||||
$target = angular.element(e.currentTarget);
|
||||
value = $target.val();
|
||||
card = Cards.fromNumber(value + digit);
|
||||
length = (value.replace(/\D/g, '') + digit).length;
|
||||
|
||||
upperLength = 16;
|
||||
|
||||
// Catch delete, tab, backspace, arrows, etc..
|
||||
if (e.which === 8 || e.which === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (card) {
|
||||
upperLength = card.length[card.length.length - 1];
|
||||
}
|
||||
|
||||
|
||||
if (isInvalidKey(e)) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (($target.prop('selectionStart') !== null) && $target.prop('selectionStart') !== value.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
re = Cards.defaultInputFormat();
|
||||
if (card) {
|
||||
re = card.inputFormat;
|
||||
}
|
||||
|
||||
if (length >= upperLength) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (re.test(value)) {
|
||||
e.preventDefault();
|
||||
return $target.val(value + ' ' + digit);
|
||||
|
||||
} else if (re.test(value + digit)) {
|
||||
e.preventDefault();
|
||||
return $target.val(value + digit + ' ');
|
||||
}
|
||||
};
|
||||
|
||||
var _restrictCardNumber = function(e) {
|
||||
var $target, card, digit, value;
|
||||
|
||||
$target = angular.element(e.currentTarget);
|
||||
digit = String.fromCharCode(e.which);
|
||||
|
||||
// Catch delete, tab, backspace, arrows, etc..
|
||||
if (e.which === 8 || e.which === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!/^\d+$/.test(digit)) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if(_hasTextSelected($target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
value = ($target.val() + digit).replace(/\D/g, '');
|
||||
card = Cards.fromNumber(value);
|
||||
|
||||
if(card) {
|
||||
if(value.length > card.length[card.length.length - 1]){
|
||||
e.preventDefault();
|
||||
}
|
||||
} else {
|
||||
if(value.length > 16){
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var _formatBackCardNumber = function(e) {
|
||||
var $target, value;
|
||||
|
||||
$target = angular.element(e.currentTarget);
|
||||
value = $target.val();
|
||||
|
||||
if(e.metaKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(e.which !== 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(($target.prop('selectionStart') !== null) && $target.prop('selectionStart') !== value.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(/\d\s$/.test(value) && !e.metaKey && e.keyCode >= 46) {
|
||||
e.preventDefault();
|
||||
return $target.val(value.replace(/\d\s$/, ''));
|
||||
} else if (/\s\d?$/.test(value)) {
|
||||
e.preventDefault();
|
||||
return $target.val(value.replace(/\s\d?$/, ''));
|
||||
}
|
||||
};
|
||||
|
||||
var _getFormattedCardNumber = function(num) {
|
||||
var card, groups, upperLength, ref;
|
||||
|
||||
card = Cards.fromNumber(num);
|
||||
|
||||
if (!card) {
|
||||
return num;
|
||||
}
|
||||
|
||||
upperLength = card.length[card.length.length - 1];
|
||||
num = num.replace(/\D/g, '');
|
||||
num = num.slice(0, +upperLength + 1 || 9e9);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
return groups !== null ? groups.join(' ') : void 0;
|
||||
}
|
||||
};
|
||||
|
||||
var _reFormatCardNumber = function(e) {
|
||||
return setTimeout(function() {
|
||||
var $target, value;
|
||||
$target = angular.element(e.target);
|
||||
|
||||
value = $target.val();
|
||||
value = _getFormattedCardNumber(value);
|
||||
return $target.val(value);
|
||||
});
|
||||
};
|
||||
|
||||
var _parseCardNumber = function(value) {
|
||||
return value !== null && value !== undefined ? value.replace(/\s/g, '') : value;
|
||||
};
|
||||
|
||||
_formats.card = function(elem, ctrl){
|
||||
elem.bind('keypress', _restrictCardNumber);
|
||||
elem.bind('keypress', _formatCardNumber);
|
||||
elem.bind('keydown', _formatBackCardNumber);
|
||||
elem.bind('paste', _reFormatCardNumber);
|
||||
|
||||
ctrl.$parsers.push(_parseCardNumber);
|
||||
ctrl.$formatters.push(_getFormattedCardNumber);
|
||||
};
|
||||
|
||||
|
||||
// cvc
|
||||
|
||||
var _formatCVC = function(e){
|
||||
var $target, digit, value;
|
||||
|
||||
$target = angular.element(e.currentTarget);
|
||||
digit = String.fromCharCode(e.which);
|
||||
|
||||
// Catch delete, tab, backspace, arrows, etc..
|
||||
if (e.which === 8 || e.which === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInvalidKey(e)) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if(_hasTextSelected($target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
value = $target.val() + digit;
|
||||
|
||||
if(value.length <= 4){
|
||||
return;
|
||||
} else {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
_formats.cvc = function(elem){
|
||||
elem.bind('keypress', _formatCVC);
|
||||
};
|
||||
|
||||
|
||||
// expiry
|
||||
|
||||
var _restrictExpiry = function(e) {
|
||||
var $target, digit, value;
|
||||
|
||||
$target = angular.element(e.currentTarget);
|
||||
digit = String.fromCharCode(e.which);
|
||||
|
||||
if (isInvalidKey(e)) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if(_hasTextSelected($target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
value = $target.val() + digit;
|
||||
value = value.replace(/\D/g, '');
|
||||
|
||||
if (value.length > 6) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
var _formatExpiry = function(e) {
|
||||
var $target, digit, val;
|
||||
|
||||
digit = String.fromCharCode(e.which);
|
||||
|
||||
if (isInvalidKey(e)) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
$target = angular.element(e.currentTarget);
|
||||
val = $target.val() + digit;
|
||||
|
||||
if (/^\d$/.test(val) && (val !== '0' && val !== '1')) {
|
||||
e.preventDefault();
|
||||
return $target.val("0" + val + " / ");
|
||||
|
||||
} else if (/^\d\d$/.test(val)) {
|
||||
e.preventDefault();
|
||||
return $target.val("" + val + " / ");
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
var _formatForwardExpiry = function(e) {
|
||||
var $target, digit, val;
|
||||
|
||||
digit = String.fromCharCode(e.which);
|
||||
|
||||
if (isInvalidKey(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$target = angular.element(e.currentTarget);
|
||||
val = $target.val();
|
||||
|
||||
if (/^\d\d$/.test(val)) {
|
||||
return $target.val("" + val + " / ");
|
||||
}
|
||||
};
|
||||
|
||||
var _formatForwardSlash = function(e) {
|
||||
var $target, slash, val;
|
||||
|
||||
slash = String.fromCharCode(e.which);
|
||||
|
||||
if (slash !== '/') {
|
||||
return;
|
||||
}
|
||||
|
||||
$target = angular.element(e.currentTarget);
|
||||
val = $target.val();
|
||||
|
||||
if (/^\d$/.test(val) && val !== '0') {
|
||||
return $target.val("0" + val + " / ");
|
||||
}
|
||||
};
|
||||
|
||||
var _formatBackExpiry = function(e) {
|
||||
var $target, value;
|
||||
|
||||
if (e.meta || e.metaKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
$target = angular.element(e.currentTarget);
|
||||
value = $target.val();
|
||||
|
||||
if (e.which !== 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (($target.prop('selectionStart') !== null) && $target.prop('selectionStart') !== value.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (/\d(\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?$/, ''));
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
var _parseExpiry = function(value) {
|
||||
if(value !== null) {
|
||||
var obj = Common.parseExpiry(value);
|
||||
var expiry = new Date(obj.year, obj.month-1);
|
||||
return $filter('date')(expiry, 'MM/yyyy');
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
var _getFormattedExpiry = function(value) {
|
||||
if(value !== null) {
|
||||
var obj = Common.parseExpiry(value);
|
||||
var expiry = new Date(obj.year, obj.month-1);
|
||||
return $filter('date')(expiry, 'MM / yyyy');
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
_formats.expiry = function(elem, ctrl){
|
||||
elem.bind('keypress', _restrictExpiry);
|
||||
elem.bind('keypress', _formatExpiry);
|
||||
elem.bind('keypress', _formatForwardSlash);
|
||||
elem.bind('keypress', _formatForwardExpiry);
|
||||
elem.bind('keydown', _formatBackExpiry);
|
||||
|
||||
ctrl.$parsers.push(_parseExpiry);
|
||||
ctrl.$formatters.push(_getFormattedExpiry);
|
||||
};
|
||||
|
||||
return function(type, elem, ctrl){
|
||||
var types, errstr;
|
||||
|
||||
if(!_formats[type]){
|
||||
|
||||
types = Object.keys(_formats);
|
||||
|
||||
errstr = 'Unknown type for formatting: "'+type+'". ';
|
||||
errstr += 'Should be one of: "'+types.join('", "')+'"';
|
||||
|
||||
throw errstr;
|
||||
}
|
||||
return _formats[type](elem, ctrl);
|
||||
};
|
||||
|
||||
}])
|
||||
|
||||
.directive('paymentsFormat', ['$window', '_Format', function($window, _Format){
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: 'ngModel',
|
||||
link: function(scope, elem, attr, ctrl){
|
||||
_Format(attr.paymentsFormat, elem, ctrl);
|
||||
}
|
||||
};
|
||||
}]);
|
||||
;angular.module('angularPayments')
|
||||
|
||||
|
||||
|
||||
.factory('_Validate', ['Cards', 'Common', '$parse', function(Cards, Common, $parse){
|
||||
|
||||
var __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; };
|
||||
|
||||
var _luhnCheck = function(num) {
|
||||
var digit, digits, odd, sum, i, len;
|
||||
|
||||
odd = true;
|
||||
sum = 0;
|
||||
digits = (num + '').split('').reverse();
|
||||
|
||||
for (i = 0, len = digits.length; i < len; i++) {
|
||||
|
||||
digit = digits[i];
|
||||
digit = parseInt(digit, 10);
|
||||
|
||||
if ((odd = !odd)) {
|
||||
digit *= 2;
|
||||
}
|
||||
|
||||
if (digit > 9) {
|
||||
digit -= 9;
|
||||
}
|
||||
|
||||
sum += digit;
|
||||
|
||||
}
|
||||
|
||||
return sum % 10 === 0;
|
||||
};
|
||||
|
||||
var _validators = {};
|
||||
|
||||
_validators.cvc = function(cvc, ctrl, scope, attr){
|
||||
var ref, ref1;
|
||||
|
||||
// valid if empty - let ng-required handle empty
|
||||
if(!cvc) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!/^\d+$/.test(cvc)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var type;
|
||||
if(attr.paymentsTypeModel) {
|
||||
var typeModel = $parse(attr.paymentsTypeModel);
|
||||
type = typeModel(scope);
|
||||
}
|
||||
|
||||
if (type) {
|
||||
return ref = cvc.length, __indexOf.call((ref1 = Cards.fromType(type)) !== null ? ref1.cvcLength : void 0, ref) >= 0;
|
||||
} else {
|
||||
return cvc.length >= 3 && cvc.length <= 4;
|
||||
}
|
||||
};
|
||||
|
||||
_validators.card = function(num, ctrl, scope, attr){
|
||||
var card, ref, typeModel, ret;
|
||||
|
||||
if(attr.paymentsTypeModel) {
|
||||
typeModel = $parse(attr.paymentsTypeModel);
|
||||
}
|
||||
|
||||
var clearCard = function(){
|
||||
if(typeModel) {
|
||||
typeModel.assign(scope, null);
|
||||
}
|
||||
ctrl.$card = null;
|
||||
};
|
||||
|
||||
// valid if empty - let ng-required handle empty
|
||||
if(!num){
|
||||
clearCard();
|
||||
return true;
|
||||
}
|
||||
|
||||
num = (num + '').replace(/\s+|-/g, '');
|
||||
|
||||
if (!/^\d+$/.test(num)) {
|
||||
clearCard();
|
||||
return false;
|
||||
}
|
||||
|
||||
card = Cards.fromNumber(num);
|
||||
|
||||
if(!card) {
|
||||
clearCard();
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl.$card = angular.copy(card);
|
||||
|
||||
if(typeModel) {
|
||||
typeModel.assign(scope, card.type);
|
||||
}
|
||||
|
||||
var length = 16;
|
||||
switch (card.type) {
|
||||
case 'amex':
|
||||
length = 15;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = (ref = num.length, __indexOf.call(card.length, ref) >= 0) && num.length === length && (card.luhn === false || _luhnCheck(num));
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
_validators.expiry = function(val){
|
||||
var month, year, obj;
|
||||
// valid if empty - let ng-required handle empty
|
||||
if(!val) return true;
|
||||
|
||||
obj = Common.parseExpiry(val);
|
||||
|
||||
month = obj.month;
|
||||
year = obj.year;
|
||||
|
||||
var currentTime, expiry, prefix;
|
||||
|
||||
if (!(month && year)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!/^\d+$/.test(month)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!/^\d+$/.test(year)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parseInt(month, 10) > 12) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (year.length === 2) {
|
||||
prefix = (new Date()).getFullYear();
|
||||
prefix = prefix.toString().slice(0, 2);
|
||||
year = prefix + year;
|
||||
}
|
||||
|
||||
expiry = new Date(year, month);
|
||||
currentTime = new Date();
|
||||
expiry.setMonth(expiry.getMonth() - 1);
|
||||
expiry.setMonth(expiry.getMonth() + 1, 1);
|
||||
|
||||
return expiry > currentTime;
|
||||
};
|
||||
|
||||
return function(type, val, ctrl, scope, attr){
|
||||
var types, errstr;
|
||||
if(!_validators[type]){
|
||||
|
||||
types = Object.keys(_validators);
|
||||
|
||||
errstr = 'Unknown type for validation: "'+type+'". ';
|
||||
errstr += 'Should be one of: "'+types.join('", "')+'"';
|
||||
|
||||
throw errstr;
|
||||
}
|
||||
return _validators[type](val, ctrl, scope, attr);
|
||||
};
|
||||
}])
|
||||
|
||||
|
||||
.factory('_ValidateWatch', ['_Validate', function(_Validate){
|
||||
|
||||
var _validatorWatches = {};
|
||||
|
||||
_validatorWatches.cvc = function(type, ctrl, scope, attr){
|
||||
if(attr.paymentsTypeModel) {
|
||||
scope.$watch(attr.paymentsTypeModel, function(newVal, oldVal) {
|
||||
if(newVal !== oldVal) {
|
||||
var valid = _Validate(type, ctrl.$modelValue, ctrl, scope, attr);
|
||||
ctrl.$setValidity(type, valid);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return function(type, ctrl, scope, attr){
|
||||
if(_validatorWatches[type]){
|
||||
return _validatorWatches[type](type, ctrl, scope, attr);
|
||||
}
|
||||
};
|
||||
}])
|
||||
|
||||
.directive('paymentsValidate', ['$window', '_Validate', '_ValidateWatch', function($window, _Validate, _ValidateWatch){
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: 'ngModel',
|
||||
link: function(scope, elem, attr, ctrl){
|
||||
|
||||
var type = attr.paymentsValidate;
|
||||
|
||||
_ValidateWatch(type, ctrl, scope, attr);
|
||||
|
||||
var validateFn = function(val) {
|
||||
var valid = _Validate(type, val, ctrl, scope, attr);
|
||||
ctrl.$setValidity(type, valid);
|
||||
return valid ? val : undefined;
|
||||
};
|
||||
|
||||
ctrl.$formatters.push(validateFn);
|
||||
ctrl.$parsers.push(validateFn);
|
||||
|
||||
}
|
||||
};
|
||||
}])
|
||||
|
||||
.directive('paymentsLength', [function() {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, elem, attr, modelCtrl) {
|
||||
modelCtrl.$parsers.push(function validateLength(value) {
|
||||
if (attr.paymentsLength === 'card') {
|
||||
var rawNumber = '';
|
||||
var minlength = scope.type === 'amex' ? 15 : 16;
|
||||
if (modelCtrl.$viewValue) {
|
||||
rawNumber = modelCtrl.$viewValue.replace(/\s/g, '');
|
||||
}
|
||||
modelCtrl.$setValidity('length', rawNumber.length >= minlength);
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
};
|
||||
}]);
|
||||
;/**
|
||||
* Stripe Form
|
||||
*/
|
||||
angular.module('angularPayments')
|
||||
|
||||
.directive('stripeForm', ['$window', '$parse', 'Common', function($window, $parse, Common) {
|
||||
|
||||
// directive intercepts form-submission, obtains Stripe's cardToken using stripe.js
|
||||
// and then passes that to callback provided in stripeForm, attribute.
|
||||
|
||||
// data that is sent to stripe is filtered from scope, looking for valid values to
|
||||
// send and converting camelCase to snake_case, e.g expMonth -> exp_month
|
||||
|
||||
|
||||
// filter valid stripe-values from scope and convert them from camelCase to snake_case
|
||||
var _getDataToSend = function(data){
|
||||
|
||||
var possibleKeys = ['number', 'expMonth', 'expYear',
|
||||
'cvc', 'name','addressLine1',
|
||||
'addressLine2', 'addressCity',
|
||||
'addressState', 'addressZip',
|
||||
'addressCountry'];
|
||||
|
||||
var camelToSnake = function(str){
|
||||
return str.replace(/([A-Z])/g, function(m){
|
||||
return "_"+m.toLowerCase();
|
||||
});
|
||||
};
|
||||
|
||||
var ret = {};
|
||||
|
||||
for(var i in possibleKeys){
|
||||
if(data.hasOwnProperty(possibleKeys[i])){
|
||||
ret[camelToSnake(possibleKeys[i])] = angular.copy(data[possibleKeys[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
ret.number = (ret.number || '').replace(/ /g,'');
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function(scope, elem, attr) {
|
||||
|
||||
if(!$window.Stripe){
|
||||
throw 'stripeForm requires that you have stripe.js installed. Include https://js.stripe.com/v2/ into your html.';
|
||||
}
|
||||
|
||||
var form = angular.element(elem);
|
||||
|
||||
form.bind('submit', function() {
|
||||
|
||||
var expMonthUsed = scope.expMonth ? true : false;
|
||||
var expYearUsed = scope.expYear ? true : false;
|
||||
|
||||
if(!(expMonthUsed && expYearUsed)){
|
||||
var exp = Common.parseExpiry(scope.expiry);
|
||||
scope.expMonth = exp.month;
|
||||
scope.expYear = exp.year;
|
||||
}
|
||||
|
||||
var button = form.find('button');
|
||||
button.prop('disabled', true);
|
||||
|
||||
if(form.hasClass('ng-valid')) {
|
||||
|
||||
$window.Stripe.createToken(_getDataToSend(scope), function() {
|
||||
var args = arguments;
|
||||
scope.$apply(function() {
|
||||
scope[attr.stripeForm].apply(scope, args);
|
||||
});
|
||||
button.prop('disabled', false);
|
||||
|
||||
});
|
||||
|
||||
} else {
|
||||
scope.$apply(function() {
|
||||
scope[attr.stripeForm].apply(scope, [400, {error: 'Invalid form submitted.'}]);
|
||||
});
|
||||
button.prop('disabled', false);
|
||||
}
|
||||
|
||||
scope.expMonth = null;
|
||||
scope.expYear = null;
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
}]);
|
Loading…
x
Reference in New Issue
Block a user