622 lines
24 KiB
JavaScript
622 lines
24 KiB
JavaScript
window.WebAssembly = undefined;
|
|
|
|
const url = new URL(window.location.href);
|
|
const pathParts = url.pathname.split('/');
|
|
const UUID = pathParts.pop() || pathParts.pop();
|
|
|
|
// DOM元素
|
|
const sidebar = document.getElementById('sidebar');
|
|
const sidebarToggle = document.getElementById('sidebar-toggle');
|
|
const overlay = document.getElementById('overlay');
|
|
const sidebarSearch = document.getElementById('sidebar-search');
|
|
const themeToggle = document.getElementById('theme-toggle');
|
|
const articleContainer = document.getElementById('article-container');
|
|
const sidebarNav = document.getElementById('sidebar-nav');
|
|
const globalSearch = document.getElementById('global-search');
|
|
const searchButton = document.getElementById('search-button');
|
|
const headerTitle = document.getElementById('header-title');
|
|
|
|
// 初始化Marked.js
|
|
if (window.marked) marked.setOptions({
|
|
highlight: function (code, lang) {
|
|
if (lang && hljs.getLanguage(lang)) {
|
|
return hljs.highlight(code, { language: lang }).value;
|
|
}
|
|
return hljs.highlightAuto(code).value;
|
|
},
|
|
breaks: true,
|
|
});
|
|
|
|
// 渲染侧边栏导航
|
|
function renderSidebar() {
|
|
sidebarNav.innerHTML = '';
|
|
|
|
tableOfContents.chapters.forEach(chapter => {
|
|
const chapterEl = document.createElement('div');
|
|
chapterEl.className = 'mb-1';
|
|
|
|
const chapterHeader = document.createElement('div');
|
|
chapterHeader.className = 'flex items-center justify-between p-2 rounded-lg hover:bg-gray-100 cursor-pointer transition-all duration-300';
|
|
chapterHeader.innerHTML = `
|
|
<span class="font-medium flex items-center">
|
|
<i class="fa fa-book mr-2 text-primary"></i>
|
|
${chapter.title}
|
|
</span>
|
|
<i class="fa fa-chevron-down text-xs transition-transform duration-300"></i>
|
|
`;
|
|
|
|
const chapterContent = document.createElement('div');
|
|
chapterContent.className = 'pl-4 mt-1 space-y-1 overflow-hidden max-h-0 transition-all duration-300';
|
|
|
|
// 添加章节链接
|
|
const chapterLink = document.createElement('a');
|
|
chapterLink.href = `#${chapter.id}`;
|
|
chapterLink.className = 'block p-2 rounded-lg hover:bg-gray-100 text-sm transition-all duration-300';
|
|
chapterLink.textContent = chapter.title;
|
|
chapterLink.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
loadArticleAsync(chapter.id);
|
|
closeSidebar();
|
|
highlightActiveLink(chapter.id);
|
|
});
|
|
chapterContent.appendChild(chapterLink);
|
|
|
|
// 添加子章节链接
|
|
if (chapter.sections && chapter.sections.length > 0) {
|
|
chapter.sections.forEach(section => {
|
|
const sectionLink = document.createElement('a');
|
|
sectionLink.href = `#${section.id}`;
|
|
sectionLink.className = 'block p-2 rounded-lg hover:bg-gray-100 text-sm transition-all duration-300';
|
|
sectionLink.innerHTML = `
|
|
<span class="ml-2">${section.title}</span>
|
|
`;
|
|
sectionLink.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
loadArticleAsync(section.id);
|
|
closeSidebar();
|
|
highlightActiveLink(section.id);
|
|
});
|
|
chapterContent.appendChild(sectionLink);
|
|
});
|
|
}
|
|
|
|
chapterHeader.addEventListener('click', () => {
|
|
const isExpanded = chapterContent.classList.contains('expanded');
|
|
|
|
if (isExpanded) {
|
|
chapterContent.classList.remove('expanded');
|
|
chapterContent.style.maxHeight = '0';
|
|
chapterHeader.querySelector('.fa-chevron-down').style.transform = 'rotate(0deg)';
|
|
} else {
|
|
chapterContent.classList.add('expanded');
|
|
chapterContent.style.maxHeight = chapterContent.scrollHeight + 'px';
|
|
chapterHeader.querySelector('.fa-chevron-down').style.transform = 'rotate(180deg)';
|
|
}
|
|
});
|
|
|
|
chapterEl.appendChild(chapterHeader);
|
|
chapterEl.appendChild(chapterContent);
|
|
sidebarNav.appendChild(chapterEl);
|
|
});
|
|
}
|
|
|
|
// 异步加载文章内容
|
|
async function loadArticleAsync(id, password = null) {
|
|
// 显示现代化加载动画
|
|
showLoadingAnimation();
|
|
// 找到侧边栏中对应的链接并模拟点击
|
|
const link = document.querySelector(`#sidebar-nav a[href="#${id}"]`);
|
|
let apiUrl = `/API/GetDoc/${id}`;
|
|
if (password) {
|
|
apiUrl += `?Pwd=${password}`;
|
|
}
|
|
try {
|
|
// 使用fetch API进行异步请求
|
|
const response = await fetch(apiUrl);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const content = await response.json();
|
|
|
|
if (content.DocDecrypt === false) {
|
|
showPasswordPrompt(content.DocContent, id);
|
|
} else if (content) {
|
|
renderArticle(content);
|
|
} else {
|
|
showError("未找到文章内容");
|
|
}
|
|
} catch (error) {
|
|
console.error('Fetch error:', error);
|
|
showError("加载文章失败,请稍后再试");
|
|
}
|
|
}
|
|
|
|
// 显示加载动画
|
|
function showLoadingAnimation() {
|
|
articleContainer.innerHTML = `
|
|
<div class="flex flex-col items-center justify-center py-16 min-h-[400px]">
|
|
<div class="loading-spinner">
|
|
<div class="spinner"></div>
|
|
</div>
|
|
<p class="mt-4 text-gray-500 dark:text-gray-400 text-lg">正在加载文章内容...</p>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
// 显示错误信息
|
|
function showError(message) {
|
|
articleContainer.innerHTML = `
|
|
<div class="flex flex-col items-center justify-center py-16 min-h-[400px]">
|
|
<i class="fa fa-exclamation-triangle text-5xl text-gray-300 dark:text-gray-600 mb-4"></i>
|
|
<h3 class="text-xl font-medium mb-2">${message}</h3>
|
|
<p class="text-gray-600 dark:text-gray-400">请尝试刷新页面或联系管理员</p>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
function sanitizeInput(input) {
|
|
if (typeof input !== 'string') return '';
|
|
// 1. 移除 script 标签
|
|
let sanitized = input.replace(/<script\b[^>]*>([\s\S]*?)<\/script>/gi, '');
|
|
// 2. 移除所有事件处理器(包括 onerror)
|
|
sanitized = sanitized.replace(/\bon\w+\s*=\s*(?:"[^"]*"|'[^']*'|[^"'>\s]+)/gi, '');
|
|
// 3. 移除 javascript: 和 data: 协议
|
|
sanitized = sanitized.replace(/(javascript|data|vbscript):/gi, '');
|
|
// 4. 编码特殊字符
|
|
sanitized = sanitized
|
|
.replace(/\bonerror\s*=\s*"[^"]*"/gi, '')
|
|
.replace(/\bonerror\s*=\s*'[^']*'/gi, '')
|
|
.replace(/\bonerror\s*=\s*[^"'>\s]+/gi, '');
|
|
return sanitized;
|
|
}
|
|
|
|
function sanitizeHTML(input) {
|
|
const parser = new DOMParser();
|
|
const doc = parser.parseFromString(input, 'text/html');
|
|
const elements = doc.body.getElementsByTagName('*');
|
|
for (let element of elements) {
|
|
const attributes = element.attributes;
|
|
for (let i = attributes.length - 1; i >= 0; i--) {
|
|
const attr = attributes[i];
|
|
if (attr.name.startsWith('on') ||
|
|
attr.name.match(/^on[a-z]+/i) ||
|
|
['src', 'href', 'xlink:href'].includes(attr.name.toLowerCase())) {
|
|
element.removeAttribute(attr.name);
|
|
}
|
|
}
|
|
if (['iframe', 'script', 'object', 'embed'].includes(element.tagName.toLowerCase())) {
|
|
element.remove();
|
|
}
|
|
}
|
|
return doc.body.innerHTML;
|
|
}
|
|
|
|
// 渲染文章内容
|
|
function renderArticle(content) {
|
|
// 解析Markdown并渲染
|
|
if (content.DocContent.substring(0, 5) === "<!DOC" && content.DocPermission) {
|
|
articleContainer.innerHTML = `<iframe onerror="return false;" id="IFcontent" class="iframe-content"></iframe>`;
|
|
const IFcontent = document.getElementById("IFcontent");
|
|
IFcontent.srcdoc = content.DocContent;
|
|
IFcontent.onload = function () {
|
|
IFcontent.style.height = IFcontent.contentWindow.document.body.scrollHeight + 100 + 'px';
|
|
IFcontent.contentDocument.body.style.color = document.documentElement.classList.contains('dark') ? '#FFFFFF' : '#000000';
|
|
}
|
|
} else if (content.DocPermission) {
|
|
articleContainer.innerHTML = marked.parse(content.DocContent);
|
|
} else {
|
|
articleContainer.innerHTML = marked.parse(sanitizeInput(content.DocContent));
|
|
}
|
|
|
|
// 渲染数学公式
|
|
document.querySelectorAll('pre code.language-math, pre code.language-katex, pre code.language-latex').forEach((block) => {
|
|
const parentPre = block.parentNode;
|
|
const displayMode = true;
|
|
const mathDiv = document.createElement('div');
|
|
mathDiv.className = 'math';
|
|
mathDiv.textContent = block.textContent;
|
|
katex.render(mathDiv.textContent, mathDiv, {
|
|
throwOnError: false,
|
|
displayMode
|
|
});
|
|
parentPre.parentNode.replaceChild(mathDiv, parentPre);
|
|
});
|
|
|
|
// 渲染流程图和序列图
|
|
document.querySelectorAll('pre code.language-flow, pre code.language-seq').forEach((block) => {
|
|
const parentPre = block.parentNode;
|
|
const diagram = document.createElement('div');
|
|
diagram.className = 'mermaid';
|
|
diagram.textContent = block.textContent;
|
|
parentPre.parentNode.replaceChild(diagram, parentPre);
|
|
});
|
|
if (window.mermaid) mermaid.init();
|
|
|
|
// 为普通代码块添加行号、标题、复制按钮和演示按钮
|
|
document.querySelectorAll('pre code').forEach((block) => {
|
|
const lang = block.getAttribute('class')?.replace('hljs', '').trim();
|
|
const supportedLanguages = ['javascript', 'html', 'plaintext']; // 定义支持高亮的语言
|
|
|
|
// 只对支持的语言进行高亮处理
|
|
if (supportedLanguages.includes(lang)) {
|
|
hljs.highlightElement(block);
|
|
}
|
|
|
|
// 跳过数学公式和图表代码块
|
|
if (['math', 'katex', 'latex', 'flow', 'seq'].includes(lang)) {
|
|
return;
|
|
}
|
|
|
|
// 添加行号
|
|
if (!block.classList.contains('nohighlight')) {
|
|
const lines = block.textContent.split('\n').length;
|
|
let lineNumbersHTML = '';
|
|
|
|
for (let i = 0; i < lines; i++) {
|
|
lineNumbersHTML += '<span></span>';
|
|
}
|
|
|
|
const lineNumbersWrapper = document.createElement('div');
|
|
lineNumbersWrapper.className = 'line-numbers';
|
|
lineNumbersWrapper.innerHTML = lineNumbersHTML;
|
|
|
|
block.className += ' line-numbers-rows';
|
|
block.parentNode.insertBefore(lineNumbersWrapper, block);
|
|
}
|
|
|
|
// 添加代码块标题
|
|
const codeTitle = document.createElement('div');
|
|
codeTitle.className = 'code-title';
|
|
codeTitle.textContent = lang || 'plaintext';
|
|
|
|
// 添加复制按钮
|
|
const copyButton = document.createElement('button');
|
|
copyButton.className = 'copy-btn';
|
|
copyButton.innerHTML = '<i class="fa fa-copy"></i>';
|
|
copyButton.addEventListener('click', () => {
|
|
const text = block.textContent;
|
|
navigator.clipboard.writeText(text).then(() => {
|
|
copyButton.innerHTML = '<i class="fa fa-check"></i>';
|
|
setTimeout(() => {
|
|
copyButton.innerHTML = '<i class="fa fa-copy"></i>';
|
|
}, 1000);
|
|
}).catch((err) => {
|
|
console.error('复制失败: ', err);
|
|
});
|
|
});
|
|
codeTitle.appendChild(copyButton);
|
|
|
|
// 添加演示按钮
|
|
if (lang === 'javascript' || lang === 'html') {
|
|
const demoButton = document.createElement('button');
|
|
demoButton.className = 'demo-btn';
|
|
demoButton.innerHTML = '<i class="fa fa-external-link"></i>';
|
|
demoButton.addEventListener('click', () => {
|
|
const code = block.textContent;
|
|
const newWindow = window.open('', '_blank');
|
|
if (lang === 'javascript') {
|
|
newWindow.document.write(`<html><body><script>${code}</script></body></html>`);
|
|
} else if (lang === 'html') {
|
|
newWindow.document.write(code);
|
|
}
|
|
});
|
|
codeTitle.appendChild(demoButton);
|
|
}
|
|
|
|
block.parentNode.insertBefore(codeTitle, block);
|
|
});
|
|
|
|
if (window.renderMathInElement) renderMathInElement(document.body);
|
|
|
|
// 添加淡入动画
|
|
articleContainer.style.opacity = '0';
|
|
setTimeout(() => {
|
|
articleContainer.style.opacity = '1';
|
|
articleContainer.style.transition = 'opacity 0.3s ease';
|
|
}, 50);
|
|
}
|
|
|
|
// 高亮活动链接
|
|
function highlightActiveLink(id) {
|
|
document.querySelectorAll('#sidebar-nav a').forEach(link => {
|
|
if (link.getAttribute('href') === `#${id}`) {
|
|
link.classList.add('bg-primary/10', 'dark:bg-primary/20', 'text-primary');
|
|
} else {
|
|
link.classList.remove('bg-primary/10', 'dark:bg-primary/20', 'text-primary');
|
|
}
|
|
});
|
|
}
|
|
|
|
// 打开侧边栏
|
|
function openSidebar() {
|
|
sidebar.classList.remove('-translate-x-full');
|
|
overlay.classList.remove('hidden');
|
|
setTimeout(() => {
|
|
overlay.classList.add('opacity-100');
|
|
}, 10);
|
|
}
|
|
|
|
// 关闭侧边栏
|
|
function closeSidebar() {
|
|
sidebar.classList.add('-translate-x-full');
|
|
overlay.classList.remove('opacity-100');
|
|
setTimeout(() => {
|
|
overlay.classList.add('hidden');
|
|
}, 300);
|
|
}
|
|
|
|
// 切换主题
|
|
function toggleTheme() {
|
|
document.documentElement.classList.toggle('dark');
|
|
IFcontent = document.getElementById("IFcontent");
|
|
if (IFcontent) {
|
|
iframeDoc = IFcontent.contentDocument || IFcontent.contentWindow.document;
|
|
iframeDoc.body.style.color = document.documentElement.classList.contains('dark') ? '#FFF' : '#000';
|
|
iframeDoc.documentElement.classList.toggle('dark');
|
|
}
|
|
localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light');
|
|
}
|
|
|
|
// 侧边栏搜索功能
|
|
function setupSidebarSearch() {
|
|
sidebarSearch.addEventListener('input', (e) => {
|
|
const searchTerm = e.target.value.toLowerCase().trim();
|
|
const links = document.querySelectorAll('#sidebar-nav a');
|
|
|
|
links.forEach(link => {
|
|
const text = link.textContent.toLowerCase();
|
|
const isVisible = text.includes(searchTerm);
|
|
|
|
link.style.display = isVisible ? 'block' : 'none';
|
|
|
|
// 如果章节下所有子项都不可见,则隐藏章节
|
|
const parent = link.closest('div');
|
|
const visibleItems = parent.querySelectorAll('a:not([style*="display: none"])').length;
|
|
|
|
const chapterHeader = parent.previousElementSibling;
|
|
if (chapterHeader && visibleItems === 0) {
|
|
parent.style.display = 'none';
|
|
chapterHeader.style.display = 'none';
|
|
} else if (chapterHeader) {
|
|
parent.style.display = '';
|
|
chapterHeader.style.display = '';
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// 搜索功能
|
|
function setupSearch() {
|
|
searchButton.addEventListener('click', performSearch);
|
|
globalSearch.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Enter') {
|
|
performSearch();
|
|
}
|
|
});
|
|
}
|
|
|
|
// 执行搜索
|
|
async function performSearch() {
|
|
const searchTerm = globalSearch.value.toLowerCase().trim();
|
|
if (!searchTerm) return;
|
|
|
|
showLoadingAnimation();
|
|
|
|
try {
|
|
// 获取所有文章ID
|
|
const allIds = [];
|
|
tableOfContents.chapters.forEach(chapter => {
|
|
allIds.push(chapter.id);
|
|
if (chapter.sections) {
|
|
chapter.sections.forEach(section => {
|
|
allIds.push(section.id);
|
|
});
|
|
}
|
|
});
|
|
|
|
// 并行请求所有文章内容
|
|
const results = await Promise.allSettled(
|
|
allIds.map(id => fetch(`/API/GetDoc/${id}`)
|
|
.then(response => response.json())
|
|
.then(content => ({ id, content }))
|
|
)
|
|
);
|
|
|
|
// 处理搜索结果
|
|
const searchResults = [];
|
|
results.forEach(result => {
|
|
if (result.status === 'fulfilled' && result.value.content) {
|
|
const { id, content } = result.value;
|
|
c = content.DocContent;
|
|
if (c.toLowerCase().includes(searchTerm)) {
|
|
const title = tableOfContents.chapters.flatMap(chapter => [
|
|
{ id: chapter.id, title: chapter.title },
|
|
...chapter.sections.map(section => ({ id: section.id, title: section.title }))
|
|
]).find(item => item.id === id)?.title || '未知标题';
|
|
|
|
const excerpt = getExcerpt(c, searchTerm);
|
|
searchResults.push({ id, title, excerpt });
|
|
}
|
|
}
|
|
});
|
|
|
|
// 渲染搜索结果
|
|
renderSearchResults(searchResults);
|
|
} catch (error) {
|
|
console.error('搜索失败:', error);
|
|
showError("搜索过程中发生错误");
|
|
}
|
|
}
|
|
|
|
// 渲染搜索结果
|
|
function renderSearchResults(results) {
|
|
if (results.length > 0) {
|
|
let resultsHTML = '<div class="search-results">';
|
|
resultsHTML += `<h2 class="text-2xl font-bold mb-6">搜索结果: ${results.length} 个匹配项</h2>`;
|
|
|
|
results.forEach(result => {
|
|
resultsHTML += `
|
|
<div class="search-result-item mb-6 p-4 rounded-lg border border-gray-200 dark:border-gray-700 hover:shadow-md transition-shadow">
|
|
<h3 class="text-xl font-semibold mb-2">
|
|
<a href="#" onclick="loadArticleAsync('${result.id}'); return false;" class="text-primary hover:underline">${result.title}</a>
|
|
</h3>
|
|
<div class="text-gray-600 dark:text-gray-400 mb-3 text-sm" style="line-height: 1.6">
|
|
${result.excerpt}
|
|
</div>
|
|
<a href="#" onclick="loadArticleAsync('${result.id}'); return false;" class="inline-flex items-center text-sm text-primary hover:text-primary/80">
|
|
阅读更多 <i class="fa fa-arrow-right ml-1"></i>
|
|
</a>
|
|
</div>
|
|
`;
|
|
});
|
|
|
|
resultsHTML += '</div>';
|
|
articleContainer.innerHTML = resultsHTML;
|
|
} else {
|
|
showError("未找到匹配的结果");
|
|
}
|
|
}
|
|
|
|
// 获取摘要(带转义和搜索词高亮)
|
|
function getExcerpt(content, searchTerm) {
|
|
// 转义HTML特殊字符
|
|
const escapeHtml = (str) => {
|
|
return str.replace(/[&<>'"]/g,
|
|
tag => ({
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
"'": ''',
|
|
'"': '"'
|
|
}[tag]));
|
|
};
|
|
|
|
// 转义内容和搜索词
|
|
const escapedContent = escapeHtml(content);
|
|
const escapedSearchTerm = escapeHtml(searchTerm);
|
|
|
|
// 查找位置(不区分大小写)
|
|
const index = escapedContent.toLowerCase().indexOf(escapedSearchTerm.toLowerCase());
|
|
if (index === -1) return ''; // 没找到搜索词
|
|
|
|
// 计算摘要范围
|
|
const start = Math.max(0, index - 100);
|
|
const end = Math.min(escapedContent.length, index + escapedSearchTerm.length + 100);
|
|
|
|
// 构建摘要
|
|
let excerpt = escapedContent.substring(start, end);
|
|
if (start > 0) excerpt = '...' + excerpt;
|
|
if (end < escapedContent.length) excerpt = excerpt + '...';
|
|
|
|
// 高亮搜索词(使用转义后的搜索词)
|
|
const regex = new RegExp(escapedSearchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
|
|
excerpt = excerpt.replace(regex, match => `<mark class="bg-yellow-200 dark:bg-yellow-800">${match}</mark>`);
|
|
|
|
return excerpt;
|
|
}
|
|
|
|
// 展开所有侧边栏章节
|
|
function expandAllSidebarSections() {
|
|
const chapterContents = document.querySelectorAll('#sidebar-nav .pl-4.mt-1.space-y-1');
|
|
const chapterHeaders = document.querySelectorAll('#sidebar-nav .flex.items-center.justify-between.p-2.rounded-lg');
|
|
|
|
chapterContents.forEach((chapterContent) => {
|
|
chapterContent.style.maxHeight = 'none';
|
|
const height = chapterContent.scrollHeight * 100;
|
|
chapterContent.style.maxHeight = '0';
|
|
requestAnimationFrame(() => {
|
|
chapterContent.classList.add('expanded');
|
|
chapterContent.style.maxHeight = height + 'px';
|
|
});
|
|
});
|
|
|
|
chapterHeaders.forEach((chapterHeader) => {
|
|
const chevron = chapterHeader.querySelector('.fa-chevron-down');
|
|
chevron.style.transform = 'rotate(180deg)';
|
|
});
|
|
}
|
|
|
|
// 显示密码输入提示
|
|
function showPasswordPrompt(prompt, id) {
|
|
articleContainer.innerHTML = `
|
|
<div class="flex flex-col items-center justify-center py-16 min-h-[400px]">
|
|
<p class="text-gray-600 dark:text-gray-400 mb-4">${prompt}</p>
|
|
<input type="password" id="password-input" class="bg-gray-100 dark:bg-gray-700 rounded-lg py-2 px-4 w-full max-w-xs focus:outline-none focus:ring-2 focus:ring-primary/50 transition-all-300 mb-4">
|
|
<p id="password-error" class="text-red-500 dark:text-red-400 hidden">密码错误,请重新输入。</p>
|
|
<button id="password-submit" class="bg-primary text-white rounded-lg py-2 px-4 hover:bg-primary/80 transition-all-300">提交密码</button>
|
|
</div>
|
|
`;
|
|
const passwordInput = document.getElementById('password-input');
|
|
const passwordSubmit = document.getElementById('password-submit');
|
|
const passwordError = document.getElementById('password-error');
|
|
|
|
passwordSubmit.addEventListener('click', () => {
|
|
const password = passwordInput.value;
|
|
loadArticleAsync(id, password).then(() => {
|
|
if (articleContainer.innerHTML.includes('密码错误')) {
|
|
passwordError.classList.remove('hidden');
|
|
} else {
|
|
passwordError.classList.add('hidden');
|
|
}
|
|
});
|
|
});
|
|
|
|
passwordInput.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Enter') {
|
|
const password = passwordInput.value;
|
|
loadArticleAsync(id, password).then(() => {
|
|
if (articleContainer.innerHTML.includes('密码错误')) {
|
|
passwordError.classList.remove('hidden');
|
|
} else {
|
|
passwordError.classList.add('hidden');
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// 初始化
|
|
function init() {
|
|
fetch(`/API/GetSerieDirectory/${UUID}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
window.tableOfContents = data;
|
|
headerTitle.innerText = data.title;
|
|
document.title = `${data.title} - 章节阅读器`;
|
|
renderSidebar();
|
|
setupSearch();
|
|
setupSidebarSearch();
|
|
expandAllSidebarSections();
|
|
|
|
if (data.document) {
|
|
loadArticleAsync(UUID);
|
|
// 展开,懒得写了
|
|
highlightActiveLink(UUID);
|
|
} else {
|
|
loadArticleAsync(`${UUID}_index`);
|
|
highlightActiveLink(`${UUID}_index`);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
// 错误处理保持不变
|
|
console.error('获取目录失败:', error);
|
|
articleContainer.innerHTML = `
|
|
<div class="flex flex-col items-center justify-center py-16">
|
|
<i class="fa fa-exclamation-triangle text-5xl text-gray-300 dark:text-gray-600 mb-4"></i>
|
|
<h3 class="text-xl font-medium mb-2">加载目录失败</h3>
|
|
<p class="text-gray-600 dark:text-gray-400">请检查网络连接或刷新页面</p>
|
|
</div>
|
|
`;
|
|
});
|
|
// 恢复主题设置
|
|
//const savedTheme = localStorage.getItem('theme');
|
|
//if (savedTheme === 'dark') {
|
|
// document.documentElement.classList.add('dark');
|
|
//}
|
|
sidebarToggle.addEventListener('click', openSidebar);
|
|
overlay.addEventListener('click', closeSidebar);
|
|
themeToggle.addEventListener('click', toggleTheme);
|
|
}
|
|
window.onload = init; |