vue-credit-card-validation
Version:
A Vue plugin for formatting and validating credit card forms to offer the same functionality as Stripe's jquery.payment library (and more!).
6 lines • 10.5 kB
JavaScript
/*!
* vue-credit-card-validation v1.0.3
* (c) 2022 Michael Wuori
* Released under the MIT License.
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.VueCreditCardValidation=t()}(this,function(){"use strict";var e=[{type:"maestro",patterns:[5018,502,503,506,56,58,639,6220,67,633],format:/(\d{1,4})/g,length:[12,13,14,15,16,17,18,19],cvcLength:[3],luhn:!0},{type:"forbrugsforeningen",patterns:[600],format:/(\d{1,4})/g,length:[16],cvcLength:[3],luhn:!0},{type:"dankort",patterns:[5019],format:/(\d{1,4})/g,length:[16],cvcLength:[3],luhn:!0},{type:"visa",patterns:[4],format:/(\d{1,4})/g,length:[13,16],cvcLength:[3],luhn:!0},{type:"mastercard",patterns:[51,52,53,54,55,22,23,24,25,26,27],format:/(\d{1,4})/g,length:[16],cvcLength:[3],luhn:!0},{type:"amex",patterns:[34,37],format:/(\d{1,4})(\d{1,6})?(\d{1,5})?/,length:[15,16],cvcLength:[3,4],luhn:!0},{type:"dinersclub",patterns:[30,36,38,39],format:/(\d{1,4})(\d{1,6})?(\d{1,4})?/,length:[14],cvcLength:[3],luhn:!0},{type:"discover",patterns:[60,64,65,622],format:/(\d{1,4})/g,length:[16],cvcLength:[3],luhn:!0},{type:"unionpay",patterns:[62,88],format:/(\d{1,4})/g,length:[16,17,18,19],cvcLength:[3],luhn:!1},{type:"jcb",patterns:[35],format:/(\d{1,4})/g,length:[16],cvcLength:[3],luhn:!0}],t={cardExpiryVal:function(e){var t=Array.from(e.split(/[\s\/]+/,2)),r=t[0],n=t[1];if(2===(null!=n?n.length:void 0)&&/^\d+$/.test(n)){var a=(new Date).getFullYear();a=a.toString().slice(0,2),n=a+n}return r=parseInt(r,10),n=parseInt(n,10),{month:r,year:n}},validateCardNumber:function(e){if(e=(e+"").replace(/\s+|-/g,""),!/^\d+$/.test(e))return!1;var t=r.cardFromNumber(e);return!!t&&(Array.from(t.length).includes(e.length)&&(!1===t.luhn||r.luhnCheck(e)))},validateCardExpiry:function(e,r){if(!e)return!1;if(!r){var n;n=t.cardExpiryVal(e),e=n.month,r=n.year}if("object"==typeof e&&"month"in e){var a;a=e,e=a.month,r=a.year}if(!e||!r)return!1;if(e=e.toString().trim(),r=r.toString().trim(),!/^\d+$/.test(e))return!1;if(!/^\d+$/.test(r))return!1;if(!(1<=e&&e<=12))return!1;if(2===r.length&&(r=r<70?"20"+r:"19"+r),console.log(r),4!==r.length)return!1;var i=new Date(r,e),u=new Date;return i.setMonth(i.getMonth()-1),i.setMonth(i.getMonth()+1,1),i>u},validateCardCVC:function(e,t){if(!e)return!1;if(e=e.toString().trim(),!/^\d+$/.test(e))return!1;var n=r.cardFromType(t);return null!=n?Array.from(n.cvcLength).includes(e.length):e.length>=3&&e.length<=4},cardType:function(e){return e?r.__guard__(r.cardFromNumber(e),function(e){return e.type})||null:null},formatCardNumber:function(e){e=e.toString().replace(/\D/g,"");var t=r.cardFromNumber(e);if(!t)return e;var n=t.length[t.length.length-1];if(e=e.slice(0,n),t.format.global)return r.__guard__(e.match(t.format),function(e){return e.join(" ")});var a=t.format.exec(e);return null!=a?(a.shift(),a.join(" ")):void 0},formatExpiry:function(e){var t=e.match(/^\D*(\d{1,2})(\D+)?(\d{1,4})?/);if(!t)return"";var r=t[1]||"",n=t[2]||"",a=t[3]||"";return a.length>0?n=" / ":" /"===n?(r=r.substring(0,1),n=""):2===r.length||n.length>0?n=" / ":1!==r.length||["0","1"].includes(r)||(r="0"+r,n=" / "),r+n+a}},r={cardFromNumber:function(t){t=(t+"").replace(/\D/g,"");for(var r in e)for(var n in e[r].patterns){var a=e[r].patterns[n]+"";if(t.substr(0,a.length)===a)return e[r]}},cardFromType:function(t){for(var r in e)if(e[r].type===t)return e[r]},luhnCheck:function(e){var t=!0,r=0,n=(e+"").split("").reverse();for(var a in n){var i=parseInt(n[a],10);(t=!t)&&(i*=2),i>9&&(i-=9),r+=i}return r%10==0},hasTextSelected:function(e){return null!=e.selectionStart&&e.selectionStart!==e.selectionEnd||!(null==r.__guard__("undefined"!=typeof document&&null!==document?document.selection:void 0,function(e){return e.createRange})||!document.selection.createRange().text)},safeVal:function(e,t,r){if("deleteContentBackward"!==r.inputType){var n;try{n=t.selectionStart}catch(e){n=null}var a=t.value;if(t.value=e,e=t.value,null!==n&&document.activeElement==t){if(n===a.length&&(n=t.value.length),a!==e){var i=a.slice(n-1,+n+1||void 0),u=t.value.slice(n-1,+n+1||void 0),d=e[n];/\d/.test(d)&&i===d+" "&&u===" "+d&&(n+=1)}return t.selectionStart=n,t.selectionEnd=n}}},replaceFullWidthChars:function(e){null==e&&(e="");var t="",r=e.split("");for(var n in r){var a="\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19".indexOf(r[n]);a>-1&&(r[n]="0123456789"[a]),t+=r[n]}return t},reFormatNumeric:function(e){var t=e.currentTarget;return setTimeout(function(){var n=t.value;return n=r.replaceFullWidthChars(n),n=n.replace(/\D/g,""),r.safeVal(n,t,e)})},reFormatCardNumber:function(e){var n=e.currentTarget;return setTimeout(function(){var a=n.value;return a=r.replaceFullWidthChars(a),a=t.formatCardNumber(a),r.safeVal(a,n,e)})},formatCardNumber:function(e){var t,n=String.fromCharCode(e.which);if(/^\d+$/.test(n)){var a=e.currentTarget,i=a.value,u=r.cardFromNumber(i+n),d=i.replace(/\D/g,"")+n,o=16;if(u&&(o=u.length[u.length.length-1]),!(d>=o||null!=a.selectionStart&&a.selectionStart!==i.length))return t=u&&"amex"===u.type?/^(\d{4}|\d{4}\s\d{6})$/:/(?:^|\s)(\d{4})$/,t.test(i+n)?(e.preventDefault(),setTimeout(function(){return a.value=i+" "+n})):t.test(i+n)?(e.preventDefault(),setTimeout(function(){return a.value=i+n+" "})):void 0}},formatBackCardNumber:function(e){var t=e.currentTarget,r=t.value;if(8===e.which&&(null==t.selectionStart||t.selectionStart===r.length))return/\d\s$/.test(r)?(e.preventDefault(),setTimeout(function(){return t.value=r.replace(/\d\s$/,"")})):/\s\d?$/.test(r)?(e.preventDefault(),setTimeout(function(){return t.value=r.replace(/\d$/,"")})):void 0},reFormatExpiry:function(e){var n=e.currentTarget;return setTimeout(function(){var a=n.value;return a=r.replaceFullWidthChars(a),a=t.formatExpiry(a),r.safeVal(a,n,e)})},formatExpiry:function(e){var t=String.fromCharCode(e.which);if(/^\d+$/.test(t)){var r=e.currentTarget,n=r.value+t;return/^\d$/.test(n)&&!["0","1"].includes(n)?(e.preventDefault(),setTimeout(function(){return r.value="0"+n+" / "})):/^\d\d$/.test(n)?(e.preventDefault(),setTimeout(function(){var e=parseInt(n[0],10),t=parseInt(n[1],10);return r.value=t>2&&0!==e?"0"+e+" / "+t:n+" / "})):void 0}},formatForwardExpiry:function(e){if(/^\d+$/.test(String.fromCharCode(e.which))){var t=e.currentTarget,r=t.value;return/^\d\d$/.test(r)?t.value=r+" / ":void 0}},formatForwardSlashAndSpace:function(e){var t=String.fromCharCode(e.which);if("/"===t||" "===t){var r=e.currentTarget,n=r.value;return/^\d$/.test(n)&&"0"!==n?r.value="0"+n+" / ":void 0}},formatBackExpiry:function(e){var t=e.currentTarget,r=t.value;if(8===e.which&&(null==t.selectionStart||t.selectionStart===r.length))return/\d\s\/\s$/.test(r)?(e.preventDefault(),setTimeout(function(){return t.value=r.replace(/\d\s\/\s$/,"")})):void 0},handleExpiryAttributes:function(e){e.setAttribute("maxlength",9)},reFormatCVC:function(e){var t=e.currentTarget;return setTimeout(function(){var n=t.value;return n=r.replaceFullWidthChars(n),n=n.replace(/\D/g,"").slice(0,4),r.safeVal(n,t,e)})},restrictNumeric:function(e){return!(!e.metaKey&&!e.ctrlKey)||32!==e.which&&(0===e.which||(e.which<33||(!!/[\d\s]/.test(String.fromCharCode(e.which))||e.preventDefault())))},restrictCardNumber:function(e){var t=e.currentTarget,n=String.fromCharCode(e.which);if(/^\d+$/.test(n)&&!r.hasTextSelected(t)){var a=(t.value+n).replace(/\D/g,""),i=r.cardFromNumber(a);return i?a.length<=i.length[i.length.length-1]:a.length<=16}},restrictExpiry:function(e){var t=e.currentTarget,n=String.fromCharCode(e.which);if(/^\d+$/.test(n)&&!r.hasTextSelected(t)){var a=t.value+n;return a=a.replace(/\D/g,""),!(a.length>6)&&void 0}},restrictCVC:function(e){var t=e.currentTarget,n=String.fromCharCode(e.which);if(/^\d+$/.test(n)&&!r.hasTextSelected(t)){return(t.value+n).length<=4}},setCardType:function(r){var n=r.currentTarget,a=n.value,i=t.cardType(a)||"unknown";if(-1===n.className.indexOf(i)){var u=[];for(var d in e)u.push(e[d].type);n.classList.remove("unknown"),n.classList.remove("identified"),(o=n.classList).remove.apply(o,u),n.classList.add(i),n.dataset.cardBrand=i,"unknown"!==i&&n.classList.add("identified")}var o},__guard__:function(e,t){return void 0!==e&&null!==e?t(e):void 0}},n={validateCardNumber:t.validateCardNumber,validateCardCVC:t.validateCardCVC,validateCardExpiry:t.validateCardExpiry,setCardType:function(e){r.setCardType(e),setTimeout(function(){e.currentTarget.dispatchEvent(new Event("keyup")),e.currentTarget.dispatchEvent(new Event("change"))},100)},formatCardCVC:function(e){return e.addEventListener("keypress",r.restrictNumeric),e.addEventListener("keypress",r.restrictCVC),e.addEventListener("paste",r.reFormatCVC),e.addEventListener("change",r.reFormatCVC),e.addEventListener("input",r.reFormatCVC),this},formatCardExpiry:function(e){return r.handleExpiryAttributes(e),e.addEventListener("keypress",r.restrictNumeric),e.addEventListener("keypress",r.formatExpiry),e.addEventListener("keypress",r.formatForwardSlashAndSpace),e.addEventListener("keypress",r.formatForwardExpiry),e.addEventListener("keydown",r.formatBackExpiry),e.addEventListener("change",r.reFormatExpiry),e.addEventListener("input",r.reFormatExpiry),e.addEventListener("blur",r.reFormatExpiry),this},formatCardNumber:function(e){return e.maxLength=19,e.addEventListener("keypress",r.restrictNumeric),e.addEventListener("keypress",r.restrictCardNumber),e.addEventListener("keypress",r.formatCardNumber),e.addEventListener("keydown",r.formatBackCardNumber),e.addEventListener("keyup",r.setCardType),e.addEventListener("paste",r.reFormatCardNumber),e.addEventListener("change",r.reFormatCardNumber),e.addEventListener("input",r.reFormatCardNumber),e.addEventListener("input",r.setCardType),this},restrictNumeric:function(e){return e.addEventListener("keypress",r.restrictNumeric),e.addEventListener("paste",r.restrictNumeric),e.addEventListener("change",r.restrictNumeric),e.addEventListener("input",r.restrictNumeric),this}};return{install:function(e,t){e.config.globalProperties.$cardFormat=n,e.directive("cardformat",{beforeMount:function(e,t,r){"input"!==e.nodeName.toLowerCase()&&(e=e.querySelector("input"));var a=Object.keys(n).find(function(e){return e.toLowerCase()===t.arg.toLowerCase()}),i=new Event("keyup");n[a](e,r),"formatCardNumber"==a&&void 0!==t.instance.cardBrand&&(e.addEventListener("keyup",function(){e.dataset.cardBrand&&(t.instance.cardBrand=e.dataset.cardBrand)}),e.addEventListener("paste",function(){setTimeout(function(){e.dispatchEvent(i)},10)}))}})}}});