diff --git a/lib/angular-payments.js b/lib/angular-payments.js index bb1939a..c26d28a 100755 --- a/lib/angular-payments.js +++ b/lib/angular-payments.js @@ -328,7 +328,9 @@ angular.module('angularPayments', []);angular.module('angularPayments') // cvc - _formatCVC = function(e){ + var _formatCVC = function(e){ + var $target, digit, val; + $target = angular.element(e.currentTarget); digit = String.fromCharCode(e.which); @@ -353,7 +355,7 @@ angular.module('angularPayments', []);angular.module('angularPayments') // expiry - _restrictExpiry = function(e) { + var _restrictExpiry = function(e) { var $target, digit, value; $target = angular.element(e.currentTarget); @@ -377,7 +379,7 @@ angular.module('angularPayments', []);angular.module('angularPayments') } }; - _formatExpiry = function(e) { + var _formatExpiry = function(e) { var $target, digit, val; digit = String.fromCharCode(e.which); @@ -401,7 +403,7 @@ angular.module('angularPayments', []);angular.module('angularPayments') } }; - _formatForwardExpiry = function(e) { + var _formatForwardExpiry = function(e) { var $target, digit, val; digit = String.fromCharCode(e.which); @@ -418,7 +420,7 @@ angular.module('angularPayments', []);angular.module('angularPayments') } }; - _formatForwardSlash = function(e) { + var _formatForwardSlash = function(e) { var $target, slash, val; slash = String.fromCharCode(e.which); @@ -435,7 +437,7 @@ angular.module('angularPayments', []);angular.module('angularPayments') } }; - _formatBackExpiry = function(e) { + var _formatBackExpiry = function(e) { var $target, value; if (e.meta) { @@ -495,6 +497,8 @@ angular.module('angularPayments', []);angular.module('angularPayments') } return function(type, elem, ctrl){ + var types, errstr; + if(!_formats[type]){ types = Object.keys(_formats); @@ -517,7 +521,8 @@ angular.module('angularPayments', []);angular.module('angularPayments') _Format(attr.paymentsFormat, elem, ctrl); } } -}]);angular.module('angularPayments') +}]) +;angular.module('angularPayments') @@ -578,7 +583,7 @@ angular.module('angularPayments', []);angular.module('angularPayments') } _validators['card'] = function(num, ctrl, scope, attr){ - var card, ref, typeModel; + var card, ref, typeModel, ret; if(attr.paymentsTypeModel) { typeModel = $parse(attr.paymentsTypeModel); @@ -623,6 +628,8 @@ angular.module('angularPayments', []);angular.module('angularPayments') } _validators['expiry'] = function(val){ + var obj, month, year; + // valid if empty - let ng-required handle empty if(val == null || val.length == 0) return true; @@ -664,6 +671,8 @@ angular.module('angularPayments', []);angular.module('angularPayments') } return function(type, val, ctrl, scope, attr){ + var types, errstr; + if(!_validators[type]){ types = Object.keys(_validators); @@ -724,7 +733,7 @@ angular.module('angularPayments', []);angular.module('angularPayments') ;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. @@ -733,14 +742,14 @@ angular.module('angularPayments', []);angular.module('angularPayments') // filter valid stripe-values from scope and convert them from camelCase to snake_case - _getDataToSend = function(data){ - - var possibleKeys = ['number', 'expMonth', 'expYear', - 'cvc', 'name','addressLine1', + 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(); @@ -749,7 +758,7 @@ angular.module('angularPayments', []);angular.module('angularPayments') var ret = {}; - for(i in possibleKeys){ + for(var i in possibleKeys){ if(data.hasOwnProperty(possibleKeys[i])){ ret[camelToSnake(possibleKeys[i])] = angular.copy(data[possibleKeys[i]]); } @@ -771,6 +780,7 @@ angular.module('angularPayments', []);angular.module('angularPayments') var form = angular.element(elem); form.bind('submit', function() { + var expMonthUsed, expYearUsed, exp; expMonthUsed = scope.expMonth ? true : false; expYearUsed = scope.expYear ? true : false; @@ -785,7 +795,7 @@ angular.module('angularPayments', []);angular.module('angularPayments') button.prop('disabled', true); if(form.hasClass('ng-valid')) { - + $window.Stripe.createToken(_getDataToSend(scope), function() { var args = arguments; diff --git a/lib/angular-payments.min.js b/lib/angular-payments.min.js index 7fc3ada..311fec6 100644 --- a/lib/angular-payments.min.js +++ b/lib/angular-payments.min.js @@ -1,2 +1,2 @@ -/*! angular-payments 11-09-2014 */ -angular.module("angularPayments",[]),angular.module("angularPayments").factory("Common",[function(){var a={};return a.parseExpiry=function(a){var b,c,d,e;return a=a||"",a=a.replace(/\s/g,""),e=a.split("/",2),b=e[0],d=e[1],2===(null!=d?d.length:void 0)&&/^\d+$/.test(d)&&(c=(new Date).getFullYear(),c=c.toString().slice(0,2),d=c+d),b=parseInt(b,10),d=parseInt(d,10),{month:b,year:d}},a}]),angular.module("angularPayments").factory("Cards",[function(){var a=/(\d{1,4})/g,b=/(?:^|\s)(\d{4})$/,c=[{type:"maestro",pattern:/^(5018|5020|5038|6304|6759|676[1-3])/,format:a,inputFormat:b,length:[12,13,14,15,16,17,18,19],cvcLength:[3],luhn:!0},{type:"dinersclub",pattern:/^(36|38|30[0-5])/,format:a,inputFormat:b,length:[14],cvcLength:[3],luhn:!0},{type:"laser",pattern:/^(6706|6771|6709)/,format:a,inputFormat:b,length:[16,17,18,19],cvcLength:[3],luhn:!0},{type:"jcb",pattern:/^35/,format:a,inputFormat:b,length:[16],cvcLength:[3],luhn:!0},{type:"unionpay",pattern:/^62/,format:a,inputFormat:b,length:[16,17,18,19],cvcLength:[3],luhn:!1},{type:"discover",pattern:/^(6011|65|64[4-9]|622)/,format:a,inputFormat:b,length:[16],cvcLength:[3],luhn:!0},{type:"mastercard",pattern:/^5[1-5]/,format:a,inputFormat:b,length:[16],cvcLength:[3],luhn:!0},{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:!0},{type:"visa",pattern:/^4/,format:a,inputFormat:b,length:[13,14,15,16],cvcLength:[3],luhn:!0}],d=function(a){var b,d,e;for(a=(a+"").replace(/\D/g,""),d=0,e=c.length;e>d;d++)if(b=c[d],b.pattern.test(a))return b},e=function(a){var b,d,e;for(d=0,e=c.length;e>d;d++)if(b=c[d],b.type===a)return b};return{fromNumber:function(a){return d(a)},fromType:function(a){return e(a)},defaultFormat:function(){return a},defaultInputFormat:function(){return b}}}]),angular.module("angularPayments").factory("_Format",["Cards","Common","$filter",function(a,b,c){var d={},e=function(a){var b;return null!=a.prop("selectionStart")&&a.prop("selectionStart")!==a.prop("selectionEnd")?!0:("undefined"!=typeof document&&null!==document&&null!=(b=document.selection)&&"function"==typeof b.createRange?b.createRange().text:void 0)?!0:!1},f=function(b){var c,d,e,f,g,h,i;if(e=String.fromCharCode(b.which),c=angular.element(b.currentTarget),i=c.val(),d=a.fromNumber(i+e),f=(i.replace(/\D/g,"")+e).length,h=16,d&&(h=d.length[d.length.length-1]),!(f>=h)){if(!/^\d+$/.test(e)&&!b.meta&&b.keyCode>=46)return void b.preventDefault();if(null==c.prop("selectionStart")||c.prop("selectionStart")===i.length)return g=a.defaultInputFormat(),d&&(g=d.inputFormat),g.test(i)?(b.preventDefault(),c.val(i+" "+e)):g.test(i+e)?(b.preventDefault(),c.val(i+e+" ")):void 0}},g=function(b){var c,d,f,g;c=angular.element(b.currentTarget),f=String.fromCharCode(b.which),/^\d+$/.test(f)&&(e(c)||(g=(c.val()+f).replace(/\D/g,""),d=a.fromNumber(g),d?g.length<=d.length[d.length.length-1]||b.preventDefault():g.length<=16||b.preventDefault()))},h=function(a){var b,c;return b=angular.element(a.currentTarget),c=b.val(),a.meta||8!==a.which||null!=b.prop("selectionStart")&&b.prop("selectionStart")!==c.length?void 0:/\d\s$/.test(c)&&!a.meta&&a.keyCode>=46?(a.preventDefault(),b.val(c.replace(/\d\s$/,""))):/\s\d?$/.test(c)?(a.preventDefault(),b.val(c.replace(/\s\d?$/,""))):void 0},i=function(b){var c,d,e,f;return(c=a.fromNumber(b))?(e=c.length[c.length.length-1],b=b.replace(/\D/g,""),b=b.slice(0,+e+1||9e9),c.format.global?null!=(f=b.match(c.format))?f.join(" "):void 0:(d=c.format.exec(b),null!=d&&d.shift(),null!=d?d.join(" "):void 0)):b},j=function(a){return setTimeout(function(){var b,c;return b=angular.element(a.target),c=b.val(),c=i(c),b.val(c)})},k=function(a){return null!=a?a.replace(/\s/g,""):a};d.card=function(a,b){a.bind("keypress",g),a.bind("keypress",f),a.bind("keydown",h),a.bind("paste",j),b.$parsers.push(k),b.$formatters.push(i)},_formatCVC=function(a){return $target=angular.element(a.currentTarget),digit=String.fromCharCode(a.which),!/^\d+$/.test(digit)&&!a.meta&&a.keyCode>=46?void a.preventDefault():(val=$target.val()+digit,val.length<=4?void 0:void a.preventDefault())},d.cvc=function(a){a.bind("keypress",_formatCVC)},_restrictExpiry=function(a){var b,c,d;return b=angular.element(a.currentTarget),c=String.fromCharCode(a.which),!/^\d+$/.test(c)&&!a.meta&&a.keyCode>=46?void a.preventDefault():e(b)?void 0:(d=b.val()+c,d=d.replace(/\D/g,""),d.length>6?void a.preventDefault():void 0)},_formatExpiry=function(a){var b,c,d;return c=String.fromCharCode(a.which),!/^\d+$/.test(c)&&!a.meta&&a.keyCode>=46?void a.preventDefault():(b=angular.element(a.currentTarget),d=b.val()+c,/^\d$/.test(d)&&"0"!==d&&"1"!==d?(a.preventDefault(),b.val("0"+d+" / ")):/^\d\d$/.test(d)?(a.preventDefault(),b.val(""+d+" / ")):void 0)},_formatForwardExpiry=function(a){var b,c,d;return c=String.fromCharCode(a.which),!/^\d+$/.test(c)&&!a.meta&&a.keyCode>=46?void 0:(b=angular.element(a.currentTarget),d=b.val(),/^\d\d$/.test(d)?b.val(""+d+" / "):void 0)},_formatForwardSlash=function(a){var b,c,d;return c=String.fromCharCode(a.which),"/"===c?(b=angular.element(a.currentTarget),d=b.val(),/^\d$/.test(d)&&"0"!==d?b.val("0"+d+" / "):void 0):void 0},_formatBackExpiry=function(a){var b,c;if(!a.meta&&(b=angular.element(a.currentTarget),c=b.val(),8===a.which&&(null==b.prop("selectionStart")||b.prop("selectionStart")===c.length)))return/\d(\s|\/)+$/.test(c)?(a.preventDefault(),b.val(c.replace(/\d(\s|\/)*$/,""))):/\s\/\s?\d?$/.test(c)?(a.preventDefault(),b.val(c.replace(/\s\/\s?\d?$/,""))):void 0};var l=function(a){if(null!=a){var d=b.parseExpiry(a),e=new Date(d.year,d.month-1);return c("date")(e,"MM/yyyy")}return null},m=function(a){if(null!=a){var d=b.parseExpiry(a),e=new Date(d.year,d.month-1);return c("date")(e,"MM / yyyy")}return null};return d.expiry=function(a,b){a.bind("keypress",_restrictExpiry),a.bind("keypress",_formatExpiry),a.bind("keypress",_formatForwardSlash),a.bind("keypress",_formatForwardExpiry),a.bind("keydown",_formatBackExpiry),b.$parsers.push(l),b.$formatters.push(m)},function(a,b,c){if(!d[a])throw types=Object.keys(d),errstr='Unknown type for formatting: "'+a+'". ',errstr+='Should be one of: "'+types.join('", "')+'"';return d[a](b,c)}}]).directive("paymentsFormat",["$window","_Format",function(a,b){return{restrict:"A",require:"ngModel",link:function(a,c,d,e){b(d.paymentsFormat,c,e)}}}]),angular.module("angularPayments").factory("_Validate",["Cards","Common","$parse",function(a,b,c){var d=[].indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(b in this&&this[b]===a)return b;return-1},e=function(a){var b,c,d,e,f,g;for(d=!0,e=0,c=(a+"").split("").reverse(),f=0,g=c.length;g>f;f++)b=c[f],b=parseInt(b,10),(d=!d)&&(b*=2),b>9&&(b-=9),e+=b;return e%10===0},f={};return f.cvc=function(b,e,f,g){var h,i;if(null==b||0==b.length)return!0;if(!/^\d+$/.test(b))return!1;var j;if(g.paymentsTypeModel){var k=c(g.paymentsTypeModel);j=k(f)}return j?(h=b.length,d.call(null!=(i=a.fromType(j))?i.cvcLength:void 0,h)>=0):b.length>=3&&b.length<=4},f.card=function(b,f,g,h){var i,j,k;h.paymentsTypeModel&&(k=c(h.paymentsTypeModel));var l=function(){k&&k.assign(g,null),f.$card=null};return null==b||0==b.length?(l(),!0):(b=(b+"").replace(/\s+|-/g,""),/^\d+$/.test(b)&&(i=a.fromNumber(b))?(f.$card=angular.copy(i),k&&k.assign(g,i.type),j=b.length,ret=d.call(i.length,j)>=0&&(i.luhn===!1||e(b)),ret):(l(),!1))},f.expiry=function(a){if(null==a||0==a.length)return!0;obj=b.parseExpiry(a),month=obj.month,year=obj.year;var c,d,e;return month&&year&&/^\d+$/.test(month)&&/^\d+$/.test(year)&&parseInt(month,10)<=12?(2===year.length&&(e=(new Date).getFullYear(),e=e.toString().slice(0,2),year=e+year),d=new Date(year,month),c=new Date,d.setMonth(d.getMonth()-1),d.setMonth(d.getMonth()+1,1),d>c):!1},function(a,b,c,d,e){if(!f[a])throw types=Object.keys(f),errstr='Unknown type for validation: "'+a+'". ',errstr+='Should be one of: "'+types.join('", "')+'"';return f[a](b,c,d,e)}}]).factory("_ValidateWatch",["_Validate",function(a){var b={};return b.cvc=function(b,c,d,e){e.paymentsTypeModel&&d.$watch(e.paymentsTypeModel,function(f,g){if(f!=g){var h=a(b,c.$modelValue,c,d,e);c.$setValidity(b,h)}})},function(a,c,d,e){return b[a]?b[a](a,c,d,e):void 0}}]).directive("paymentsValidate",["$window","_Validate","_ValidateWatch",function(a,b,c){return{restrict:"A",require:"ngModel",link:function(a,d,e,f){var g=e.paymentsValidate;c(g,f,a,e);var h=function(c){var d=b(g,c,f,a,e);return f.$setValidity(g,d),d?c:void 0};f.$formatters.push(h),f.$parsers.push(h)}}}]),angular.module("angularPayments").directive("stripeForm",["$window","$parse","Common",function(a,b,c){return _getDataToSend=function(a){var b=["number","expMonth","expYear","cvc","name","addressLine1","addressLine2","addressCity","addressState","addressZip","addressCountry"],c=function(a){return a.replace(/([A-Z])/g,function(a){return"_"+a.toLowerCase()})},d={};for(i in b)a.hasOwnProperty(b[i])&&(d[c(b[i])]=angular.copy(a[b[i]]));return d.number=(d.number||"").replace(/ /g,""),d},{restrict:"A",link:function(b,d,e){if(!a.Stripe)throw"stripeForm requires that you have stripe.js installed. Include https://js.stripe.com/v2/ into your html.";var f=angular.element(d);f.bind("submit",function(){expMonthUsed=b.expMonth?!0:!1,expYearUsed=b.expYear?!0:!1,expMonthUsed&&expYearUsed||(exp=c.parseExpiry(b.expiry),b.expMonth=exp.month,b.expYear=exp.year);var d=f.find("button");d.prop("disabled",!0),f.hasClass("ng-valid")?a.Stripe.createToken(_getDataToSend(b),function(){var a=arguments;b.$apply(function(){b[e.stripeForm].apply(b,a)}),d.prop("disabled",!1)}):(b.$apply(function(){b[e.stripeForm].apply(b,[400,{error:"Invalid form submitted."}])}),d.prop("disabled",!1)),b.expMonth=null,b.expYear=null})}}}]); \ No newline at end of file +/*! angular-payments 05-03-2015 */ +angular.module("angularPayments",[]),angular.module("angularPayments").factory("Common",[function(){var a={};return a.parseExpiry=function(a){var b,c,d,e;return a=a||"",a=a.replace(/\s/g,""),e=a.split("/",2),b=e[0],d=e[1],2===(null!=d?d.length:void 0)&&/^\d+$/.test(d)&&(c=(new Date).getFullYear(),c=c.toString().slice(0,2),d=c+d),b=parseInt(b,10),d=parseInt(d,10),{month:b,year:d}},a}]),angular.module("angularPayments").factory("Cards",[function(){var a=/(\d{1,4})/g,b=/(?:^|\s)(\d{4})$/,c=[{type:"maestro",pattern:/^(5018|5020|5038|6304|6759|676[1-3])/,format:a,inputFormat:b,length:[12,13,14,15,16,17,18,19],cvcLength:[3],luhn:!0},{type:"dinersclub",pattern:/^(36|38|30[0-5])/,format:a,inputFormat:b,length:[14],cvcLength:[3],luhn:!0},{type:"laser",pattern:/^(6706|6771|6709)/,format:a,inputFormat:b,length:[16,17,18,19],cvcLength:[3],luhn:!0},{type:"jcb",pattern:/^35/,format:a,inputFormat:b,length:[16],cvcLength:[3],luhn:!0},{type:"unionpay",pattern:/^62/,format:a,inputFormat:b,length:[16,17,18,19],cvcLength:[3],luhn:!1},{type:"discover",pattern:/^(6011|65|64[4-9]|622)/,format:a,inputFormat:b,length:[16],cvcLength:[3],luhn:!0},{type:"mastercard",pattern:/^5[1-5]/,format:a,inputFormat:b,length:[16],cvcLength:[3],luhn:!0},{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:!0},{type:"visa",pattern:/^4/,format:a,inputFormat:b,length:[13,14,15,16],cvcLength:[3],luhn:!0}],d=function(a){var b,d,e;for(a=(a+"").replace(/\D/g,""),d=0,e=c.length;e>d;d++)if(b=c[d],b.pattern.test(a))return b},e=function(a){var b,d,e;for(d=0,e=c.length;e>d;d++)if(b=c[d],b.type===a)return b};return{fromNumber:function(a){return d(a)},fromType:function(a){return e(a)},defaultFormat:function(){return a},defaultInputFormat:function(){return b}}}]),angular.module("angularPayments").factory("_Format",["Cards","Common","$filter",function(a,b,c){var d={},e=function(a){var b;return null!=a.prop("selectionStart")&&a.prop("selectionStart")!==a.prop("selectionEnd")?!0:("undefined"!=typeof document&&null!==document&&null!=(b=document.selection)&&"function"==typeof b.createRange?b.createRange().text:void 0)?!0:!1},f=function(b){var c,d,e,f,g,h,i;if(e=String.fromCharCode(b.which),c=angular.element(b.currentTarget),i=c.val(),d=a.fromNumber(i+e),f=(i.replace(/\D/g,"")+e).length,h=16,d&&(h=d.length[d.length.length-1]),!(f>=h)){if(!/^\d+$/.test(e)&&!b.meta&&b.keyCode>=46)return void b.preventDefault();if(null==c.prop("selectionStart")||c.prop("selectionStart")===i.length)return g=a.defaultInputFormat(),d&&(g=d.inputFormat),g.test(i)?(b.preventDefault(),c.val(i+" "+e)):g.test(i+e)?(b.preventDefault(),c.val(i+e+" ")):void 0}},g=function(b){var c,d,f,g;c=angular.element(b.currentTarget),f=String.fromCharCode(b.which),/^\d+$/.test(f)&&(e(c)||(g=(c.val()+f).replace(/\D/g,""),d=a.fromNumber(g),d?g.length<=d.length[d.length.length-1]||b.preventDefault():g.length<=16||b.preventDefault()))},h=function(a){var b,c;return b=angular.element(a.currentTarget),c=b.val(),a.meta||8!==a.which||null!=b.prop("selectionStart")&&b.prop("selectionStart")!==c.length?void 0:/\d\s$/.test(c)&&!a.meta&&a.keyCode>=46?(a.preventDefault(),b.val(c.replace(/\d\s$/,""))):/\s\d?$/.test(c)?(a.preventDefault(),b.val(c.replace(/\s\d?$/,""))):void 0},i=function(b){var c,d,e,f;return(c=a.fromNumber(b))?(e=c.length[c.length.length-1],b=b.replace(/\D/g,""),b=b.slice(0,+e+1||9e9),c.format.global?null!=(f=b.match(c.format))?f.join(" "):void 0:(d=c.format.exec(b),null!=d&&d.shift(),null!=d?d.join(" "):void 0)):b},j=function(a){return setTimeout(function(){var b,c;return b=angular.element(a.target),c=b.val(),c=i(c),b.val(c)})},k=function(a){return null!=a?a.replace(/\s/g,""):a};d.card=function(a,b){a.bind("keypress",g),a.bind("keypress",f),a.bind("keydown",h),a.bind("paste",j),b.$parsers.push(k),b.$formatters.push(i)};var l=function(a){var b,c,d;return b=angular.element(a.currentTarget),c=String.fromCharCode(a.which),!/^\d+$/.test(c)&&!a.meta&&a.keyCode>=46?void a.preventDefault():(d=b.val()+c,d.length<=4?void 0:void a.preventDefault())};d.cvc=function(a){a.bind("keypress",l)};var m=function(a){var b,c,d;return b=angular.element(a.currentTarget),c=String.fromCharCode(a.which),!/^\d+$/.test(c)&&!a.meta&&a.keyCode>=46?void a.preventDefault():e(b)?void 0:(d=b.val()+c,d=d.replace(/\D/g,""),d.length>6?void a.preventDefault():void 0)},n=function(a){var b,c,d;return c=String.fromCharCode(a.which),!/^\d+$/.test(c)&&!a.meta&&a.keyCode>=46?void a.preventDefault():(b=angular.element(a.currentTarget),d=b.val()+c,/^\d$/.test(d)&&"0"!==d&&"1"!==d?(a.preventDefault(),b.val("0"+d+" / ")):/^\d\d$/.test(d)?(a.preventDefault(),b.val(""+d+" / ")):void 0)},o=function(a){var b,c,d;return c=String.fromCharCode(a.which),!/^\d+$/.test(c)&&!a.meta&&a.keyCode>=46?void 0:(b=angular.element(a.currentTarget),d=b.val(),/^\d\d$/.test(d)?b.val(""+d+" / "):void 0)},p=function(a){var b,c,d;return c=String.fromCharCode(a.which),"/"===c?(b=angular.element(a.currentTarget),d=b.val(),/^\d$/.test(d)&&"0"!==d?b.val("0"+d+" / "):void 0):void 0},q=function(a){var b,c;if(!a.meta&&(b=angular.element(a.currentTarget),c=b.val(),8===a.which&&(null==b.prop("selectionStart")||b.prop("selectionStart")===c.length)))return/\d(\s|\/)+$/.test(c)?(a.preventDefault(),b.val(c.replace(/\d(\s|\/)*$/,""))):/\s\/\s?\d?$/.test(c)?(a.preventDefault(),b.val(c.replace(/\s\/\s?\d?$/,""))):void 0},r=function(a){if(null!=a){var d=b.parseExpiry(a),e=new Date(d.year,d.month-1);return c("date")(e,"MM/yyyy")}return null},s=function(a){if(null!=a){var d=b.parseExpiry(a),e=new Date(d.year,d.month-1);return c("date")(e,"MM / yyyy")}return null};return d.expiry=function(a,b){a.bind("keypress",m),a.bind("keypress",n),a.bind("keypress",p),a.bind("keypress",o),a.bind("keydown",q),b.$parsers.push(r),b.$formatters.push(s)},function(a,b,c){var e,f;if(!d[a])throw e=Object.keys(d),f='Unknown type for formatting: "'+a+'". ',f+='Should be one of: "'+e.join('", "')+'"';return d[a](b,c)}}]).directive("paymentsFormat",["$window","_Format",function(a,b){return{restrict:"A",require:"ngModel",link:function(a,c,d,e){b(d.paymentsFormat,c,e)}}}]),angular.module("angularPayments").factory("_Validate",["Cards","Common","$parse",function(a,b,c){var d=[].indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(b in this&&this[b]===a)return b;return-1},e=function(a){var b,c,d,e,f,g;for(d=!0,e=0,c=(a+"").split("").reverse(),f=0,g=c.length;g>f;f++)b=c[f],b=parseInt(b,10),(d=!d)&&(b*=2),b>9&&(b-=9),e+=b;return e%10===0},f={};return f.cvc=function(b,e,f,g){var h,i;if(null==b||0==b.length)return!0;if(!/^\d+$/.test(b))return!1;var j;if(g.paymentsTypeModel){var k=c(g.paymentsTypeModel);j=k(f)}return j?(h=b.length,d.call(null!=(i=a.fromType(j))?i.cvcLength:void 0,h)>=0):b.length>=3&&b.length<=4},f.card=function(b,f,g,h){var i,j,k,l;h.paymentsTypeModel&&(k=c(h.paymentsTypeModel));var m=function(){k&&k.assign(g,null),f.$card=null};return null==b||0==b.length?(m(),!0):(b=(b+"").replace(/\s+|-/g,""),/^\d+$/.test(b)&&(i=a.fromNumber(b))?(f.$card=angular.copy(i),k&&k.assign(g,i.type),j=b.length,l=d.call(i.length,j)>=0&&(i.luhn===!1||e(b)),l):(m(),!1))},f.expiry=function(a){var c,d,e;if(null==a||0==a.length)return!0;c=b.parseExpiry(a),d=c.month,e=c.year;var f,g,h;return d&&e&&/^\d+$/.test(d)&&/^\d+$/.test(e)&&parseInt(d,10)<=12?(2===e.length&&(h=(new Date).getFullYear(),h=h.toString().slice(0,2),e=h+e),g=new Date(e,d),f=new Date,g.setMonth(g.getMonth()-1),g.setMonth(g.getMonth()+1,1),g>f):!1},function(a,b,c,d,e){var g,h;if(!f[a])throw g=Object.keys(f),h='Unknown type for validation: "'+a+'". ',h+='Should be one of: "'+g.join('", "')+'"';return f[a](b,c,d,e)}}]).factory("_ValidateWatch",["_Validate",function(a){var b={};return b.cvc=function(b,c,d,e){e.paymentsTypeModel&&d.$watch(e.paymentsTypeModel,function(f,g){if(f!=g){var h=a(b,c.$modelValue,c,d,e);c.$setValidity(b,h)}})},function(a,c,d,e){return b[a]?b[a](a,c,d,e):void 0}}]).directive("paymentsValidate",["$window","_Validate","_ValidateWatch",function(a,b,c){return{restrict:"A",require:"ngModel",link:function(a,d,e,f){var g=e.paymentsValidate;c(g,f,a,e);var h=function(c){var d=b(g,c,f,a,e);return f.$setValidity(g,d),d?c:void 0};f.$formatters.push(h),f.$parsers.push(h)}}}]),angular.module("angularPayments").directive("stripeForm",["$window","$parse","Common",function(a,b,c){var d=function(a){var b=["number","expMonth","expYear","cvc","name","addressLine1","addressLine2","addressCity","addressState","addressZip","addressCountry"],c=function(a){return a.replace(/([A-Z])/g,function(a){return"_"+a.toLowerCase()})},d={};for(var e in b)a.hasOwnProperty(b[e])&&(d[c(b[e])]=angular.copy(a[b[e]]));return d.number=(d.number||"").replace(/ /g,""),d};return{restrict:"A",link:function(b,e,f){if(!a.Stripe)throw"stripeForm requires that you have stripe.js installed. Include https://js.stripe.com/v2/ into your html.";var g=angular.element(e);g.bind("submit",function(){var e,h,i;e=b.expMonth?!0:!1,h=b.expYear?!0:!1,e&&h||(i=c.parseExpiry(b.expiry),b.expMonth=i.month,b.expYear=i.year);var j=g.find("button");j.prop("disabled",!0),g.hasClass("ng-valid")?a.Stripe.createToken(d(b),function(){var a=arguments;b.$apply(function(){b[f.stripeForm].apply(b,a)}),j.prop("disabled",!1)}):(b.$apply(function(){b[f.stripeForm].apply(b,[400,{error:"Invalid form submitted."}])}),j.prop("disabled",!1)),b.expMonth=null,b.expYear=null})}}}]); diff --git a/src/form.js b/src/form.js index 121c1f2..14c8106 100644 --- a/src/form.js +++ b/src/form.js @@ -1,7 +1,7 @@ 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. @@ -10,14 +10,14 @@ angular.module('angularPayments') // filter valid stripe-values from scope and convert them from camelCase to snake_case - _getDataToSend = function(data){ - - var possibleKeys = ['number', 'expMonth', 'expYear', - 'cvc', 'name','addressLine1', + 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(); @@ -26,7 +26,7 @@ angular.module('angularPayments') var ret = {}; - for(i in possibleKeys){ + for(var i in possibleKeys){ if(data.hasOwnProperty(possibleKeys[i])){ ret[camelToSnake(possibleKeys[i])] = angular.copy(data[possibleKeys[i]]); } @@ -48,6 +48,7 @@ angular.module('angularPayments') var form = angular.element(elem); form.bind('submit', function() { + var expMonthUsed, expYearUsed, exp; expMonthUsed = scope.expMonth ? true : false; expYearUsed = scope.expYear ? true : false; @@ -62,7 +63,7 @@ angular.module('angularPayments') button.prop('disabled', true); if(form.hasClass('ng-valid')) { - + $window.Stripe.createToken(_getDataToSend(scope), function() { var args = arguments; diff --git a/src/format.js b/src/format.js index 68455cf..7db9fa8 100644 --- a/src/format.js +++ b/src/format.js @@ -174,7 +174,9 @@ angular.module('angularPayments') // cvc - _formatCVC = function(e){ + var _formatCVC = function(e){ + var $target, digit, val; + $target = angular.element(e.currentTarget); digit = String.fromCharCode(e.which); @@ -199,7 +201,7 @@ angular.module('angularPayments') // expiry - _restrictExpiry = function(e) { + var _restrictExpiry = function(e) { var $target, digit, value; $target = angular.element(e.currentTarget); @@ -223,7 +225,7 @@ angular.module('angularPayments') } }; - _formatExpiry = function(e) { + var _formatExpiry = function(e) { var $target, digit, val; digit = String.fromCharCode(e.which); @@ -247,7 +249,7 @@ angular.module('angularPayments') } }; - _formatForwardExpiry = function(e) { + var _formatForwardExpiry = function(e) { var $target, digit, val; digit = String.fromCharCode(e.which); @@ -264,7 +266,7 @@ angular.module('angularPayments') } }; - _formatForwardSlash = function(e) { + var _formatForwardSlash = function(e) { var $target, slash, val; slash = String.fromCharCode(e.which); @@ -281,7 +283,7 @@ angular.module('angularPayments') } }; - _formatBackExpiry = function(e) { + var _formatBackExpiry = function(e) { var $target, value; if (e.meta) { @@ -341,6 +343,8 @@ angular.module('angularPayments') } return function(type, elem, ctrl){ + var types, errstr; + if(!_formats[type]){ types = Object.keys(_formats); @@ -363,4 +367,4 @@ angular.module('angularPayments') _Format(attr.paymentsFormat, elem, ctrl); } } -}]) \ No newline at end of file +}]) diff --git a/src/validate.js b/src/validate.js index ecf412c..909bdd8 100644 --- a/src/validate.js +++ b/src/validate.js @@ -59,7 +59,7 @@ angular.module('angularPayments') } _validators['card'] = function(num, ctrl, scope, attr){ - var card, ref, typeModel; + var card, ref, typeModel, ret; if(attr.paymentsTypeModel) { typeModel = $parse(attr.paymentsTypeModel); @@ -104,6 +104,8 @@ angular.module('angularPayments') } _validators['expiry'] = function(val){ + var obj, month, year; + // valid if empty - let ng-required handle empty if(val == null || val.length == 0) return true; @@ -145,6 +147,8 @@ angular.module('angularPayments') } return function(type, val, ctrl, scope, attr){ + var types, errstr; + if(!_validators[type]){ types = Object.keys(_validators);