1document.addEventListener("DOMContentLoaded", function () { 2 // Pages carry different carousel libs: most load swiper.min.js, some only 3 // get Embla (bundled with the product scripts). Drive the bar with whichever 4 // one is on the page â Swiper first, Embla otherwise. 5 const bar = document.querySelector(".hello-bar-item-left"); 6 7 // The bar used to start rotating ~5s after DOMContentLoaded, putting its first 8 // slide transition at ~6s â which was the last visual change in the entire 9 // Lighthouse trace, and therefore what set Speed Index (6.5s reported, on a 10 // page whose paint actually finishes at 374ms observed). A promo bar that 11 // starts cycling once the visitor is engaged loses nothing; one that cycles 12 // while the page is still loading costs a measurable amount, both in the 13 // metric and in frames the page needs elsewhere. 14 // 15 // So: never before load, then on the first sign of engagement. The fallback 16 // is for visitors who never touch the page â long enough to stay clear of 17 // the load window, short enough that they still see the other slides. 18 const AUTOPLAY_FALLBACK_MS = 15000; 19 const ENGAGEMENT_EVENTS = ["pointerdown", "touchstart", "keydown", "wheel", "scroll"]; 20 21 function whenReadyToAnimate(callback) { 22 let fired = false; 23 const run = () => { 24 if (fired) return; 25 fired = true; 26 ENGAGEMENT_EVENTS.forEach((name) => 27 window.removeEventListener(name, run, { passive: true, capture: true }) 28 ); 29 callback(); 30 }; 31 const armTriggers = () => { 32 ENGAGEMENT_EVENTS.forEach((name) => 33 window.addEventListener(name, run, { passive: true, capture: true, once: true }) 34 ); 35 setTimeout(run, AUTOPLAY_FALLBACK_MS); 36 }; 37 if (document.readyState === "complete") armTriggers(); 38 else window.addEventListener("load", armTriggers); 39 } 40 41 function initHelloBarSwiper(bar) { 42 const swiper = new Swiper(bar, { 43 loop: true, 44 fadeEffect: { crossFade: true }, 45 autoplay: { 46 delay: helloBarSlideDelay, 47 disableOnInteraction: false, 48 }, 49 }); 50 51 bar.addEventListener("mouseenter", () => swiper.autoplay.stop()); 52 bar.addEventListener("mouseleave", () => swiper.autoplay.start()); 53 } 54 55 // Embla core has no autoplay plugin, so the timer is ours. 56 function initHelloBarEmbla(bar) { 57 const embla = EmblaCarousel(bar, { 58 container: ".swiper-wrapper", 59 slides: ".swiper-slide", 60 loop: true, 61 align: "start", 62 containScroll: false, 63 }); 64 65 let timer = null; 66 67 const stopAutoplay = () => { 68 if (timer) { 69 clearInterval(timer); 70 timer = null; 71 } 72 }; 73 74 const startAutoplay = () => { 75 stopAutoplay(); 76 if (helloBarSlideDelay <= 0) return; 77 timer = setInterval(() => { 78 if (!document.hidden) embla.scrollNext(); 79 }, helloBarSlideDelay); 80 }; 81 82 bar.addEventListener("mouseenter", stopAutoplay); 83 bar.addEventListener("mouseleave", startAutoplay); 84 // Swiper's disableOnInteraction: false â a drag pauses, release resumes. 85 embla.on("pointerDown", stopAutoplay); 86 embla.on("pointerUp", startAutoplay); 87 88 whenReadyToAnimate(startAutoplay); 89 } 90 91 // Bundles that define either lib may load async, i.e. after DOMContentLoaded, 92 // so keep looking for a short while. If neither shows up the bar just sits on 93 // its first slide instead of throwing. 94 if (bar && bar.querySelectorAll(".swiper-slide").length > 1) { 95 let initialized = false; 96 97 function initWhenLibReady() { 98 if (initialized) return; 99 100 if (typeof Swiper !== "undefined") { 101 initialized = true; 102 initHelloBarSwiper(bar); 103 return; 104 } 105 106 if (typeof EmblaCarousel !== "undefined") { 107 initialized = true; 108 initHelloBarEmbla(bar); 109 return; 110 } 111 112 setTimeout(initWhenLibReady, 100); 113 } 114 whenReadyToAnimate(initWhenLibReady); 115 } 116 117 const openBtn = document.getElementById('js-get-printerval-app'); 118 const popup = document.querySelector('.hello-app-popup'); 119 const closeBtn = document.querySelector('.hello-app-popup-button'); 120 const closeBg = document.querySelector('.hello-app-popup-bg'); 121 122 if (openBtn) { 123 openBtn.addEventListener('click', function () { 124 popup?.classList.add('is-active'); 125 }); 126 } 127 128 function closePopup() { 129 popup?.classList.remove('is-active'); 130 } 131 132 closeBtn?.addEventListener('click', closePopup); 133 closeBg?.addEventListener('click', closePopup); 134 135 document.addEventListener("click", function (event) { 136 const wrapper = event.target.closest(".copy-wrapper"); 137 if (!wrapper) return; 138 139 const textToCopy = wrapper.dataset.copy; 140 if (!textToCopy) return; 141 142 function showCopied(wrapper) { 143 const oldTooltip = wrapper.querySelector(".hello-bar-tooltip"); 144 if (oldTooltip) oldTooltip.remove(); 145 146 const tooltip = document.createElement("span"); 147 tooltip.className = "hello-bar-tooltip"; 148 tooltip.textContent = "{{ __('Copied') }}"; 149 150 wrapper.appendChild(tooltip); 151 152 setTimeout(() => { 153 tooltip.remove(); 154 }, 1500); 155 } 156 157 // Copy API má»i 158 if (navigator.clipboard && navigator.clipboard.writeText) { 159 navigator.clipboard.writeText(textToCopy) 160 .then(() => { 161 showCopied(wrapper); 162 }) 163 .catch(err => { 164 console.error("Clipboard error:", err); 165 }); 166 } else { 167 // Copy fallback cÅ© 168 const textarea = document.createElement("textarea"); 169 textarea.value = textToCopy; 170 textarea.style.position = "fixed"; 171 textarea.style.top = "-9999px"; 172 textarea.style.left = "-9999px"; 173 document.body.appendChild(textarea); 174 textarea.select(); 175 176 try { 177 document.execCommand("copy"); 178 showCopied(wrapper); 179 } catch (err) { 180 console.error("Fallback copy failed:", err); 181 } 182 183 document.body.removeChild(textarea); 184 } 185 }); 186 187});
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.