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.