1(function ($) { 2 3 $.extend($.fn, { 4 validateCreditCard: function (options) { 5 card_types = $.validateCreditCard.card_types; 6 options = options || {}; 7 options.accept = options.accept || []; 8 if (!options.accept.length) { 9 options.accept = eval($(this).attr('data-card-types')); 10 } 11 options.accept = $.validateCreditCard.get_accepted_card_types(options.accept); 12 13 this.on('input', function () { 14 $(this).off('keyup'); 15 return $.validateCreditCard.validate(this, options.accept); 16 }); 17 this.on('keyup', function () { 18 return $.validateCreditCard.validate(this, options.accept); 19 }); 20 return this; 21 } 22 }); 23 24 $.validateCreditCard = function (element) { 25 return $.validateCreditCard.validate(element); 26 }; 27 28 $.validateCreditCard.card_types = [ 29 { 30 name: 'amex', 31 pattern: /^3[47]/, 32 valid_length: [15] 33 }, { 34 name: 'diners_club_carte_blanche', 35 pattern: /^30[0-5]/, 36 valid_length: [14] 37 }, { 38 name: 'diners_club_international', 39 pattern: /^36/, 40 valid_length: [14] 41 }, { 42 name: 'jcb', 43 pattern: /^35(2[89]|[3-8][0-9])/, 44 valid_length: [16] 45 }, { 46 name: 'laser', 47 pattern: /^(6304|670[69]|6771)/, 48 valid_length: [16, 17, 18, 19] 49 }, { 50 name: 'visa_electron', 51 pattern: /^(4026|417500|4508|4844|491(3|7))/, 52 valid_length: [16] 53 }, { 54 name: 'visa', 55 pattern: /^4/, 56 valid_length: [13, 16, 19] 57 }, { 58 name: 'mastercard', 59 pattern: /^(2|5[1-5])/, 60 valid_length: [16] 61 }, { 62 name: 'maestro', 63 pattern: /^(5018|5020|5038|6304|6759|676[1-3])/, 64 valid_length: [12, 13, 14, 15, 16, 17, 18, 19] 65 }, { 66 name: 'discover', 67 pattern: /^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)/, 68 valid_length: [16] 69 } 70 ]; 71 72 $.validateCreditCard.get_card_type = function (number, accept) { 73 accept = $.validateCreditCard.get_accepted_card_types(accept); 74 var card_types = $.validateCreditCard.card_types; 75 card_types = (function () { 76 var results = []; 77 for (var i = 0; i < card_types.length; i++) { 78 var card = card_types[i]; 79 if (accept.contains(card.name)) { 80 results.push(card); 81 } 82 } 83 return results; 84 })(); 85 for (i = 0; i < card_types.length; i++) { 86 var card_type = card_types[i]; 87 if (number.match(card_type.pattern)) { 88 return card_type; 89 } 90 } 91 return null; 92 }; 93 94 $.validateCreditCard.is_valid_luhn = function (number) { 95 var digit, n, sum, _j, _len1, _ref2; 96 sum = 0; 97 _ref2 = number.split('').reverse(); 98 for (n = _j = 0, _len1 = _ref2.length; _j < _len1; n = ++_j) { 99 digit = _ref2[n]; 100 digit = +digit; 101 if (n % 2) { 102 digit *= 2; 103 if (digit < 10) { 104 sum += digit; 105 } else { 106 sum += digit - 9; 107 } 108 } else { 109 sum += digit; 110 } 111 } 112 return sum % 10 === 0; 113 }; 114 115 $.validateCreditCard.is_valid_length = function (number, card_type) { 116 return card_type.valid_length.contains(number.length); 117 }; 118 119 $.validateCreditCard.validate_number = function (number, accept, element) { 120 accept = $.validateCreditCard.get_accepted_card_types(accept); 121 var length_valid = false, 122 luhn_valid = false, 123 type_valid = false, 124 cardNumberGroups = null, 125 cardMask = "", 126 cardNumber = $.validateCreditCard.normalize(number || ''), 127 cardMaskPattern = /^([0-9]{4})([0-9]+?)([0-9]{4})$/, 128 card_type = $.validateCreditCard.get_card_type(cardNumber, accept); 129 130 if (card_type != null) { 131 luhn_valid = $.validateCreditCard.is_valid_luhn(cardNumber); 132 length_valid = $.validateCreditCard.is_valid_length(cardNumber, card_type); 133 type_valid = accept.contains(card_type.name); 134 } 135 136 cardNumberGroups = cardMaskPattern.exec(cardNumber); 137 if (cardNumberGroups) { 138 for (var i = cardNumberGroups.length - 1; i >= 0; i--) { 139 if (cardNumberGroups[i] === cardNumber) { 140 cardNumberGroups.splice(i, 1); 141 } 142 } 143 cardNumberGroups = [(cardNumberGroups[0] || ''), (cardNumberGroups[1] || ''), (cardNumberGroups[2] || '')]; 144 cardMask = cardNumberGroups[0] + 'X'.repeat(cardNumberGroups[1].length) + cardNumberGroups[2]; 145 } 146 if (element) {
147 $(element).data('CardDetails', 148 { 149 card_type: card_type ? card_type.name : '', 150 card_number: cardNumber, 151 card_mask: cardMask, 152 card_valid: length_valid && luhn_valid && type_valid 153 }); 154 } 155 return luhn_valid && length_valid && type_valid; 156 }; 157 158 $.validateCreditCard.normalize = function (number) { 159 return number.replace(/[^0-9]/g, ''); 160 }; 161 162 $.validateCreditCard.validate = function (element, accept) { 163 var number = $.validateCreditCard.normalize($(element).val()); 164 if (number == "" && $(element).attr("data-required") != true) { 165 return true; 166 } 167 accept = $.validateCreditCard.get_accepted_card_types(eval($(element).attr('data-card-types'))); 168 return $.validateCreditCard.validate_number(number, accept, element); 169 }; 170 171 $.validateCreditCard.get_accepted_card_types = function (accept) { 172 accept = accept || []; 173 if (!accept.length) { 174 var card_types = $.validateCreditCard.card_types; 175 for (var i = 0 ; i < card_types.length; i++) { 176 accept.push(card_types[i].name); 177 } 178 } 179 return accept; 180 }; 181 182})(jQuery); 183 184 185Array.prototype.contains = function (obj) { 186 var i = this.length; 187 while (i--) { 188 if (this[i] === obj) { 189 return true; 190 } 191 } 192 return false; 193};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.