PageSourceSearch

https://vmpetsmart.com/wp-content/plugins/international-phone-numb…/js/intl-phone-number-format.js?ver=1.0.0

js vmpetsmart.com collected 2026-10-08 11:07:18 UTC 10,003 bytes, 391 lines download raw bytes

1const baseCountry = IntlPhoneNumberFormatData.base_country;
2const fields = IntlPhoneNumberFormatData.fields;
3const shippingCountries = IntlPhoneNumberFormatData.shipping_countries;
4const allowedCountries = IntlPhoneNumberFormatData.allowed_countries;
5const allCountries = IntlPhoneNumberFormatData.all_countries;
6const validationMessages = IntlPhoneNumberFormatData.validations;
7const patterns = IntlPhoneNumberFormatData.patterns;
8const lookup = IntlPhoneNumberFormatData.lookup;
9const inputHelperClass = IntlPhoneNumberFormatData.input_helper_class;
10const apiUrl = "https://ipapi.co/json";
11
12jQuery(document).ready(function ($) {
13  getFields().forEach((entry) => {
14    let field = entry.id;
15    let required = entry.required;
16    let countries = entry.countries;
17    buildIntlPhoneNumberField(field, required, countries);
18  });
19
20  validateForms();
21});
22
23function validateForms() {
24  checkoutPage();
25  otherForms();
26}
27
28function checkoutPage() {
29  let checkoutForm = jQuery("form.checkout");
30
31  if (checkoutForm.length) {
32    checkoutForm.on("checkout_place_order", function (event) {
33      let isValid = true;
34
35      getFields().forEach((entry) => {
36        let field = entry.id;
37        let required = entry.required;
38        let type = entry.type;
39        let isShippingField = type === "shipping";
40
41        if (getInput(field) && required) {
42          let isValidField = true;
43
44          if (isShippingField) {
45            let shipToDifferentAddress = document.querySelector(
46              "#ship-to-different-address-checkbox"
47            );
48            if (
49              shipToDifferentAddress &&
50              shipToDifferentAddress.checked &&
51              !validatePhoneNumber(field)
52            ) {
53              isValidField = false;
54            }
55          } else if (!validatePhoneNumber(field)) {
56            isValidField = false;
57          }
58
59          if (!isValidField) {
60            isValid = false;
61          }
62        }
63      });
64
65      if (!isValid) {
66        event.preventDefault(); // Prevent form submission if any field is invalid
67        return false;
68      }
69    });
70  }
71
72  return true;
73}
74
75function otherForms() {
76  getFields().forEach((entry) => {
77    let field = entry.id;
78    let required = entry.required;
79    let form = getFormByField(field);
80    if (form && required) {
81      form.addEventListener("submit", function (event) {
82        let isValid = validatePhoneNumber(field);
83
84        if (!isValid) {
85          event.preventDefault();
86          return false;
87        }
88        return isValid;
89      });
90    }
91  });
92
93  return true;
94}
95
96function getFormByField(field) {
97  let input = getInput(field);
98  if (!input) {
99    return null;
100  }
101
102  let form = input;
103  while (form && form.tagName !== "FORM") {
104    form = form.parentElement;
105  }
106
107  return form;
108}
109
110function buildIntlPhoneNumberField(field, required, countries) {
111  let inputID = "#" + field;
112  let input = document.querySelector(inputID);
113  if (input) {
114    let configs = {
115      hiddenInput: field,
116      separateDialCode: true,
117      nationalMode: true,
118    };
119
120    let preferredCountries = [];
121    let defaultCountry = baseCountry;
122    let onlyCountries = getCountriesBy(countries);
123
124    if (!onlyCountries.includes(defaultCountry) && onlyCountries.length > 0) {
125      defaultCountry = onlyCountries[0] ?? "";
126    } else if (
127      !onlyCountries.includes(defaultCountry) &&
128      onlyCountries.length == 0
129    ) {
130      defaultCountry = defaultCountry;
131    } else {
132      preferredCountries = [defaultCountry];
133    }
134
135    let hasMultipleCountry = onlyCountries.length > 1;
136
137    if (lookup.active && hasMultipleCountry) {
138      let lockupCountry = getCountryFromLocalStorage();
139
140      if (lockupCountry) {
141        if (onlyCountries.includes(lockupCountry)) {
142          if (lockupCountry != defaultCountry) {
143            preferredCountries.unshift(lockupCountry);
144          }
145        }
146
147        if (!onlyCountries.includes(lockupCountry)) {
148          configs.initialCountry = defaultCountry;
149        }
150      } else {
151        let lockupCountryCallback = (callback) => {
152          fetch(apiUrl)
153            .then((res) => res.json())
154            .then((data) => {
155              let country;
156              if (
157                data?.country_code &&
158                onlyCountries.includes(data.country_code)
159              ) {
160                country = data.country_code;
161                setCountryLocalStorage(country);
162              } else {
163                country = defaultCountry;
164              }
165              callback(country);
166            })
167            .catch(() => callback(defaultCountry));
168        };
169
170        configs.geoIpLookup = lockupCountryCallback;
171        configs.initialCountry = "auto";
172      }
173    } else {
174      configs.initialCountry = defaultCountry;
175    }
176
177    configs.onlyCountries = onlyCountries;
178    configs.allowDropdown = hasMultipleCountry;
179    configs.preferredCountries = preferredCountries;
180
181    let iti = window.intlTelInput(input, configs);
182
183    let filterInput = (event) => {
184      let input = event.target;
185      let cleanedValue = input.value.replace(/[^\d\s-]/g, "");
186      cleanedValue = cleanedValue.trim();
187
188      if (cleanedValue.length > 15) {
189        cleanedValue = cleanedValue.substring(0, 15);
190      }
191
192      input.value = cleanedValue;
193    };
194
195    let handleChange = () => {
196      if (required) {
197        validateError(iti, input);
198      }
199    };
200
201    input.addEventListener("input", filterInput);
202    input.addEventListener("change", handleChange);
203    input.addEventListener("keyup", handleChange);
204    input.addEventListener("countrychange", handleChange);
205    input.addEventListener("blur", handleChange);
206    input.addEventListener("input", handleChange);
207  }
208}
209
210function validatePhoneNumber(field) {
211  let phoneInput = getInput(field);
212
213  if (!phoneInput) {
214    return false;
215  }
216
217  let iti = getFieldIntlInstance(field);
218  if (!iti) {
219    return false;
220  }
221
222  let hasError = false;
223  let hasErrorMessage = validateError(iti, phoneInput);
224  let validPhoneNumber = iti.isValidNumber();
225
226  if (hasErrorMessage) {
227    hasError = true;
228  }
229
230  if (!validPhoneNumber) {
231    hasError = true;
232  }
233
234  if (hasError) {
235    phoneInput.scrollIntoView({ behavior: "smooth" });
236    return false;
237  }
238
239  return true;
240}
241
242function getFieldIntlInstance(field) {
243  return window.intlTelInputGlobals.getInstance(getInput(field));
244}
245
246function getInput(field) {
247  let inputID = "#" + field;
248  return document.querySelector(inputID);
249}
250
251function validateError(iti, input) {
252  let hasError = false;
253  let text;
254
255  if (input.value) {
256    text = iti.isValidNumber()
257      ? ""
258      : validationMessages.invalid_phone_number_format;
259
260    let fullNumber = iti.getNumber();
261
262    Object.entries(patterns).forEach((patternEntry) => {
263      let [prefix, regexString] = patternEntry;
264      if (fullNumber.startsWith(prefix)) {
265        let regex = new RegExp(regexString);
266        if (!regex.test(fullNumber)) {
267          text = validationMessages.invalid_phone_number_format;
268          return;
269        }
270      }
271    });
272  } else {
273    text = validationMessages.required_phone_number;
274  }
275
276  hasError = text !== "";
277
278  let classArray = ["validate-required", "form-row"];
279  let closestAncestor = null;
280
281  for (let className of classArray) {
282    closestAncestor = findClosestAncestor(input, className);
283    if (closestAncestor) {
284      break;
285    }
286  }
287
288  if (closestAncestor) {
289    closestAncestor.classList.remove(
290      "woocommerce-invalid",
291      "woocommerce-validated"
292    );
293    if (text !== "") {
294      closestAncestor.classList.add("woocommerce-invalid");
295    } else {
296      closestAncestor.classList.add("woocommerce-validated");
297    }
298  }
299
300  let existingHelpText = input.parentElement.nextElementSibling;
301  if (existingHelpText) {
302    existingHelpText.textContent = text;
303    if (text) {
304      existingHelpText.style.display = "block";
305    } else {
306      existingHelpText.style.display = "none";
307    }
308  } else {
309    let errorMessage = document.createElement("span");
310    errorMessage.className = inputHelperClass;
311    errorMessage.textContent = text;
312    if (text) {
313      errorMessage.style.display = "block";
314    } else {
315      errorMessage.style.display = "none";
316    }
317    input.parentElement.insertAdjacentElement("afterend", errorMessage);
318  }
319
320  return hasError;
321}
322
323function findClosestAncestor(element, className) {
324  let parent = element.parentElement;
325  while (parent) {
326    if (parent.classList.contains(className)) {
327      return parent;
328    }
329    parent = parent.parentElement;
330  }
331  return null;
332}
333
334function getFields() {
335  return fields.length
336    ? fields
337        .map((field) => ({
338          ...field,
339          element: document.getElementById(field.id),
340        }))
341        .filter((field) => field.element !== null)
342        .sort((a, b) => {
343          return compareElementPositions(a.element, b.element);
344        })
345    : [];
346}
347
348function compareElementPositions(elementA, elementB) {
349  if (elementA === elementB) {
350    return 0;
351  }
352  if (
353    elementA.compareDocumentPosition(elementB) &
354    Node.DOCUMENT_POSITION_PRECEDING
355  ) {
356    return -1;
357  }
358  return 1;
359}
360
361function getCountriesBy(countriesType) {
362  let onlyCountries = [];
363  if (countriesType === "billing") {
364    onlyCountries = allowedCountries;
365  } else if (countriesType === "shipping") {
366    onlyCountries = shippingCountries;
367  } else if (countriesType === "all") {
368    onlyCountries = allCountries;
369  }
370  return onlyCountries;
371}
372
373function setCountryLocalStorage(countryCode) {
374  let expiration = new Date().getTime() + 60 * 60 * 1000 * lookup.ttl;
375  let data = { countryCode, expiration };
376  localStorage.setItem(
377    "intl_phone_number_lcokup_country",
378    JSON.stringify(data)
379  );
380}
381
382function getCountryFromLocalStorage() {
383  let storedData = localStorage.getItem("intl_phone_number_lcokup_country");
384  if (storedData) {
385    let data = JSON.parse(storedData);
386    if (data.expiration && new Date().getTime() < data.expiration) {
387      return data.countryCode || "";
388    }
389  }
390  return "";
391}

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.