1var Creditly = (function() { 2 var getInputValue = function(e, selector) { 3 var inputValue = document.querySelector(selector).value.trim(); 4 inputValue = inputValue + String.fromCharCode(e.which); 5 return getNumber(inputValue); 6 }; 7 8 var getNumber = function(string) { 9 return string.replace(/[^\d]/g, ""); 10 }; 11 12 var removeErrors = function(element) { 13 element.className = element.className.replace(/\bhas-error\b/,''); 14 }; 15 16 var reachedMaximumLength = function(e, maximumLength, selector) { 17 return getInputValue(e, selector).length > maximumLength; 18 }; 19 20 // Backspace, delete, tab, escape, enter, ., Ctrl+a, Ctrl+c, Ctrl+v, home, end, left, right 21 var isEscapedKeyStroke = function(e) { 22 // Key event is for a browser shortcut 23 if (e.metaKey || e.ctrlKey) return true; 24 25 // If keycode is a space 26 if (e.which === 32) return false; 27 28 // If keycode is a special char (WebKit) 29 if (e.which === 0) return true; 30 31 // If char is a special char (Firefox) 32 if (e.which < 33) return true; 33 34 return false; 35 }; 36 37 var isNumberEvent = function(e) { 38 return (/^\d+$/.test(String.fromCharCode(e.which))); 39 }; 40 41 var onlyAllowNumeric = function(e, maximumLength, selector) { 42 e.preventDefault(); 43 // Ensure that it is a number and stop the keypress 44 if (!isNumberEvent(e)) { 45 return false; 46 } 47 return true; 48 }; 49 50 var isAmericanExpress = function(number) { 51 return number.match("^(34|37)"); 52 }; 53 54 var shouldProcessInput = function(e, maximumLength, selector) { 55 var target = e.currentTarget; 56 if (reachedMaximumLength(e, maximumLength, selector)) { 57 e.preventDefault(); 58 return false; 59 } 60 if ((target.selectionStart !== target.value.length)) { 61 return false; 62 } 63 return (!isEscapedKeyStroke(e)) && onlyAllowNumeric(e, maximumLength, selector); 64 }; 65 66 var CvvInput = (function() { 67 68 var createCvvInput = function(selector, numberSelector) { 69 var getMaximumLength = function(isAmericanExpressCard) { 70 if (isAmericanExpressCard) { 71 return 4; 72 } else { 73 return 3; 74 } 75 }; 76 77 document.querySelector(selector).addEventListener("keypress", function(e) { 78 var element = document.querySelector(selector); 79 removeErrors(element); 80 var number = getInputValue(e, numberSelector); 81 var cvv = getInputValue(e, selector) 82 var isAmericanExpressCard = isAmericanExpress(number); 83 var maximumLength = getMaximumLength(isAmericanExpressCard); 84 if (shouldProcessInput(e, maximumLength, selector)) { 85 element.value = cvv; 86 } 87 }); 88 }; 89 90 return { 91 createCvvInput: createCvvInput 92 }; 93 })(); 94 95 var NumberInput = (function() { 96 var americanExpressSpaces = [4, 10, 15]; 97 var defaultSpaces = [4, 8, 12, 16]; 98 99 var getMaximumLength = function(isAmericanExpressCard) { 100 if (isAmericanExpressCard) { 101 return 15; 102 } else { 103 return 16; 104 } 105 }; 106 107 var createNumberInput = function(selector) { 108 document.querySelector(selector).addEventListener("keypress", function(e) { 109 var element = document.querySelector(selector); 110 removeErrors(element); 111 var number = getInputValue(e, selector); 112 var isAmericanExpressCard = isAmericanExpress(number); 113 var maximumLength = getMaximumLength(isAmericanExpressCard); 114 if (shouldProcessInput(e, maximumLength, selector)) { 115 var newInput; 116 if (isAmericanExpressCard) { 117 newInput = addSpaces(number, americanExpressSpaces); 118 } else { 119 newInput = addSpaces(number, defaultSpaces); 120 } 121 122 element.value = newInput; 123 var ev = document.createEvent("HTMLEvents"); 124 ev.initEvent("changed_input", true, true); 125 element.dispatchEvent(ev); 126 } 127 }); 128 }; 129 130 var addSpaces = function(number, spaces) { 131 var parts = [] 132 var j = 0; 133 for (var i=0; i<spaces.length; i++) { 134 if (number.length > spaces[i]) { 135 parts.push(number.slice(j, spaces[i])); 136 j = spaces[i]; 137 } else { 138 if (i < spaces.length) { 139 parts.push(number.slice(j, spaces[i])); 140 } else { 141 parts.push(number.slice(j)); 142 } 143 break; 144 } 145 } 146 147 if (parts.length > 0) { 148 return parts.join(" "); 149 } else { 150 return number; 151 } 152 }; 153 154 return { 155 createNumberInput: createNumberInput 156 }; 157 })(); 158 159 var Validation = (function() {
160 var Validators = (function() { 161 var expirationRegex = /(\d\d)\s*\/\s*(\d\d)/; 162 163 var creditCardExpiration = function(selector, data) { 164 var expirationVal = document.querySelector(selector).value.trim() 165 var match = expirationRegex.exec(expirationVal); 166 var isValid = false; 167 var outputValue = ["", ""]; 168 if (match && match.length === 3) { 169 var month = parseInt(match[1], 10); 170 var year = parseInt("20" + match[2], 10); 171 if (month >= 0 && month <= 12) { 172 isValid = true; 173 var outputValue = [month, year]; 174 } 175 } 176 177 return { 178 "is_valid": isValid, 179 "messages": [data["message"]], 180 "output_value": outputValue 181 }; 182 }; 183 184 var isValidSecurityCode = function(isAmericanExpress, securityCode) { 185 if ((isAmericanExpress && securityCode.length == 4) || 186 (!isAmericanExpress && securityCode.length == 3)) { 187 return true; 188 } 189 return false; 190 }; 191 192 var creditCard = function(selector, data) { 193 var rawNumber = document.querySelector(data["creditCardNumberSelector"]).value; 194 var number = rawNumber.trim().replace(/\D/g, ""); 195 var messages = []; 196 var isValid = true; 197 var selectors = []; 198 199 if (!isValidCreditCardNumber(number)) { 200 messages.push(data["message"]["number"]); 201 selectors.push(data["creditCardNumberSelector"]); 202 isValid = false; 203 } 204 205 if (data.cvvSelector) { 206 var rawSecurityCode = document.querySelector(data["cvvSelector"]).value; 207 var securityCode = rawSecurityCode.trim().replace(/\D/g, ""); 208 209 if (!isValidSecurityCode(isAmericanExpress(number), securityCode)) { 210 messages.push(data["message"]["security_code"]); 211 selectors.push(data["cvvSelector"]); 212 isValid = false; 213 } 214 } 215 216 result = { 217 "is_valid": isValid, 218 "output_value": [number, securityCode], 219 "selectors": selectors, 220 "messages": messages 221 }; 222 return result; 223 }; 224 225 var isAmericanExpress = function(number) { 226 return (number.length == 15); 227 }; 228 229 // Luhn Algorithm. 230 var isValidCreditCardNumber = function(value) { 231 if (value.length === 0) return false; 232 // accept only digits, dashes or spaces 233 if (/[^0-9-\s]+/.test(value)) return false; 234 235 var nCheck = 0, nDigit = 0, bEven = false; 236 for (var n = value.length - 1; n >= 0; n--) { 237 var cDigit = value.charAt(n); 238 var nDigit = parseInt(cDigit, 10); 239 if (bEven) { 240 if ((nDigit *= 2) > 9) nDigit -= 9; 241 } 242 nCheck += nDigit; 243 bEven = !bEven; 244 } 245 return (nCheck % 10) == 0; 246 }; 247 248 return { 249 creditCard: creditCard, 250 creditCardExpiration: creditCardExpiration, 251 }; 252 })(); 253 254 var ValidationErrorHolder = (function() { 255 var errorMessages = []; 256 var selectors = []; 257 258 var addError = function(selector, validatorResults) { 259 if (validatorResults.hasOwnProperty("selectors")) { 260 selectors = selectors.concat(validatorResults["selectors"]); 261 } else { 262 selectors.push(selector) 263 } 264 265 errorMessages = errorMessages.concat(validatorResults["messages"]); 266 }; 267 268 var triggerErrorMessage = function() { 269 var errorsPayload = { 270 "selectors": selectors, 271 "messages": errorMessages 272 }; 273 for (var i=0; i<selectors.length; i++) { 274 document.querySelector(selectors[i]).className = document.querySelector(selectors[i]).className + " has-error"; 275 } 276 277 if (window.jQuery) { 278 window.jQuery("body").trigger("creditly_client_validation_error", errorsPayload); 279 } else { 280 var ev = document.createEvent("MessageEvent"); 281 ev.initMessageEvent("creditly_client_validation_error", true, true, errorsPayload, "", "", "", null); 282 document.body.dispatchEvent(ev); 283 } 284 }; 285 286 return { 287 addError: addError, 288 triggerErrorMessage: triggerErrorMessage 289 }; 290 }); 291
292 var ValidationOutputHolder = (function() { 293 var output = {}; 294 295 var addOutput = function(outputName, value) { 296 var outputParts = outputName.split("."); 297 var currentPart = output; 298 for (var i=0; i<outputParts.length; i++) { 299 if (!currentPart.hasOwnProperty(outputParts[i])) { 300 currentPart[outputParts[i]] = {}; 301 } 302 303 // Either place the value into the output, or continue going down the 304 // search space. 305 if (i === outputParts.length-1) { 306 currentPart[outputParts[i]] = value 307 } else { 308 currentPart = currentPart[outputParts[i]]; 309 } 310 } 311 }; 312 313 var getOutput = function() { 314 return output; 315 }; 316 317 return { 318 addOutput: addOutput, 319 getOutput: getOutput 320 } 321 }); 322 323 var processSelector = function(selector, selectorValidatorMap, errorHolder, outputHolder) { 324 if (selectorValidatorMap.hasOwnProperty(selector)) { 325 var currentMapping = selectorValidatorMap[selector]; 326 var validatorType = currentMapping["type"]; 327 var fieldName = currentMapping["name"]; 328 var validatorResults = Validators[validatorType](selector, currentMapping["data"]); 329 330 if (validatorResults["is_valid"]) { 331 if (currentMapping["output_name"] instanceof Array) { 332 for (var i=0; i<currentMapping["output_name"].length; i++) { 333 outputHolder.addOutput(currentMapping["output_name"][i], 334 validatorResults["output_value"][i]); 335 } 336 } else { 337 outputHolder.addOutput(currentMapping["output_name"], 338 validatorResults["output_value"]); 339 } 340 } else { 341 errorHolder.addError(selector, validatorResults); 342 return true; 343 } 344 } 345 }; 346 347 var validate = function(selectorValidatorMap) { 348 var errorHolder = ValidationErrorHolder(); 349 var outputHolder = ValidationOutputHolder(); 350 var anyErrors = false; 351 for (var selector in selectorValidatorMap) { 352 if (processSelector(selector, selectorValidatorMap, errorHolder, outputHolder)) { 353 anyErrors = true; 354 } 355 } 356 if (anyErrors) { 357 errorHolder.triggerErrorMessage(); 358 return false; 359 } else { 360 return outputHolder.getOutput(); 361 } 362 }; 363 364 return { 365 validate: validate 366 }; 367 })(); 368 369 var ExpirationInput = (function() { 370 var maximumLength = 4; 371 372 var createExpirationInput = function(selector) { 373 document.querySelector(selector).addEventListener("keypress", function(e) { 374 var element = document.querySelector(selector) 375 removeErrors(element); 376 if (shouldProcessInput(e, maximumLength, selector)) { 377 var inputValue = getInputValue(e, selector); 378 if (inputValue.length >= 2) { 379 var newInput = inputValue.slice(0, 2) + " / " + inputValue.slice(2); 380 element.value = newInput; 381 } else { 382 element.value = inputValue; 383 } 384 } 385 }); 386 }; 387 388 return { 389 createExpirationInput: createExpirationInput, 390 }; 391 })(); 392 393 var CardTypeListener = (function() { 394 var determineCardType = function(value) { 395 if (/^(34|37)/.test(value)) { 396 return "American Express"; 397 } else if (/^4/.test(value)) { 398 return "Visa"; 399 } else if (/^5[0-5]/.test(value)) { 400 return "MasterCard"; 401 } else if (/^(6011|622|64[4-9]|65)/.test(value)) { 402 return "Discover"; 403 } else { 404 return ""; 405 } 406 }; 407 408 var changeCardType = function(numberSelector, cardTypeSelector) { 409 var element = document.querySelector(numberSelector); 410 var changeCardTypeListener = function(e) { 411 var data = document.querySelector(numberSelector).value; 412 var cardType = determineCardType(getNumber(data)); 413 document.querySelector(cardTypeSelector).innerHTML = cardType; 414 }; 415 element.addEventListener("changed_input", changeCardTypeListener); 416 element.addEventListener("keypress", changeCardTypeListener); 417 element.addEventListener("keydown", changeCardTypeListener); 418 element.addEventListener("keyup", changeCardTypeListener); 419 }; 420 421 return { 422 changeCardType: changeCardType 423 }; 424 425 })(); 426 427 var initialize = function(expirationSelector, creditCardNumberSelector, cvvSelector, cardTypeSelector, options) { 428 var selectorValidatorMap = createSelectorValidatorMap(expirationSelector, creditCardNumberSelector, cvvSelector, options); 429 430 ExpirationInput.createExpirationInput(expirationSelector); 431 NumberInput.createNumberInput(creditCardNumberSelector); 432 if (cvvSelector) { 433 CvvInput.createCvvInput(cvvSelector, creditCardNumberSelector); 434 } 435 if (cardTypeSelector) { 436 CardTypeListener.changeCardType(creditCardNumberSelector, cardTypeSelector); 437 } 438 439 return { 440 validate: function() { 441 return Validation.validate(selectorValidatorMap); 442 } 443 }; 444 }; 445 446 var createSelectorValidatorMap = function(expirationSelector, creditCardNumberSelector, cvvSelector, options) { 447 var optionValues = options || {}; 448 optionValues["security_code_message"] = optionValues["security_code_message"] || "Your security code is invali
448d"; 449 optionValues["number_message"] = optionValues["number_message"] || "Your credit card number is invalid"; 450 optionValues["expiration_message"] = optionValues["expiration_message"] || "Your credit card expiration is invalid"; 451 452 var selectorValidatorMap = {}; 453 selectorValidatorMap[creditCardNumberSelector] = { 454 "type": "creditCard", 455 "data": { 456 "cvvSelector": cvvSelector, 457 "creditCardNumberSelector": creditCardNumberSelector, 458 "message": { 459 "security_code": optionValues["security_code_message"], 460 "number": optionValues["number_message"] 461 } 462 }, 463 "output_name": ["number", "security_code"] 464 }; 465 selectorValidatorMap[expirationSelector] = { 466 "type": "creditCardExpiration", 467 "data": { 468 "message": optionValues["expiration_message"] 469 }, 470 "output_name": ["expiration_month", "expiration_year"] 471 }; 472 return selectorValidatorMap; 473 }; 474 475 return { 476 initialize: initialize 477 }; 478})();
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.