// clab-tooltip.js - 完全隔离事件版本(修改后的显示位置逻辑) (function() { // 全局变量存储从 RN.html 提取的内容 let rnContentCache = {}; let isRnContentLoaded = false; let activeTooltip = null; let hideTimer = null; let isMouseOverTooltip = false; // 从 RN.html 提取内容(保持不变) async function loadRnContent() { try { console.log('加载 RN.html...'); const response = await fetch('RN.html'); if (!response.ok) throw new Error(`HTTP error: ${response.status}`); const htmlText = await response.text(); const parser = new DOMParser(); const rnDoc = parser.parseFromString(htmlText, 'text/html'); // 查找所有包含 data-options 的元素 const optionElements = rnDoc.querySelectorAll('[data-options]'); console.log(`找到 ${optionElements.length} 个 data-options 元素`); optionElements.forEach(element => { const optionValue = element.getAttribute('data-options'); if (!optionValue) return; // 向前查找最近的 blockquote let prevElement = element.previousElementSibling; let blockquote = null; // 先找前一个兄弟元素 while (prevElement) { if (prevElement.tagName === 'BLOCKQUOTE') { blockquote = prevElement; break; } prevElement = prevElement.previousElementSibling; } // 如果没找到,向上查找 if (!blockquote) { let parent = element.parentElement; while (parent) { let sibling = parent.previousElementSibling; while (sibling) { if (sibling.tagName === 'BLOCKQUOTE') { blockquote = sibling; break; } sibling = sibling.previousElementSibling; } if (blockquote) break; parent = parent.parentElement; } } if (blockquote) { const lis = blockquote.querySelectorAll('li'); if (lis.length > 0) { const liContents = Array.from(lis).map(li => li.textContent.trim()); if (!rnContentCache[optionValue]) { rnContentCache[optionValue] = []; } // 存储所有引用 rnContentCache[optionValue].push({ contents: liContents }); } } }); isRnContentLoaded = true; console.log('内容加载完成'); Object.keys(rnContentCache).forEach(key => { console.log(`"${key}": ${rnContentCache[key].length} Questions`); }); } catch (error) { console.error('加载失败:', error); } } // 创建 tooltip(保持不变) function createTooltip() { const tooltip = document.createElement('div'); tooltip.className = 'clab-tooltip'; tooltip.id = 'clab-tooltip-element'; // 完全阻止所有事件冒泡 const stopAllEvents = (e) => { e.stopPropagation(); e.stopImmediatePropagation(); e.preventDefault(); return false; }; // 阻止所有可能的事件 const events = [ 'mousedown', 'mouseup', 'click', 'dblclick', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave', 'wheel', 'scroll', 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'pointerdown', 'pointermove', 'pointerup', 'pointercancel', 'dragstart', 'dragover', 'drop' ]; events.forEach(eventType => { tooltip.addEventListener(eventType, stopAllEvents, true); // 捕获阶段 tooltip.addEventListener(eventType, stopAllEvents, false); // 冒泡阶段 }); // 允许 wheel 事件用于滚动,但阻止冒泡 tooltip.addEventListener('wheel', function(e) { e.stopPropagation(); e.stopImmediatePropagation(); // 允许默认的滚动行为 }, { passive: false }); // 允许鼠标在 tooltip 内移动 tooltip.addEventListener('mousemove', function(e) { e.stopPropagation(); }, { passive: true }); document.body.appendChild(tooltip); return tooltip; } // 显示 tooltip - 已修改位置逻辑 function showTooltip(element, tooltip) { const rect = element.getBoundingClientRect(); const optionValue = element.getAttribute('data-options'); // 清空内容 tooltip.innerHTML = ''; if (rnContentCache[optionValue] && rnContentCache[optionValue].length > 0) { const entries = rnContentCache[optionValue]; // 标题显示选项 const title = document.createElement('div'); title.className = 'tooltip-title'; title.textContent = optionValue; if (entries.length > 1) { title.textContent += ` (${entries.length} questions)`; } tooltip.appendChild(title); // 显示所有引用 entries.forEach((entry, entryIndex) => { const content = entry.contents; if (content.length === 1) { // 单一条目 const entryDiv = document.createElement('div'); entryDiv.className = 'entry-single'; if (entries.length >= 1) { entryDiv.innerHTML = `Q${entryIndex + 1}: ${content[0]}`; } else { entryDiv.textContent = content[0]; } tooltip.appendChild(entryDiv); } else { // 多个条目 const entryDiv = document.createElement('div'); entryDiv.className = 'entry-multiple'; if (entries.length > 1) { const header = document.createElement('div'); header.className = 'q-header'; header.textContent = `Q${entryIndex + 1}:`; entryDiv.appendChild(header); } const ol = document.createElement('ol'); ol.className = 'q-list'; content.forEach((item, itemIndex) => { const li = document.createElement('li'); li.innerHTML = `${entryIndex + 1}.${itemIndex + 1} ${item}`; ol.appendChild(li); }); entryDiv.appendChild(ol); tooltip.appendChild(entryDiv); } }); } else { // 没有找到内容 const noContent = document.createElement('div'); noContent.className = 'tooltip-no-content'; noContent.textContent = '未找到相关内容'; tooltip.appendChild(noContent); } // 确保 tooltip 有合适的尺寸 tooltip.style.position = 'fixed'; tooltip.style.zIndex = '10000'; tooltip.style.maxWidth = '400px'; tooltip.style.maxHeight = '500px'; tooltip.style.overflowY = 'auto'; tooltip.style.boxSizing = 'border-box'; // 首先隐藏并获取尺寸 tooltip.style.visibility = 'hidden'; tooltip.classList.add('active'); document.body.appendChild(tooltip); const tooltipWidth = Math.min(tooltip.scrollWidth, 400); const tooltipHeight = Math.min(tooltip.scrollHeight, 500); tooltip.style.width = tooltipWidth + 'px'; tooltip.style.height = 'auto'; const padding = 5; const minDistanceFromEdge = 20; let left, top; let position = 'right'; // 首选右侧 // 检查右侧空间 if (rect.right + padding + tooltipWidth <= window.innerWidth - minDistanceFromEdge) { // 右侧有足够空间 left = rect.right + padding; top = rect.top; position = 'right'; } else if (rect.left - padding - tooltipWidth >= minDistanceFromEdge) { // 左侧有足够空间 left = rect.left - padding - tooltipWidth; top = rect.top; position = 'left'; } else { // 两侧都没有足够空间,显示在下方 left = Math.max( minDistanceFromEdge, Math.min( rect.left + (rect.width - tooltipWidth) / 2, window.innerWidth - tooltipWidth - minDistanceFromEdge ) ); top = rect.bottom + padding; position = 'bottom'; } // 垂直边界检查 - 确保不超出屏幕 if (top + tooltipHeight > window.innerHeight - minDistanceFromEdge) { // 如果下方空间不足,尝试显示在上方 if (rect.top - padding - tooltipHeight >= minDistanceFromEdge) { top = rect.top - padding - tooltipHeight; } else { // 上下都不够,显示在中间 top = Math.max( minDistanceFromEdge, Math.min( top, window.innerHeight - tooltipHeight - minDistanceFromEdge ) ); } } // 水平边界检查 - 确保不超出屏幕 if (position === 'right' || position === 'left') { left = Math.max( minDistanceFromEdge, Math.min(left, window.innerWidth - tooltipWidth - minDistanceFromEdge) ); } tooltip.style.left = left + 'px'; tooltip.style.top = top + 'px'; tooltip.style.visibility = 'visible'; // 添加一个小箭头指示方向 tooltip.setAttribute('data-position', position); activeTooltip = tooltip; isMouseOverTooltip = true; // 添加 overlay 防止 body 交互 addOverlay(); } // 添加半透明 overlay(保持不变) function addOverlay() { // 移除现有的 overlay removeOverlay(); const overlay = document.createElement('div'); overlay.id = 'tooltip-overlay'; overlay.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 9999; background: transparent; pointer-events: none; `; document.body.appendChild(overlay); // 将 overlay 的 pointer-events 设为 auto,但阻止所有事件 overlay.addEventListener('mousedown', stopEvent, true); overlay.addEventListener('mouseup', stopEvent, true); overlay.addEventListener('click', stopEvent, true); overlay.addEventListener('mousemove', stopEvent, true); overlay.addEventListener('wheel', stopEvent, true); function stopEvent(e) { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); return false; } } // 移除 overlay(保持不变) function removeOverlay() { const overlay = document.getElementById('tooltip-overlay'); if (overlay) { overlay.remove(); } } // 隐藏 tooltip(保持不变) function hideTooltip() { if (!isMouseOverTooltip && activeTooltip) { activeTooltip.classList.remove('active'); activeTooltip = null; removeOverlay(); } } // 强制隐藏 tooltip(保持不变) function forceHideTooltip() { if (activeTooltip) { activeTooltip.classList.remove('active'); activeTooltip = null; isMouseOverTooltip = false; removeOverlay(); } } // 初始化(保持不变) document.addEventListener('DOMContentLoaded', function() { console.log('初始化 clab-tooltip'); const clabElements = document.querySelectorAll('.clab[data-options]'); console.log(`找到 ${clabElements.length} 个 .clab 元素`); if (clabElements.length === 0) return; // 加载内容 loadRnContent(); // 创建 tooltip const tooltip = createTooltip(); // tooltip 鼠标进入/离开 tooltip.addEventListener('mouseenter', function() { isMouseOverTooltip = true; clearTimeout(hideTimer); }); tooltip.addEventListener('mouseleave', function() { isMouseOverTooltip = false; hideTimer = setTimeout(() => { forceHideTooltip(); }, 100); }); // 为所有 .clab 元素添加事件监听 clabElements.forEach(clab => { clab.addEventListener('mouseenter', function() { clearTimeout(hideTimer); setTimeout(() => { if (isRnContentLoaded) { showTooltip(this, tooltip); } }, 100); }); clab.addEventListener('mouseleave', function() { hideTimer = setTimeout(() => { hideTooltip(); }, 100); }); }); // ESC 键隐藏 tooltip document.addEventListener('keydown', function(e) { if (e.key === 'Escape' && activeTooltip) { forceHideTooltip(); } }); // 点击其他地方隐藏 tooltip document.addEventListener('click', function(e) { if (activeTooltip && !activeTooltip.contains(e.target)) { forceHideTooltip(); } }); // 窗口大小改变时隐藏 tooltip window.addEventListener('resize', forceHideTooltip); // 滚动时隐藏 tooltip window.addEventListener('scroll', forceHideTooltip); }); })();