// js/ui/immersive_layout_logic.js (function ImmersiveLayoutLogic(global) { let toggleBtn, immersiveContainer; let mainPageContainer, tocPopupElement, chatbotModalElement, dockElement; let immersiveTocArea, immersiveMainArea, immersiveChatbotArea, immersiveDockPlaceholderElement; let tocVsDockResizeHandle; let isTocDockResizing = false; // Flag to indicate dragging state let initialTocDockMouseY, initialTocHeight, initialDockHeight; // Original parent and next sibling of the elements to be moved let originalMainContainerParent = null; let originalMainContainerNextSibling = null; let originalTocPopupParent = null; let originalTocPopupNextSibling = null; let originalChatbotModalParent = null; let originalChatbotModalNextSibling = null; let originalDockElementParent = null; let originalDockElementNextSibling = null; let isImmersiveActive = false; let isSimpleImmersiveActive = false; // 新增:简单沉浸模式状态 const LS_IMMERSIVE_KEY = 'immersiveLayoutActive'; const LS_SIMPLE_IMMERSIVE_KEY = 'simpleImmersiveLayoutActive'; // 新增:简单沉浸模式存储键 const LS_PANEL_SIZES_KEY = 'immersivePanelSizes'; function initializeDomElements() { toggleBtn = document.getElementById('toggle-immersive-btn'); immersiveContainer = document.getElementById('immersive-layout-container'); mainPageContainer = document.querySelector('.container'); tocPopupElement = document.getElementById('toc-popup'); chatbotModalElement = document.getElementById('chatbot-modal'); dockElement = document.getElementById('bottom-left-dock'); immersiveTocArea = document.getElementById('immersive-toc-area'); immersiveMainArea = document.getElementById('immersive-main-content-area'); immersiveChatbotArea = document.getElementById('immersive-chatbot-area'); // Create the dock placeholder dynamically immersiveDockPlaceholderElement = document.createElement('div'); immersiveDockPlaceholderElement.id = 'toc-dock-placeholder'; // Basic styles can be applied here if not fully covered by CSS, or rely on CSS. // For now, CSS will handle styling based on the ID. return toggleBtn && immersiveContainer && mainPageContainer && tocPopupElement && immersiveTocArea && immersiveMainArea && immersiveChatbotArea && dockElement /* && immersiveDockPlaceholderElement (element itself exists, not a check if found in DOM here) */; } function reQueryDynamicElements() { if (!chatbotModalElement) { chatbotModalElement = document.getElementById('chatbot-modal'); } if (!mainPageContainer) mainPageContainer = document.querySelector('.container'); if (!tocPopupElement) tocPopupElement = document.getElementById('toc-popup'); if (!dockElement) dockElement = document.getElementById('bottom-left-dock'); } function storeOriginalPositions() { if (mainPageContainer) { originalMainContainerParent = mainPageContainer.parentNode; originalMainContainerNextSibling = mainPageContainer.nextSibling; } if (tocPopupElement) { originalTocPopupParent = tocPopupElement.parentNode; originalTocPopupNextSibling = tocPopupElement.nextSibling; } if (chatbotModalElement) { originalChatbotModalParent = chatbotModalElement.parentNode; originalChatbotModalNextSibling = chatbotModalElement.nextSibling; } else { console.warn('storeOriginalPositions: chatbotModalElement not found.'); } if (dockElement) { originalDockElementParent = dockElement.parentNode; originalDockElementNextSibling = dockElement.nextSibling; } else { console.warn('storeOriginalPositions: dockElement not found.'); } } function savePanelSizes() { if (!isImmersiveActive || !immersiveContainer || immersiveContainer.style.display === 'none') return; if (!immersiveTocArea || !immersiveMainArea || !immersiveChatbotArea) return; const tocWidth = immersiveTocArea.style.width; const mainWidth = immersiveMainArea.style.width; const chatbotWidth = immersiveChatbotArea.style.width; localStorage.setItem(LS_PANEL_SIZES_KEY, JSON.stringify({ toc: tocWidth, main: mainWidth, chatbot: chatbotWidth })); } function loadPanelSizes() { if (!immersiveTocArea || !immersiveMainArea || !immersiveChatbotArea) return; const savedSizes = localStorage.getItem(LS_PANEL_SIZES_KEY); if (savedSizes) { try { const sizes = JSON.parse(savedSizes); if (sizes.toc) immersiveTocArea.style.width = sizes.toc; if (sizes.chatbot) immersiveChatbotArea.style.width = sizes.chatbot; } catch (e) { console.error('Error loading panel sizes:', e); immersiveTocArea.style.width = '20%'; immersiveMainArea.style.flex = '1'; immersiveMainArea.style.width = ''; immersiveChatbotArea.style.width = '25%'; } } else { immersiveTocArea.style.width = '20%'; immersiveMainArea.style.flex = '1'; immersiveMainArea.style.width = ''; immersiveChatbotArea.style.width = '25%'; } } function initializeTocDockResizer() { if (!tocVsDockResizeHandle || !tocPopupElement || !immersiveDockPlaceholderElement || !immersiveTocArea) { console.warn("TOC vs Dock resizer: Missing one or more elements."); return; } // Ensure event listeners are not duplicated if called multiple times tocVsDockResizeHandle.removeEventListener('mousedown', handleTocDockDragStart); tocVsDockResizeHandle.addEventListener('mousedown', handleTocDockDragStart); } function handleTocDockDragStart(event) { event.preventDefault(); isTocDockResizing = true; initialTocDockMouseY = event.clientY; initialTocHeight = tocPopupElement.offsetHeight; initialDockHeight = immersiveDockPlaceholderElement.offsetHeight; // Add class to body for global cursor/selection styles document.body.classList.add('toc-dock-resizing'); // Add temporary flex-grow overrides if needed, or rely on flex-basis // tocPopupElement.style.flexGrow = '0'; // immersiveDockPlaceholderElement.style.flexGrow = '0'; document.addEventListener('mousemove', handleTocDockDragMove); document.addEventListener('mouseup', handleTocDockDragEnd); } function handleTocDockDragMove(event) { if (!isTocDockResizing) return; event.preventDefault(); const deltaY = event.clientY - initialTocDockMouseY; let newTocHeight = initialTocHeight + deltaY; let newDockHeight = initialDockHeight - deltaY; const minPanelHeight = 40; // Minimum height for TOC and Dock panels // Constrain TOC height if (newTocHeight < minPanelHeight) { newTocHeight = minPanelHeight; // Recalculate dock height based on constrained TOC newDockHeight = initialTocHeight + initialDockHeight - newTocHeight; } // Constrain Dock height if (newDockHeight < minPanelHeight) { newDockHeight = minPanelHeight; // Recalculate TOC height based on constrained Dock newTocHeight = initialTocHeight + initialDockHeight - newDockHeight; } // Ensure total height of tocArea children doesn't exceed tocArea height if it's fixed // For flexbox, adjusting flex-basis is usually better. // The sum of newTocHeight and newDockHeight should ideally be initialTocHeight + initialDockHeight. // The logic above ensures this if one hits minPanelHeight. // Apply new heights using flex-basis for better control in a flex container tocPopupElement.style.flexBasis = newTocHeight + 'px'; immersiveDockPlaceholderElement.style.flexBasis = newDockHeight + 'px'; // If not using flex-basis, and want to force height and disable grow/shrink during drag: // tocPopupElement.style.height = newTocHeight + 'px'; // immersiveDockPlaceholderElement.style.height = newDockHeight + 'px'; // tocPopupElement.style.flexGrow = '0'; // immersiveDockPlaceholderElement.style.flexGrow = '0'; } function handleTocDockDragEnd() { if (!isTocDockResizing) return; isTocDockResizing = false; document.body.classList.remove('toc-dock-resizing'); document.removeEventListener('mousemove', handleTocDockDragMove); document.removeEventListener('mouseup', handleTocDockDragEnd); // Restore original flex-grow properties if they were changed during drag // tocPopupElement.style.flexGrow = ''; // Or to its original value e.g., '10' // immersiveDockPlaceholderElement.style.flexGrow = ''; // Or to its original value e.g., '1' // However, since we are using flex-basis, the original flex-grow values from CSS should still apply // once flex-basis is set, unless grow/shrink are explicitly set to 0. // The CSS has flex-grow: 10 for toc and flex-grow: 1 for dock placeholder. // Setting flex-basis should work fine with these grow factors if space allows. // Optional: Save the new heights/proportions to localStorage // const tocAreaHeight = immersiveTocArea.offsetHeight; // if (tocAreaHeight > 0) { // const tocRatio = tocPopupElement.offsetHeight / tocAreaHeight; // localStorage.setItem('immersiveTocDockRatio', tocRatio.toFixed(4)); // } } function destroyTocDockResizer() { if (tocVsDockResizeHandle) { tocVsDockResizeHandle.removeEventListener('mousedown', handleTocDockDragStart); } // Clean up global listeners if somehow left hanging (should be removed by handleTocDockDragEnd) document.removeEventListener('mousemove', handleTocDockDragMove); document.removeEventListener('mouseup', handleTocDockDragEnd); document.body.classList.remove('toc-dock-resizing'); isTocDockResizing = false; // Reset flag } function enterImmersiveMode() { // 检查是否为移动端设备 if (window.innerWidth <= 700) { console.warn('拒绝在移动端(≤700px)进入沉浸式布局'); return; } reQueryDynamicElements(); let missingElements = []; if (!immersiveContainer) missingElements.push('immersiveContainer'); if (!mainPageContainer) missingElements.push('mainPageContainer'); if (!tocPopupElement) missingElements.push('tocPopupElement'); if (!chatbotModalElement) missingElements.push('chatbotModalElement'); if (!dockElement) missingElements.push('dockElement'); if (!immersiveTocArea) missingElements.push('immersiveTocArea'); if (!immersiveMainArea) missingElements.push('immersiveMainArea'); if (!immersiveChatbotArea) missingElements.push('immersiveChatbotArea'); if (!immersiveDockPlaceholderElement) missingElements.push('immersiveDockPlaceholderElement (logic error if this happens)'); if (missingElements.length > 0) { console.warn('Immersive mode elements not found:', missingElements.join(', ')); return; } isImmersiveActive = true; storeOriginalPositions(); // 添加进入动画类 document.body.classList.add('immersive-entering'); immersiveContainer.style.opacity = '0'; immersiveContainer.style.transform = 'scale(0.95)'; immersiveContainer.style.transition = 'opacity 0.4s ease, transform 0.4s ease'; // Append TOC content first if (tocPopupElement && immersiveTocArea) { immersiveTocArea.appendChild(tocPopupElement); } // Create and insert the resize handle between TOC and Dock Placeholder if (immersiveTocArea) { if (!tocVsDockResizeHandle) { // Create if it doesn't exist tocVsDockResizeHandle = document.createElement('div'); tocVsDockResizeHandle.id = 'toc-vs-dock-resize-handle'; } if (tocPopupElement && tocPopupElement.parentNode === immersiveTocArea) { immersiveTocArea.insertBefore(tocVsDockResizeHandle, tocPopupElement.nextSibling); } else { immersiveTocArea.appendChild(tocVsDockResizeHandle); } } // Then append the dock placeholder to TOC area if (immersiveDockPlaceholderElement && immersiveTocArea) { if (tocVsDockResizeHandle && tocVsDockResizeHandle.parentNode === immersiveTocArea) { immersiveTocArea.insertBefore(immersiveDockPlaceholderElement, tocVsDockResizeHandle.nextSibling); } else { immersiveTocArea.appendChild(immersiveDockPlaceholderElement); } } // Move other elements if (mainPageContainer && immersiveMainArea) { immersiveMainArea.appendChild(mainPageContainer); } if (chatbotModalElement && immersiveChatbotArea) { immersiveChatbotArea.appendChild(chatbotModalElement); } // Move the actual dock into its placeholder if (dockElement && immersiveDockPlaceholderElement) { immersiveDockPlaceholderElement.appendChild(dockElement); // Force Dock to be expanded in immersive mode if (dockElement.classList.contains('dock-collapsed')) { dockElement.classList.remove('dock-collapsed'); const dockToggleBtn = document.getElementById('dock-toggle-btn'); if (dockToggleBtn) { dockToggleBtn.innerHTML = ''; dockToggleBtn.title = '折叠'; } if (typeof window !== 'undefined' && window.docIdForLocalStorage) { localStorage.setItem(`dockCollapsed_${window.docIdForLocalStorage}`, 'false'); } } } document.body.classList.add('immersive-active', 'no-scroll'); immersiveContainer.style.display = 'flex'; // 简单的强制重新计算,修复初始化时的布局问题 setTimeout(() => { if (immersiveContainer) { immersiveContainer.offsetHeight; // 触发重新布局 } }, 0); // 动画进入效果 requestAnimationFrame(() => { immersiveContainer.style.opacity = '1'; immersiveContainer.style.transform = 'scale(1)'; setTimeout(() => { document.body.classList.remove('immersive-entering'); immersiveContainer.style.transition = ''; }, 400); }); if (toggleBtn) { toggleBtn.innerHTML = ''; toggleBtn.classList.add('immersive-exit-btn-active'); toggleBtn.title = '退出沉浸模式'; } // 其他初始化逻辑保持不变... if (typeof window.refreshTocList === 'function') { window.refreshTocList(); } if (window.ChatbotUI && typeof window.ChatbotUI.updateChatbotUI === 'function') { window.isChatbotOpen = true; window.isChatbotFullscreen = false; window.forceChatbotWidthReset = true; window.ChatbotUI.updateChatbotUI(); } if (window.DockLogic && typeof window.DockLogic.updateStats === 'function' && window.data && window.currentVisibleTabId) { dockElement.style.display = ''; window.DockLogic.updateStats(window.data, window.currentVisibleTabId); } setTimeout(() => { if (window.DockLogic) { if (typeof window.DockLogic.unbindScrollForCurrentScrollable === 'function') { console.log("[ImmersiveLayout] 进入沉浸模式前,先解绑旧的滚动事件"); window.DockLogic.unbindScrollForCurrentScrollable(); } if (typeof window.DockLogic.forceUpdateReadingProgress === 'function') { console.log("[ImmersiveLayout] 进入沉浸模式后,延迟调用 forceUpdateReadingProgress"); window.DockLogic.forceUpdateReadingProgress(); } } // 为滚动容器添加标记 class,供 JS 查询使用 if (immersiveMainArea) { const container = immersiveMainArea.querySelector('.container'); if (container) { const tabContent = container.querySelector('.tab-content'); if (tabContent) { // 添加 .js-scroll-container 标记,供 DockLogic 等模块查询 // CSS 通过 body.immersive-active 选择器自动控制 overflow tabContent.classList.add('js-scroll-container'); console.log("[ImmersiveLayout] 已为 tab-content 添加 js-scroll-container 标记"); } } } }, 300); // Force TOC to be expanded in immersive mode if (tocPopupElement && !tocPopupElement.classList.contains('toc-expanded')) { const tocExpandBtn = document.getElementById('toc-expand-btn'); if (tocExpandBtn) { tocPopupElement.classList.add('toc-expanded'); const icon = tocExpandBtn.querySelector('i'); if (icon) { icon.classList.remove('fa-angles-right'); icon.classList.add('fa-angles-left'); } tocExpandBtn.title = '收起目录'; } } loadPanelSizes(); initializeTocDockResizer(); localStorage.setItem(LS_IMMERSIVE_KEY, 'true'); document.dispatchEvent(new CustomEvent('immersiveModeEntered')); } function exitImmersiveMode() { reQueryDynamicElements(); isImmersiveActive = false; // 添加退出动画 document.body.classList.add('immersive-exiting'); if (immersiveContainer) { immersiveContainer.style.transition = 'opacity 0.3s ease, transform 0.3s ease'; immersiveContainer.style.opacity = '0'; immersiveContainer.style.transform = 'scale(0.98)'; } setTimeout(() => { destroyTocDockResizer(); // Remove the TOC vs Dock resize handle if (tocVsDockResizeHandle && tocVsDockResizeHandle.parentNode === immersiveTocArea) { immersiveTocArea.removeChild(tocVsDockResizeHandle); } // 恢复元素位置的逻辑保持不变... if (originalTocPopupParent && tocPopupElement && tocPopupElement.parentNode === immersiveTocArea) { originalTocPopupParent.insertBefore(tocPopupElement, originalTocPopupNextSibling); } else if (tocPopupElement && immersiveTocArea.contains(tocPopupElement)) { immersiveTocArea.removeChild(tocPopupElement); if (originalTocPopupParent) { originalTocPopupParent.insertBefore(tocPopupElement, originalTocPopupNextSibling); } } if (originalMainContainerParent && mainPageContainer && mainPageContainer.parentNode === immersiveMainArea) { originalMainContainerParent.insertBefore(mainPageContainer, originalMainContainerNextSibling); } else if (mainPageContainer && immersiveMainArea.contains(mainPageContainer)) { immersiveMainArea.removeChild(mainPageContainer); if (originalMainContainerParent) { originalMainContainerParent.insertBefore(mainPageContainer, originalMainContainerNextSibling); } } if (chatbotModalElement && originalChatbotModalParent && chatbotModalElement.parentNode === immersiveChatbotArea) { originalChatbotModalParent.insertBefore(chatbotModalElement, originalChatbotModalNextSibling); } else if (chatbotModalElement && immersiveChatbotArea.contains(chatbotModalElement)) { immersiveChatbotArea.removeChild(chatbotModalElement); if (originalChatbotModalParent) { originalChatbotModalParent.insertBefore(chatbotModalElement, originalChatbotModalNextSibling); } } else if (!chatbotModalElement && originalChatbotModalParent) { immersiveChatbotArea.innerHTML = ''; } if (dockElement && originalDockElementParent) { if (immersiveDockPlaceholderElement && immersiveDockPlaceholderElement.contains(dockElement)) { immersiveDockPlaceholderElement.removeChild(dockElement); } originalDockElementParent.insertBefore(dockElement, originalDockElementNextSibling); } else if (dockElement && immersiveDockPlaceholderElement && immersiveDockPlaceholderElement.contains(dockElement)){ immersiveDockPlaceholderElement.removeChild(dockElement); } document.body.classList.remove('immersive-active', 'no-scroll', 'immersive-exiting'); if (immersiveContainer) { immersiveContainer.style.display = 'none'; immersiveContainer.style.transition = ''; immersiveContainer.style.opacity = ''; immersiveContainer.style.transform = ''; } // 清理滚动容器标记 class if (mainPageContainer) { const tabContent = mainPageContainer.querySelector('.tab-content'); if (tabContent) { tabContent.classList.remove('js-scroll-container'); console.log("[ImmersiveLayout] 已移除 tab-content 的 js-scroll-container 标记"); } } if (toggleBtn) { toggleBtn.innerHTML = ''; toggleBtn.classList.remove('immersive-exit-btn-active'); toggleBtn.title = '进入沉浸式布局'; } // 其他退出逻辑保持不变... if (typeof window.refreshTocList === 'function') { window.refreshTocList(); } if (typeof window.docIdForLocalStorage !== 'undefined' && window.docIdForLocalStorage) { const savedChatbotOpenState = localStorage.getItem(`chatbotOpenState_${window.docIdForLocalStorage}`); if (savedChatbotOpenState === 'true') { window.isChatbotOpen = true; } else if (savedChatbotOpenState === 'false') { window.isChatbotOpen = false; } } if (window.ChatbotUI && typeof window.ChatbotUI.updateChatbotUI === 'function') { window.ChatbotUI.updateChatbotUI(); } if (window.DockLogic && typeof window.DockLogic.updateStats === 'function' && window.data && window.currentVisibleTabId) { dockElement.style.display = ''; window.DockLogic.updateStats(window.data, window.currentVisibleTabId); } setTimeout(() => { if (window.DockLogic) { if (typeof window.DockLogic.unbindScrollForCurrentScrollable === 'function') { console.log("[ImmersiveLayout] 退出沉浸模式前,先解绑旧的滚动事件"); window.DockLogic.unbindScrollForCurrentScrollable(); } if (typeof window.DockLogic.forceUpdateReadingProgress === 'function') { console.log("[ImmersiveLayout] 退出沉浸模式后,延迟调用 forceUpdateReadingProgress"); window.DockLogic.forceUpdateReadingProgress(); } } }, 300); localStorage.setItem(LS_IMMERSIVE_KEY, 'false'); document.dispatchEvent(new CustomEvent('immersiveModeExited')); }, 300); } function initResizeHandles() { const handles = document.querySelectorAll('.immersive-resize-handle'); let activeHandle = null; let startX, startWidthPrev, startWidthNext; handles.forEach(handle => { handle.addEventListener('mousedown', function(e) { activeHandle = this; startX = e.clientX; const prevPanelId = activeHandle.dataset.targetPrev; const nextPanelId = activeHandle.dataset.targetNext; const prevPanel = document.getElementById(prevPanelId); const nextPanel = document.getElementById(nextPanelId); if (!prevPanel || !nextPanel) { console.warn(`Resize panels not found: ${prevPanelId} or ${nextPanelId}`); activeHandle = null; return; } startWidthPrev = prevPanel.offsetWidth; startWidthNext = nextPanel.offsetWidth; document.body.classList.add('immersive-dragging'); document.body.style.userSelect = 'none'; document.body.style.cursor = 'col-resize'; e.preventDefault(); }); }); document.addEventListener('mousemove', function(e) { if (!activeHandle) return; const dx = e.clientX - startX; const prevPanel = document.getElementById(activeHandle.dataset.targetPrev); const nextPanel = document.getElementById(activeHandle.dataset.targetNext); if (!prevPanel || !nextPanel) return; const newWidthPrev = startWidthPrev + dx; const newWidthNext = startWidthNext - dx; const minPanelWidth = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--immersive-panel-min-width')) || 80; if (newWidthPrev >= minPanelWidth && newWidthNext >= minPanelWidth) { prevPanel.style.width = newWidthPrev + 'px'; nextPanel.style.width = newWidthNext + 'px'; // 平滑的过渡动画 prevPanel.style.transition = 'none'; nextPanel.style.transition = 'none'; } }); document.addEventListener('mouseup', function() { if (activeHandle) { savePanelSizes(); // 恢复样式 document.body.classList.remove('immersive-dragging'); document.body.style.userSelect = ''; document.body.style.cursor = ''; // 恢复过渡动画 const prevPanel = document.getElementById(activeHandle.dataset.targetPrev); const nextPanel = document.getElementById(activeHandle.dataset.targetNext); if (prevPanel) prevPanel.style.transition = ''; if (nextPanel) nextPanel.style.transition = ''; activeHandle = null; } }); } function mainInit() { if (!initializeDomElements()) { console.warn('Immersive layout core static elements not found on DOMContentLoaded. Retrying shortly...'); setTimeout(mainInit, 500); return; } reQueryDynamicElements(); // 标准沉浸模式切换按钮 const standardToggleBtn = document.getElementById('toggle-immersive-btn'); // 简单沉浸模式切换按钮 const simpleToggleBtn = document.getElementById('toggle-simple-immersive-btn'); // 标准沉浸模式功能 if (standardToggleBtn) { standardToggleBtn.addEventListener('click', () => { // 检查是否为移动端设备(屏幕宽度小于等于700px) if (window.innerWidth <= 700) { console.warn('沉浸式布局在移动端(≤700px)不可用'); // 可选:显示提示消息 if (window.showToast) { window.showToast('沉浸式布局在手机端不可用', 'warning'); } else { alert('沉浸式布局在手机端不可用,请在更大的屏幕上使用'); } return; } if (isImmersiveActive) { exitImmersiveMode(); } else { enterImmersiveMode(); } }); } // 简单沉浸模式功能 if (simpleToggleBtn) { simpleToggleBtn.addEventListener('click', () => { isSimpleImmersiveActive = !isSimpleImmersiveActive; // 检查是否在"原始文件"标签页(PDF查看器) const isOriginalFileTab = window.currentVisibleTabId === 'original-file'; const pdfIframeWrapper = document.getElementById('pdf-iframe-wrapper'); const pdfIframe = document.getElementById('pdf-viewer-iframe'); const mainContainer = document.querySelector('.container'); if (isSimpleImmersiveActive) { // 如果是PDF查看器标签页,进行特殊处理 if (isOriginalFileTab && pdfIframeWrapper && mainContainer) { // 添加特殊类用于PDF全屏模式 document.body.classList.add('simple-immersive-pdf-mode'); // 移除container的padding mainContainer.dataset.originalPadding = mainContainer.style.padding || ''; mainContainer.style.padding = '0 !important'; // 让iframe wrapper充满container(接近全屏) pdfIframeWrapper.style.cssText = ` width: 100%; height: calc(100vh - 20px); min-height: calc(100vh - 20px); position: relative; background: #525659; `; if (pdfIframe) { pdfIframe.style.cssText = ` width: 100%; height: 100%; border: none; `; } // 隐藏其他UI元素 const elementsToHide = [ { selector: '.tabs-container', el: document.querySelector('.tabs-container') }, { selector: '.history-export-controls', el: document.querySelector('.history-export-controls') }, { selector: '#bottom-left-dock', el: document.getElementById('bottom-left-dock') }, { selector: '#toc-popup', el: document.getElementById('toc-popup') }, { selector: '#fileName', el: document.getElementById('fileName') }, { selector: '#fileMeta', el: document.getElementById('fileMeta') } ]; elementsToHide.forEach(item => { if (item.el) { item.el.dataset.originalDisplay = item.el.style.display || ''; item.el.style.display = 'none'; } }); // 隐藏loading指示器 const loading = document.getElementById('pdf-viewer-loading'); if (loading) loading.style.display = 'none'; // 确保iframe显示 if (pdfIframe) pdfIframe.style.display = 'block'; } else { // 非PDF查看器标签页,使用原有的简单沉浸模式 document.body.classList.add('simple-immersive-pdf-mode'); } simpleToggleBtn.innerHTML = ''; simpleToggleBtn.title = '退出简单沉浸模式'; localStorage.setItem(LS_SIMPLE_IMMERSIVE_KEY, 'true'); } else { // 退出简单沉浸模式 document.body.classList.remove('simple-immersive-pdf-mode'); document.body.classList.remove('simple-immersive-pdf-mode'); // 恢复container的padding if (mainContainer && mainContainer.dataset.originalPadding !== undefined) { mainContainer.style.padding = mainContainer.dataset.originalPadding; delete mainContainer.dataset.originalPadding; } // 恢复所有被隐藏的元素 const elementsToRestore = [ { selector: '.tabs-container', el: document.querySelector('.tabs-container') }, { selector: '.history-export-controls', el: document.querySelector('.history-export-controls') }, { selector: '#bottom-left-dock', el: document.getElementById('bottom-left-dock') }, { selector: '#toc-popup', el: document.getElementById('toc-popup') }, { selector: '#fileName', el: document.getElementById('fileName') }, { selector: '#fileMeta', el: document.getElementById('fileMeta') } ]; elementsToRestore.forEach(item => { if (item.el && item.el.dataset.originalDisplay !== undefined) { item.el.style.display = item.el.dataset.originalDisplay; delete item.el.dataset.originalDisplay; } }); // 恢复iframe wrapper的原始样式 if (pdfIframeWrapper) { pdfIframeWrapper.style.cssText = ` width: 100%; height: 100%; min-height: 500px; position: relative; background: #525659; `; } simpleToggleBtn.innerHTML = ''; simpleToggleBtn.title = '进入简单沉浸模式'; localStorage.setItem(LS_SIMPLE_IMMERSIVE_KEY, 'false'); } }); } initResizeHandles(); // 监听窗口大小变化,如果变成移动端尺寸则自动退出沉浸模式 function handleWindowResize() { if (window.innerWidth <= 700 && isImmersiveActive) { console.log('检测到屏幕缩小到移动端尺寸,自动退出沉浸式布局'); exitImmersiveMode(); } } // 添加窗口大小变化监听器 window.addEventListener('resize', handleWindowResize); // Restore immersive state from localStorage const savedImmersiveState = localStorage.getItem(LS_IMMERSIVE_KEY); if (savedImmersiveState === 'true') { // 检查是否为移动端,如果是则不恢复沉浸模式 if (window.innerWidth <= 700) { console.log('检测到移动端设备,不恢复沉浸式布局状态'); localStorage.setItem(LS_IMMERSIVE_KEY, 'false'); // 清除保存的状态 return; } // Slight delay to ensure other initializations (like TOC, Chatbot) can occur first // especially if they also interact with elements moved by immersive mode. setTimeout(() => { if (!isImmersiveActive) { // Check again in case of race conditions or manual toggle enterImmersiveMode(); } }, 200); // Adjust delay if needed } // Restore simple immersive state from localStorage const savedSimpleImmersiveState = localStorage.getItem(LS_SIMPLE_IMMERSIVE_KEY); if (savedSimpleImmersiveState === 'true') { // 检查是否为移动端,如果是则不启用简单沉浸模式 if (window.innerWidth <= 700) { console.log('检测到移动端设备,不启用简单沉浸式布局状态'); localStorage.setItem(LS_SIMPLE_IMMERSIVE_KEY, 'false'); // 清除保存的状态 } else { // 如果不在标准沉浸模式下,才启用简单沉浸模式 if (!isImmersiveActive) { setTimeout(() => { if (!isSimpleImmersiveActive) { document.body.classList.add('simple-immersive-pdf-mode'); isSimpleImmersiveActive = true; if (toggleBtn) { toggleBtn.innerHTML = ''; toggleBtn.title = '退出简单沉浸模式'; } } }, 200); } } } console.log('Immersive layout logic initialized.'); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', mainInit); } else { mainInit(); } global.ImmersiveLayout = { isActive: () => isImmersiveActive, isSimpleActive: () => isSimpleImmersiveActive, // 新增:简单沉浸模式状态查询 enter: enterImmersiveMode, exit: exitImmersiveMode }; })(window);