PageSourceSearch

https://broadbandswitch.uk/assets/js/home-default-widget.js

js broadbandswitch.uk collected 2026-10-04 08:38:34 UTC 4,605 bytes, 148 lines download raw bytes

1(() => {
2  const STICKEE_ID = 'search-switch-save-521';
3  const WAIT_BEFORE_RETRY_MS = 8000;
4  const WAIT_AFTER_REMOUNT_MS = 12000;
5
6  const host = document.getElementById('homeStickeeHost');
7  const status = document.getElementById('homeCompareStatus');
8  const fallback = document.getElementById('homeCompareFallback');
9  const loaderApi = window.BSStickeeLoader;
10
11  if (!host) return;
12
13  let loadStarted = false;
14
15  const setStatus = (text) => {
16    if (status) status.textContent = text || '';
17  };
18
19  const setFallback = (show) => {
20    if (!fallback) return;
21    fallback.hidden = !show;
22  };
23
24  const mountWidget = (forceRemount = false) => {
25    const existing = host.querySelector('#stickee-widget');
26    if (existing && !forceRemount) return existing;
27    if (existing && forceRemount) host.innerHTML = '';
28    host.innerHTML = `<div id="stickee-widget" data-stickee-widget-id="${STICKEE_ID}" data-sort="HEADLINE_PRICE">Live broadband results load below.</div>`;
29    return host.querySelector('#stickee-widget');
30  };
31
32  const hasRenderedWidget = () => {
33    if (host.querySelector('iframe')) return true;
34    if (host.querySelector('whitelabels-broadband-full')) return true;
35    const mount = host.querySelector('#stickee-widget');
36    if (!mount) return false;
37    const text = (mount.textContent || '').replace(/\s+/g, ' ').trim().toLowerCase();
38    return Boolean((mount.children && mount.children.length) || (text && text !== 'loading...' && text !== 'loading...'));
39  };
40
41  const waitForRender = (waitMs) =>
42    new Promise((resolve) => {
43      if (hasRenderedWidget()) {
44        resolve(true);
45        return;
46      }
47      let resolved = false;
48      const done = (result) => {
49        if (resolved) return;
50        resolved = true;
51        clearTimeout(timer);
52        clearInterval(poll);
53        observer.disconnect();
54        resolve(result);
55      };
56      const observer = new MutationObserver(() => {
57        if (hasRenderedWidget()) done(true);
58      });
59      observer.observe(host, { childList: true, subtree: true });
60      const poll = setInterval(() => {
61        if (hasRenderedWidget()) done(true);
62      }, 500);
63      const timer = setTimeout(() => done(hasRenderedWidget()), waitMs);
64    });
65
66  const init = async () => {
67    setFallback(false);
68    setStatus('Loading default broadband comparison...');
69    mountWidget(false);
70
71    if (!loaderApi || typeof loaderApi.ensure !== 'function') {
72      setStatus('Live broadband results are still loading.');
73      setFallback(true);
74      return;
75    }
76
77    try {
78      await loaderApi.ensure({ timeoutMs: 12000 });
79      let ready = await waitForRender(WAIT_BEFORE_RETRY_MS);
80      if (!ready) {
81        mountWidget(true);
82        ready = await waitForRender(WAIT_AFTER_REMOUNT_MS);
83      }
84      if (!ready) {
85        setStatus('Live broadband results are still loading.');
86        setFallback(true);
87        return;
88      }
89      setStatus('Showing live broadband comparison.');
90    } catch (_error) {
91      setStatus('Live broadband results are still loading.');
92      setFallback(true);
93    }
94  };
95
96  const startLoad = () => {
97    if (loadStarted) return;
98    loadStarted = true;
99    init();
100  };
101
102  /**
103   * Defer Stickee until the compare section is near/in the viewport (or #compare),
104   * reducing main-thread work during initial LCP. Fallback timer ensures the widget still loads.
105   */
106  const scheduleLoad = () => {
107    if (location.hash && /#compare/i.test(location.hash)) {
108      startLoad();
109      return;
110    }
111    const target = document.getElementById('comparison-results');
112    if (!target) {
113      startLoad();
114      return;
115    }
116    const rect = target.getBoundingClientRect();
117    const inView = rect.top < window.innerHeight && rect.bottom > 0;
118    if (inView) {
119      startLoad();
120      return;
121    }
122    let io = null;
123    try {
124      io = new IntersectionObserver(
125        (entries) => {
126          if (entries.some((e) => e.isIntersecting)) {
127            if (io) io.disconnect();
128            startLoad();
129          }
130        },
131        { root: null, rootMargin: '240px 0px 360px 0px', threshold: 0 }
132      );
133      io.observe(target);
134    } catch (_err) {
135      startLoad();
136      return;
137    }
138    window.setTimeout(() => {
139      if (!loadStarted) startLoad();
140    }, 5000);
141  };
142
143  if (document.readyState === 'loading') {
144    document.addEventListener('DOMContentLoaded', scheduleLoad, { once: true });
145  } else {
146    scheduleLoad();
147  }
148})();

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.