Path: blob/main/src/resources/projects/website/navigation/quarto-nav.js
12923 views
const headroomChanged = new CustomEvent("quarto-hrChanged", {1detail: {},2bubbles: true,3cancelable: false,4composed: false,5});67const announceDismiss = () => {8const annEl = window.document.getElementById("quarto-announcement");9if (annEl) {10annEl.remove();1112const annId = annEl.getAttribute("data-announcement-id");13window.localStorage.setItem(`quarto-announce-${annId}`, "true");14}15};1617const announceRegister = () => {18const annEl = window.document.getElementById("quarto-announcement");19if (annEl) {20const annId = annEl.getAttribute("data-announcement-id");21const isDismissed =22window.localStorage.getItem(`quarto-announce-${annId}`) || false;23if (isDismissed) {24announceDismiss();25return;26} else {27annEl.classList.remove("hidden");28}2930const actionEl = annEl.querySelector(".quarto-announcement-action");31if (actionEl) {32actionEl.addEventListener("click", function (e) {33e.preventDefault();34// Hide the bar immediately35announceDismiss();36});37}38}39};4041window.document.addEventListener("DOMContentLoaded", function () {42let init = false;4344announceRegister();4546// Manage the back to top button, if one is present.47let lastScrollTop = window.pageYOffset || document.documentElement.scrollTop;48const scrollDownBuffer = 5;49const scrollUpBuffer = 35;50const btn = document.getElementById("quarto-back-to-top");51const hideBackToTop = () => {52btn.style.display = "none";53};54const showBackToTop = () => {55btn.style.display = "inline-block";56};57if (btn) {58window.document.addEventListener(59"scroll",60function () {61const currentScrollTop =62window.pageYOffset || document.documentElement.scrollTop;6364// Shows and hides the button 'intelligently' as the user scrolls65if (currentScrollTop - scrollDownBuffer > lastScrollTop) {66hideBackToTop();67lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop;68} else if (currentScrollTop < lastScrollTop - scrollUpBuffer) {69showBackToTop();70lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop;71}7273// Show the button at the bottom, hides it at the top74if (currentScrollTop <= 0) {75hideBackToTop();76} else if (77window.innerHeight + currentScrollTop >=78document.body.offsetHeight79) {80showBackToTop();81}82},83false84);85}8687function throttle(func, wait) {88var timeout;89return function () {90const context = this;91const args = arguments;92const later = function () {93clearTimeout(timeout);94timeout = null;95func.apply(context, args);96};9798if (!timeout) {99timeout = setTimeout(later, wait);100}101};102}103104function headerOffset() {105// Set an offset if there is are fixed top navbar106const headerEl = window.document.querySelector("header.fixed-top");107if (headerEl) {108return headerEl.clientHeight;109} else {110return 0;111}112}113114function footerOffset() {115const footerEl = window.document.querySelector("footer.footer");116if (footerEl) {117return footerEl.clientHeight;118} else {119return 0;120}121}122123function dashboardOffset() {124const dashboardNavEl = window.document.getElementById(125"quarto-dashboard-header"126);127if (dashboardNavEl !== null) {128return dashboardNavEl.clientHeight;129} else {130return 0;131}132}133134function updateDocumentOffsetWithoutAnimation() {135updateDocumentOffset(false);136}137138function updateDocumentOffset(animated) {139// set body offset140const topOffset = headerOffset();141const bodyOffset = topOffset + footerOffset() + dashboardOffset();142const bodyEl = window.document.body;143bodyEl.setAttribute("data-bs-offset", topOffset);144bodyEl.style.paddingTop = topOffset + "px";145146// deal with sidebar offsets147const sidebars = window.document.querySelectorAll(148".sidebar, .headroom-target"149);150sidebars.forEach((sidebar) => {151if (!animated) {152sidebar.classList.add("notransition");153// Remove the no transition class after the animation has time to complete154setTimeout(function () {155sidebar.classList.remove("notransition");156}, 201);157}158159if (window.Headroom && sidebar.classList.contains("sidebar-unpinned")) {160sidebar.style.top = "0";161sidebar.style.maxHeight = "100vh";162} else {163sidebar.style.top = topOffset + "px";164sidebar.style.maxHeight = "calc(100vh - " + topOffset + "px)";165}166});167168// allow space for footer169const mainContainer = window.document.querySelector(".quarto-container");170if (mainContainer) {171mainContainer.style.minHeight = "calc(100vh - " + bodyOffset + "px)";172}173174// link offset175let linkStyle = window.document.querySelector("#quarto-target-style");176if (!linkStyle) {177linkStyle = window.document.createElement("style");178linkStyle.setAttribute("id", "quarto-target-style");179window.document.head.appendChild(linkStyle);180}181while (linkStyle.firstChild) {182linkStyle.removeChild(linkStyle.firstChild);183}184if (topOffset > 0) {185linkStyle.appendChild(186window.document.createTextNode(`187section:target::before {188content: "";189display: block;190height: ${topOffset}px;191margin: -${topOffset}px 0 0;192}`)193);194}195if (init) {196window.dispatchEvent(headroomChanged);197}198init = true;199}200201// initialize headroom202var header = window.document.querySelector("#quarto-header");203if (header && window.Headroom) {204const headroom = new window.Headroom(header, {205tolerance: 5,206onPin: function () {207const sidebars = window.document.querySelectorAll(208".sidebar, .headroom-target"209);210sidebars.forEach((sidebar) => {211sidebar.classList.remove("sidebar-unpinned");212});213updateDocumentOffset();214},215onUnpin: function () {216const sidebars = window.document.querySelectorAll(217".sidebar, .headroom-target"218);219sidebars.forEach((sidebar) => {220sidebar.classList.add("sidebar-unpinned");221});222updateDocumentOffset();223},224});225headroom.init();226227let frozen = false;228window.quartoToggleHeadroom = function () {229if (frozen) {230headroom.unfreeze();231frozen = false;232} else {233headroom.freeze();234frozen = true;235}236};237}238239window.addEventListener(240"hashchange",241function (e) {242if (243getComputedStyle(document.documentElement).scrollBehavior !== "smooth"244) {245window.scrollTo(0, window.pageYOffset - headerOffset());246}247},248false249);250251// Observe size changed for the header252const headerEl = window.document.querySelector("header.fixed-top");253if (headerEl && window.ResizeObserver) {254const observer = new window.ResizeObserver(() => {255setTimeout(updateDocumentOffsetWithoutAnimation, 0);256});257observer.observe(headerEl, {258attributes: true,259childList: true,260characterData: true,261});262} else {263window.addEventListener(264"resize",265throttle(updateDocumentOffsetWithoutAnimation, 50)266);267}268setTimeout(updateDocumentOffsetWithoutAnimation, 250);269270// fixup index.html links if we aren't on the filesystem271if (window.location.protocol !== "file:") {272const links = window.document.querySelectorAll("a");273for (let i = 0; i < links.length; i++) {274if (links[i].href) {275links[i].dataset.originalHref = links[i].href;276links[i].href = links[i].href.replace(/\/index\.html/, "/");277}278}279280// Fixup any sharing links that require urls281// Append url to any sharing urls282const sharingLinks = window.document.querySelectorAll(283"a.sidebar-tools-main-item, a.quarto-navigation-tool, a.quarto-navbar-tools, a.quarto-navbar-tools-item"284);285for (let i = 0; i < sharingLinks.length; i++) {286const sharingLink = sharingLinks[i];287const href = sharingLink.getAttribute("href");288if (href) {289sharingLink.setAttribute(290"href",291href.replace("|url|", window.location.href)292);293}294}295296// Scroll the active navigation item into view, if necessary297const navSidebar = window.document.querySelector("nav#quarto-sidebar");298if (navSidebar) {299// Find the active item300const activeItem = navSidebar.querySelector("li.sidebar-item a.active");301if (activeItem) {302// Wait for the scroll height and height to resolve by observing size changes on the303// nav element that is scrollable304const resizeObserver = new ResizeObserver((_entries) => {305// The bottom of the element306const elBottom = activeItem.offsetTop;307const viewBottom = navSidebar.scrollTop + navSidebar.clientHeight;308309// The element height and scroll height are the same, then we are still loading310if (viewBottom !== navSidebar.scrollHeight) {311// Determine if the item isn't visible and scroll to it312if (elBottom >= viewBottom) {313navSidebar.scrollTop = elBottom;314}315316// stop observing now since we've completed the scroll317resizeObserver.unobserve(navSidebar);318}319});320resizeObserver.observe(navSidebar);321}322}323}324});325326327