1(function () { 2 'use strict'; 3 4 /** 5 * Promo bar front-end behavior: tracks two directional states â 6 * can-scroll-left (scrolled away from the start) and can-scroll-right 7 * (more content past the right edge). Each toggles a class on the bar 8 * that drives the matching edge fade + chevron (see promo-bar.scss). 9 * Re-evaluated on scroll and on resize (ResizeObserver). 10 */ 11 12 const LEFT_CLASS = 'promo-bar--can-scroll-left'; 13 const RIGHT_CLASS = 'promo-bar--can-scroll-right'; 14 const EDGE_TOLERANCE = 1; 15 const FADE_OFFSET = 25; 16 17 function init(bar) { 18 const list = bar.querySelector('.promo-bar__list'); 19 const prevBtn = bar.querySelector('.promo-bar__scroll--prev'); 20 const nextBtn = bar.querySelector('.promo-bar__scroll--next'); 21 if (!list || !prevBtn || !nextBtn) return; 22 23 function update() { 24 const canLeft = list.scrollLeft > EDGE_TOLERANCE; 25 const canRight = 26 list.scrollLeft + list.clientWidth < list.scrollWidth - EDGE_TOLERANCE; 27 bar.classList.toggle(LEFT_CLASS, canLeft); 28 bar.classList.toggle(RIGHT_CLASS, canRight); 29 } 30 31 function step(direction) { 32 // Advance by one item boundary. Targets the next/previous item 33 // relative to the list's left edge, so a click works even when a 34 // single item is wider than the viewport (mobile). 35 const items = list.querySelectorAll('.promo-bar__item'); 36 if (!items.length) return; 37 const listRect = list.getBoundingClientRect(); 38 let target = null; 39 if (direction > 0) { 40 // First item past the landing zone â anything already at or before 41 // the landing zone is "already shown clear of the fade." 42 for (const item of items) { 43 if (item.getBoundingClientRect().left - listRect.left > FADE_OFFSET + EDGE_TOLERANCE) { 44 target = item; 45 break; 46 } 47 } 48 } else { 49 // Last item that hasn't reached the landing zone yet. 50 for (let i = items.length - 1; i >= 0; i--) { 51 if (items[i].getBoundingClientRect().left - listRect.left < FADE_OFFSET - EDGE_TOLERANCE) { 52 target = items[i]; 53 break; 54 } 55 } 56 } 57 if (!target) return; 58 const left = 59 list.scrollLeft + 60 (target.getBoundingClientRect().left - listRect.left) - 61 FADE_OFFSET; 62 const reduce = 63 window.matchMedia && 64 window.matchMedia('(prefers-reduced-motion: reduce)').matches; 65 list.scrollTo({ left, behavior: reduce ? 'auto' : 'smooth' }); 66 } 67 68 prevBtn.addEventListener('click', () => step(-1)); 69 nextBtn.addEventListener('click', () => step(1)); 70 71 list.addEventListener('scroll', update, { passive: true }); 72 73 if (typeof window.ResizeObserver !== 'undefined') { 74 new window.ResizeObserver(update).observe(list); 75 } else { 76 window.addEventListener('resize', update); 77 } 78 79 update(); 80 } 81 82 function setup() { 83 document.querySelectorAll('.promo-bar').forEach(init); 84 } 85 86 if (document.readyState === 'loading') { 87 document.addEventListener('DOMContentLoaded', setup); 88 } else { 89 setup(); 90 } 91})();
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.