PageSourceSearch

https://assets.reviews.io/webflow/app/reviews/js/core.js?v=02-04-2026a

js reviews.io collected 2026-10-01 08:32:32 UTC 12,105 bytes, 422 lines download raw bytes

1/**
2 * This script loads the GeoJS library to get the user's location
3 * based on their IP address.
4 */
5function loadGeoJsScript() {
6  const geoScript = document.createElement("script");
7  geoScript.src = "https://get.geojs.io/v1/ip/geo.js";
8  document.body.appendChild(geoScript);
9}
10
11loadGeoJsScript();
12
13function loadIntlTelInputStylesheet() {
14  const link = document.createElement("link");
15  link.href =
16    "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.12/css/intlTelInput.min.css";
17  link.rel = "stylesheet";
18  document.head.appendChild(link);
19}
20
21loadIntlTelInputStylesheet();
22
23function loadIntlTelInputScript(callback) {
24  const script = document.createElement("script");
25  script.src =
26    "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.12/js/intlTelInput.min.js";
27  script.onload = callback;
28  document.body.appendChild(script);
29}
30
31function loadIntlTelInputUtils(callback) {
32  const script = document.createElement("script");
33  script.src =
34    "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.12/js/utils.min.js";
35  script.onload = callback;
36  document.body.appendChild(script);
37}
38
39/**
40 * This function replaces the "Book a Demo" link with "Watch Demo" for
41 * specific countries.
42 */
43function replaceBookDemoLinks() {
44  const blacklistCountryCodes = [
45    "IN", // India
46    "BD", // Bangladesh
47    "PK", // Pakistan
48    "KZ", // Kazakhstan
49    "TR", // Turkey
50    "EG", // Egypt
51    "NG", // Nigeria
52    "KW", // Kuwait
53    "RU", // Russia
54    "BR", // Brazil
55    "AG", // Antigua and Barbuda
56    "DO", // Dominican Republic
57    "CO", // Colombia
58    "AD", // Andorra
59    "AL", // Albania
60    "AX", // Åland Islands
61    "BA", // Bosnia and Herzegovina
62    "BG", // Bulgaria
63    "BY", // Belarus
64    "CZ", // Czech Republic
65    "EE", // Estonia
66    "FO", // Faroe Islands
67    "GI", // Gibraltar
68    "GR", // Greece
69    "HR", // Croatia
70    "HU", // Hungary
71    "IS", // Iceland
72    "JE", // Jersey
73    "LI", // Liechtenstein
74    "LT", // Lithuania
75    "LV", // Latvia
76    "MC", // Monaco
77    "MD", // Moldova
78    "ME", // Montenegro
79    "MK", // North Macedonia
80    "MT", // Malta
81    "RO", // Romania
82    "RS", // Serbia
83    "SI", // Slovenia
84    "SJ", // Svalbard and Jan Mayen
85    "SK", // Slovakia
86    "SM", // San Marino
87    "UA", // Ukraine
88    "VA", // Vatican City
89  ];
90
91  const bookDemoLink = "/lets-chat";
92  const videoWalkthroughLink = "/product-demo";
93
94  window.addEventListener("load", () => {
95    const currentPath = window.location.pathname;
96    const bodyClasses = document.body.classList;
97    const isMatchingCountry = blacklistCountryCodes.some((code) =>
98      bodyClasses.contains(code)
99    );
100
101    if (isMatchingCountry) {
102      if (currentPath === "/front/pricingplans") {
103        const link = document.querySelector(
104          '[data-class="clr-navbar__component"] a[href="' + bookDemoLink + '"]'
105        );
106        if (link) {
107          link.setAttribute("href", videoWalkthroughLink);
108          link.textContent = "Watch Demo";
109          if (link.hasAttribute("data-tracking")) {
110            link.removeAttribute("data-tracking");
111          }
112          if (link.hasAttribute("data-optibase-click-conversion-id")) {
113            link.removeAttribute("data-optibase-click-conversion-id");
114          }
115        }
116      } else {
117        document
118          .querySelectorAll(`a[href="${bookDemoLink}"]`)
119          .forEach((link) => {
120            if (link) {
121              // Change the link URL
122              link.setAttribute("href", videoWalkthroughLink);
123              link.textContent = "Watch Demo";
124              if (link.hasAttribute("data-tracking")) {
125                link.removeAttribute("data-tracking");
126              }
127              if (link.hasAttribute("data-optibase-click-conversion-id")) {
128                link.removeAttribute("data-optibase-click-conversion-id");
129              }
130            }
131          });
132      }
133    }
134  });
135}
136
137// replaceBookDemoLinks();
138
139/**
140 * This function removes query parameters from the URL and sets the
141 * value of a hidden element with the ID "PageURL" to the modified URL.
142 */
143function removeQueryParams() {
144  // This code checks for the existence of a hidden element with the ID
145  // "PageURL" and sets its value to the current URL without query parameters.
146  var currentURL = window.location.href;
147  var urlWithoutQuery =
148    new URL(currentURL).origin + new URL(currentURL).pathname;
149
150  window.addEventListener("load", () => {
151    var pageURLElement = document.getElementById("PageURL");
152    if (pageURLElement) {
153      pageURLElement.value = urlWithoutQuery;
154    }
155  });
156}
157
158removeQueryParams();
159
160/**
161 * This function validates the form fields in the "wf-form-RE-Lead-Form"
162 * form. It checks if the full name, email, and company URL fields
163 * are filled out correctly. If any field is invalid, it prevents
164 * form submission and shows an error message.
165 */
166function validateForm() {
167  window.addEventListener("load", () => {
168    const form = document.getElementById("wf-form-RE-Lead-Form");
169    if (!form) return;
170
171    const fullName = form.querySelector('input[data-name="Full Name"]');
172    const email = form.querySelector('input[data-name="Email"]');
173    const companyName = form.querySelector('input[data-name="Company Name"]');
174    const companyUrl = form.querySelector('input[data-name="Company URL"]');
175    const submitButton = form.querySelector(
176      'input[type="submit"], button[type="submit"]'
177    );
178
179    if (!submitButton) return;
180
181    submitButton.addEventListener("click", function (e) {
182      // Full Name check
183      if (fullName) {
184        if (!fullName.value.trim()) {
185          fullName.setCustomValidity("Full name is required.");
186          fullName.reportValidity();
187          e.preventDefault();
188          return;
189        } else {
190          fullName.setCustomValidity("");
191        }
192      }
193
194      // Email check
195      if (email) {
196        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
197        if (!emailRegex.test(email.value)) {
198          email.setCustomValidity("Please enter a valid email address.");
199          email.reportValidity();
200          e.preventDefault();
201          return;
202        } else {
203          email.setCustomValidity("");
204        }
205      }
206
207      // Company Name check
208      if (companyName) {
209        if (!companyName.value.trim()) {
210          companyName.setCustomValidity("Company name is required.");
211          companyName.reportValidity();
212          e.preventDefault();
213          return;
214        } else {
215          companyName.setCustomValidity("");
216        }
217      }
218
219      // Company URL check
220      if (companyUrl) {
221        const input = companyUrl.value.trim();
222
223        // 1. Add protocol if missing (default to https)
224        let normalized = input;
225        if (!/^https?:\/\//i.test(normalized)) {
226          normalized = `https://${normalized}`;
227        }
228
229        // 2. Validate full URL using regex
230        const urlPattern =
231          /^(https?:\/\/)?([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})(\/\S*)?$/;
232        if (!urlPattern.test(normalized)) {
233          companyUrl.setCustomValidity(
234            "Please enter a valid company URL (e.g., https://your-company-url.com)"
235          );
236          companyUrl.reportValidity();
237          e.preventDefault();
238          return;
239        }
240
241        try {
242          // 3. Use URL object for parsing
243          const url = new URL(normalized);
244
245          // 4. Ensure protocol is http or https only
246          if (!["http:", "https:"].includes(url.protocol)) {
247            throw new Error("Unsupported protocol");
248          }
249
250          // 5. Apply sanitized URL back to input
251          companyUrl.value = url.href;
252          companyUrl.setCustomValidity("");
253        } catch (err) {
254          companyUrl.setCustomValidity(
255            "Please enter a valid company URL (e.g., https://www.your-company-url.com)"
256          );
257          companyUrl.reportValidity();
258          e.preventDefault();
259          return;
260        }
261      }
262    });
263  });
264}
265
266validateForm();
267
268/**
269 * This function validates the phone number input field using the
270 * intl-tel-input library. It checks if the phone number is valid
271 * and updates the dial code accordingly. It also handles error
272 * messages and keyboard validation.
273 */
274function validatePhoneNumber() {
275  let input;
276  let dialCode;
277  let errorMsg;
278  let validMsg;
279  const errorMap = [
280    "Invalid number",
281    "Invalid country code",
282    "Number too short",
283    "Number too long",
284    "Invalid number",
285  ];
286
287  const pageLoaded = new Promise((resolve) => {
288    window.addEventListener("load", resolve);
289  });
290
291  pageLoaded.then(() => {
292    input = document.querySelector("#phone");
293    dialCode = document.querySelector(".dialCode");
294    errorMsg = document.querySelector("#error-msg");
295    validMsg = document.querySelector("#valid-msg");
296
297    if (!input || !dialCode || !errorMsg || !validMsg) return;
298
299    input.setAttribute("pattern", "^[\\d\\+\\-\\(\\)\\s\\.]*$");
300
301    function addKeyboardValidation() {
302      input.addEventListener("keydown", function (event) {
303        const allowedKeys = [
304          "Backspace",
305          "Delete",
306          "ArrowLeft",
307          "ArrowRight",
308          "Tab",
309        ];
310        if (allowedKeys.includes(event.key) || event.ctrlKey || event.metaKey)
311          return;
312        if (!/[\d\+\-\(\)\s\.]/.test(event.key)) event.preventDefault();
313      });
314    }
315
316    function initIntlTelInput() {
317      try {
318        return intlTelInput(input, {
319          initialCountry: "us",
320          placeholderNumberType: "FIXED_LINE",
321          preferredCountries: ["us", "gb", "ca", "de", "au", "nz"],
322        });
323      } catch (error) {
324        console.error("Error initializing intlTelInput:", error);
325        return null;
326      }
327    }
328
329    function resetMessages() {
330      input.classList.remove("error");
331      errorMsg.textContent = "";
332      errorMsg.classList.add("hide");
333      validMsg.classList.add("hide");
334    }
335
336    function setupEventListeners(iti) {
337      const updateDialCode = () => {
338        try {
339          dialCode.value = `+${iti.getSelectedCountryData().dialCode}`;
340        } catch (err) {
341          console.error("Failed to update dial code:", err);
342        }
343      };
344
345      input.addEventListener("input", updateDialCode);
346      input.addEventListener("countrychange", updateDialCode);
347
348      input.addEventListener("blur", () => {
349        resetMessages();
350        const trimmed = input.value.trim();
351        if (trimmed) {
352          if (iti.isValidNumber()) {
353            validMsg.classList.remove("hide");
354          } else {
355            input.classList.add("error");
356            const code = iti.getValidationError();
357            errorMsg.textContent = errorMap[code] || "Unknown error";
358            errorMsg.classList.remove("hide");
359          }
360        }
361      });
362
363      ["change", "keyup"].forEach((evt) =>
364        input.addEventListener(evt, resetMessages)
365      );
366    }
367
368    addKeyboardValidation();
369    const iti = initIntlTelInput();
370    if (!iti) return;
371
372    setupEventListeners(iti);
373  });
374}
375
376loadIntlTelInputScript(() => {
377  loadIntlTelInputUtils(() => {
378    validatePhoneNumber();
379  });
380});
381
382/**
383 * This function shows a popup form when the "openSignUp" query
384 * parameter is present in the URL. It also binds click events to
385 * elements with the class "js-open-popup-form" to show the popup.
386 */
387function showFormPopup() {
388  const popup = document.querySelector(".popup-wrapper");
389  if (!popup) {
390    return;
391  }
392  popup.style.display = "flex";
393  popup.style.opacity = "1";
394}
395
396/**
397 * This function shows the popup form when the "openSignUp" query is present in
398 * the URL.
399 */
400function signupUrlCheck() {
401  const query = window.location.search;
402  const params = new URLSearchParams(query);
403  if (params.has("openSignUp")) {
404    showFormPopup();
405  }
406}
407
408function bindPopupTriggers() {
409  const triggers = document.querySelectorAll(".js-open-popup-form");
410  if (triggers.length === 0) {
411    return;
412  }
413
414  triggers.forEach((trigger) => {
415    trigger.addEventListener("click", showFormPopup);
416  });
417}
418
419window.addEventListener("load", () => {
420  signupUrlCheck();
421  bindPopupTriggers();
422});

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.