paper-burner/js/ui/chunk_compare_integration.js

443 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 分块对比优化器集成脚本
* 负责将优化器与现有的历史详情页面集成
*/
(function() {
'use strict';
// 等待页面和优化器加载完成
function initializeChunkCompareOptimization() {
// 避免重复初始化(多次 setTimeout 或脚本重复触发)
if (window.__chunkCompareIntegrationInitialized) {
return;
}
if (!window.ChunkCompareOptimizer || !window.ChunkCompareOptimizer.instance) {
console.warn('[ChunkIntegration] 优化器未加载,延迟初始化');
setTimeout(initializeChunkCompareOptimization, 100);
return;
}
console.log('[ChunkIntegration] 开始集成分块对比优化器');
// 标记已初始化,防止重复绑定事件
window.__chunkCompareIntegrationInitialized = true;
// 保存原有的渲染函数引用(如需使用,可在后续扩展)
const originalShowTab = window.showTab;
// 增强切换按钮功能
enhanceSwapChunksButton();
// 增强性能监控
enhancePerformanceMonitoring();
// 绑定优化器控制事件
bindOptimizerControls();
console.log('[ChunkIntegration] 分块对比优化器集成完成');
}
/**
* 增强切换按钮功能
*/
function enhanceSwapChunksButton() {
// 使用事件委托处理切换按钮
document.addEventListener('click', function(e) {
if (e.target.id === 'swap-chunks-btn') {
e.preventDefault();
handleChunkSwap();
}
// 处理性能模式切换
if (e.target.id === 'performance-toggle-btn' || e.target.closest('#performance-toggle-btn')) {
e.preventDefault();
togglePerformanceMode();
}
});
}
/**
* 处理分块位置切换
*/
function handleChunkSwap() {
const startTime = performance.now();
console.log('[ChunkIntegration] 开始切换分块位置');
// 切换全局标志
window.isOriginalFirstInChunkCompare = !window.isOriginalFirstInChunkCompare;
// 保存用户偏好
if (window.docIdForLocalStorage) {
localStorage.setItem(
`isOriginalFirst_${window.docIdForLocalStorage}`,
window.isOriginalFirstInChunkCompare
);
}
// 更新按钮状态
const swapBtn = document.getElementById('swap-chunks-btn');
if (swapBtn) {
swapBtn.style.transform = window.isOriginalFirstInChunkCompare ? 'rotate(0deg)' : 'rotate(180deg)';
swapBtn.title = window.isOriginalFirstInChunkCompare ? '切换原文/译文位置' : '切换译文/原文位置';
}
// 如果使用优化器,需要重新渲染
if (window.ChunkCompareOptimizer && window.ChunkCompareOptimizer.instance) {
// 清除缓存以重新渲染
window.ChunkCompareOptimizer.instance.renderCache.clear();
// 重新显示当前标签
if (typeof window.showTab === 'function') {
window.showTab('chunk-compare');
}
}
const endTime = performance.now();
console.log(`[ChunkIntegration] 分块位置切换完成,耗时: ${(endTime - startTime).toFixed(2)}ms`);
}
/**
* 切换性能模式
*/
function togglePerformanceMode() {
const container = document.querySelector('.chunk-compare-container');
const toggleBtn = document.getElementById('performance-toggle-btn');
if (!container || !toggleBtn) return;
const isPerformanceMode = container.classList.contains('performance-mode');
if (isPerformanceMode) {
// 关闭性能模式
container.classList.remove('performance-mode');
toggleBtn.classList.remove('active');
toggleBtn.title = '启用性能模式';
console.log('[ChunkIntegration] 性能模式已关闭');
} else {
// 启用性能模式
container.classList.add('performance-mode');
toggleBtn.classList.add('active');
toggleBtn.title = '关闭性能模式';
console.log('[ChunkIntegration] 性能模式已启用');
}
// 保存用户偏好
localStorage.setItem('chunkComparePerformanceMode', !isPerformanceMode);
}
/**
* 增强性能监控
*/
function enhancePerformanceMonitoring() {
// 监控分块对比的渲染性能
const originalConsoleTime = console.time;
const originalConsoleTimeEnd = console.timeEnd;
console.time = function(label) {
if (label.includes('分块对比') || label.includes('chunk')) {
performance.mark(`${label}-start`);
}
return originalConsoleTime.apply(this, arguments);
};
console.timeEnd = function(label) {
if (label.includes('分块对比') || label.includes('chunk')) {
performance.mark(`${label}-end`);
try {
performance.measure(label, `${label}-start`, `${label}-end`);
const measure = performance.getEntriesByName(label, 'measure')[0];
if (measure) {
console.log(`[性能监控] ${label}: ${measure.duration.toFixed(2)}ms`);
// 如果渲染时间过长,提示用户
if (measure.duration > 2000) { // 超过2秒
showPerformanceWarning(label, measure.duration);
}
}
} catch (error) {
console.warn('性能测量失败:', error);
}
}
return originalConsoleTimeEnd.apply(this, arguments);
};
}
/**
* 显示性能警告
*/
function showPerformanceWarning(operation, duration) {
const warningEl = document.createElement('div');
warningEl.className = 'performance-warning';
warningEl.innerHTML = `
<div class="warning-content">
<i class="fas fa-exclamation-triangle"></i>
<span>渲染耗时较长 (${(duration / 1000).toFixed(1)}秒)</span>
<button onclick="this.parentElement.parentElement.remove()">×</button>
</div>
`;
warningEl.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: #fef3cd;
border: 1px solid #fecba1;
border-radius: 6px;
padding: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
z-index: 10000;
max-width: 300px;
`;
document.body.appendChild(warningEl);
// 5秒后自动移除
setTimeout(() => {
if (warningEl.parentElement) {
warningEl.remove();
}
}, 5000);
}
/**
* 绑定优化器控制事件
*/
function bindOptimizerControls() {
// 恢复用户偏好设置
const savedPerformanceMode = localStorage.getItem('chunkComparePerformanceMode');
if (savedPerformanceMode === 'true') {
setTimeout(() => {
const container = document.querySelector('.chunk-compare-container');
const toggleBtn = document.getElementById('performance-toggle-btn');
if (container && toggleBtn) {
container.classList.add('performance-mode');
toggleBtn.classList.add('active');
}
}, 100);
}
// 绑定键盘快捷键(仅绑定一次)
if (!window.__chunkCompareKeydownBound) {
window.__chunkCompareKeydownBound = true;
document.addEventListener('keydown', function(e) {
// Ctrl/Cmd + Shift + P: 切换性能模式
if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'P') {
e.preventDefault();
togglePerformanceMode();
}
// Ctrl/Cmd + Shift + S: 切换原文/译文位置
if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'S') {
e.preventDefault();
const swapBtn = document.getElementById('swap-chunks-btn');
if (swapBtn && window.currentVisibleTabId === 'chunk-compare') {
handleChunkSwap();
}
}
});
}
// 添加快捷键提示
addKeyboardShortcutHints();
}
/**
* 添加键盘快捷键提示
*/
function addKeyboardShortcutHints() {
// 防止重复绑定观察者
if (window.__chunkCompareHintsObserverBound) return;
window.__chunkCompareHintsObserverBound = true;
// 监听分块对比标签的激活
const observer = new MutationObserver(function(mutations) {
for (const mutation of mutations) {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
const target = mutation.target;
if (target.id === 'tab-chunk-compare' && target.classList.contains('active')) {
showKeyboardHints(observer);
}
}
}
});
const chunkTab = document.getElementById('tab-chunk-compare');
if (chunkTab) {
observer.observe(chunkTab, { attributes: true });
}
}
/**
* 显示键盘快捷键提示
*/
function showKeyboardHints(observerInstance) {
// 本地与内存双重防抖:防止多次渲染
if (window.__chunkCompareHintsShown || localStorage.getItem('chunkCompareHintsShown') === 'true') {
return;
}
// 如果DOM中已存在同名元素也不再渲染
if (document.querySelector('.keyboard-hints')) return;
// 先设置标记,避免短时间内重复触发造成多次追加
window.__chunkCompareHintsShown = true;
localStorage.setItem('chunkCompareHintsShown', 'true');
setTimeout(() => {
// 若已存在,不重复创建
if (document.querySelector('.keyboard-hints')) return;
const hintsEl = document.createElement('div');
hintsEl.className = 'keyboard-hints';
hintsEl.innerHTML = `
<div class="hints-content">
<h4>键盘快捷键</h4>
<div class="hint-item">
<kbd>Ctrl/Cmd + Shift + P</kbd>
<span>切换性能模式</span>
</div>
<div class="hint-item">
<kbd>Ctrl/Cmd + Shift + S</kbd>
<span>切换原文/译文位置</span>
</div>
<button class="close-hints" onclick="this.parentElement.parentElement.remove()">知道了</button>
</div>
`;
hintsEl.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 20px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
z-index: 10001;
max-width: 300px;
`;
document.body.appendChild(hintsEl);
// 10秒后自动移除
setTimeout(() => {
if (hintsEl.parentElement) {
hintsEl.remove();
}
}, 10000);
// 观察者可在首次显示后断开,避免无意义监听
if (observerInstance && typeof observerInstance.disconnect === 'function') {
observerInstance.disconnect();
}
}, 500);
}
/**
* 优化分块导航
*/
function enhanceChunkNavigation() {
// 添加快速导航功能
document.addEventListener('click', function(e) {
if (e.target.classList.contains('block-nav-btn')) {
e.preventDefault();
const direction = e.target.dataset.dir;
const currentBlock = parseInt(e.target.dataset.block);
if (direction === 'prev' && currentBlock > 0) {
scrollToChunk(currentBlock - 1);
} else if (direction === 'next') {
scrollToChunk(currentBlock + 1);
}
}
});
}
/**
* 滚动到指定分块
*/
function scrollToChunk(index) {
const chunk = document.getElementById(`chunk-${index}`) || document.getElementById(`block-${index}`);
if (chunk) {
chunk.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
// 高亮显示目标分块
chunk.classList.add('chunk-highlight');
setTimeout(() => {
chunk.classList.remove('chunk-highlight');
}, 1500);
}
}
/**
* 添加分块高亮样式
*/
function addChunkHighlightStyles() {
const style = document.createElement('style');
style.textContent = `
.chunk-highlight {
box-shadow: 0 0 0 3px #3b82f6 !important;
transition: box-shadow 0.3s ease !important;
}
.performance-warning .warning-content {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.9em;
color: #92400e;
}
.keyboard-hints .hints-content h4 {
margin: 0 0 12px 0;
color: #1e293b;
font-size: 1.1em;
}
.keyboard-hints .hint-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
font-size: 0.9em;
}
.keyboard-hints kbd {
background: #f1f5f9;
border: 1px solid #cbd5e1;
border-radius: 3px;
padding: 2px 6px;
font-size: 0.8em;
font-family: monospace;
}
.keyboard-hints .close-hints {
background: #3b82f6;
color: white;
border: none;
border-radius: 4px;
padding: 6px 12px;
cursor: pointer;
font-size: 0.9em;
margin-top: 12px;
width: 100%;
}
`;
document.head.appendChild(style);
}
// 初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
addChunkHighlightStyles();
enhanceChunkNavigation();
initializeChunkCompareOptimization();
});
} else {
addChunkHighlightStyles();
enhanceChunkNavigation();
initializeChunkCompareOptimization();
}
})();