1(function () { 2 var trigger = document.getElementById('network-live-trigger'); 3 var loader = document.getElementById('network-live-loader'); 4 if (!trigger || !loader) { 5 return; 6 } 7 8 var loaded = false; 9 function loadScript(src, done) { 10 var script = document.createElement('script'); 11 script.src = src; 12 script.onload = done; 13 document.body.appendChild(script); 14 } 15 function loadNetworkLive() { 16 if (loaded) { 17 return; 18 } 19 loaded = true; 20 loadScript(loader.getAttribute('data-map-src'), function () { 21 loadScript(loader.getAttribute('data-script-src')); 22 }); 23 } 24 25 if (!('IntersectionObserver' in window)) { 26 loadNetworkLive(); 27 return; 28 } 29 var observer = new IntersectionObserver(function (entries) { 30 if (entries[0].isIntersecting) { 31 observer.disconnect(); 32 loadNetworkLive(); 33 } 34 }, { rootMargin: '0px' }); 35 observer.observe(trigger); 36})(); 37 38(function () { 39 var trigger = document.querySelector('[data-wistia-video]'); 40 if (!trigger) { 41 return; 42 } 43 44 trigger.addEventListener('click', function () { 45 var videoId = trigger.getAttribute('data-wistia-video'); 46 var frame = document.createElement('iframe'); 47 frame.src = 'https://fast.wistia.com/embed/iframe/' + encodeURIComponent(videoId) + '?autoplay=1'; 48 frame.title = 'SerpClix introduction video'; 49 frame.allow = 'autoplay; fullscreen; picture-in-picture'; 50 frame.allowFullscreen = true; 51 frame.loading = 'eager'; 52 frame.style.cssText = 'border:0;display:block;height:100%;left:0;position:absolute;top:0;width:100%;'; 53 54 var wrapper = trigger.parentNode; 55 wrapper.replaceChild(frame, trigger); 56 }, { once: true }); 57})(); 58 59(function () { 60 // CTR Calculator â monthly display; core math in static/js/recommended_daily_clicks.js 61 var costPerClick = 0.29; 62 var ss = document.getElementById("slider-searches"); 63 var sc = document.getElementById("slider-current"); 64 var st = document.getElementById("slider-target"); 65 66 function recommendedDaily(monthlySearches, currentPosition) { 67 var api = window.SerpclixRecommendedDailyClicks; 68 if (!api || typeof api.recommendedDailyClicks !== "function") { 69 return 30; 70 } 71 return api.recommendedDailyClicks(monthlySearches, currentPosition) * 30; 72 } 73 74 function calc() { 75 if (!ss || !sc || !st) { 76 return; 77 } 78 var s = parseInt(ss.value, 10); 79 var c = parseInt(sc.value, 10); 80 var t = parseInt(st.value, 10); 81 document.getElementById("sv-searches").textContent = s.toLocaleString(); 82 document.getElementById("sv-current").textContent = c; 83 document.getElementById("sv-target").textContent = t; 84 var monthly = recommendedDaily(s, c); 85 document.getElementById("calc-clicks").textContent = monthly.toLocaleString(); 86 document.getElementById("calc-budget").textContent = "$" + (monthly * costPerClick).toFixed(2); 87 } 88 89 if (ss && sc && st) { 90 ss.addEventListener("input", calc); 91 sc.addEventListener("input", calc); 92 st.addEventListener("input", calc); 93 calc(); 94 } 95})(); 96 97(function () { 98 // Testimonial Carousel 99 var pages = document.querySelectorAll(".carousel-page"); 100 var dots = document.querySelectorAll(".carousel-dot"); 101 var prev = document.getElementById("testimonial-prev"); 102 var next = document.getElementById("testimonial-next"); 103 var wrapper = document.querySelector(".carousel-wrapper"); 104 if (!pages.length || !dots.length || !prev || !next || !wrapper) { 105 return; 106 } 107 108 var current = 0; 109 var total = pages.length; 110 var autoPlay = null; 111 112 function goTo(n) { 113 pages[current].classList.remove("active"); 114 dots[current].classList.remove("active"); 115 current = (n + total) % total; 116 pages[current].classList.add("active"); 117 dots[current].classList.add("active"); 118 } 119 120 prev.addEventListener("click", function () { 121 goTo(current - 1); 122 }); 123 next.addEventListener("click", function () { 124 goTo(current + 1); 125 }); 126 dots.forEach(function (dot) { 127 dot.addEventListener("click", function () { 128 goTo(parseInt(this.dataset.page, 10)); 129 }); 130 }); 131 132 autoPlay = setInterval(function () { 133 goTo(current + 1); 134 }, 8000); 135 136 wrapper.addEventListener("mouseenter", function () { 137 clearInterval(autoPlay); 138 }); 139 wrapper.addEventListener("mouseleave", function () { 140 autoPlay = setInterval(function () { 141 goTo(current + 1); 142 }, 8000); 143 }); 144})(); 145 146(function () { 147 // FAQ Accordion 148 var faqQuestions = document.querySelectorAll('.faq-question'); 149 faqQuestions.forEach(function(question) { 150 question.addEventListener('click', function() { 151 var item = this.closest('.faq-item'); 152 var isOpen = item.classList.contains('open'); 153 154 // Close all FAQ items 155 document.querySelectorAll('.faq-item').forEach(function(otherItem) { 156 otherItem.classList.remove('open'); 157 }); 158 159 // Toggle current item 160 if (!isOpen) { 161 item.classList.add('open'); 162 } 163 }); 164 }); 165})(); 166 167(function () { 168 // Hero Get Started Form 169 var heroUrlBtn = document.getElementById('hero_url_submit'); 170 var heroUrl = document.getElementById('hero_url'); 171 172 if (heroUrlBtn && heroUrl) { 173 // Handle Enter key press in input field 174 heroUrl.addEventListener('keydown', function(event) { 175 if (event.key === 'Enter') { 176 event.preventDefault(); 177 heroUrlBtn.click(); 178 } 179 }); 180 181 // Handle button click 182 heroUrlBtn.addEventListener('click', function() { 183 var v = (heroUrl.value || '').trim(); 184 if (!v) { 185 window.location.assign('/pricing'); 186 return; 187 } 188 189 localStorage.setItem('AB-URL', v); 190 document.cookie = 'AB-test=1'; 191 window.location.assign('/pricing?url=' + encodeURIComponent(v)); 192 }); 193 } else { 194 document.cookie = 'AB-test=0'; 195 localStorage.removeItem('AB-URL'); 196 } 197})(); 198 199(function () { 200 // Highlight homepage section anchors in the vnext header while scrolling 201 if (!document.querySelector('.home-page')) { 202 return; 203 } 204 var sectionIds = ['how-it-works', 'why-serpclix', 'evidence', 'case-studies']; 205 var nav = document.querySelector('.vnext-nav'); 206 if (!nav) { 207 return; 208 } 209 210 function sectionVisibleHeight(el) { 211 var navH = nav.offsetHeight || 72; 212 var viewTop = navH; 213 var viewBottom = window.innerHeight; 214 var rect = el.getBoundingClientRect(); 215 var top = Math.max(rect.top, viewTop); 216 var bottom = Math.min(rect.bottom, viewBottom); 217 return Math.max(0, bottom - top); 218 } 219 220 function clearSectionActives() { 221 sectionIds.forEach(function (id) { 222 nav.querySelectorAll('a[href*="#' + id + '"]').forEach(function (a) { 223 a.classList.remove('active'); 224 }); 225 }); 226 } 227 228 function updateSectionNav() { 229 var current = null; 230 var bestVis = 0; 231 sectionIds.forEach(function (id) { 232 var el = document.getElementById(id); 233 if (!el) { 234 return; 235 } 236 var vis = sectionVisibleHeight(el); 237 if (vis > bestVis) { 238 bestVis = vis; 239 current = id; 240 } 241 }); 242 if (bestVis === 0) { 243 current = null; 244 } 245 246 clearSectionActives(); 247 if (current) { 248 nav.querySelectorAll('a[href*="#' + current + '"]').forEach(function (a) { 249 a.classList.add('active'); 250 }); 251 } 252 } 253 254 var ticking = false;
255 function onScroll() { 256 if (!ticking) { 257 window.requestAnimationFrame(function () { 258 updateSectionNav(); 259 ticking = false; 260 }); 261 ticking = true; 262 } 263 } 264 265 window.addEventListener('scroll', onScroll, { passive: true }); 266 window.addEventListener('resize', onScroll, { passive: true }); 267 window.addEventListener('hashchange', updateSectionNav); 268 if (document.readyState === 'loading') { 269 document.addEventListener('DOMContentLoaded', function () { 270 updateSectionNav(); 271 window.requestAnimationFrame(updateSectionNav); 272 }); 273 } else { 274 updateSectionNav(); 275 window.requestAnimationFrame(updateSectionNav); 276 } 277})(); 278 279(function () { 280 function readDualEntryConfig() { 281 var el = document.getElementById("home-dual-entry-config"); 282 if (!el || !el.textContent) { 283 return null; 284 } 285 try { 286 return JSON.parse(el.textContent); 287 } catch (e) { 288 return null; 289 } 290 } 291 292 function getCfg() { 293 return readDualEntryConfig() || {}; 294 } 295 296 function getSavedLocation() { 297 try { 298 var v = localStorage.getItem("dfs_location"); 299 if (v) { 300 return v; 301 } 302 } catch (e) {} 303 return "2840"; 304 } 305 306 // url/keyword prefills older than this are ignored (the email is kept -- 307 // it aids signup continuity and isn't the staleness problem). Without an 308 // expiry, a URL typed months ago kept re-hydrating these inputs forever. 309 var ORDER_PREFILL_TTL_MS = 24 * 60 * 60 * 1000; 310 311 function readOrderPrefillObj() { 312 try { 313 var raw = localStorage.getItem("serpclix_order_prefill"); 314 if (!raw) { 315 return { url: "", keyword: "", email: "" }; 316 } 317 var o = JSON.parse(raw); 318 if (!o || typeof o !== "object") { 319 return { url: "", keyword: "", email: "" }; 320 } 321 var writtenAt = Number(o._ts); 322 var stale = !writtenAt || (Date.now() - writtenAt) > ORDER_PREFILL_TTL_MS; 323 return { 324 url: stale ? "" : String(o.url || "").trim(), 325 keyword: stale ? "" : String(o.keyword || "").trim(), 326 email: String(o.email || "").trim(), 327 }; 328 } catch (e) { 329 return { url: "", keyword: "", email: "" }; 330 } 331 } 332 333 function writeOrderPrefillMerged(patch) { 334 var cur = readOrderPrefillObj(); 335 if (patch.url) { 336 cur.url = String(patch.url).trim(); 337 } 338 if (patch.keyword) { 339 cur.keyword = String(patch.keyword).trim(); 340 } 341 if (patch.email) { 342 cur.email = String(patch.email).trim(); 343 } 344 cur._ts = Date.now(); 345 try { 346 localStorage.setItem("serpclix_order_prefill", JSON.stringify(cur)); 347 } catch (e) {} 348 } 349 350 function wizardHrefWithQuery(cfgLocal, paramName, rawValue) { 351 var base = (cfgLocal && cfgLocal.order_wizard) || ""; 352 if (!base) { 353 return ""; 354 } 355 var sep = base.indexOf("?") >= 0 ? "&" : "?"; 356 return base + sep + paramName + "=" + encodeURIComponent(rawValue); 357 } 358 359 function normalizeHomepageUrlInput(raw) { 360 var url = String(raw || "").trim(); 361 if (!url) { 362 return ""; 363 } 364 if (/[\u0000-\u001f\u007f]/.test(url)) { 365 return ""; 366 } 367 if (/^https?:\/\//i.test(url)) { 368 return url; 369 } 370 if (/^[a-z][a-z0-9+.-]*:\/\//i.test(url)) { 371 return ""; 372 } 373 if (/^\/\//.test(url)) { 374 return "https:" + url; 375 } 376 return "https://" + url.replace(/^\/+/, ""); 377 } 378 379 /** Mirrors analyzer.helpers.is_valid_public_url: fail fast before SEO API / wizard. */ 380 function isLikelyValidPublicUrl(raw) { 381 if (!raw || String(raw).length > 500) { 382 return false; 383 } 384 try { 385 var u = new URL(raw); 386 if (!/^https?:$/i.test(u.protocol)) { 387 return false; 388 } 389 var host = (u.hostname || "").toLowerCase(); 390 if (!host || /\s/.test(host)) { 391 return false; 392 } 393 if (host.indexOf("..") !== -1 || host.charAt(0) === "." || host.charAt(host.length - 1) === ".") { 394 return false; 395 } 396 if (host.indexOf(".") === -1) { 397 return false; 398 } 399 var labels = host.split("."); 400 var i; 401 for (i = 0; i < labels.length; i++) { 402 if (!labels[i] || labels[i].length > 63) { 403 return false;
404 } 405 } 406 if (u.port !== "") { 407 var p = parseInt(u.port, 10); 408 if (isNaN(p) || p <= 0 || p > 65535) { 409 return false; 410 } 411 } 412 return true; 413 } catch (e) { 414 return false; 415 } 416 } 417 418 function setInlineError(inputEl, errorEl, message) { 419 if (!inputEl || !errorEl) { 420 return; 421 } 422 errorEl.textContent = message; 423 errorEl.classList.add("is-visible"); 424 inputEl.classList.add("choice-input--error"); 425 inputEl.setAttribute("aria-invalid", "true"); 426 } 427 428 function clearInlineError(inputEl, errorEl) { 429 if (!inputEl || !errorEl) { 430 return; 431 } 432 errorEl.textContent = ""; 433 errorEl.classList.remove("is-visible"); 434 inputEl.classList.remove("choice-input--error"); 435 inputEl.removeAttribute("aria-invalid"); 436 } 437 438 function goToRankings() { 439 var cfg = getCfg(); 440 var inp = document.getElementById("urlInput"); 441 var errEl = document.getElementById("urlInputError"); 442 if (!inp) { 443 return; 444 } 445 var kwInp = document.getElementById("keywordInput"); 446 var kwErr = document.getElementById("keywordInputError"); 447 if (kwInp && kwErr) { 448 clearInlineError(kwInp, kwErr); 449 } 450 var url = inp.value.trim(); 451 if (!url) { 452 setInlineError(inp, errEl, "Please enter a website URL."); 453 inp.focus(); 454 return; 455 } 456 url = normalizeHomepageUrlInput(url); 457 if (!url || !isLikelyValidPublicUrl(url)) { 458 setInlineError( 459 inp, 460 errEl, 461 "Please enter a valid URL, for example https://example.com/page." 462 ); 463 inp.focus(); 464 return; 465 } 466 clearInlineError(inp, errEl); 467 var email = ""; 468 try { 469 email = (localStorage.getItem("serpclix_email") || "").trim(); 470 } catch (e) {} 471 writeOrderPrefillMerged({ url: url, email: email }); 472 if (cfg.skip_analyzer_for_buyer && cfg.order_wizard) { 473 var wh = wizardHrefWithQuery(cfg, "url", url); 474 if (!wh) { 475 setInlineError( 476 inp, 477 errEl, 478 "Something went wrong loading this page. Please refresh and try again." 479 ); 480 return; 481 } 482 window.location.href = wh; 483 return; 484 } 485 if (!cfg.seo_analyzer) { 486 setInlineError( 487 inp, 488 errEl, 489 "Something went wrong loading this page. Please refresh and try again." 490 ); 491 return; 492 } 493 var loc = encodeURIComponent(getSavedLocation()); 494 var sep = cfg.seo_analyzer.indexOf("?") >= 0 ? "&" : "?"; 495 window.location.href = 496 cfg.seo_analyzer + sep + "url=" + encodeURIComponent(url) + "&loc=" + loc; 497 } 498 499 function goToReputation() { 500 var cfg = getCfg(); 501 var inp = document.getElementById("keywordInput"); 502 var errEl = document.getElementById("keywordInputError"); 503 if (!inp) { 504 return; 505 } 506 var urlInp = document.getElementById("urlInput"); 507 var urlErr = document.getElementById("urlInputError"); 508 if (urlInp && urlErr) { 509 clearInlineError(urlInp, urlErr); 510 } 511 var keyword = inp.value.trim(); 512 if (!keyword) { 513 setInlineError(inp, errEl, "Please enter a name or keyword."); 514 inp.focus(); 515 return; 516 } 517 clearInlineError(inp, errEl); 518 var email = ""; 519 try { 520 email = (localStorage.getItem("serpclix_email") || "").trim(); 521 } catch (e) {} 522 writeOrderPrefillMerged({ keyword: keyword, email: email }); 523 if (cfg.skip_analyzer_for_buyer && cfg.order_wizard) { 524 var wh = wizardHrefWithQuery(cfg, "keyword", keyword); 525 if (!wh) { 526 setInlineError( 527 inp, 528 errEl, 529 "Something went wrong loading this page. Please refresh and try again." 530 ); 531 return; 532 } 533 window.location.href = wh; 534 return; 535 } 536 if (!cfg.reputation_analyzer) { 537 setInlineError( 538 inp, 539 errEl, 540 "Something went wrong loading this page. Please refresh and try again." 541 ); 542 return; 543 } 544 var loc = encodeURIComponent(getSavedLocation()); 545 var sep = cfg.reputation_analyzer.indexOf("?") >= 0 ? "&" : "?"; 546 window.location.href = 547 cfg.reputation_analyzer + sep + "q=" + encodeURIComponent(keyword) + "&loc=" + loc; 548 } 549 550 window.goToRankings = goToRankings; 551 window.goToReputation = goToReputation; 552 553 try { 554 var prefill = readOrderPrefillObj(); 555 var urlEl = document.getElementById("urlInput"); 556 var kwEl = document.getElementById("keywordInput"); 557 if (prefill.url && urlEl) { 558 urlEl.value = prefill.url; 559 } 560 if (prefill.keyword && kwEl) { 561 kwEl.value = prefill.keyword; 562 } 563 } catch (e) {} 564 565 var urlInput = document.getElementById("urlInput"); 566 var keywordInput = document.getElementById("keywordInput"); 567 var urlInputError = document.getElementById("urlInputError"); 568 var keywordInputError = document.getElementById("keywordInputError"); 569 var urlBtn = document.getElementById("urlBtn"); 570 var keywordBtn = document.getElementById("keywordBtn"); 571 if (urlBtn) { 572 urlBtn.addEventListener("click", function (ev) { 573 ev.preventDefault(); 574 goToRankings(); 575 }); 576 } 577 if (keywordBtn) { 578 keywordBtn.addEventListener("click", function (ev) { 579 ev.preventDefault(); 580 goToReputation(); 581 }); 582 } 583 if (urlInput && urlInputError) { 584 urlInput.addEventListener("input", function () { 585 clearInlineError(urlInput, urlInputError); 586 }); 587 urlInput.addEventListener("keydown", function (e) { 588 if (e.key === "Enter") { 589 goToRankings(); 590 } 591 }); 592 } 593 if (keywordInput && keywordInputError) { 594 keywordInput.addEventListener("input", function () { 595 clearInlineError(keywordInput, keywordInputError); 596 }); 597 keywordInput.addEventListener("keydown", function (e) { 598 if (e.key === "Enter") { 599 goToReputation(); 600 } 601 }); 602 } 603})();
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.