PageSourceSearch

https://serpclix.com/static/vnext/home/js/home.js?v=1790693073000

js serpclix.com collected 2026-10-03 21:52:43 UTC 17,185 bytes, 603 lines download raw bytes

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.