1/** 2 * STL revolving quote square. Each .stl-quote-revolver auto-rotates through 3 * its quotes; pauses on hover; click a dot to jump. 4 */ 5(function () { 6 'use strict'; 7 8 function init(root) { 9 var dataEl = root.querySelector('.js-stl-quote-data'); 10 if (!dataEl) return; 11 var quotes; 12 try { quotes = JSON.parse(dataEl.textContent); } catch (e) { return; } 13 if (!quotes || quotes.length < 2) return; // nothing to rotate 14 15 var rotateMs = parseInt(root.getAttribute('data-rotate-ms') || '6000', 10); 16 var stage = root.querySelector('.js-stl-quote-stage'); 17 var qEl = root.querySelector('.js-stl-quote-text'); 18 var nEl = root.querySelector('.js-stl-quote-name'); 19 var rEl = root.querySelector('.js-stl-quote-role'); 20 var dots = Array.prototype.slice.call(root.querySelectorAll('.js-stl-quote-dots .stl-quote-revolver__dot')); 21 22 var idx = 0, paused = false, timer = null; 23 24 // --- Height lock --------------------------------------------------- 25 // The quote text swaps in place, so quotes of different lengths would 26 // otherwise resize the revolver and stretch/shrink the whole case- 27 // studies grid on every rotation. We measure the tallest quote at the 28 // current width and pin the stage's min-height to it, so the block 29 // height stays constant no matter which quote is showing. Re-measured 30 // on resize because wrapping (and therefore height) changes with width. 31 function lockHeight() { 32 if (!stage) return; 33 var prevQ = qEl ? qEl.textContent : ''; 34 var prevN = nEl ? nEl.textContent : ''; 35 var prevR = rEl ? rEl.textContent : ''; 36 stage.style.minHeight = '0px'; 37 var maxH = 0; 38 quotes.forEach(function (q) { 39 if (qEl) qEl.textContent = q.q || ''; 40 if (nEl) nEl.textContent = q.n || ''; 41 if (rEl) rEl.textContent = q.r || ''; 42 if (stage.scrollHeight > maxH) maxH = stage.scrollHeight; 43 }); 44 if (qEl) qEl.textContent = prevQ; 45 if (nEl) nEl.textContent = prevN; 46 if (rEl) rEl.textContent = prevR; 47 stage.style.minHeight = maxH + 'px'; 48 } 49 50 function paint() { 51 var q = quotes[idx]; 52 stage.classList.add('is-out'); 53 setTimeout(function () { 54 qEl.textContent = q.q || ''; 55 nEl.textContent = q.n || ''; 56 rEl.textContent = q.r || ''; 57 root.style.background = q.bg || '#6b8fd6'; 58 dots.forEach(function (d, i) { d.classList.toggle('is-active', i === idx); }); 59 stage.classList.remove('is-out'); 60 }, 450); 61 } 62 63 function tick() { 64 if (paused) return; 65 idx = (idx + 1) % quotes.length; 66 paint(); 67 } 68 69 function start() { 70 stop(); 71 timer = setInterval(tick, rotateMs); 72 } 73 function stop() { if (timer) { clearInterval(timer); timer = null; } } 74 75 root.addEventListener('mouseenter', function () { paused = true; }); 76 root.addEventListener('mouseleave', function () { paused = false; }); 77 78 dots.forEach(function (d) { 79 d.addEventListener('click', function () { 80 var i = parseInt(d.getAttribute('data-index'), 10); 81 if (isNaN(i) || i === idx) return; 82 idx = i; 83 paint(); 84 start(); // reset timer 85 }); 86 }); 87 88 // Lock height now, again after full load (webfonts can change wrap 89 // metrics), and on resize (debounced). 90 lockHeight(); 91 window.addEventListener('load', lockHeight); 92 var resizeTimer = null; 93 window.addEventListener('resize', function () { 94 if (resizeTimer) clearTimeout(resizeTimer); 95 resizeTimer = setTimeout(lockHeight, 150); 96 }); 97 98 start(); 99 } 100 101 function initAll() { 102 document.querySelectorAll('.stl-quote-revolver').forEach(init); 103 } 104 105 if (document.readyState === 'loading') { 106 document.addEventListener('DOMContentLoaded', initAll); 107 } else { 108 initAll(); 109 } 110})();
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.