1(() => { 2 const root = document.querySelector(".r22-proof"); 3 if (!root) return; 4 const slides = [...root.querySelectorAll(".r22-proof-slide")], 5 choices = [...root.querySelectorAll("[data-slide]")]; 6 const region = root.querySelector(".r22-proof-slides"), 7 announcement = root.querySelector("[data-carousel-announcement]"); 8 const reduced = matchMedia("(prefers-reduced-motion: reduce)"); 9 let current = 0, 10 paused = reduced.matches, 11 visible = false, 12 hovered = false, 13 focused = false, 14 timer = 0, 15 fade = null, 16 revision = 0; 17 root.querySelectorAll("[hidden]").forEach((el) => { 18 if (!el.classList.contains("r22-proof-slide")) el.hidden = false; 19 }); 20 const help = document.createElement("p"); 21 help.id = "story-controls-help"; 22 help.className = "r22-sr-only"; 23 help.textContent = 24 "Stories rotate automatically. Choose a story or use the arrows to stop rotation. Rotation also stops while you read with a pointer or keyboard."; 25 root.append(help); 26 root.setAttribute("aria-describedby", help.id); 27 function schedule() { 28 clearTimeout(timer);
29 root.dataset.rotating = String( 30 !paused && visible && !hovered && !focused && !document.hidden, 31 ); 32 if (root.dataset.rotating === "true") 33 timer = setTimeout(() => show(current + 1), 8500); 34 } 35 function render() { 36 slides.forEach((slide, i) => (slide.hidden = i !== current)); 37 choices.forEach((button, i) => { 38 if (i === current) button.setAttribute("aria-current", "true"); 39 else button.removeAttribute("aria-current"); 40 }); 41 } 42 function show(n, manual = false, immediate = false) { 43 if (manual) paused = true; 44 current = (n + slides.length) % slides.length; 45 const ticket = ++revision; 46 if (fade) { 47 fade.onfinish = null; 48 fade.cancel(); 49 } 50 const apply = () => { 51 render(); 52 if (manual) 53 announcement.textContent = slides[current].getAttribute("aria-label"); 54 }; 55 if (immediate || reduced.matches) { 56 apply(); 57 fade = null; 58 schedule(); 59 return; 60 } 61 fade = region.animate( 62 [ 63 { 64 opacity: 1, 65 }, 66 { 67 opacity: 0, 68 }, 69 ], 70 { 71 duration: 180, 72 fill: "forwards", 73 }, 74 ); 75 fade.onfinish = () => { 76 if (ticket !== revision) return; 77 fade.cancel(); 78 apply(); 79 fade = region.animate( 80 [ 81 { 82 opacity: 0, 83 }, 84 { 85 opacity: 1, 86 }, 87 ], 88 { 89 duration: 320, 90 easing: "ease-out", 91 }, 92 ); 93 fade.onfinish = () => { 94 fade = null; 95 }; 96 }; 97 schedule(); 98 } 99 root 100 .querySelector('[data-carousel="prev"]') 101 .addEventListener("click", () => show(current - 1, true)); 102 root 103 .querySelector('[data-carousel="next"]') 104 .addEventListener("click", () => show(current + 1, true)); 105 choices.forEach((button, i) => 106 button.addEventListener("click", () => show(i, true)), 107 ); 108 root.addEventListener("mouseenter", () => { 109 hovered = true; 110 schedule(); 111 }); 112 root.addEventListener("mouseleave", () => { 113 hovered = false; 114 schedule(); 115 }); 116 root.addEventListener("focusin", () => { 117 focused = true; 118 paused = true; 119 schedule(); 120 }); 121 root.addEventListener("focusout", (e) => { 122 if (!root.contains(e.relatedTarget)) { 123 focused = false; 124 schedule(); 125 } 126 }); 127 document.addEventListener("visibilitychange", schedule); 128 reduced.addEventListener("change", () => { 129 paused = true; 130 show(current, false, true); 131 }); 132 new IntersectionObserver( 133 (entries) => { 134 visible = entries[0].isIntersecting; 135 schedule(); 136 }, 137 { 138 threshold: 0.25, 139 }, 140 ).observe(root); 141 function size() { 142 const hidden = slides.map((el) => el.hidden); 143 region.style.minHeight = ""; 144 let height = 0; 145 slides.forEach((slide) => { 146 slide.hidden = false; 147 slide.style.position = "absolute"; 148 slide.style.visibility = "hidden"; 149 slide.style.width = "100%"; 150 height = Math.max(height, slide.offsetHeight); 151 slide.style.position = ""; 152 slide.style.visibility = ""; 153 slide.style.width = ""; 154 }); 155 region.style.minHeight = `${height}px`; 156 slides.forEach((slide, i) => (slide.hidden = hidden[i])); 157 } 158 let lastWidth = 0; 159 new ResizeObserver((entries) => { 160 const width = entries[0].contentRect.width; 161 if (width === lastWidth) return; 162 lastWidth = width; 163 size(); 164 }).observe(root); 165 document.fonts.ready.then(size); 166 root 167 .querySelectorAll("img") 168 .forEach((img) => img.addEventListener("load", size)); 169 show(0, false, true); 170 window.customerStories = { 171 show: (n) => show(n, true), 172 get state() { 173 return { 174 current: current, 175 paused: paused, 176 visible: visible, 177 rotating: root.dataset.rotating === "true", 178 }; 179 }, 180 }; 181})();
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.