1document.addEventListener('alpine:init', () => { 2 Alpine.data('tableOfContents', links => ({ 3 links: links?.map(link => ({ text: _unescape(link.text), anchor: link.anchor })) || [], 4 open: false, 5 selection: { text: 'Table of Contents', anchor: location.hash?.replace('#', '') ?? null }, 6 leftRailTOCHeightStyle: '', 7 select(link, isLeftRailTOC = false) { 8 this.selection = link; 9 if (!isLeftRailTOC) this.open = false; 10 const anchor = this.selection.anchor; 11 12 if (anchor === '' || anchor === null) { 13 return; 14 } 15 16 location.hash = anchor; 17 let scrollHeight = window.scrollY || window.pageYOffset; 18 const offset = (anchor === 'compare-our-picks' ? 125 : 25) + (isLeftRailTOC ? 0 : 75); 19 20 window.scrollTo({ top: document.getElementById(anchor).getBoundingClientRect().top + scrollHeight - 200, behavior: 'auto' }) 21 // Timeout so ads/embeds load before anchoring to content 22 setTimeout(() => { 23 scrollHeight = window.scrollY || window.pageYOffset; 24 window.scrollTo({ top: document.getElementById(anchor).getBoundingClientRect().top + scrollHeight - offset, behavior: 'smooth' }); 25 }, 500); 26 }, 27 isValidLink: anchor => !!document.getElementById(anchor), 28 calculateLeftRailTOCHeight() { 29 if (!this.$refs.leftRailTOC) return 'height: 0px'; 30 31 const cellCount = this.open ? 10 : 6 32 const childNodes = [...this.$refs.leftRailTOC.children].filter(child =>
32 child.offsetHeight).slice(0, this.links.length < cellCount ? this.links.length : cellCount) 33 const height = Math.round(childNodes.reduce((sum, child) => sum + child.offsetHeight, 0)) 34 return `height: ${height}px`; 35 }, 36 init() { 37 if (this.links?.length > 3) { 38 const callback = entries => entries.forEach(entry => entry.isIntersecting ? this.selection = this.links.find(link => link.anchor === entry.target.id) : null); 39 const observer = new IntersectionObserver(callback, { 40 rootMargin: '-35px 0px -' + (window.innerHeight - 175) + 'px 0px', 41 threshold: 0 42 }) 43 44 this.links.forEach(link => { 45 const linkNode = document.getElementById(link.anchor); 46 linkNode !== null && observer.observe(linkNode); 47 }) 48 49 this.$nextTick(() => { 50 if (location.hash) { 51 history.scrollRestoration = 'manual' 52 this.select(this.selection) 53 } 54 this.leftRailTOCHeightStyle = this.calculateLeftRailTOCHeight() 55 }) 56 57 this.$watch('open', () => this.leftRailTOCHeightStyle = this.calculateLeftRailTOCHeight()) 58 } 59 } 60 })) 61})
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.