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.