(function() {
'use strict';
var tocToggle = document.querySelector('.toc-toggle');
var book = document.querySelector('.book');
var pageToc = document.querySelector('.page-toc');
function isMobileToc() {
return window.innerWidth <= 768;
}
if (tocToggle && book && pageToc) {
if (!isMobileToc()) {
var tocHidden = localStorage.getItem('guidebook-toc-hidden') === 'true';
if (tocHidden) {
book.classList.add('toc-hidden');
}
}
tocToggle.addEventListener('click', function() {
if (!isMobileToc()) {
book.classList.toggle('toc-hidden');
var isHidden = book.classList.contains('toc-hidden');
localStorage.setItem('guidebook-toc-hidden', isHidden);
}
});
window.addEventListener('resize', function() {
if (isMobileToc()) {
} else {
var tocHidden = localStorage.getItem('guidebook-toc-hidden') === 'true';
if (tocHidden) {
book.classList.add('toc-hidden');
} else {
book.classList.remove('toc-hidden');
}
}
});
}
function setupTocScrollSpy() {
var tocLinks = document.querySelectorAll('.page-toc .toc-list a');
if (tocLinks.length === 0) return;
var headings = [];
tocLinks.forEach(function(link) {
var href = link.getAttribute('href');
if (href && href.startsWith('#')) {
var id = href.substring(1);
try {
id = decodeURIComponent(id);
} catch (e) {}
var heading = document.getElementById(id);
if (heading) {
headings.push({ element: heading, link: link });
}
}
});
if (headings.length === 0) return;
function updateActiveLink() {
var scrollTop = window.scrollY + 100; var activeIndex = 0;
for (var i = 0; i < headings.length; i++) {
if (headings[i].element.offsetTop <= scrollTop) {
activeIndex = i;
}
}
tocLinks.forEach(function(link) {
link.parentElement.classList.remove('active');
});
headings[activeIndex].link.parentElement.classList.add('active');
}
window.addEventListener('scroll', updateActiveLink);
updateActiveLink(); }
setupTocScrollSpy();
function setupTocLinks() {
var pageToc = document.querySelector('.page-toc');
if (!pageToc) return;
pageToc.addEventListener('click', function(e) {
var link = e.target.closest('a');
if (!link) return;
var href = link.getAttribute('href');
if (!href || !href.startsWith('#')) return;
e.preventDefault();
var id = href.substring(1);
try {
id = decodeURIComponent(id);
} catch (ex) {}
var target = document.getElementById(id);
if (target) {
target.scrollIntoView({ behavior: 'smooth' });
history.pushState(null, '', href);
}
});
}
setupTocLinks();
var backToTop = document.querySelector('.back-to-top');
if (backToTop) {
window.addEventListener('scroll', function() {
if (window.scrollY > 300) {
backToTop.classList.add('visible');
} else {
backToTop.classList.remove('visible');
}
});
backToTop.addEventListener('click', function(e) {
e.preventDefault();
window.scrollTo({ top: 0, behavior: 'smooth' });
});
}
var sidebarToggle = document.querySelector('.sidebar-toggle');
var book = document.querySelector('.book');
var bookSummary = document.querySelector('.book-summary');
function isMobile() {
return window.innerWidth <= 768;
}
var wasMobile = isMobile();
if (sidebarToggle && book && bookSummary) {
if (!isMobile()) {
var sidebarHidden = localStorage.getItem('guidebook-sidebar-hidden') === 'true';
if (sidebarHidden) {
book.classList.add('sidebar-hidden');
}
}
sidebarToggle.addEventListener('click', function() {
if (isMobile()) {
bookSummary.classList.toggle('open');
} else {
book.classList.add('sidebar-toggling');
book.classList.toggle('sidebar-hidden');
var isHidden = book.classList.contains('sidebar-hidden');
localStorage.setItem('guidebook-sidebar-hidden', isHidden);
setTimeout(function() {
book.classList.remove('sidebar-toggling');
}, 350);
}
});
document.addEventListener('click', function(e) {
if (isMobile() && bookSummary.classList.contains('open')) {
if (!bookSummary.contains(e.target) && !sidebarToggle.contains(e.target)) {
bookSummary.classList.remove('open');
}
}
});
window.addEventListener('resize', function() {
var nowMobile = isMobile();
if (wasMobile !== nowMobile) {
if (nowMobile) {
book.classList.remove('sidebar-hidden');
book.classList.remove('sidebar-toggling');
bookSummary.classList.remove('open');
} else {
bookSummary.classList.remove('open');
var sidebarHidden = localStorage.getItem('guidebook-sidebar-hidden') === 'true';
if (sidebarHidden) {
book.classList.add('sidebar-hidden');
} else {
book.classList.remove('sidebar-hidden');
}
}
wasMobile = nowMobile;
}
});
}
document.querySelectorAll('a[href*="#"]').forEach(function(anchor) {
anchor.addEventListener('click', function(e) {
var href = this.getAttribute('href');
var hashIndex = href.indexOf('#');
if (hashIndex === -1) return;
var hash = href.substring(hashIndex + 1);
try {
hash = decodeURIComponent(hash);
} catch (ex) {
}
var target = document.getElementById(hash);
if (target) {
e.preventDefault();
target.scrollIntoView({ behavior: 'smooth' });
history.pushState(null, '', '#' + encodeURIComponent(hash));
}
});
});
var HEADING_ANCHOR_ICON = '<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M7.775 3.275a.75.75 0 0 0 1.06 1.06l1.25-1.25a2 2 0 1 1 2.83 2.83l-2.5 2.5a2 2 0 0 1-2.83 0 .75.75 0 0 0-1.06 1.06 3.5 3.5 0 0 0 4.95 0l2.5-2.5a3.5 3.5 0 0 0-4.95-4.95l-1.25 1.25Zm-4.69 9.64a2 2 0 0 1 0-2.83l2.5-2.5a2 2 0 0 1 2.83 0 .75.75 0 0 0 1.06-1.06 3.5 3.5 0 0 0-4.95 0l-2.5 2.5a3.5 3.5 0 0 0 4.95 4.95l1.25-1.25a.75.75 0 0 0-1.06-1.06l-1.25 1.25a2 2 0 0 1-2.83 0Z"></path></svg>';
function setupHeadingAnchors() {
var section = document.querySelector('.markdown-section');
if (!section) return;
section.querySelectorAll('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').forEach(function(heading) {
if (heading.querySelector('.heading-anchor')) return;
var anchor = document.createElement('a');
anchor.className = 'heading-anchor';
anchor.href = '#' + encodeURIComponent(heading.id);
anchor.setAttribute('aria-label', 'Copy link to this section');
anchor.setAttribute('title', 'Copy link to this section');
anchor.innerHTML = HEADING_ANCHOR_ICON;
heading.appendChild(anchor);
});
}
function copyTextToClipboard(text) {
if (navigator.clipboard && window.isSecureContext) {
return navigator.clipboard.writeText(text);
}
return new Promise(function(resolve, reject) {
var textarea = document.createElement('textarea');
textarea.value = text;
textarea.setAttribute('readonly', '');
textarea.style.position = 'fixed';
textarea.style.top = '-1000px';
textarea.style.opacity = '0';
document.body.appendChild(textarea);
textarea.select();
var ok = false;
try {
ok = document.execCommand('copy');
} catch (ex) {
ok = false;
}
document.body.removeChild(textarea);
ok ? resolve() : reject(new Error('copy failed'));
});
}
function flashAnchorTip(anchor, message) {
anchor.setAttribute('data-tip', message);
anchor.classList.add('copied');
if (anchor._tipTimer) clearTimeout(anchor._tipTimer);
anchor._tipTimer = setTimeout(function() {
anchor.classList.remove('copied');
anchor.removeAttribute('data-tip');
}, 1500);
}
document.addEventListener('click', function(e) {
var anchor = e.target.closest ? e.target.closest('.heading-anchor') : null;
if (!anchor) return;
if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;
var heading = anchor.closest('h1, h2, h3, h4, h5, h6');
if (!heading || !heading.id) return;
e.preventDefault();
var hash = '#' + encodeURIComponent(heading.id);
history.pushState(null, '', location.pathname + location.search + hash);
heading.scrollIntoView({ behavior: 'smooth' });
copyTextToClipboard(location.href)
.then(function() {
flashAnchorTip(anchor, 'Link copied!');
})
.catch(function() {
flashAnchorTip(anchor, 'Press Ctrl/Cmd+C to copy');
});
});
function getBaseUrl() {
var base = document.querySelector('base');
if (base && base.href) {
return base.href;
}
return window.location.href.replace(/[^/]*$/, '');
}
var isNavigating = false;
function normalizeLinks(container) {
if (!container) return;
container.querySelectorAll('a[href]').forEach(function(link) {
var href = link.getAttribute('href');
if (!href || href.startsWith('#')) return;
var absoluteUrl;
if (href.startsWith('http')) {
absoluteUrl = href;
} else if (href.startsWith('/')) {
absoluteUrl = new URL(href, window.location.origin).href;
} else {
absoluteUrl = new URL(href, getBaseUrl()).href;
}
link.setAttribute('href', absoluteUrl);
var isSameOrigin = absoluteUrl.startsWith(window.location.origin);
if (!isSameOrigin) {
link.setAttribute('target', '_blank');
} else if (!absoluteUrl.endsWith('.html') && !absoluteUrl.includes('.html#')) {
link.setAttribute('target', '_blank');
}
});
}
function normalizeSidebarHrefs() {
normalizeLinks(document.querySelector('.book-summary'));
}
function normalizeContentLinks() {
normalizeLinks(document.querySelector('.markdown-section'));
}
function setupSpaNavigation() {
var sidebar = document.querySelector('.book-summary');
if (!sidebar) return;
normalizeSidebarHrefs();
sidebar.addEventListener('click', function(e) {
var link = e.target.closest('a');
if (!link) return;
var href = link.getAttribute('href');
if (!href || href.startsWith('#')) return;
if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) {
return;
}
if (href.startsWith('http') && !href.startsWith(window.location.origin)) {
return;
}
if (link.getAttribute('target') === '_blank') {
return;
}
e.preventDefault();
if (isNavigating) return;
var isSearchResult = link.classList.contains('search-result-item');
if (isSearchResult) {
var searchResults = document.querySelector('.search-results');
if (searchResults) {
searchResults.classList.remove('visible');
}
}
loadPage(href, isSearchResult ? null : link);
});
}
function setupPageNavigation() {
document.querySelectorAll('.page-nav').forEach(function(nav) {
nav.addEventListener('click', function(e) {
if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) {
return;
}
e.preventDefault();
if (isNavigating) return;
var href = this.getAttribute('href');
if (!href) return;
loadPage(href, null);
});
});
}
function loadPage(url, clickedLink) {
if (isNavigating) return;
isNavigating = true;
document.body.classList.add('loading');
var absoluteUrl = new URL(url, getBaseUrl()).href;
var hashIndex = url.indexOf('#');
var hash = hashIndex !== -1 ? url.substring(hashIndex + 1) : null;
fetch(absoluteUrl)
.then(function(response) {
if (!response.ok) throw new Error('Page not found');
return response.text();
})
.then(function(html) {
var parser = new DOMParser();
var doc = parser.parseFromString(html, 'text/html');
var newContent = doc.querySelector('.markdown-section');
var currentContent = document.querySelector('.markdown-section');
if (!newContent) {
isNavigating = false;
document.body.classList.remove('loading');
window.open(absoluteUrl, '_blank');
return;
}
if (currentContent) {
currentContent.innerHTML = newContent.innerHTML;
}
var newTitle = doc.querySelector('title');
if (newTitle) {
document.title = newTitle.textContent;
}
document.querySelectorAll('.book-summary .chapter.active').forEach(function(ch) {
ch.classList.remove('active');
});
var newActiveHref = absoluteUrl.split('#')[0];
document.querySelectorAll('.book-summary .chapter a').forEach(function(link) {
var href = link.getAttribute('href');
if (href === newActiveHref) {
var chapter = link.closest('.chapter');
if (chapter) {
chapter.classList.add('active');
var parent = chapter.parentElement;
while (parent) {
if (parent.classList && parent.classList.contains('chapter')) {
parent.classList.add('expanded');
}
parent = parent.parentElement;
}
}
}
});
history.pushState(null, '', absoluteUrl);
if (hash) {
try {
var decodedHash = decodeURIComponent(hash);
var target = document.getElementById(decodedHash);
if (target) {
setTimeout(function() {
target.scrollIntoView({ behavior: 'auto' });
}, 50);
} else {
window.scrollTo(0, 0);
}
} catch (ex) {
window.scrollTo(0, 0);
}
} else {
window.scrollTo(0, 0);
}
if (typeof mermaid !== 'undefined') {
mermaid.init(undefined, '.markdown-section .mermaid');
}
if (typeof hljs !== 'undefined') {
document.querySelectorAll('.markdown-section pre code').forEach(function(block) {
hljs.highlightElement(block);
});
}
if (window.guidebookFontsettings && window.guidebookFontsettings.reapply) {
window.guidebookFontsettings.reapply();
}
var newToc = doc.querySelector('.page-toc');
var currentToc = document.querySelector('.page-toc');
var newTocToggle = doc.querySelector('.toc-toggle');
var currentTocToggle = document.querySelector('.toc-toggle');
if (currentToc) currentToc.remove();
if (currentTocToggle) currentTocToggle.remove();
if (newToc) {
var bookBody = document.querySelector('.book-body');
if (bookBody) {
var tocClone = newToc.cloneNode(true);
bookBody.insertBefore(tocClone, bookBody.querySelector('.body-inner'));
if (newTocToggle) {
var toggleClone = newTocToggle.cloneNode(true);
bookBody.insertBefore(toggleClone, tocClone);
toggleClone.addEventListener('click', function() {
if (window.innerWidth > 768) {
document.querySelector('.book').classList.toggle('toc-hidden');
var isHidden = document.querySelector('.book').classList.contains('toc-hidden');
localStorage.setItem('guidebook-toc-hidden', isHidden);
}
});
}
setupTocScrollSpy();
setupTocLinks();
}
}
var newPrev = doc.querySelector('.page-nav.prev');
var newNext = doc.querySelector('.page-nav.next');
var currentPrev = document.querySelector('.page-nav.prev');
var currentNext = document.querySelector('.page-nav.next');
if (currentPrev) currentPrev.remove();
if (currentNext) currentNext.remove();
var bodyInner = document.querySelector('.body-inner');
if (bodyInner) {
if (newPrev) {
var prevClone = newPrev.cloneNode(true);
bodyInner.insertBefore(prevClone, bodyInner.firstChild);
}
if (newNext) {
var nextClone = newNext.cloneNode(true);
bodyInner.insertBefore(nextClone, bodyInner.querySelector('.page-wrapper'));
}
setupPageNavigation();
}
normalizeContentLinks();
setupHeadingAnchors();
if (!clickedLink) {
setTimeout(function() {
scrollSidebarToActive();
}, 100);
}
isNavigating = false;
document.body.classList.remove('loading');
})
.catch(function(err) {
console.error('Navigation error:', err);
isNavigating = false;
document.body.classList.remove('loading');
window.location.href = url;
});
}
window.addEventListener('popstate', function() {
loadPage(location.pathname + location.hash, null);
});
setupSpaNavigation();
setupPageNavigation();
normalizeContentLinks();
setupHeadingAnchors();
function scrollToHashOnLoad() {
if (!window.location.hash) return;
var hash = window.location.hash.substring(1);
try {
hash = decodeURIComponent(hash);
} catch (ex) {
}
var target = document.getElementById(hash);
if (target) {
setTimeout(function() {
target.scrollIntoView({ behavior: 'auto' });
}, 100);
}
}
if (document.readyState === 'complete') {
scrollToHashOnLoad();
} else {
window.addEventListener('load', scrollToHashOnLoad);
}
if (typeof hljs !== 'undefined') {
hljs.highlightAll();
}
function scrollSidebarToActive() {
var sidebar = document.querySelector('.book-summary');
var activeItem = document.querySelector('.book-summary .chapter.active');
if (!sidebar || !activeItem) return;
var activeLink = activeItem.querySelector('a') || activeItem;
var sidebarRect = sidebar.getBoundingClientRect();
var activeRect = activeLink.getBoundingClientRect();
var sidebarScrollTop = sidebar.scrollTop;
var activeOffsetTop = activeRect.top - sidebarRect.top + sidebarScrollTop;
var sidebarHeight = sidebar.clientHeight;
var activeHeight = activeRect.height;
var targetScrollTop = activeOffsetTop - (sidebarHeight / 2) + (activeHeight / 2);
var maxScroll = sidebar.scrollHeight - sidebarHeight;
targetScrollTop = Math.max(0, Math.min(targetScrollTop, maxScroll));
sidebar.scrollTop = targetScrollTop;
}
if (document.readyState === 'complete') {
scrollSidebarToActive();
} else {
window.addEventListener('load', scrollSidebarToActive);
}
window.scrollSidebarToActive = scrollSidebarToActive;
})();