PageSourceSearch

https://www.pingdom.com/wp-content/themes/sw-global/dev/scripts/form-logic/validation.js?ver=1786605102

js pingdom.com collected 2026-09-24 06:23:19 UTC 6,141 bytes, 172 lines download raw bytes

1// Form Logic: Validation utilities
2// Dependencies: none (no direct load-time JS dependencies)
3//
4// WordPress enqueue dep: sw-form-logic-helpers (safeguard, ensures helpers.js
5// is present before this file runs, though validation.js does not call any
6// helpers function directly).
7//
8// Runtime globals — available by DOMContentLoaded when event handlers fire:
9//   - isEmailValid      declared in corp-form.js (load order: corp-form → this)
10//   - checkSubmitButton declared in corp-form.js
11//   Note: corp-form.js depends on this file (calls swEmailValidationInit),
12//   so there is no circular WordPress enqueue dep — corp-form loads after this.
13//
14// Provides:
15//   - checkBEValidationGET  — GET request to the SolarAPI validation endpoint
16//   - checkBEValidationPOST — POST request to the SolarAPI validation endpoint
17//   - swEmailValidationInit — async email field validation on change
18//   - swPhoneValidationInit  — phone + phone-code field validation on blur/change
19
20async function checkBEValidationGET(validationEndpoint, queryParamsObject) {
21  const qs = new URLSearchParams(queryParamsObject).toString();
22  const url = `/wp-json/solarapi/api/validation/${validationEndpoint}?${qs}`;
23  const res = await fetch(url);
24  return await res.json();
25}
26
27async function checkBEValidationPOST(validationEndpoint, data) {
28  const url = `/wp-json/solarapi/api/validation/${validationEndpoint}`;
29  const res = await fetch(url, {
30    method: "POST",
31    headers: { "Content-Type": "application/json" },
32    body: JSON.stringify(data)
33  });
34  return await res.json();
35}
36
37// Attaches async email validation to the #sw19_email field within the given form.
38// After each change event, runs parallel API checks and writes to the global
39// `isEmailValid` (declared in corp-form.js), then calls checkSubmitButton().
40function swEmailValidationInit(form) {
41  const emailField = form.querySelector("#sw19_email");
42  if (!emailField) return;
43
44  emailField.addEventListener("input", function () {
45    emailField.setCustomValidity("");
46  });
47
48  // If the field is pre-filled on page load (e.g. redirect), trigger immediately.
49  if (emailField.value.trim()) {
50    setTimeout(function () {
51      emailField.dispatchEvent(new Event("change"));
52    }, 0);
53  }
54
55  emailField.addEventListener("change", async function () {
56    const fieldParent = emailField.closest(".sw19s-corp-field");
57    fieldParent.classList.remove("invalid");
58    emailField.setCustomValidity("");
59    emailField.checkValidity();
60
61    const emailInUseNote = form.querySelector(".email-in-use-note");
62    if (emailInUseNote) emailInUseNote.style.display = "none";
63
64    if (!emailField.validity.valid) {
65      isEmailValid = false;
66      checkSubmitButton();
67      return;
68    }
69
70    fieldParent.classList.add("loading");
71
72    const emailVal = emailField.value.trim();
73    const hasPingdomClass = Array.from(document.body.classList).some(
74      function (cls) {
75        return cls.includes("pingdom");
76      }
77    );
78    const hasPasswordField = !!form.querySelector('input[type="password"]');
79
80    let isFreeEmailRes, isEmailValidRes, uniqueRes;
81    try {
82      [isFreeEmailRes, isEmailValidRes, uniqueRes] = await Promise.all([
83        hasPingdomClass
84          ? Promise.resolve(false)
85          : checkBEValidationGET("free-email", { email: emailVal }),
86        checkBEValidationGET("email", { email: emailVal }),
87        hasPasswordField
88          ? checkBEValidationPOST("unique", {
89              ElementName: "email",
90              TYPE: 6,
91              Value: emailVal
92            })
93          : Promise.resolve(null)
94      ]);
95    } catch (_) {
96      // Network or parse error — treat as valid so the user can proceed.
97      isEmailValid = true;
98      fieldParent.classList.remove("loading");
99      checkSubmitButton();
100      return;
101    }
102
103    fieldParent.classList.remove("loading");
104    isEmailValid = isEmailValidRes?.IsValid;
105
106    if (isFreeEmailRes || !isEmailValid) {
107      emailField.setCustomValidity("Please enter a business email address.");
108      emailField.checkValidity();
109    } else if (uniqueRes === false || uniqueRes?.IsValid === false) {
110      isEmailValid = false;
111      emailField.setCustomValidity("This email address is already in use.");
112      emailField.checkValidity();
113      fieldParent.classList.add("invalid");
114      if (emailInUseNote) emailInUseNote.style.display = "";
115    }
116
117    checkSubmitButton();
118  });
119}
120
121// Attaches phone number + phone-code field cross-validation to the given form.
122function swPhoneValidationInit(form) {
123  const phoneCodeSelect = form.querySelector("#sw19_phone_code");
124  const phoneInput = form.querySelector("#sw19_phone");
125  if (!phoneCodeSelect || !phoneInput) return;
126
127  const phonePattern = /^[0-9\-\(\)\s+]{8,25}$/;
128
129  function validatePhoneFields() {
130    const codeVal = phoneCodeSelect.value.trim();
131    const phoneVal = phoneInput.value.trim();
132    phoneInput.setCustomValidity("");
133    phoneCodeSelect.setCustomValidity("");
134
135    if (!codeVal && !phoneVal) return;
136
137    if (phoneVal && !phonePattern.test(phoneVal)) {
138      phoneInput.setCustomValidity(
139        "Please enter a valid phone number (digits, spaces, dashes and parentheses only, 8\u201325 characters)."
140      );
141      return;
142    }
143    if (phoneVal && !codeVal) {
144      phoneCodeSelect.setCustomValidity("Please select a country phone code.");
145      return;
146    }
147    if (codeVal && !phoneVal) {
148      phoneInput.setCustomValidity("Please enter a phone number.");
149    }
150  }
151
152  phoneInput.addEventListener("input", function () {
153    phoneInput.setCustomValidity("");
154    phoneCodeSelect.setCustomValidity("");
155  });
156
157  phoneCodeSelect.addEventListener("change", function () {
158    phoneInput.setCustomValidity("");
159    phoneCodeSelect.setCustomValidity("");
160    validatePhoneFields();
161  });
162
163  phoneInput.addEventListener("blur", validatePhoneFields);
164
165  phoneInput.addEventListener("invalid", function () {
166    phoneInput.closest(".sw19s-corp-field")?.classList.add("invalid");
167  });
168
169  phoneCodeSelect.addEventListener("invalid", function () {
170    phoneCodeSelect.closest(".sw19s-corp-field")?.classList.add("invalid");
171  });
172}

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.