1import{Controller}from"@hotwired/stimulus";const clamp=(e,t,n)=>Math.min(n,Math.max(t,e));export default class extends Controller{static targets=["article","bar","sticky","sentinel"];static values={barActiveClass:{type:String,default:"reading-progress--active"},stickyActiveClass:{type:String,default:"is-visible"}};connect(){this.scrollElement=document.scrollingElement||document.documentElement,this.headerOutOfView=!1,this.progress=0,this.raf=null,this.navbarHeight=this.getNavbarHeight(),this.boundEnqueue=this.enqueueUpdate.bind(this),this.boundUpdatePositions=this.updatePositions.bind(this),window.addEventListener("scroll",this.boundEnqueue,{passive:!0}),window.addEventListener("resize",this.boundUpdatePositions,{passive:!0}),this.setupObserver(),this.enqueueUpdate()}disconnect(){window.removeEventListener("scroll",this.boundEnqueue),window.removeEventListener("resize",this.boundUpdatePositions),this.observer&&(this.observer.disconnect(),this.observer=null),this.raf&&(cancelAnimationFrame(this.raf),this.raf=null)}getNavbarHeight(){const e=document.getElementById("navbar");return e?e.offsetHeight:0}updatePositions(){this.navbarHeight=this.getNavbarHeight(),this.hasBarTarget&&this.barTarget.style.setProperty("--reading-progress-top",`${this.navbarHeight}px`),this.hasStickyTarget&&this.stickyTarget.style.setProperty("--reading-sticky-top",`${this.navbarHeight}px`)}enqueueUpdate(){if(this.raf!==null)return;this.raf=requestAnimationFrame(()=>{this.raf=null,this.updateProgress()})}setupObserver(){if(!this.hasSentinelTarget)return;this.observer=new IntersectionObserver(e=>{if(!e.length)return;const t=e[0];this.headerOutOfView=!t.isIntersecting,this.updateClasses()},{threshold:0}),this.observer.observe(this.sentinelTarget)}updateProgress(){if(!this.hasArticleTarget||!this.hasBarTarget)return;this.updatePositions();const t=this.articleTarget,n=this.scrollElement,s=window.scrollY||n.scrollTop||0,c=t.getBoundingClientRect().top+s,e=t.scrollHeight,o=window.innerHeight||n.clientHeight||0,i=e>o?e-o:e;let a=0;i>0&&(a=(s-c)/i),this.progress=clamp(a,0,1);const r=(this.progress*100).toFixed(2);this.barTarget.style.setProperty("--reading-progress",`${r}%`),this.barTarget.style.width=`${r}%`,this.updateClasses()}
1updateClasses(){if(this.hasBarTarget){const e=this.headerOutOfView||this.progress>0;this.barTarget.classList.toggle(this.barActiveClassValue,e)}this.hasStickyTarget&&this.stickyTarget.classList.toggle(this.stickyActiveClassValue,this.headerOutOfView)}}
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.