1// Reading progress bar. The element is hidden on desktop/tablet via CSS and 2// only shown inside the slim fixed header on smartphones, so this runs cheaply 3// everywhere but is only visible where it matters. 4(function () { 5 var bar = document.querySelector('.reading-progress > span'); 6 if (!bar) return; 7 8 var ticking = false; 9 10 function update() { 11 var doc = document.documentElement; 12 var scrollTop = doc.scrollTop || document.body.scrollTop || 0; 13 var height = doc.scrollHeight - doc.clientHeight; 14 var pct = height > 0 ? (scrollTop / height) * 100 : 0; 15 if (pct < 0) pct = 0; 16 if (pct > 100) pct = 100; 17 bar.style.width = pct + '%'; 18 ticking = false; 19 } 20 21 function onScroll() { 22 if (!ticking) { 23 window.requestAnimationFrame(update); 24 ticking = true; 25 } 26 } 27 28 window.addEventListener('scroll', onScroll, { passive: true }); 29 window.addEventListener('resize', onScroll); 30 update(); 31 32 // Scrubbing: tap or drag along the bar to jump to that point in the page. 33 var track = document.querySelector('.reading-progress'); 34 if (track) { 35 var dragging = false; 36 37 function scrubTo(clientX) { 38 var rect = track.getBoundingClientRect(); 39 if (rect.width <= 0) return; // hidden (desktop/tablet) 40 var frac = (clientX - rect.left) / rect.width; 41 if (frac < 0) frac = 0; 42 if (frac > 1) frac = 1; 43 var doc = document.documentElement; 44 var height = doc.scrollHeight - doc.clientHeight; 45 // behavior:'instant' overrides the page's `scroll-behavior: smooth`, so the 46 // scrub tracks the finger immediately instead of animating behind it. 47 window.scrollTo({ top: frac * height, behavior: 'instant' }); 48 update(); 49 } 50 51 track.addEventListener('pointerdown', function (e) { 52 dragging = true; 53 if (track.setPointerCapture) { 54 try { track.setPointerCapture(e.pointerId); } catch (err) {} 55 } 56 scrubTo(e.clientX); 57 e.preventDefault(); 58 }); 59 60 track.addEventListener('pointermove', function (e) { 61 if (dragging) scrubTo(e.clientX); 62 }); 63 64 function endDrag() { dragging = false; } 65 track.addEventListener('pointerup', endDrag); 66 track.addEventListener('pointercancel', endDrag); 67 } 68}());
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.