198 行
7.1 KiB
JavaScript
198 行
7.1 KiB
JavaScript
document.addEventListener('DOMContentLoaded', function() {
|
|
const markdownBody = document.getElementById('markdownBody');
|
|
const rawContent = markdownBody.innerHTML;
|
|
markdownBody.innerHTML = marked.parse(rawContent);
|
|
|
|
const themeToggle = document.getElementById('themeToggle');
|
|
const mobileThemeToggle = document.getElementById('mobileThemeToggle');
|
|
const html = document.documentElement;
|
|
|
|
function setTheme(theme) {
|
|
html.setAttribute('data-theme', theme);
|
|
localStorage.setItem('theme', theme);
|
|
}
|
|
|
|
function toggleTheme() {
|
|
const current = html.getAttribute('data-theme');
|
|
setTheme(current === 'dark' ? 'light' : 'dark');
|
|
}
|
|
|
|
const saved = localStorage.getItem('theme');
|
|
if (saved) {
|
|
setTheme(saved);
|
|
} else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
|
setTheme('dark');
|
|
}
|
|
|
|
themeToggle.addEventListener('click', toggleTheme);
|
|
if (mobileThemeToggle) mobileThemeToggle.addEventListener('click', toggleTheme);
|
|
|
|
const menuToggle = document.getElementById('menuToggle');
|
|
const sidebar = document.querySelector('.sidebar');
|
|
const overlay = document.getElementById('overlay');
|
|
|
|
if (menuToggle) {
|
|
menuToggle.addEventListener('click', function() {
|
|
sidebar.classList.toggle('open');
|
|
overlay.classList.toggle('show');
|
|
});
|
|
}
|
|
|
|
if (overlay) {
|
|
overlay.addEventListener('click', function() {
|
|
sidebar.classList.remove('open');
|
|
overlay.classList.remove('show');
|
|
});
|
|
}
|
|
|
|
const folders = document.querySelectorAll('.folder-toggle');
|
|
folders.forEach(function(folder) {
|
|
folder.addEventListener('click', function() {
|
|
const li = this.parentElement;
|
|
li.classList.toggle('open');
|
|
});
|
|
});
|
|
|
|
const searchInput = document.getElementById('searchInput');
|
|
if (searchInput) {
|
|
searchInput.addEventListener('input', function() {
|
|
const query = this.value.toLowerCase().trim();
|
|
const files = document.querySelectorAll('.nav-tree .file');
|
|
const dirs = document.querySelectorAll('.nav-tree .folder');
|
|
|
|
if (!query) {
|
|
files.forEach(f => f.classList.remove('hidden'));
|
|
dirs.forEach(d => d.classList.remove('hidden'));
|
|
return;
|
|
}
|
|
|
|
files.forEach(function(file) {
|
|
const text = file.textContent.toLowerCase();
|
|
if (text.includes(query)) {
|
|
file.classList.remove('hidden');
|
|
let parent = file.parentElement;
|
|
while (parent) {
|
|
if (parent.classList && parent.classList.contains('folder')) {
|
|
parent.classList.remove('hidden');
|
|
parent.classList.add('open');
|
|
}
|
|
parent = parent.parentElement;
|
|
}
|
|
} else {
|
|
file.classList.add('hidden');
|
|
}
|
|
});
|
|
|
|
dirs.forEach(function(dir) {
|
|
const visibleFiles = dir.querySelectorAll('.file:not(.hidden)');
|
|
if (visibleFiles.length === 0) {
|
|
const folderText = dir.querySelector('.folder-toggle').textContent.toLowerCase();
|
|
if (!folderText.includes(query)) {
|
|
dir.classList.add('hidden');
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
const currentFile = document.querySelector('.nav-tree .file.active');
|
|
if (currentFile) {
|
|
let parent = currentFile.parentElement;
|
|
while (parent) {
|
|
if (parent.classList && parent.classList.contains('folder')) {
|
|
parent.classList.add('open');
|
|
}
|
|
parent = parent.parentElement;
|
|
}
|
|
currentFile.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
}
|
|
|
|
const navTree = document.getElementById('navTree');
|
|
if (navTree) {
|
|
navTree.addEventListener('click', function(e) {
|
|
const link = e.target.closest('a');
|
|
if (!link) return;
|
|
const href = link.getAttribute('href');
|
|
if (!href || href.startsWith('http') || href.startsWith('#') || href.startsWith('javascript')) return;
|
|
e.preventDefault();
|
|
|
|
const sidebarEl = document.querySelector('.sidebar');
|
|
const overlayEl = document.getElementById('overlay');
|
|
if (sidebarEl.classList.contains('open')) {
|
|
sidebarEl.classList.remove('open');
|
|
overlayEl.classList.remove('show');
|
|
}
|
|
|
|
history.pushState(null, '', href);
|
|
loadDoc(href);
|
|
});
|
|
}
|
|
|
|
// ===== 使用 XMLHttpRequest 替代 fetch =====
|
|
function loadDoc(href) {
|
|
var url = '/doc/index.php' + href + '&_ajax=1';
|
|
markdownBody.style.opacity = '0.5';
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open('GET', url, true);
|
|
xhr.timeout = 30000; // 30秒超时
|
|
|
|
xhr.onreadystatechange = function() {
|
|
if (xhr.readyState === 4) {
|
|
markdownBody.style.opacity = '1';
|
|
|
|
if (xhr.status === 200) {
|
|
var data = xhr.responseText;
|
|
// 检查是否返回了 HTML(说明请求失败)
|
|
if (data.trim().startsWith('<!DOCTYPE') || data.trim().startsWith('<html')) {
|
|
// 降级:直接跳转
|
|
window.location.href = href;
|
|
return;
|
|
}
|
|
markdownBody.innerHTML = marked.parse(data);
|
|
var titleEl = markdownBody.querySelector('h1');
|
|
var newTitle = titleEl ? titleEl.textContent + ' - Docs' : 'Docs - Docs';
|
|
document.title = newTitle;
|
|
updateActiveLink(href);
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
} else {
|
|
// 请求失败,降级跳转
|
|
console.error('加载失败,状态码: ' + xhr.status);
|
|
window.location.href = href;
|
|
}
|
|
}
|
|
};
|
|
|
|
xhr.onerror = function() {
|
|
markdownBody.style.opacity = '1';
|
|
console.error('网络错误');
|
|
window.location.href = href;
|
|
};
|
|
|
|
xhr.ontimeout = function() {
|
|
markdownBody.style.opacity = '1';
|
|
console.error('请求超时');
|
|
window.location.href = href;
|
|
};
|
|
|
|
xhr.send();
|
|
}
|
|
|
|
function updateActiveLink(href) {
|
|
document.querySelectorAll('.nav-tree .file').forEach(function(f) {
|
|
f.classList.remove('active');
|
|
var a = f.querySelector('a');
|
|
if (a && a.getAttribute('href') === href) {
|
|
f.classList.add('active');
|
|
}
|
|
});
|
|
}
|
|
|
|
window.addEventListener('popstate', function() {
|
|
var params = new URLSearchParams(window.location.search);
|
|
var f = params.get('file');
|
|
if (f) {
|
|
loadDoc('?file=' + f);
|
|
}
|
|
});
|
|
}); |