1(function () { 2 'use strict'; 3 4 function scrollportEl(track) { 5 if (!track) return null; 6 var parent = track.parentElement; 7 if (parent && parent.classList.contains('season-track-scroll')) return parent; 8 if (track.classList.contains('season-track') && track.scrollWidth > track.clientWidth) return track; 9 return track; 10 } 11 12 function scrollTarget(track, preferActive) { 13 if (preferActive) { 14 return ( 15 track.querySelector('.season-ep.active') || 16 track.querySelector('.season-ep[aria-pressed="true"]') || 17 track.querySelector('[data-uxm-timeline-latest="true"]') 18 ); 19 } 20 return ( 21 track.querySelector('[data-uxm-timeline-latest="true"]') || 22 track.querySelector('.season-ep.active') || 23 track.querySelector('.season-ep[aria-pressed="true"]') || 24 track.querySelector('.season-ep--nav:last-of-type, .season-ep--hub:last-of-type') 25 ); 26 } 27 28 function centerStop(track, stop, behavior) { 29 var port = scrollportEl(track); 30 if (!port || !stop) return; 31 var max = port.scrollWidth - port.clientWidth; 32 if (max <= 0) return; 33 var left = stop.offsetLeft - port.clientWidth / 2 + stop.offsetWidth / 2; 34 port.scrollTo({ left: Math.max(0, Math.min(left, max)), behavior: behavior || 'auto' }); 35 } 36 37 function dotCenterY(stop) { 38 var dot = stop.querySelector('.season-ep-dot'); 39 if (!dot) return stop.offsetTop + stop.offsetHeight / 2; 40 return stop.offsetTop + dot.offsetTop + dot.offsetHeight / 2; 41 } 42 43 function layoutTimelineLine(track) { 44 var line = track.querySelector('.season-line'); 45 if (!line) return; 46 var stops = track.querySelectorAll('.season-ep'); 47 if (stops.length < 2) { 48 line.style.display = 'none'; 49 return; 50 } 51 line.style.display = ''; 52 var first = stops[0]; 53 var last = stops[stops.length - 1]; 54 var x1 = first.offsetLeft + first.offsetWidth / 2; 55 var x2 = last.offsetLeft + last.offsetWidth / 2; 56 var yCenter = dotCenterY(first); 57 line.style.left = x1 + 'px'; 58 line.style.width = Math.max(0, x2 - x1) + 'px'; 59 line.style.right = 'auto'; 60 line.style.top = (yCenter - 1) + 'px'; 61 } 62 63 function scheduleLineLayout(track) { 64 requestAnimationFrame(function () { 65 layoutTimelineLine(track); 66 }); 67 } 68 69 function updateScrollDims(track) { 70 var port = scrollportEl(track); 71 if (!port) return; 72 var stops = track.querySelectorAll('.season-ep--nav, .season-ep--hub'); 73 stops.forEach(function (stop) { 74 var r = stop.getBoundingClientRect(); 75 var pr = port.getBoundingClientRect(); 76 var partial = r.right > pr.right + 2 || r.left < pr.left - 2; 77 stop.classList.toggle('season-ep--scroll-dim', partial && !stop.classList.contains('active') && stop.getAttribute('aria-pressed') !== 'true'); 78 }); 79 } 80 81 function bindLineLayout(track) { 82 if (track.__uxmLineLayoutBound) return; 83 track.__uxmLineLayoutBound = true; 84 scheduleLineLayout(track); 85 if (typeof ResizeObserver !== 'undefined') { 86 var ro = new ResizeObserver(function () { 87 layoutTimelineLine(track); 88 }); 89 ro.observe(track); 90 track.__uxmLineRo = ro; 91 } 92 window.addEventListener('resize', function () { 93 layoutTimelineLine(track); 94 }, { passive: true }); 95 } 96 97 function initArc(arc, behavior, preferActive) { 98 var track = arc.querySelector('.season-track'); 99 if (!track) return; 100 bindLineLayout(track); 101 centerStop(track, scrollTarget(track, preferActive), behavior); 102 updateScrollDims(track); 103 var port = scrollportEl(track); 104 if (port) { 105 port.addEventListener('scroll', function () { 106 updateScrollDims(track); 107 }, { passive: true }); 108 } 109 } 110 111 function initAll(behavior, preferActive) { 112 document.querySelectorAll('.uxm-season-timeline').forEach(function (arc) { 113 var useActive = preferActive != null ? preferActive : arc.classList.contains('season-arc--ideation'); 114 initArc(arc, behavior, useActive); 115 }); 116 } 117 118 window.UXM_scrollSeasonTimeline = function (root, behavior, preferActive) { 119 var arc = root && root.closest ? root.closest('.uxm-season-timeline') : null; 120 if (arc) initArc(arc, behavior || 'smooth', !!preferActive); 121 else initAll(behavior || 'smooth', !!preferActive); 122 }; 123 124 window.UXM_layoutSeasonTimelineLine = function (root) { 125 var track = root && root.querySelector ? root.querySelector('.season-track') : null; 126 if (!track && root && root.classList && root.classList.contains('season-track')) track = root; 127 if (track) layoutTimelineLine(track); 128 else { 129 document.querySelectorAll('.uxm-season-timeline .season-track').forEach(layoutTimelineLine); 130 } 131 }; 132 133 if (document.readyState === 'loading') { 134 document.addEventListener('DOMContentLoaded', function () { 135 initAll('auto', false); 136 }); 137 } else { 138 initAll('auto', false); 139 } 140 141 if (document.fonts && document.fonts.ready) { 142 document.fonts.ready.then(function () { 143 document.querySelectorAll('.uxm-season-timeline .season-track').forEach(layoutTimelineLine); 144 }); 145 } 146})();
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.