1const headroomChanged = new CustomEvent("quarto-hrChanged", { 2 detail: {}, 3 bubbles: true, 4 cancelable: false, 5 composed: false, 6}); 7 8window.document.addEventListener("DOMContentLoaded", function () { 9 let init = false; 10 11 // Manage the back to top button, if one is present. 12 let lastScrollTop = window.pageYOffset || document.documentElement.scrollTop; 13 const scrollDownBuffer = 5; 14 const scrollUpBuffer = 35; 15 const btn = document.getElementById("quarto-back-to-top"); 16 const hideBackToTop = () => { 17 btn.style.display = "none"; 18 }; 19 const showBackToTop = () => { 20 btn.style.display = "inline-block"; 21 }; 22 if (btn) { 23 window.document.addEventListener( 24 "scroll", 25 function () { 26 const currentScrollTop = 27 window.pageYOffset || document.documentElement.scrollTop; 28 29 // Shows and hides the button 'intelligently' as the user scrolls 30 if (currentScrollTop - scrollDownBuffer > lastScrollTop) { 31 hideBackToTop(); 32 lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop; 33 } else if (currentScrollTop < lastScrollTop - scrollUpBuffer) { 34 showBackToTop(); 35 lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop; 36 } 37 38 // Show the button at the bottom, hides it at the top 39 if (currentScrollTop <= 0) { 40 hideBackToTop(); 41 } else if ( 42 window.innerHeight + currentScrollTop >= 43 document.body.offsetHeight 44 ) { 45 showBackToTop(); 46 } 47 }, 48 false 49 ); 50 } 51 52 function throttle(func, wait) { 53 var timeout; 54 return function () { 55 const context = this; 56 const args = arguments; 57 const later = function () { 58 clearTimeout(timeout); 59 timeout = null; 60 func.apply(context, args); 61 }; 62 63 if (!timeout) { 64 timeout = setTimeout(later, wait); 65 } 66 }; 67 } 68 69 function headerOffset() { 70 // Set an offset if there is are fixed top navbar 71 const headerEl = window.document.querySelector("header.fixed-top"); 72 if (headerEl) { 73 return headerEl.clientHeight; 74 } else { 75 return 0; 76 } 77 } 78 79 function footerOffset() { 80 const footerEl = window.document.querySelector("footer.footer"); 81 if (footerEl) { 82 return footerEl.clientHeight; 83 } else { 84 return 0; 85 } 86 } 87 88 function dashboardOffset() { 89 const dashboardNavEl = window.document.getElementById( 90 "quarto-dashboard-header" 91 ); 92 if (dashboardNavEl !== null) { 93 return dashboardNavEl.clientHeight; 94 } else { 95 return 0; 96 } 97 } 98 99 function updateDocumentOffsetWithoutAnimation() { 100 updateDocumentOffset(false); 101 } 102 103 function updateDocumentOffset(animated) { 104 // set body offset 105 const topOffset = headerOffset(); 106 const bodyOffset = topOffset + footerOffset() + dashboardOffset(); 107 const bodyEl = window.document.body; 108 bodyEl.setAttribute("data-bs-offset", topOffset); 109 bodyEl.style.paddingTop = topOffset + "px"; 110 111 // deal with sidebar offsets 112 const sidebars = window.document.querySelectorAll( 113 ".sidebar, .headroom-target" 114 ); 115 sidebars.forEach((sidebar) => { 116 if (!animated) { 117 sidebar.classList.add("notransition"); 118 // Remove the no transition class after the animation has time to complete 119 setTimeout(function () { 120 sidebar.classList.remove("notransition"); 121 }, 201); 122 } 123 124 if (window.Headroom && sidebar.classList.contains("sidebar-unpinned")) { 125 sidebar.style.top = "0"; 126 sidebar.style.maxHeight = "100vh"; 127 } else { 128 sidebar.style.top = topOffset + "px"; 129 sidebar.style.maxHeight = "calc(100vh - " + topOffset + "px)"; 130 } 131 }); 132 133 // allow space for footer 134 const mainContainer = window.document.querySelector(".quarto-container"); 135 if (mainContainer) { 136 mainContainer.style.minHeight = "calc(100vh - " + bodyOffset + "px)"; 137 } 138 139 // link offset 140 let linkStyle = window.document.querySelector("#quarto-target-style"); 141 if (!linkStyle) { 142 linkStyle = window.document.createElement("style"); 143 linkStyle.setAttribute("id", "quarto-target-style"); 144 window.document.head.appendChild(linkStyle); 145 } 146 while (linkStyle.firstChild) { 147 linkStyle.removeChild(linkStyle.firstChild); 148 } 149 if (topOffset > 0) { 150 linkStyle.appendChild( 151 window.document.createTextNode(` 152 section:target::before { 153 content: ""; 154 display: block; 155 height: ${topOffset}px; 156 margin: -${topOffset}px 0 0; 157 }`) 158 ); 159 } 160 if (init) { 161 window.dispatchEvent(headroomChanged); 162 } 163 init = true; 164 } 165 166 // initialize headroom 167 var header = window.document.querySelector("#quarto-header"); 168 if (header && window.Headroom) { 169 const headroom = new window.Headroom(header, { 170 tolerance: 5, 171 onPin: function () { 172 const sidebars = window.document.querySelectorAll( 173 ".sidebar, .headroom-target" 174 );
175 sidebars.forEach((sidebar) => { 176 sidebar.classList.remove("sidebar-unpinned"); 177 }); 178 updateDocumentOffset(); 179 }, 180 onUnpin: function () { 181 const sidebars = window.document.querySelectorAll( 182 ".sidebar, .headroom-target" 183 ); 184 sidebars.forEach((sidebar) => { 185 sidebar.classList.add("sidebar-unpinned"); 186 }); 187 updateDocumentOffset(); 188 }, 189 }); 190 headroom.init(); 191 192 let frozen = false; 193 window.quartoToggleHeadroom = function () { 194 if (frozen) { 195 headroom.unfreeze(); 196 frozen = false; 197 } else { 198 headroom.freeze(); 199 frozen = true; 200 } 201 }; 202 } 203 204 window.addEventListener( 205 "hashchange", 206 function (e) { 207 if ( 208 getComputedStyle(document.documentElement).scrollBehavior !== "smooth" 209 ) { 210 window.scrollTo(0, window.pageYOffset - headerOffset()); 211 } 212 }, 213 false 214 ); 215 216 // Observe size changed for the header 217 const headerEl = window.document.querySelector("header.fixed-top"); 218 if (headerEl && window.ResizeObserver) { 219 const observer = new window.ResizeObserver(() => { 220 setTimeout(updateDocumentOffsetWithoutAnimation, 0); 221 }); 222 observer.observe(headerEl, { 223 attributes: true, 224 childList: true, 225 characterData: true, 226 }); 227 } else { 228 window.addEventListener( 229 "resize", 230 throttle(updateDocumentOffsetWithoutAnimation, 50) 231 ); 232 } 233 setTimeout(updateDocumentOffsetWithoutAnimation, 250); 234 235 // fixup index.html links if we aren't on the filesystem 236 if (window.location.protocol !== "file:") { 237 const links = window.document.querySelectorAll("a"); 238 for (let i = 0; i < links.length; i++) { 239 if (links[i].href) { 240 links[i].href = links[i].href.replace(/\/index\.html/, "/"); 241 } 242 } 243 244 // Fixup any sharing links that require urls 245 // Append url to any sharing urls 246 const sharingLinks = window.document.querySelectorAll( 247 "a.sidebar-tools-main-item, a.quarto-navigation-tool, a.quarto-navbar-tools, a.quarto-navbar-tools-item" 248 ); 249 for (let i = 0; i < sharingLinks.length; i++) { 250 const sharingLink = sharingLinks[i]; 251 const href = sharingLink.getAttribute("href"); 252 if (href) { 253 sharingLink.setAttribute( 254 "href", 255 href.replace("|url|", window.location.href) 256 ); 257 } 258 } 259 260 // Scroll the active navigation item into view, if necessary 261 const navSidebar = window.document.querySelector("nav#quarto-sidebar"); 262 if (navSidebar) { 263 // Find the active item 264 const activeItem = navSidebar.querySelector("li.sidebar-item a.active"); 265 if (activeItem) { 266 // Wait for the scroll height and height to resolve by observing size changes on the 267 // nav element that is scrollable 268 const resizeObserver = new ResizeObserver((_entries) => { 269 // The bottom of the element 270 const elBottom = activeItem.offsetTop; 271 const viewBottom = navSidebar.scrollTop + navSidebar.clientHeight; 272 273 // The element height and scroll height are the same, then we are still loading 274 if (viewBottom !== navSidebar.scrollHeight) { 275 // Determine if the item isn't visible and scroll to it 276 if (elBottom >= viewBottom) { 277 navSidebar.scrollTop = elBottom; 278 } 279 280 // stop observing now since we've completed the scroll 281 resizeObserver.unobserve(navSidebar); 282 } 283 }); 284 resizeObserver.observe(navSidebar); 285 } 286 } 287 } 288});
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.