document.addEventListener('DOMContentLoaded', function() {
const rightToc = document.createElement('div');
rightToc.className = 'right-toc';
const tocTitle = document.createElement('div');
tocTitle.className = 'right-toc-title';
tocTitle.textContent = '页面目录';
rightToc.appendChild(tocTitle);
const tocList = document.createElement('ul');
rightToc.appendChild(tocList);
const toggleButton = document.createElement('button');
toggleButton.className = 'right-toc-toggle';
toggleButton.innerHTML = '☰';
toggleButton.title = '显示/隐藏目录';
document.body.appendChild(rightToc);
document.body.appendChild(toggleButton);
function buildTableOfContents() {
tocList.innerHTML = '';
const usedIds = new Set();
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
headings.forEach(heading => {
if (heading.parentElement.classList.contains('wy-side-nav-search') ||
heading.parentElement.classList.contains('wy-menu-vertical')) {
return;
}
const listItem = document.createElement('li');
const link = document.createElement('a');
let cleanText = heading.innerText.trim();
cleanText = cleanText.replace(/[\x00-\x1F\x7F-\x9F\u00AD\u061C\u200B-\u200F\u2028-\u202F\u2060-\u206F]/g, '');
cleanText = cleanText.replace(/[??\s]+$/g, '');
cleanText = cleanText.replace(/[^\x20-\x7E\u4e00-\u9fa5]/g, '');
cleanText = cleanText.trim().replace(/[??\s.,;:]+$/g, '');
let headingId = heading.id;
if (!headingId) {
headingId = generateIdFromText(cleanText);
heading.id = headingId;
}
if (usedIds.has(headingId)) {
let counter = 1;
let uniqueId = `${headingId}-${counter}`;
while (usedIds.has(uniqueId)) {
counter++;
uniqueId = `${headingId}-${counter}`;
}
headingId = uniqueId;
heading.id = headingId;
}
usedIds.add(headingId);
link.textContent = cleanText;
link.href = '#' + headingId;
const level = parseInt(heading.tagName.charAt(1));
listItem.style.paddingLeft = (level - 1) * 10 + 'px';
listItem.style.fontSize = (16 - (level - 1) * 1) + 'px';
link.addEventListener('click', function(e) {
e.preventDefault();
const targetElement = document.getElementById(headingId);
if (targetElement) {
const headerOffset = 80;
const elementPosition = targetElement.getBoundingClientRect().top;
const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
window.scrollTo({
top: offsetPosition,
behavior: 'smooth'
});
}
if (window.innerWidth <= 992) {
rightToc.classList.remove('visible');
}
});
listItem.appendChild(link);
tocList.appendChild(listItem);
});
if (tocList.children.length === 0) {
const emptyItem = document.createElement('li');
emptyItem.textContent = '本页面没有目录';
emptyItem.style.color = '#777';
tocList.appendChild(emptyItem);
}
}
function generateIdFromText(text) {
let id = text.toLowerCase();
id = id.replace(/[\u4e00-\u9fa5]/g, function(char) {
return 'id';
});
id = id.replace(/[^a-z0-9]/g, '-');
id = id.replace(/-+/g, '-');
id = id.replace(/^-+|-+$/g, '');
return id || 'section';
}
toggleButton.addEventListener('click', function() {
rightToc.classList.toggle('visible');
});
if (window.innerWidth > 992) {
rightToc.classList.add('visible');
}
window.addEventListener('resize', function() {
if (window.innerWidth > 992) {
rightToc.classList.add('visible');
} else {
rightToc.classList.remove('visible');
}
});
buildTableOfContents();
});