PageSourceSearch

https://www.bonusfinder.com/wp-content/cache/min/1/wp-content/them…/js/sticky_toc.js?ver=1790938179

js bonusfinder.com collected 2026-10-03 21:31:32 UTC 9,386 bytes, 50 lines download raw bytes

1(function(){'use strict';const ROOT_ID='sticky-toc';const ACTIVATION_OFFSET_PX=16;const PANEL_CLOSE_DELAY_MS=60;const ACTIVE_LOCK_MS=900;const DOCUMENT_BOTTOM_TOLERANCE_PX=4;const HEADER_ID='header-v2';const STATEBAR_SELECTOR='.statebar-block';const CONTENT_SELECTOR='section.entry-content';const TOPLIST_SELECTOR='.toplist-container';const FOOTER_ID='footer';class StickyToc{constructor(root){this.root=root;this.toggle=root.querySelector('.sticky-toc-toggle');this.panel=root.querySelector('.sticky-toc-panel');this.activeTitle=root.querySelector('.sticky-toc-active');this.pctLabel=root.querySelector('.sticky-toc-pct');this.progress=root.querySelector('.sticky-toc-progress');this.progressFill=root.querySelector('.sticky-toc-progress-fill');this.links=Array.from(root.querySelectorAll('.sticky-toc-link'));this.targets=this.links.map((link)=>StickyToc.resolveTarget(link));this.content=document.querySelector(CONTENT_SELECTOR)||this.targets.find(Boolean)||null;this.header=document.getElementById(HEADER_ID);this.statebar=document.querySelector(STATEBAR_SELECTOR);this.footer=document.getElementById(FOOTER_ID);this.pctTemplate=this.pctLabel?this.pctLabel.dataset.template||'[pct]%':'[pct]%';this.state={pinned:!1,open:!1,active:0,pct:-1,stackBottom:0,stackHeight:0,};this.ticking=!1;this.closeTimer=0;this.lockedActive=-1;this.lockTimer=0}
2static resolveTarget(link){const hash=link.hash||'';if(hash.length<2){return null}
3let id=hash.slice(1);try{id=decodeURIComponent(id)}catch(e){}
4return document.getElementById(id)}
5static prefersReducedMotion(){return(window.matchMedia&&window.matchMedia('(prefers-reduced-motion: reduce)').matches)}
6init(){if(!this.toggle||!this.panel||!this.content){return}
7this.onScroll=()=>this.requestMeasure();document.addEventListener('scroll',this.onScroll,{passive:!0,capture:!0,});window.addEventListener('resize',this.onScroll);this.toggle.addEventListener('click',()=>this.setOpen(!this.state.open));this.links.forEach((link,index)=>link.addEventListener('click',(event)=>this.onLinkClick(event,index)));document.addEventListener('keydown',(event)=>this.onKeydown(event));document.addEventListener('click',(event)=>this.onDocumentClick(event));window.addEventListener('hashchange',()=>this.syncToHash());window.addEventListener('load',()=>this.syncToHash(),{once:!0,});document.addEventListener('visibilitychange',()=>{if(document.visibilityState==='visible'){this.measure()}});this.render();this.measure();this.syncToHash()}
8indexForHash(hash){if(!hash||hash.length<2){return-1}
9let id=hash.slice(1);try{id=decodeURIComponent(id)}catch(e){}
10return this.targets.findIndex((target)=>target&&target.id===id)}
11syncToHash(){const index=this.indexForHash(window.location.hash);if(index<0){return}
12this.measure();this.scrollToTarget(index,'auto');this.lockActive(index)}
13lockActive(index){window.clearTimeout(this.lockTimer);this.lockedActive=index;this.lockTimer=window.setTimeout(()=>{this.lockedActive=-1;this.requestMeasure()},ACTIVE_LOCK_MS);if(this.state.active!==index){this.state.active=index;this.render();if(this.state.open){this.scrollActiveIntoView()}}}
14scrollToTarget(index,behavior){const target=this.targets[index];if(!target){return}
15const styles=window.getComputedStyle(document.documentElement);const barHeight=parseFloat(styles.getPropertyValue('--bf-sticky-toc-h'))||this.root.offsetHeight;const gap=parseFloat(styles.getPropertyValue('--bf-sticky-toc-jump-gap'))||12;const offset=this.measureStackHeight()+barHeight+gap;const top=Math.max(0,target.getBoundingClientRect().top+window.scrollY-offset);window.scrollTo({top,behavior})}
16requestMeasure(){if(this.ticking){return}
17this.ticking=!0;window.requestAnimationFrame(()=>{this.ticking=!1;this.measure()})}
18measureStackBottom(){let bottom=0;if(this.header){bottom=this.header.getBoundingClientRect().bottom}
19if(this.statebar){const rect=this.statebar.getBoundingClientRect();const isStuckUnderHeader=rect.height>0&&rect.top<=bottom+1&&rect.bottom>bottom;if(isStuckUnderHeader){bottom=rect.bottom}}
20return Math.max(0,bottom)}
21measureStackHeight(){let height=0;if(this.header){const stickyTop=parseFloat(window.getComputedStyle(this.header).top)||0;height=Math.max(0,stickyTop)+this.header.offsetHeight}
22if(this.statebar){height+=this.statebar.offsetHeight}
23return height}
24measureContentTop(){let top=this.content.getBoundingClientRect().top;const first=this.targets.find(Boolean);if(first){top=Math.min(top,first.getBoundingClientRect().top)}
25document.querySelectorAll(TOPLIST_SELECTOR).forEach((toplist)=>{top=Math.max(top,toplist.getBoundingClientRect().bottom)});return top}
26measurePercent(viewportHeight){const rect=this.content.getBoundingClientRect();let bottom=rect.bottom;const top=this.measureContentTop();for(let i=this.targets.length-1;i>=0;i--){if(this.targets[i]){bottom=Math.max(bottom,this.targets[i].getBoundingClientRect().bottom);break}}
27const span=Math.max(1,bottom-top-viewportHeight);let pct=Math.round((-top/span)*100);const atDocumentBottom=window.scrollY+viewportHeight>=document.documentElement.scrollHeight-DOCUMENT_BOTTOM_TOLERANCE_PX;if(atDocumentBottom){pct=100}
28return Math.max(0,Math.min(100,pct))}
29measureActive(line){let active=0;for(let i=0;i<this.targets.length;i++){const target=this.targets[i];if(target&&target.getBoundingClientRect().top<=line){active=i}}
30return active}
31measure(){const viewportHeight=window.innerHeight;const stackBottom=this.measureStackBottom();const stackHeight=this.measureStackHeight();const contentTop=this.measureContentTop();const footerReached=!!this.footer&&this.footer.getBoundingClientRect().top<viewportHeight;const pinned=contentTop<=stackBottom&&!footerReached;const barHeight=pinned?this.root.offsetHeight:0;const line=stackBottom+barHeight+ACTIVATION_OFFSET_PX;const active=this.lockedActive>=0?this.lockedActive:this.measureActive(line);const pct=this.measurePercent(viewportHeight);const changed=pinned!==this.state.pinned||active!==this.state.active||pct!==this.state.pct||stackBottom!==this.state.stackBottom||stackHeight!==this.state.stackHeight;if(!changed){return}
32const activeChanged=active!==this.state.active;this.state={...this.state,pinned,active,pct,stackBottom,stackHeight,};if(!pinned&&this.state.open){this.setOpen(!1)}
33this.render();if(activeChanged&&this.state.open){this.scrollActiveIntoView()}}
34render(){const{pinned,active,pct,stackBottom,stackHeight}=this.state;document.documentElement.style.setProperty('--bf-sticky-toc-top',Math.floor(stackBottom)+'px');document.documentElement.style.setProperty('--bf-sticky-toc-stack-h',stackHeight+'px');this.root.dataset.pinned=pinned?'true':'false';this.links.forEach((link,index)=>{if(index===active){link.setAttribute('aria-current','location')}else{link.removeAttribute('aria-current')}
35link.dataset.visited=index<active?'true':'false'});const activeLink=this.links[active];if(this.activeTitle&&activeLink){const title=activeLink.querySelector('.sticky-toc-title');this.activeTitle.textContent=title?title.textContent:activeLink.textContent}
36const shownPct=Math.max(0,pct);if(this.pctLabel){this.pctLabel.textContent=this.pctTemplate.replace('[pct]',String(shownPct))}
37if(this.progressFill){this.progressFill.style.width=shownPct+'%'}
38if(this.progress){this.progress.setAttribute('aria-valuenow',String(shownPct))}}
39setOpen(open){window.clearTimeout(this.closeTimer);this.state.open=open;this.root.dataset.open=open?'true':'false';this.toggle.setAttribute('aria-expanded',open?'true':'false');if(open){this.scrollActiveIntoView()}}
40scrollActiveIntoView(){const activeLink=this.links[this.state.active];if(activeLink&&typeof activeLink.scrollIntoView==='function'){activeLink.scrollIntoView({block:'nearest'})}}
41onLinkClick(event,index){const target=this.targets[index];if(!target){this.closeTimer=window.setTimeout(()=>this.setOpen(!1),PANEL_CLOSE_DELAY_MS);return}
42event.preventDefault();this.scrollToTarget(index,StickyToc.prefersReducedMotion()?'auto':'smooth');this.lockActive(index);if(window.history&&window.history.replaceState){window.history.replaceState(null,'','#'+target.id)}
43if(!target.hasAttribute('tabindex')){target.setAttribute('tabindex','-1')}
44target.focus({preventScroll:!0});this.closeTimer=window.setTimeout(()=>this.setOpen(!1),PANEL_CLOSE_DELAY_MS)}
45onKeydown(event){if(event.key==='Escape'&&this.state.open){this.setOpen(!1);this.toggle.focus()}}
46onDocumentClick(event){if(this.state.open&&!this.root.contains(event.target)){this.setOpen(!1)}}}
47function startHeaderBottomVar(){const header=document.getElementById(HEADER_ID);if(!header){return}
48let ticking=!1;const apply=()=>{ticking=!1;const bottom=Math.max(0,Math.floor(header.getBoundingClientRect().bottom));document.documentElement.style.setProperty('--bf-header-bottom',bottom+'px')};const request=()=>{if(!ticking){ticking=!0;
48window.requestAnimationFrame(apply)}};document.addEventListener('scroll',request,{passive:!0,capture:!0,});window.addEventListener('resize',request);window.addEventListener('load',apply,{once:!0});window.addEventListener('hashchange',apply);document.addEventListener('visibilitychange',()=>{if(document.visibilityState==='visible'){apply()}});apply()}
49function boot(){startHeaderBottomVar();const root=document.getElementById(ROOT_ID);if(root){const instance=new StickyToc(root);instance.init();window.bfStickyToc=instance}}
50if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',boot)}else{boot()}})()

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.