From 5191dd2c369e4997a36778c9b502b12b2a80e255 Mon Sep 17 00:00:00 2001 From: Ferrari Date: Thu, 21 Aug 2014 18:29:04 +0800 Subject: [PATCH 1/8] remove meaningless checking for expiry value --- lib/angular-payments.js | 14 +++----------- lib/angular-payments.min.js | 4 ++-- src/form.js | 14 +++----------- 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/lib/angular-payments.js b/lib/angular-payments.js index 771d934..a9be505 100755 --- a/lib/angular-payments.js +++ b/lib/angular-payments.js @@ -772,14 +772,9 @@ angular.module('angularPayments', []);angular.module('angularPayments') form.bind('submit', function() { - expMonthUsed = scope.expMonth ? true : false; - expYearUsed = scope.expYear ? true : false; - - if(!(expMonthUsed && expYearUsed)){ - exp = Common.parseExpiry(scope.expiry) - scope.expMonth = exp.month - scope.expYear = exp.year - } + exp = Common.parseExpiry(scope.expiry) + scope.expMonth = exp.month + scope.expYear = exp.year var button = form.find('button'); button.prop('disabled', true); @@ -803,9 +798,6 @@ angular.module('angularPayments', []);angular.module('angularPayments') button.prop('disabled', false); } - scope.expiryMonth = expMonthUsed ? scope.expMonth : null; - scope.expiryYear = expYearUsed ? scope.expMonth : null; - }); } } diff --git a/lib/angular-payments.min.js b/lib/angular-payments.min.js index 3983312..d792bee 100644 --- a/lib/angular-payments.min.js +++ b/lib/angular-payments.min.js @@ -1,2 +1,2 @@ -/*! angular-payments 31-01-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:void 0: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):(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:!1:!1:!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)b.hasOwnProperty(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.expiryMonth=expMonthUsed?b.expMonth:null,b.expiryYear=expYearUsed?b.expMonth:null})}}}]); \ No newline at end of file +/*! angular-payments 21-08-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)b.hasOwnProperty(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(){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))})}}}]); \ No newline at end of file diff --git a/src/form.js b/src/form.js index accc3cd..c048117 100644 --- a/src/form.js +++ b/src/form.js @@ -49,14 +49,9 @@ angular.module('angularPayments') form.bind('submit', function() { - expMonthUsed = scope.expMonth ? true : false; - expYearUsed = scope.expYear ? true : false; - - if(!(expMonthUsed && expYearUsed)){ - exp = Common.parseExpiry(scope.expiry) - scope.expMonth = exp.month - scope.expYear = exp.year - } + exp = Common.parseExpiry(scope.expiry) + scope.expMonth = exp.month + scope.expYear = exp.year var button = form.find('button'); button.prop('disabled', true); @@ -80,9 +75,6 @@ angular.module('angularPayments') button.prop('disabled', false); } - scope.expiryMonth = expMonthUsed ? scope.expMonth : null; - scope.expiryYear = expYearUsed ? scope.expMonth : null; - }); } } From d155b230157d26e26c3446916093729590fc5984 Mon Sep 17 00:00:00 2001 From: Ferrari Date: Fri, 22 Aug 2014 02:34:12 +0800 Subject: [PATCH 2/8] return specific error message --- lib/angular-payments.js | 21 ++++++++++++++------- lib/angular-payments.min.js | 4 ++-- src/form.js | 21 ++++++++++++++------- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/lib/angular-payments.js b/lib/angular-payments.js index a9be505..cee484a 100755 --- a/lib/angular-payments.js +++ b/lib/angular-payments.js @@ -724,7 +724,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. @@ -734,13 +734,13 @@ 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 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(); @@ -780,7 +780,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; @@ -792,8 +792,15 @@ angular.module('angularPayments', []);angular.module('angularPayments') }); } else { + var errorItem = []; + if (form.hasClass('ng-invalid-card')) errorItem.push('Credit Card'); + if (form.hasClass('ng-invalid-expiry')) errorItem.push('Expiry'); + if (form.hasClass('ng-invalid-cvc')) errorItem.push('CVC'); + if (form.hasClass('ng-invalid-required')) errorItem.push('Missing required fields'); + var errorMessage = 'Invalid form submitted: ' + errorItem.join(', '); + scope.$apply(function() { - scope[attr.stripeForm].apply(scope, [400, {error: 'Invalid form submitted.'}]); + scope[attr.stripeForm].apply(scope, [400, {error: errorMessage }]); }); button.prop('disabled', false); } diff --git a/lib/angular-payments.min.js b/lib/angular-payments.min.js index d792bee..00c9fc3 100644 --- a/lib/angular-payments.min.js +++ b/lib/angular-payments.min.js @@ -1,2 +1,2 @@ -/*! angular-payments 21-08-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)b.hasOwnProperty(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(){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))})}}}]); \ No newline at end of file +/*! angular-payments 22-08-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)b.hasOwnProperty(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(){exp=c.parseExpiry(b.expiry),b.expMonth=exp.month,b.expYear=exp.year;var d=f.find("button");if(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)});else{var g=[];f.hasClass("ng-invalid-card")&&g.push("Credit Card"),f.hasClass("ng-invalid-expiry")&&g.push("Expiry"),f.hasClass("ng-invalid-cvc")&&g.push("CVC"),f.hasClass("ng-invalid-required")&&g.push("Missing required fields");var h="Invalid form submitted: "+g.join(", ");b.$apply(function(){b[e.stripeForm].apply(b,[400,{error:h}])}),d.prop("disabled",!1)}})}}}]); \ No newline at end of file diff --git a/src/form.js b/src/form.js index c048117..aff65d2 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. @@ -11,13 +11,13 @@ 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 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(); @@ -57,7 +57,7 @@ angular.module('angularPayments') button.prop('disabled', true); if(form.hasClass('ng-valid')) { - + $window.Stripe.createToken(_getDataToSend(scope), function() { var args = arguments; @@ -69,8 +69,15 @@ angular.module('angularPayments') }); } else { + var errorItem = []; + if (form.hasClass('ng-invalid-card')) errorItem.push('Credit Card'); + if (form.hasClass('ng-invalid-expiry')) errorItem.push('Expiry'); + if (form.hasClass('ng-invalid-cvc')) errorItem.push('CVC'); + if (form.hasClass('ng-invalid-required')) errorItem.push('Missing required fields'); + var errorMessage = 'Invalid form submitted: ' + errorItem.join(', '); + scope.$apply(function() { - scope[attr.stripeForm].apply(scope, [400, {error: 'Invalid form submitted.'}]); + scope[attr.stripeForm].apply(scope, [400, {error: errorMessage }]); }); button.prop('disabled', false); } From f4f50fa7b149015a33a1a6d5daa56a43fe7fd9a9 Mon Sep 17 00:00:00 2001 From: Ferrari Lee Date: Mon, 20 Oct 2014 00:07:34 +0800 Subject: [PATCH 3/8] remove disable button for flexiable usage --- lib/angular-payments.js | 6 ------ lib/angular-payments.min.js | 4 ++-- src/form.js | 6 ------ 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/lib/angular-payments.js b/lib/angular-payments.js index cee484a..44c543b 100755 --- a/lib/angular-payments.js +++ b/lib/angular-payments.js @@ -776,9 +776,6 @@ angular.module('angularPayments', []);angular.module('angularPayments') scope.expMonth = exp.month scope.expYear = exp.year - var button = form.find('button'); - button.prop('disabled', true); - if(form.hasClass('ng-valid')) { @@ -787,8 +784,6 @@ angular.module('angularPayments', []);angular.module('angularPayments') scope.$apply(function() { scope[attr.stripeForm].apply(scope, args); }); - button.prop('disabled', false); - }); } else { @@ -802,7 +797,6 @@ angular.module('angularPayments', []);angular.module('angularPayments') scope.$apply(function() { scope[attr.stripeForm].apply(scope, [400, {error: errorMessage }]); }); - button.prop('disabled', false); } }); diff --git a/lib/angular-payments.min.js b/lib/angular-payments.min.js index 00c9fc3..3ee6582 100644 --- a/lib/angular-payments.min.js +++ b/lib/angular-payments.min.js @@ -1,2 +1,2 @@ -/*! angular-payments 22-08-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)b.hasOwnProperty(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(){exp=c.parseExpiry(b.expiry),b.expMonth=exp.month,b.expYear=exp.year;var d=f.find("button");if(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)});else{var g=[];f.hasClass("ng-invalid-card")&&g.push("Credit Card"),f.hasClass("ng-invalid-expiry")&&g.push("Expiry"),f.hasClass("ng-invalid-cvc")&&g.push("CVC"),f.hasClass("ng-invalid-required")&&g.push("Missing required fields");var h="Invalid form submitted: "+g.join(", ");b.$apply(function(){b[e.stripeForm].apply(b,[400,{error:h}])}),d.prop("disabled",!1)}})}}}]); \ No newline at end of file +/*! angular-payments 20-10-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)b.hasOwnProperty(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(){if(exp=c.parseExpiry(b.expiry),b.expMonth=exp.month,b.expYear=exp.year,f.hasClass("ng-valid"))a.Stripe.createToken(_getDataToSend(b),function(){var a=arguments;b.$apply(function(){b[e.stripeForm].apply(b,a)})});else{var d=[];f.hasClass("ng-invalid-card")&&d.push("Credit Card"),f.hasClass("ng-invalid-expiry")&&d.push("Expiry"),f.hasClass("ng-invalid-cvc")&&d.push("CVC"),f.hasClass("ng-invalid-required")&&d.push("Missing required fields");var g="Invalid form submitted: "+d.join(", ");b.$apply(function(){b[e.stripeForm].apply(b,[400,{error:g}])})}})}}}]); \ No newline at end of file diff --git a/src/form.js b/src/form.js index aff65d2..f881cad 100644 --- a/src/form.js +++ b/src/form.js @@ -53,9 +53,6 @@ angular.module('angularPayments') scope.expMonth = exp.month scope.expYear = exp.year - var button = form.find('button'); - button.prop('disabled', true); - if(form.hasClass('ng-valid')) { @@ -64,8 +61,6 @@ angular.module('angularPayments') scope.$apply(function() { scope[attr.stripeForm].apply(scope, args); }); - button.prop('disabled', false); - }); } else { @@ -79,7 +74,6 @@ angular.module('angularPayments') scope.$apply(function() { scope[attr.stripeForm].apply(scope, [400, {error: errorMessage }]); }); - button.prop('disabled', false); } }); From d71c68d2acfdd45f0ad5e623b70b911fe2b987ec Mon Sep 17 00:00:00 2001 From: Ferrari Lee Date: Tue, 28 Oct 2014 01:54:29 +0800 Subject: [PATCH 4/8] prevent multiple submit --- lib/angular-payments.js | 11 ++++++++++- lib/angular-payments.min.js | 4 ++-- src/form.js | 11 ++++++++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/lib/angular-payments.js b/lib/angular-payments.js index 44c543b..6bd402d 100755 --- a/lib/angular-payments.js +++ b/lib/angular-payments.js @@ -769,21 +769,28 @@ angular.module('angularPayments', []);angular.module('angularPayments') } var form = angular.element(elem); + var isProcessing = false; form.bind('submit', function() { + if (isProcessing === true) return; exp = Common.parseExpiry(scope.expiry) scope.expMonth = exp.month scope.expYear = exp.year - if(form.hasClass('ng-valid')) { + var button = form.find('button'); + button.prop('disabled', true); + isProcessing = 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); + isProcessing = false; }); } else { @@ -797,6 +804,8 @@ angular.module('angularPayments', []);angular.module('angularPayments') scope.$apply(function() { scope[attr.stripeForm].apply(scope, [400, {error: errorMessage }]); }); + button.prop('disabled', false); + isProcessing = false; } }); diff --git a/lib/angular-payments.min.js b/lib/angular-payments.min.js index 3ee6582..af7980d 100644 --- a/lib/angular-payments.min.js +++ b/lib/angular-payments.min.js @@ -1,2 +1,2 @@ -/*! angular-payments 20-10-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)b.hasOwnProperty(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(){if(exp=c.parseExpiry(b.expiry),b.expMonth=exp.month,b.expYear=exp.year,f.hasClass("ng-valid"))a.Stripe.createToken(_getDataToSend(b),function(){var a=arguments;b.$apply(function(){b[e.stripeForm].apply(b,a)})});else{var d=[];f.hasClass("ng-invalid-card")&&d.push("Credit Card"),f.hasClass("ng-invalid-expiry")&&d.push("Expiry"),f.hasClass("ng-invalid-cvc")&&d.push("CVC"),f.hasClass("ng-invalid-required")&&d.push("Missing required fields");var g="Invalid form submitted: "+d.join(", ");b.$apply(function(){b[e.stripeForm].apply(b,[400,{error:g}])})}})}}}]); \ No newline at end of file +/*! angular-payments 28-10-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)b.hasOwnProperty(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),g=!1;f.bind("submit",function(){if(g!==!0){exp=c.parseExpiry(b.expiry),b.expMonth=exp.month,b.expYear=exp.year;var d=f.find("button");if(d.prop("disabled",!0),g=!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),g=!1});else{var h=[];f.hasClass("ng-invalid-card")&&h.push("Credit Card"),f.hasClass("ng-invalid-expiry")&&h.push("Expiry"),f.hasClass("ng-invalid-cvc")&&h.push("CVC"),f.hasClass("ng-invalid-required")&&h.push("Missing required fields");var i="Invalid form submitted: "+h.join(", ");b.$apply(function(){b[e.stripeForm].apply(b,[400,{error:i}])}),d.prop("disabled",!1),g=!1}}})}}}]); \ No newline at end of file diff --git a/src/form.js b/src/form.js index f881cad..4be6331 100644 --- a/src/form.js +++ b/src/form.js @@ -46,21 +46,28 @@ angular.module('angularPayments') } var form = angular.element(elem); + var isProcessing = false; form.bind('submit', function() { + if (isProcessing === true) return; exp = Common.parseExpiry(scope.expiry) scope.expMonth = exp.month scope.expYear = exp.year - if(form.hasClass('ng-valid')) { + var button = form.find('button'); + button.prop('disabled', true); + isProcessing = 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); + isProcessing = false; }); } else { @@ -74,6 +81,8 @@ angular.module('angularPayments') scope.$apply(function() { scope[attr.stripeForm].apply(scope, [400, {error: errorMessage }]); }); + button.prop('disabled', false); + isProcessing = false; } }); From 61d52a090846543ab1431c48181317b3eca18a5b Mon Sep 17 00:00:00 2001 From: Ferrari Lee Date: Wed, 29 Oct 2014 03:08:05 +0800 Subject: [PATCH 5/8] add btn-auto-disabled which allow user to control submit button disabled behavior --- README.md | 9 +++++++++ lib/angular-payments.js | 15 ++++++++++++--- lib/angular-payments.min.js | 4 ++-- src/form.js | 15 ++++++++++++--- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f2df98e..4c2c45c 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,15 @@ And then: Basically the directive sends the credit card details directly to stripe, which then returns a token that you can use to charge the card, subscribe a user or to do other things. This ensures that the card details themselves never hit your backend and thus you have to worry a little bit less. +### flexible submit button + +In default behavior, submit button will disable during request submit and enable again after finish. Although sometimes user might need more flexible action, like turn off or disable but not enable after stripe return. So try to add new attribute to control submit button disable timing. + +