PageSourceSearch

https://nasapay.com.vc/nasapay_files/custom-mask-script.js

js nasapay.com.vc collected 2026-10-02 02:10:44 UTC 27,669 bytes, 607 lines download raw bytes

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.