1(function($) { 2 $(document).ready(function() { 3 // ----------------- Global Settings ----------------- 4 let currencySymbol = "$"; // Change to any currency symbol dynamically 5 let decimalPlaces = 2; // Adjust between 2 or 3 dynamically 6 7 // ----------------- Formatting Functions ----------------- 8 function formatString(digits, pattern) { 9 let formatted = ""; 10 let index = 0; 11 for (let char of pattern) { 12 if (char === "#") { 13 if (index < digits.length) { 14 formatted += digits[index++]; 15 } else { 16 break; 17 } 18 } else { 19 formatted += char; 20 } 21 } 22 return formatted; 23 } 24 25 // ----------------- Money Mask Formatting ----------------- 26 function formatMoneyInput(value, type, prefix,input) { 27 let decimalSeparator = type === "C" ? "." : ","; 28 let thousandSeparator = type === "C" ? "," : "."; 29 let rawDigits = value.replace(/\D/g, ""); 30 decimalPlaces = 2; 31 if(input !== ''){ 32 decimalPlaces = Number(input.dataset.decimalPlaces) 33 } 34 35 if (rawDigits.length === 0) { 36 return `${prefix}0${decimalSeparator}${"0".repeat(decimalPlaces)}`; 37 } 38 39 while (rawDigits.length < decimalPlaces + 1) { 40 rawDigits = "0" + rawDigits; 41 } 42 43 let cents = rawDigits.slice(-decimalPlaces); 44 let wholeNumber = rawDigits.slice(0, -decimalPlaces).replace(/^0+/, "") || "0"; 45 46 wholeNumber = wholeNumber.replace(/\B(?=(\d{3})+(?!\d))/g, thousandSeparator); 47 return `${prefix}${wholeNumber}${decimalSeparator}${cents}`; 48 } 49 50 function handleMoneyInput(event) { 51 let input = event.target; 52 let oldValue = input.value; 53 let oldCursorPos = input.selectionStart; 54 55 let moneyPrefix = input.dataset.moneymaskPrefix 56 let moneymaskFormat = input.dataset.moneymaskFormat 57 let type = (moneymaskFormat === 'dot' ? 'D' : 'C') 58 let newValue = formatMoneyInput(input.value, type,moneyPrefix,input); 59 if (input.value === newValue) return; 60 61 input.value = newValue; 62 let newCursorPos = oldCursorPos + (newValue.length - oldValue.length); 63 setCaretPosition(input, newCursorPos); 64 } 65 66 // ----------------- Handling Focus & Blur for Money Mask ----------------- 67 $(document).on("focus", ".mask-moneyc", function() { 68 let moneymaskFormat = $(this)[0].dataset.moneymaskFormat 69 let type = (moneymaskFormat === 'dot' ? 'D' : 'C') 70 let decimalSeparator = type === "C" ? "." : ","; 71 let baseFormat = `${currencySymbol}0${decimalSeparator}${"0".repeat(decimalPlaces)}`; 72 73 if ($(this).val().trim() === "") { 74 $(this).val(baseFormat); 75 // setCaretPosition(this, $(this).val().length - (decimalPlaces + 1)); 76 } 77 }); 78 79 $(document).on("blur", ".mask-moneyc", function() { 80 let moneymaskFormat = $(this)[0].dataset.moneymaskFormat 81 let type = (moneymaskFormat === 'dot' ? 'D' : 'C') 82 let decimalSeparator = type === "C" ? "." : ","; 83 let baseFormat = `${currencySymbol}0${decimalSeparator}${"0".repeat(decimalPlaces)}`; 84 85 let val = $(this).val().trim(); 86 87 let numericValue = val.replace(new RegExp(`[^0-9${decimalSeparator}]`, "g"), "").replace(decimalSeparator, "."); 88 89 if (parseFloat(numericValue) === 0 || val === baseFormat) { 90 $(this).val(""); 91 } 92 }); 93 94 95 // ----------------- Formatting Credit Card ----------------- 96 function formatCreditCard(digits, formatType) { 97 let cardType = detectCardType(digits); 98 99 if (cardType === "American Express") { 100 digits = digits.slice(0, 15); 101 return formatType === "space" 102 ? formatString(digits, "#### ###### #####") 103 : formatString(digits, "####-######-#####"); 104 } else { 105 digits = digits.slice(0, 16); 106 return formatType === "space" 107 ? formatString(digits, "#### #### #### ####") 108 : formatString(digits, "####-####-####-####"); 109 } 110 } 111 112 // ----------------- Card Logos ----------------- 113 const cardLogos = { 114 "Visa": fmeData.pluginUrl+ "assets/svg-icons/visa-logo.svg", 115 "MasterCard": fmeData.pluginUrl+ "assets/svg-icons/mastercard-logo.svg", 116 "American Express": fmeData.pluginUrl+ "assets/svg-icons/amex-logo.svg", 117 "Discover": fmeData.pluginUrl+ "assets/svg-icons/discover-logo.svg", 118 "JCB": fmeData.pluginUrl+ "assets/svg-icons/jcb-logo.svg", 119 "Diners Club": fmeData.pluginUrl+ "assets/svg-icons/cc-logo.svg", 120 "Maestro": fmeData.pluginUrl+ "assets/svg-icons/maestro-logo.svg", 121 "UnionPay": fmeData.pluginUrl+ "assets/svg-icons/cc-logo.svg", 122 "RuPay": fmeData.pluginUrl+ "assets/svg-icons/repay-logo.svg", 123 "Unknown": fmeData.pluginUrl+ "assets/svg-icons/cc-logo.svg" 124 }; 125 126 // ----------------- Function to Detect Card Type -----------------
127 function detectCardType(number) { 128 const cleaned = number.replace(/\D/g, ""); // Remove non-numeric characters 129 130 const cardPatterns = { 131 "Visa": /^4/, 132 "MasterCard": /^5[1-5]/, // MasterCard starts with 51-55 133 "American Express": /^3[47]/, // AmEx starts with 34 or 37 134 "Discover": /^6(?:011|5)/, // Discover starts with 6011 or 65 135 "JCB": /^(?:2131|1800|35)/, // JCB starts with 2131, 1800, or 35 136 "Diners Club": /^3(?:0[0-5]|[689])/, // Diners Club starts with 300-305, 36, or 38-39 137 "UnionPay": /^(62|81)/, // UnionPay starts with 62 or 81 138 "RuPay": /^(60|65|81|82|508)/, // RuPay starts with 60, 65, 81, 82, or 508 139 "Maestro": /^(50|5[6-9]|6[0-9])/ // Maestro starts with 50, 56-59, 60-69 140 }; 141 142 for (let card in cardPatterns) { 143 if (cardPatterns[card].test(cleaned)) { 144 return card; 145 } 146 } 147 148 return "Unknown"; // Default if no match is found 149 } 150 151 // ----------------- Function to Update Card Logo Dynamically ----------------- 152 function updateCardLogo(inputSelector) { 153 let input = $(inputSelector); 154 let logo = input.siblings(".card-logo"); // Select logo next to input 155 let cardNumber = input.val().replace(/\D/g, ''); // Remove non-digit characters 156 157 if (cardNumber === "") { 158 logo.hide(); // Hide the logo if the input is empty 159 } else { 160 let cardType = detectCardType(cardNumber); 161 if (cardType in cardLogos) { 162 logo.attr("src", cardLogos[cardType]).show(); 163 } else { 164 logo.hide(); // Hide logo if card type is unknown 165 } 166 } 167 } 168 169 // ----------------- Universal Field Formatting ----------------- 170 const formatFunctions = { 171 ".mask-cnpj": (digits) => formatString(digits, "##.###.###/####-##"), 172 ".mask-cpf": (digits) => formatString(digits, "###.###.###-##"), 173 ".mask-cep": (digits) => formatString(digits, "#####-###"), 174 ".mask-phus": (digits) => formatString(digits, "(###) ###-####"), 175 ".mask-ph8": (digits) => formatString(digits, "####-####"), 176 ".mask-ddd8": (digits) => formatString(digits, "(##) ####-####"), 177 ".mask-ddd9": (digits) => formatString(digits, "(##) #####-####"), 178 ".mask-dmy": (digits) => formatString(digits, "##/##/####"), 179 ".mask-mdy": (digits) => formatString(digits, "##/##/####"), 180 ".mask-hms": (digits) => formatString(digits, "##:##:##"), 181 ".mask-hm": (digits) => formatString(digits, "##:##"), 182 ".mask-dmyhm": (digits) => formatString(digits, "##/##/#### ##:##"), 183 ".mask-mdyhm": (digits) => formatString(digits, "##/##/#### ##:##"), 184 ".mask-my": (digits) => formatString(digits, "##/####"), 185 ".mask-ccs": (digits) => formatCreditCard(digits, "space"), 186 ".mask-cch": (digits) => formatCreditCard(digits, "hyphen"), 187 ".mask-ccmy": (digits) => formatString(digits, "##/##"), 188 ".mask-ccmyy": (digits) => formatString(digits, "##/####"), 189 ".mask-moneyc": (digits) => formatMoneyInput(digits, "C",'$',''), 190 ".mask-moneyd": (digits) => formatMoneyInput(digits, "D",'$',''), 191 ".mask-ipv4": (digits) => formatString(digits, "###.###.###.###") // New IPv4 Masking 192 }; 193 194 // Apply formatting dynamically for all fields, including money inputs 195 Object.entries(formatFunctions).forEach(([selector, formatFunction]) => { 196 $(document).on("input focus", selector, function (event) { 197 var input = this; 198 var oldCaret = getCaretPosition(input); 199 200 // Handle money input separately 201 if ($(input).hasClass("mask-moneyc") || $(input).hasClass("mask-moneyd")) { 202 let type = $(input).hasClass("mask-moneyc") ? "C" : "D"; 203 handleMoneyInput(event); 204 return; 205 } 206 207 // Standard digit-based formatting for other fields 208 var rawDigits = input.value.replace(/\D/g, ""); // Remove non-digits 209 var digitIndex = getDigitIndexFromCaret(input.value, oldCaret); 210 var newVal = formatFunction(rawDigits); // Use predefined function for other fields 211 var newCaret = mapDigitIndexToCaret(newVal, digitIndex); 212 213 input.value = newVal; 214 215 setCaretPosition(input, newCaret || 0); // Keep caret in place 216 217 // Update card logo dynamically for credit card fields 218 if ($(input).hasClass("mask-ccs") || $(input).hasClass("mask-cch")) { 219 updateCardLogo(input); 220 } 221 }); 222 }); 223 224 // ----------------- Helper Functions for Caret Management ----------------- 225 function getCaretPosition(input) { 226 return input.selectionStart; 227 } 228 function getDigitIndexFromCaret(formattedStr, caretPos) { 229 var count = 0; 230 for (var i = 0; i < caretPos; i++) { 231 if (/\d/.test(formattedStr.charAt(i))) { 232 count++; 233 } 234 } 235 return count; 236 } 237 function mapDigitIndexToCaret(formattedStr, digitIndex) { 238 var count = 0; 239 for (var i = 0; i < formattedStr.length; i++) { 240 if (/\d/.test(formattedStr.charAt(i))) { 241 if (count === digitIndex) { 242 return i; 243 } 244 count++; 245 } 246 } 247 return formattedStr.length; 248 } 249 function setCaretPosition(elem, pos) { 250 if (elem.setSelectionRange) { 251 elem.focus(); 252 elem.setSelectionRange(pos, pos); 253 } else if (elem.createTextRange) { 254 var range = elem.createTextRange(); 255 range.collapse(true); 256 range.moveEnd('character', pos); 257 range.moveStart('character', pos); 258 range.select(); 259 } 260 } 261 262 // ----------------- Backspace Handling ----------------- 263 $(document).on("keydown", "input", function (e) { 264 if (e.key === "Backspace") { 265 var input = this; 266
267 // Special handling for money inputs 268 if ($(input).hasClass("mask-moneyc") || $(input).hasClass("mask-moneyd")) { 269 let decimalSeparator = $(input).hasClass("mask-moneyc") ? "." : ","; 270 let baseFormat = `${currencySymbol}0${decimalSeparator}${"0".repeat(decimalPlaces)}`; 271 272 if (input.value === baseFormat) { 273 e.preventDefault(); // Prevent deletion beyond the base format 274 return; 275 } 276 277 // Handle money input dynamically and prevent default formatting conflict 278 handleMoneyInput(e); 279 return; 280 } 281 282 // Standard backspace handling for all other masked inputs 283 if (input.selectionStart !== input.selectionEnd) { 284 e.preventDefault(); 285 input.value = ""; 286 setCaretPosition(input, 0); 287 return; 288 } 289 290 var caretPos = getCaretPosition(input); 291 var digitIndex = getDigitIndexFromCaret(input.value, caretPos); 292 if (digitIndex === 0) return; 293 294 var rawDigits = input.value.replace(/\D/g, ""); 295 var newDigits = rawDigits.slice(0, digitIndex - 1) + rawDigits.slice(digitIndex); 296 297 // Find matching class for format function 298 let matchedClass = Object.keys(formatFunctions).find(cls => $(input).hasClass(cls.substring(1))); 299 300 if (matchedClass) { 301 var formatted = formatFunctions[matchedClass](newDigits); 302 input.value = formatted; 303 var newCaretPos = mapDigitIndexToCaret(formatted, digitIndex - 1); 304 setCaretPosition(input, newCaretPos); 305 } 306 } 307 }); 308 309 // ----------------- Error Validation ----------------- 310 function validateInput(selector, errorClass, validationFunction, errorMessage) { 311 $(document).on("blur", selector, function () { 312 var input = $(this); 313 var val = input.val(); 314 var errorElement = input.closest('.elementor-field-group').find("." + errorClass); 315 316 // Remove predefined symbol if it's the ONLY character left 317 if (val.length === 1 && !/\d/.test(val)) { 318 input.val(""); 319 errorElement.hide().text(""); 320 return; 321 } 322 323 // Show error message if validation fails 324 if (val !== "" && !validationFunction(val)) { 325 errorElement.text(errorMessage).css("display", "flex").hide().fadeIn(200); 326 } else { 327 errorElement.fadeOut(100, function () { 328 $(this).css("display", "none"); 329 }); 330 } 331 }); 332 333 $(document).on("input", selector, function () { 334 var input = $(this); 335 var errorElement = input.closest('.elementor-field-group').find("." + errorClass); 336 337 if (errorElement.is(":visible")) { 338 var val = input.val(); 339 if (validationFunction(val)) { 340 errorElement.fadeOut(100, function () { 341 $(this).css("display", "none"); 342 }); 343 } 344 } 345 }); 346 } 347 348 // Apply validation dynamically for all fields 349 const validations = { 350 ".mask-cnpj": { errorClass: "error-cnpj", validate: isValidCNPJ, msg: fmeData.errorMessages["mask-cnpj"] }, 351 ".mask-cpf": { errorClass: "error-cpf", validate: isValidCPF, msg: fmeData.errorMessages["mask-cpf"] }, 352 ".mask-cep": { errorClass: "error-cep", validate: isValidCEP, msg: fmeData.errorMessages["mask-cep"] }, 353 ".mask-phus": { errorClass: "error-phus", validate: isValidPhoneUSA, msg: fmeData.errorMessages["mask-phus"] }, 354 ".mask-ph8": { errorClass: "error-ph8", validate: isValidPhone8, msg: fmeData.errorMessages["mask-ph8"] }, 355 ".mask-ddd8": { errorClass: "error-ddd8", validate: isValidPhoneDDD8, msg: fmeData.errorMessages["mask-ddd8"] }, 356 ".mask-ddd9": { errorClass: "error-ddd9", validate: isValidPhoneDDD9, msg: fmeData.errorMessages["mask-ddd9"] }, 357 ".mask-dmy": { errorClass: "error-dmy", validate: isValidDateDMY, msg: fmeData.errorMessages["mask-dmy"] }, 358 ".mask-mdy": { errorClass: "error-mdy", validate: isValidDateMDY, msg: fmeData.errorMessages["mask-mdy"] }, 359 ".mask-hms": { errorClass: "error-hms", validate: isValidTimeHMS, msg: fmeData.errorMessages["mask-hms"] },
360 ".mask-hm": { errorClass: "error-hm", validate: isValidTimeHM, msg: fmeData.errorMessages["mask-hm"] }, 361 ".mask-dmyhm": { errorClass: "error-dmyhm", validate: isValidDateDMYHM, msg: fmeData.errorMessages["mask-dmyhm"] }, 362 ".mask-mdyhm": { errorClass: "error-mdyhm", validate: isValidDateMDYHM, msg: fmeData.errorMessages["mask-mdyhm"] }, 363 ".mask-my": { errorClass: "error-my", validate: isValidDateMY, msg: fmeData.errorMessages["mask-my"] }, 364 ".mask-ccs": { errorClass: "error-ccs", validate: isValidCreditCard, msg: fmeData.errorMessages["mask-ccs"] }, 365 ".mask-cch": { errorClass: "error-cch", validate: isValidCreditCard, msg: fmeData.errorMessages["mask-cch"] }, 366 ".mask-ccmy": { errorClass: "error-ccmy", validate: isValidExpiryMMYY, msg: fmeData.errorMessages["mask-ccmy"] }, 367 ".mask-ccmyy": { errorClass: "error-ccmyy", validate: isValidExpiryMMYYYY, msg: fmeData.errorMessages["mask-ccmyy"] }, 368 ".mask-ipv4": { errorClass: "error-ipv4", validate: isValidIPv4, msg: fmeData.errorMessages["mask-ipv4"] } 369 }; 370 371 372 for (const [selector, { errorClass, validate, msg }] of Object.entries(validations)) { 373 validateInput(selector, errorClass, validate, msg); 374 } 375 376 // ----------------- Validation Functions ----------------- 377 function isValidPhoneUSA(phoneStr) { 378 return /^\(\d{3}\) \d{3}-\d{4}$/.test(phoneStr); 379 } 380 function isValidPhone8(phoneStr) { 381 return /^\d{4}-\d{4}$/.test(phoneStr); 382 } 383 function isValidPhoneDDD8(phoneStr) { 384 return /^\(\d{2}\) \d{4}-\d{4}$/.test(phoneStr); 385 } 386 function isValidPhoneDDD9(phoneStr) { 387 return /^\(\d{2}\) 9\d{4}-\d{4}$/.test(phoneStr); 388 } 389 390 // ----------------- Universal Date & Time Validation Function ----------------- 391 function isValidDateTime(value, format) { 392 let regexPattern; 393 let expectedParts; 394 395 switch (format) { 396 case "DMY": // dd/mm/yyyy 397 regexPattern = /^(\d{2})\/(\d{2})\/(\d{4})$/; 398 expectedParts = ["day", "month", "year"]; 399 break; 400 case "MDY": // mm/dd/yyyy 401 regexPattern = /^(\d{2})\/(\d{2})\/(\d{4})$/; 402 expectedParts = ["month", "day", "year"]; 403 break; 404 case "HMS": // hh:mm:ss 405 regexPattern = /^(\d{2}):(\d{2}):(\d{2})$/; 406 expectedParts = ["hour", "minute", "second"]; 407 break; 408 case "HM": // hh:mm 409 regexPattern = /^(\d{2}):(\d{2})$/; 410 expectedParts = ["hour", "minute"]; 411 break; 412 case "DMY-HM": // dd/mm/yyyy hh:mm 413 regexPattern = /^(\d{2})\/(\d{2})\/(\d{4}) (\d{2}):(\d{2})$/; 414 expectedParts = ["day", "month", "year", "hour", "minute"]; 415 break; 416 case "MDY-HM": // mm/dd/yyyy hh:mm 417 regexPattern = /^(\d{2})\/(\d{2})\/(\d{4}) (\d{2}):(\d{2})$/; 418 expectedParts = ["month", "day", "year", "hour", "minute"]; 419 break; 420 case "MY": // mm/yyyy 421 regexPattern = /^(\d{2})\/(\d{4})$/; 422 expectedParts = ["month", "year"]; 423 break; 424 default: 425 return false; // Unsupported format 426 } 427 428 // Match input with regex 429 let match = value.match(regexPattern); 430 if (!match) return false; 431 432 // Extract values dynamically 433 let parts = {}; 434 expectedParts.forEach((part, index) => { 435 parts[part] = parseInt(match[index + 1], 10); 436 }); 437 438 // Validate Date (Day, Month, Year) 439 if (parts.year && (parts.year < 1500 || parts.year > 3000)) return false; 440 if (parts.month && (parts.month < 1 || parts.month > 12)) return false; 441 if (parts.day) { 442 let daysInMonth = new Date(parts.year, parts.month, 0).getDate(); 443 if (parts.day < 1 || parts.day > daysInMonth) return false;
444 } 445 446 // Validate Time (Hour, Minute, Second) 447 if (parts.hour && (parts.hour < 0 || parts.hour >= 24)) return false; 448 if (parts.minute && (parts.minute < 0 || parts.minute >= 60)) return false; 449 if (parts.second && (parts.second < 0 || parts.second >= 60)) return false; 450 451 return true; 452 } 453 454 // ----------------- Expiry Date Validation ----------------- 455 function isValidExpiryDate(value, format) { 456 let regexPattern = format === "MM/YY" ? /^(\d{2})\/(\d{2})$/ : /^(\d{2})\/(\d{4})$/; 457 let match = value.match(regexPattern); 458 459 if (!match) return false; // Invalid format 460 461 let month = parseInt(match[1], 10); 462 let year = parseInt(match[2], 10); 463 464 let currentYear = new Date().getFullYear(); 465 let currentMonth = new Date().getMonth() + 1; // JS months are 0-based 466 467 // Adjust year format if MM/YY (Assume 20XX for past/future dates) 468 if (format === "MM/YY") { 469 year += 2000; 470 } 471 472 // Validate month (01-12) 473 if (month < 1 || month > 12) return false; 474 475 // Validate expiry date (must be in the future) 476 if (year < currentYear || (year === currentYear && month < currentMonth)) { 477 return false; 478 } 479 480 return true; 481 } 482 483 // ----------------- Exportable Functions Using Universal Validator ----------------- 484 function isValidDateDMY(dateStr) { return isValidDateTime(dateStr, "DMY"); } 485 function isValidDateMDY(dateStr) { return isValidDateTime(dateStr, "MDY"); } 486 function isValidTimeHMS(timeStr) { return isValidDateTime(timeStr, "HMS"); } 487 function isValidTimeHM(timeStr) { return isValidDateTime(timeStr, "HM"); } 488 function isValidDateDMYHM(dateTimeStr) { return isValidDateTime(dateTimeStr, "DMY-HM"); } 489 function isValidDateMDYHM(dateTimeStr) { return isValidDateTime(dateTimeStr, "MDY-HM"); } 490 function isValidDateMY(dateStr) { return isValidDateTime(dateStr, "MY"); } 491 function isValidExpiryMMYY(dateStr) { return isValidExpiryDate(dateStr, "MM/YY"); } 492 function isValidExpiryMMYYYY(dateStr) { return isValidExpiryDate(dateStr, "MM/YYYY"); } 493 494 // Apply validation for credit card fields 495 function isValidCreditCard(cardNumber) { 496 const cleaned = cardNumber.replace(/\D/g, ''); // Remove non-digits 497 if (cleaned.length < 15 || cleaned.length > 16) return false; // AMEX: 15, Others: 16 498 let sum = 0; 499 let shouldDouble = false; 500 // Luhn Algorithm to validate card number 501 for (let i = cleaned.length - 1; i >= 0; i--) { 502 let digit = parseInt(cleaned.charAt(i), 10); 503 504 if (shouldDouble) { 505 digit *= 2; 506 if (digit > 9) digit -= 9; 507 } 508 509 sum += digit; 510 shouldDouble = !shouldDouble; 511 } 512 return sum % 10 === 0; 513 } 514 515 // Validate CNPJ (Brazilian Business ID - 14 digits) 516 function isValidCNPJ(cnpj) { 517 cnpj = cnpj.replace(/\D/g, ''); // Remove non-numeric characters 518 if (cnpj.length !== 14) return false; 519 520 // Eliminate obvious invalid CNPJs (repeated digits) 521 if (/^(\d)\1+$/.test(cnpj)) return false; 522 523 let calcCheckDigit = (cnpj, length) => { 524 let weights = length === 12 ? [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2] : [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]; 525 let sum = 0; 526 527 for (let i = 0; i < weights.length; i++) { 528 sum += parseInt(cnpj.charAt(i)) * weights[i]; 529 } 530 531 let remainder = sum % 11; 532 return remainder < 2 ? 0 : 11 - remainder; 533 }; 534 535 // Validate both check digits 536 let firstCheck = calcCheckDigit(cnpj, 12); 537 let secondCheck = calcCheckDigit(cnpj, 13); 538 539 return firstCheck === parseInt(cnpj.charAt(12)) && secondCheck === parseInt(cnpj.charAt(13)); 540 } 541 542 // Validate CPF (Brazilian Individual ID - 11 digits) 543 function isValidCPF(cpf) { 544 cpf = cpf.replace(/\D/g, ''); // Remove non-numeric characters 545 if (cpf.length !== 11) return false;
546 547 // Eliminate obvious invalid CPFs (repeated digits) 548 if (/^(\d)\1+$/.test(cpf)) return false; 549 550 let calculateDigit = (cpf, length) => { 551 let sum = 0; 552 for (let i = 0; i < length; i++) { 553 sum += parseInt(cpf.charAt(i)) * (length + 1 - i); 554 } 555 let result = (sum * 10) % 11; 556 return result === 10 ? 0 : result; 557 }; 558 559 let firstDigit = calculateDigit(cpf, 9); 560 let secondDigit = calculateDigit(cpf, 10); // Now correctly includes first digit in the calculation 561 562 return firstDigit === parseInt(cpf.charAt(9)) && secondDigit === parseInt(cpf.charAt(10)); 563 } 564 565 // Validate CEP (Brazilian Postal Code - XXXXX-XXX) 566 function isValidCEP(cep) { 567 return /^\d{5}-\d{3}$/.test(cep); // Matches format XXXXX-XXX 568 } 569 570 // Validate IPv4 (Format: 192.168.001.001) 571 function isValidIPv4(ip) { 572 // Ensure correct format (###.###.###.###) 573 const ipv4Pattern = /^(?:\d{1,3}\.){3}\d{1,3}$/; 574 575 if (!ipv4Pattern.test(ip)) return false; // Check general format 576 577 // Split by dots and validate each octet (0-255) 578 const octets = ip.split("."); 579 return octets.every(octet => { 580 let num = parseInt(octet, 10); // Convert to number 581 return num >= 0 && num <= 255; // Each octet must be between 0-255 582 }); 583 } 584 585 // ----------------- Form Submit ----------------- 586 $(document).on("click", ".elementor-field-type-submit", function(e){ 587 var $form = $(this).closest("form"); 588 $form.find("input").trigger("blur"); 589 590 var $errors = $form.find(".mask-error").filter(function() { 591 return $(this).text().trim() !== ""; 592 }); 593 594 if($errors.length > 0){ 595 $errors.each(function(){ 596 if($(this)[0].style.display !== 'none'){ 597 e.preventDefault(); 598 $('html, body').animate({ 599 scrollTop: $(this).offset().top - 200 600 }, 500); 601 } 602 }) 603 } 604 }) 605 606 }); 607})(jQuery);
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.