// ==UserScript== // @name NodeSeek Addon // @namespace http://tampermonkey.net/ // @version 0.4 // @description NodeSeek 插件 // @author lauvinson // @match https://www.nodeseek.com/* // @match http://www.nodeseek.com/* // @grant none // @license GNU GPLv3 // @downloadURL https://update.greasyfork.icu/scripts/533850/NodeSeek%20Addon.user.js // @updateURL https://update.greasyfork.icu/scripts/533850/NodeSeek%20Addon.meta.js // ==/UserScript== (function() { 'use strict'; // 主题控制函数 function applyTheme() { // 检查当前主题 const isDarkMode = document.body.classList.contains('dark-layout'); // 更新主题相关的CSS变量 const themeStyles = document.createElement('style'); themeStyles.id = 'ns-theme-styles'; // 移除已存在的主题样式 const existingStyles = document.getElementById('ns-theme-styles'); if (existingStyles) { existingStyles.remove(); } // 设置主题相关的CSS变量 themeStyles.textContent = ` :root { --ns-bg-color: ${isDarkMode ? '#272727' : '#FFFFFF'}; --ns-text-color: ${isDarkMode ? '#f0f0f0' : '#333333'}; --ns-border-color: ${isDarkMode ? '#444444' : '#dddddd'}; --ns-hover-bg-color: ${isDarkMode ? '#383838' : '#f5f5f5'}; --ns-card-bg-color: ${isDarkMode ? 'rgba(39, 39, 39, 0.95)' : 'rgba(255, 255, 255, 0.95)'}; --ns-card-bg-hover: ${isDarkMode ? 'rgba(45, 45, 45, 0.95)' : 'rgba(255, 255, 255, 0.95)'}; --ns-card-shadow: ${isDarkMode ? '0 4px 15px rgba(0, 0, 0, 0.5)' : '0 4px 15px rgba(0, 0, 0, 0.2)'}; --ns-card-text-color: ${isDarkMode ? '#e0e0e0' : '#333'}; --ns-card-secondary-text: ${isDarkMode ? '#a0a0a0' : '#666'}; --ns-overlay-bg: ${isDarkMode ? 'rgba(0, 0, 0, 0.8)' : 'rgba(0, 0, 0, 0.7)'}; --ns-loader-bg: ${isDarkMode ? '#272727' : 'white'}; --ns-loader-border: ${isDarkMode ? '#444444' : '#f3f3f3'}; --ns-emoji-results-bg: ${isDarkMode ? '#333333' : '#f9f9f9'}; --ns-emoji-item-bg: ${isDarkMode ? '#3a3a3a' : 'white'}; --ns-emoji-item-border: ${isDarkMode ? '#555555' : '#eeeeee'}; --ns-debug-bg: ${isDarkMode ? '#333333' : '#f8f9fa'}; --ns-debug-border: ${isDarkMode ? '#444444' : '#dddddd'}; } `; document.head.appendChild(themeStyles); console.log(`NodeSeek Addon: 应用${isDarkMode ? '深色' : '浅色'}主题`); } // 监听主题变化 function observeThemeChanges() { // 使用MutationObserver监听body的class变化 const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.attributeName === 'class') { applyTheme(); } }); }); // 开始观察body的class变化 observer.observe(document.body, { attributes: true }); } // 样式 const style = document.createElement('style'); style.textContent = ` .ns-iframe-container { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: var(--ns-overlay-bg); z-index: 9999; display: flex; justify-content: flex-end; /* 调整为靠右对齐 */ align-items: center; } .ns-iframe-wrapper { position: relative; width: 70%; height: 100%; background: var(--ns-bg-color); border-radius: 8px; overflow: hidden; } /* 添加左侧信息卡片样式 */ .ns-sidebar-info { position: fixed; left: 15%; top: 30%; transform: translate(-50%, -50%); width: 280px; background: var(--ns-card-bg-color); border-radius: 8px; padding: 20px; box-shadow: var(--ns-card-shadow); z-index: 9998; display: none; /* 初始状态为隐藏 */ flex-direction: column; align-items: center; text-align: center; } /* 添加前后帖子导航卡片样式 */ .ns-post-nav-card { position: fixed; left: 5%; width: 250px; background: var(--ns-card-bg-color); border-radius: 8px; padding: 15px; box-shadow: var(--ns-card-shadow); z-index: 9997; display: none; /* 初始状态为隐藏 */ flex-direction: column; align-items: center; text-align: center; cursor: pointer; transition: all 0.3s ease; opacity: 0.7; } .ns-post-nav-card:hover { opacity: 1; background: var(--ns-card-bg-hover); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25); } .ns-post-nav-card.prev { top: 10%; transform: translateY(-50%); } .ns-post-nav-card.next { top: 50%; transform: translateY(-50%); } .ns-post-nav-card .nav-label { display: block; font-size: 13px; color: var(--ns-card-secondary-text); margin-bottom: 5px; } .ns-post-nav-card .nav-title { font-size: 15px; color: var(--ns-card-text-color); font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; width: 100%; } .ns-sidebar-info .avatar-container { margin-bottom: 15px; } .ns-sidebar-info .avatar-container img { width: 60px; height: 60px; border-radius: 50%; object-fit: cover; border: 2px solid #2ea44f; } .ns-sidebar-info .title { font-size: 18px; font-weight: bold; margin: 0 0 15px 0; color: var(--ns-card-text-color); } .ns-sidebar-info .user-info { margin-bottom: 10px; color: var(--ns-card-secondary-text); font-size: 14px; } /* 添加媒体查询,小屏幕使用100%宽度 */ @media screen and (max-width: 800px) { .ns-iframe-wrapper { width: 100%; border-radius: 0; } .ns-iframe-container { justify-content: center; } .ns-sidebar-info { display: none !important; /* 小屏幕隐藏左侧信息 */ } /* 小屏幕下隐藏上一篇/下一篇导航卡片 */ .ns-post-nav-card { display: none !important; } } .ns-iframe { width: 100%; height: 100%; border: none; opacity: 0; /* 初始隐藏iframe */ transition: opacity 0.3s ease; } .ns-close-btn { position: absolute; top: 10px; right: 10px; background: #f44336; color: white; border: none; border-radius: 50%; width: 30px; height: 30px; font-size: 16px; cursor: pointer; display: flex; justify-content: center; align-items: center; z-index: 10; } /* 回到顶部和底部按钮样式 */ .ns-to-top-btn, .ns-to-bottom-btn, .ns-to-comment-btn { position: absolute; right: 20px; width: 40px; height: 40px; background: rgba(46, 164, 79, 0.8); color: white; border: none; border-radius: 50%; font-size: 20px; cursor: pointer; display: flex; justify-content: center; align-items: center; z-index: 100; opacity: 0; transition: opacity 0.3s ease, background-color 0.2s ease; box-shadow: 0 2px 5px rgba(0,0,0,0.2); } .ns-to-top-btn:hover, .ns-to-bottom-btn:hover, .ns-to-comment-btn:hover { background: rgba(46, 164, 79, 1); } .ns-to-top-btn { bottom: 120px; } .ns-to-bottom-btn { bottom: 70px; } .ns-to-comment-btn { bottom: 20px; } /* 新增按钮显示动画 */ .ns-btn-show { opacity: 1; } /* 新增样式 - 使列表项可点击并添加悬停效果 */ .post-list-item { cursor: pointer; transition: background-color 0.2s ease; } .post-list-item:hover { background-color: var(--ns-hover-bg-color); } /* 添加外部链接图标样式 */ .ns-external-link { display: none; cursor: pointer; margin-left: 5px; color: var(--ns-card-secondary-text); vertical-align: middle; transition: color 0.2s ease; position: absolute; top: 50%; transform: translateY(-50%); } .post-title { position: relative; } .post-title:hover .ns-external-link { display: inline-block; } .post-list-item:hover .ns-external-link { display: inline-block; } .ns-external-link:hover { color: #2ea44f; } /* 加载指示器 */ .ns-loader { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 50px; height: 50px; border: 2px solid var(--ns-loader-border); border-top: 2px solid #2ea44f; border-radius: 50%; animation: spin 1s linear infinite; z-index: 5; } @keyframes spin { 0% { transform: translate(-50%, -50%) rotate(0deg); } 100% { transform: translate(-50%, -50%) rotate(360deg); } } /* 表情包搜索样式 */ .ns-emoji-search { position: relative; margin-top: 5px; margin-bottom: 5px; padding: 0 1% 0 1%; width: 98%; display: flex; align-items: center; } .ns-emoji-search input { flex: 1; padding: 6px 10px; border: 1px solid var(--ns-border-color); border-radius: 4px; font-size: 14px; margin-right: 5px; background-color: var(--ns-bg-color); color: var(--ns-text-color); } /* 搜索按钮样式 - 保留用于自定义exp-item */ .exp-item.ns-emoji-btn { cursor: pointer; background-color: #2ea44f !important; color: white !important; transition: background-color 0.2s; } .exp-item.ns-emoji-btn:hover { background-color: #2c974b !important; opacity: 0.9; } .ns-emoji-results { position: absolute; bottom: 100%; left: 0; right: 0; margin-bottom: 5px; display: flex; flex-wrap: wrap; gap: 10px; max-height: 300px; overflow-y: auto; padding: 10px; background-color: var(--ns-emoji-results-bg); border: 1px solid var(--ns-border-color); border-radius: 4px; box-shadow: 0 -2px 10px rgba(0,0,0,0.1); z-index: 100; } .ns-emoji-results-header { width: 100%; text-align: center; margin-bottom: 10px; font-size: 14px; color: var(--ns-card-secondary-text); } .ns-emoji-item { width: 80px; height: 80px; border-radius: 4px; cursor: pointer; overflow: hidden; transition: transform 0.2s; border: 1px solid var(--ns-emoji-item-border); background-color: var(--ns-emoji-item-bg); flex-shrink: 0; } .ns-emoji-item:hover { transform: scale(1.1); box-shadow: 0 2px 5px rgba(0,0,0,0.2); border-color: #2ea44f; z-index: 1; } .ns-emoji-item img { width: 100%; height: 100%; object-fit: contain; } /* 调试信息样式 */ .ns-debug-info { background-color: var(--ns-debug-bg); border: 1px solid var(--ns-debug-border); border-radius: 4px; padding: 8px; margin-top: 5px; font-family: monospace; font-size: 12px; max-height: 100px; overflow-y: auto; white-space: pre-wrap; word-break: break-all; color: var(--ns-text-color); } /* 自定义滚动条样式 */ .ns-custom-scrollbar::-webkit-scrollbar { width: 6px; height: 6px; } .ns-custom-scrollbar::-webkit-scrollbar-track { background: transparent; } .ns-custom-scrollbar::-webkit-scrollbar-thumb { background: rgba(128, 128, 128, 0.35); border-radius: 3px; } .ns-custom-scrollbar::-webkit-scrollbar-thumb:hover { background: rgba(128, 128, 128, 0.5); } /* 深色模式滚动条 */ .dark-layout .ns-custom-scrollbar::-webkit-scrollbar-thumb { background: rgba(180, 180, 180, 0.35); } .dark-layout .ns-custom-scrollbar::-webkit-scrollbar-thumb:hover { background: rgba(180, 180, 180, 0.5); } /* 新的固定评论区样式 */ .md-editor.ns-fixed-editor { position: fixed; bottom: 2%; left: 5%; width: 85%; z-index: 1000; background-color: var(--ns-bg-color); box-shadow: 0 0 20px rgba(0, 0, 0, 0.2); padding: 2px; border-radius: 8px; } .ns-editor-placeholder { min-height: 200px; background-color: rgba(200, 200, 200, 0.1); border: 1px dashed var(--ns-border-color); display: flex; align-items: center; justify-content: center; color: var(--ns-card-secondary-text); font-style: italic; } /* 添加快捷回复按钮样式 */ .ns-quick-reply { position: fixed; left: 15%; bottom: 5%; transform: translateX(-50%); z-index: 9998; display: none; /* 初始状态为隐藏 */ flex-direction: column; gap: 8px; width: 200px; } .ns-quick-reply-title { font-size: 14px; color: var(--ns-card-secondary-text); margin-bottom: 5px; text-align: center; } .ns-quick-reply-buttons { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; } .ns-quick-reply-btn { color: white; font-size: 13px; cursor: pointer; background: rgba(0, 0, 0, 0.2); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 15px; padding: 5px 12px; transition: all 0.2s ease; opacity: 0.8; white-space: nowrap; } .ns-quick-reply-btn:hover { color: white; opacity: 1; background-color: rgba(46, 164, 79, 0.8); border-color: rgba(46, 164, 79, 0.6); } @media screen and (max-width: 800px) { .ns-iframe-wrapper { width: 100%; border-radius: 0; } } `; document.head.appendChild(style); // 主函数 function init() { // 应用当前主题并监听主题变化 applyTheme(); observeThemeChanges(); // 找到所有帖子列表项 const postItems = document.querySelectorAll('.post-list-item'); // 创建帖子列表映射,用于获取前后帖子 const postMap = new Map(); let postOrder = []; // 将所有帖子信息存入映射 postItems.forEach((item, index) => { const postLink = item.querySelector('.post-title a[href^="/post-"]'); if (postLink) { const href = postLink.href; const title = postLink.textContent.trim(); postMap.set(href, { title: title, element: item, index: index }); postOrder.push(href); // 添加外部链接图标 const postTitle = item.querySelector('.post-title'); if (postTitle) { const externalIcon = document.createElement('span'); externalIcon.className = 'ns-external-link'; externalIcon.innerHTML = ``; externalIcon.title = '在新标签页中打开'; // 添加点击事件处理,直接打开原始链接 externalIcon.addEventListener('click', function(e) { e.stopPropagation(); // 阻止冒泡,避免触发父级点击事件 // 创建一个临时链接元素,模拟正常点击行为 const tempLink = document.createElement('a'); tempLink.href = postLink.href; tempLink.target = '_blank'; // 在新标签页中打开 tempLink.rel = 'noopener noreferrer'; tempLink.click(); }); postTitle.appendChild(externalIcon); } } }); // 为每个帖子列表项添加点击事件处理 postItems.forEach(item => { item.addEventListener('click', function(e) { // 检查点击的是否是头像或头像的容器 const isAvatarClick = e.target.classList.contains('avatar') || e.target.classList.contains('avatar-normal') || e.target.closest('a[href^="/space/"]') !== null || e.target.closest('.avatar-wrapper') !== null; // 如果点击的是头像相关元素,不阻止默认行为,允许正常跳转 if (isAvatarClick) { return; // 直接返回,不阻止事件,允许正常导航 } // 检查是否点击的是评论时间链接 const commentTimeLink = e.target.closest('.info-last-comment-time'); if (commentTimeLink) { // 阻止默认行为 e.preventDefault(); e.stopPropagation(); // 收集评论链接URL const commentUrl = commentTimeLink.href; // 找到当前列表项中的帖子信息 - 与普通点击相同的方式收集信息 const postLink = item.querySelector('.post-title a[href^="/post-"]'); if (postLink) { const postTitle = postLink.textContent.trim(); const avatarImg = item.querySelector('.avatar-normal, img.avatar'); const userElement = item.querySelector('.author-name, .post-username, .username'); const postInfoElement = item.querySelector('.post-info, .info'); // 获取前后帖子信息 const currentPostUrl = postLink.href; const currentIndex = postMap.get(currentPostUrl)?.index; let prevPost = null; let nextPost = null; if (currentIndex !== undefined) { // 获取前一篇帖子 if (currentIndex > 0) { const prevUrl = postOrder[currentIndex - 1]; const prevInfo = postMap.get(prevUrl); if (prevInfo) { prevPost = { url: prevUrl, title: prevInfo.title }; } } // 获取后一篇帖子 if (currentIndex < postOrder.length - 1) { const nextUrl = postOrder[currentIndex + 1]; const nextInfo = postMap.get(nextUrl); if (nextInfo) { nextPost = { url: nextUrl, title: nextInfo.title }; } } } // 使用评论链接URL在iframe中打开 openInIframe(commentUrl, { title: postTitle, avatarElement: avatarImg, userElement: userElement, infoElement: postInfoElement, prevPost: prevPost, nextPost: nextPost, postMap: postMap, postOrder: postOrder }); } return; } // 找到当前列表项中的帖子链接 - 普通点击处理 const postLink = item.querySelector('.post-title a[href^="/post-"]'); if (postLink) { // 阻止事件冒泡和默认行为 e.preventDefault(); e.stopPropagation(); // 收集帖子信息 - 直接使用原有DOM元素 const postTitle = postLink.textContent.trim(); const avatarImg = item.querySelector('.avatar-normal, img.avatar'); const userElement = item.querySelector('.author-name, .post-username, .username'); const postInfoElement = item.querySelector('.post-info, .info'); // 获取前后帖子信息 const currentPostUrl = postLink.href; const currentIndex = postMap.get(currentPostUrl)?.index; let prevPost = null; let nextPost = null; if (currentIndex !== undefined) { // 获取前一篇帖子 if (currentIndex > 0) { const prevUrl = postOrder[currentIndex - 1]; const prevInfo = postMap.get(prevUrl); if (prevInfo) { prevPost = { url: prevUrl, title: prevInfo.title }; } } // 获取后一篇帖子 if (currentIndex < postOrder.length - 1) { const nextUrl = postOrder[currentIndex + 1]; const nextInfo = postMap.get(nextUrl); if (nextInfo) { nextPost = { url: nextUrl, title: nextInfo.title }; } } } // 在iframe中打开帖子,传入原始DOM元素和前后帖子信息 openInIframe(postLink.href, { title: postTitle, avatarElement: avatarImg, userElement: userElement, infoElement: postInfoElement, prevPost: prevPost, nextPost: nextPost, postMap: postMap, postOrder: postOrder }); } }); }); } // 表情包搜索API async function searchEmojis(query) { // 使用提供的API const url = `https://oiapi.net/API/EmoticonPack/?keyword=${encodeURIComponent(query)}`; try { console.log('搜索表情包,请求URL:', url); const response = await fetch(url); console.log('API响应状态:', response.status); if (!response.ok) { console.error('API响应非200:', response.status, response.statusText); return { error: `API响应错误: ${response.status}`, data: [] }; } const data = await response.json(); console.log('API返回数据:', data); // 检查是否有数据 - 注意这里API返回的成功code是1而不是200 if (data.code === 1 && Array.isArray(data.data) && data.data.length > 0) { console.log(`找到${data.data.length}个表情包`); return { error: null, data: data.data.map(item => ({ url: item.url, preview: item.url, width: item.width, height: item.height, type: item.type, size: item.size })) }; } else { console.log('API返回成功但无数据:', data); return { error: '未找到相关表情包', data: [] }; } } catch (error) { console.error('搜索表情包出错:', error); return { error: '请求出错: ' + error.message, data: [] }; } } // 在iframe中打开链接 function openInIframe(url, domElements = null) { // 禁用父页面滚动 const originalBodyOverflow = document.body.style.overflow; document.body.style.overflow = 'hidden'; // 创建容器 const container = document.createElement('div'); container.className = 'ns-iframe-container'; // 创建iframe包装器 const wrapper = document.createElement('div'); wrapper.className = 'ns-iframe-wrapper'; // 创建加载指示器容器 const loaderContainer = document.createElement('div'); loaderContainer.className = 'ns-loader-container'; loaderContainer.style.cssText = ` position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; background-color: var(--ns-loader-bg); z-index: 10; `; // 如果有帖子信息,创建并添加左侧信息卡片 if (domElements) { // 创建左侧信息卡片 const sidebarInfo = document.createElement('div'); sidebarInfo.className = 'ns-sidebar-info'; // 创建并添加前一篇帖子导航卡片(如果有) if (domElements.prevPost) { const prevNav = document.createElement('div'); prevNav.className = 'ns-post-nav-card prev'; prevNav.innerHTML = ` 上一篇 `; prevNav.setAttribute('data-url', domElements.prevPost.url); prevNav.addEventListener('click', function() { loadNewPost(this.getAttribute('data-url'), domElements); }); container.appendChild(prevNav); } // 添加帖子标题 if (domElements.title) { const titleElement = document.createElement('div'); titleElement.className = 'title'; titleElement.textContent = domElements.title; titleElement.style.cssText = ` font-size: 18px; font-weight: bold; margin: 0 0 15px 0; text-align: center; color: var(--ns-card-text-color); width: 100%; `; sidebarInfo.appendChild(titleElement); } // 添加头像 if (domElements.avatarElement) { const avatarContainer = document.createElement('div'); avatarContainer.className = 'avatar-container'; // 克隆原始头像并添加样式 const avatarClone = domElements.avatarElement.cloneNode(true); avatarContainer.appendChild(avatarClone); sidebarInfo.appendChild(avatarContainer); } // 添加用户名和其他信息 if (domElements.userElement) { const userInfo = document.createElement('div'); userInfo.className = 'user-info'; const usernameClone = domElements.userElement.cloneNode(true); userInfo.appendChild(usernameClone); sidebarInfo.appendChild(userInfo); } // 添加帖子信息 if (domElements.infoElement) { const postInfo = document.createElement('div'); postInfo.className = 'post-info'; const infoClone = domElements.infoElement.cloneNode(true); postInfo.appendChild(infoClone); sidebarInfo.appendChild(postInfo); } // 将信息卡片添加到容器中 container.appendChild(sidebarInfo); // 创建并添加下一篇帖子导航卡片(如果有) if (domElements.nextPost) { const nextNav = document.createElement('div'); nextNav.className = 'ns-post-nav-card next'; nextNav.innerHTML = ` 下一篇 `; nextNav.setAttribute('data-url', domElements.nextPost.url); nextNav.addEventListener('click', function() { loadNewPost(this.getAttribute('data-url'), domElements); }); container.appendChild(nextNav); } // 添加快捷回复按钮(仅在大屏模式下) const quickReplyContainer = document.createElement('div'); quickReplyContainer.className = 'ns-quick-reply'; // 添加标题 const quickReplyTitle = document.createElement('div'); quickReplyTitle.className = 'ns-quick-reply-title'; quickReplyTitle.textContent = '快捷回复'; quickReplyContainer.appendChild(quickReplyTitle); // 创建按钮容器 const quickReplyButtons = document.createElement('div'); quickReplyButtons.className = 'ns-quick-reply-buttons'; // 定义快捷回复内容 const quickReplies = [ { text: 'bd', title: '快速回复bd' }, { text: '前排', title: '快速回复前排' }, { text: '牛逼', title: '快速回复牛逼' }, { text: '好鸡', title: '快速回复好鸡' }, { text: '围观', title: '快速回复围观' }, { text: '支持', title: '快速回复支持' } ]; // 为每个快捷回复创建按钮 quickReplies.forEach(reply => { const replyBtn = document.createElement('div'); replyBtn.className = 'ns-quick-reply-btn'; replyBtn.textContent = reply.text; replyBtn.title = reply.title; // 添加点击事件 replyBtn.addEventListener('click', function() { // 获取iframe文档对象 const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; // 找到评论编辑器 const editor = iframeDoc.querySelector('.CodeMirror'); if (editor && editor.CodeMirror) { // 设置评论内容为快捷回复文本 editor.CodeMirror.setValue(reply.text); // 找到提交按钮并点击 const submitBtn = iframeDoc.querySelector('.md-editor .submit.btn'); if (submitBtn) { submitBtn.click(); } } else { // 如果找不到编辑器,提示用户 alert('找不到评论编辑器,请手动评论'); } }); quickReplyButtons.appendChild(replyBtn); }); // 将按钮容器添加到快捷回复容器 quickReplyContainer.appendChild(quickReplyButtons); // 添加表情包搜索功能到快捷回复区域 const emojiSearchContainer = document.createElement('div'); emojiSearchContainer.className = 'ns-quick-emoji-search'; emojiSearchContainer.style.cssText = ` margin-top: 10px; width: 100%; display: flex; flex-direction: column; `; // 创建搜索输入框 const emojiSearchInput = document.createElement('input'); emojiSearchInput.type = 'text'; emojiSearchInput.placeholder = '搜索表情包...'; emojiSearchInput.style.cssText = ` color: white; font-size: 13px; cursor: pointer; background: rgba(0, 0, 0, 0.2); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 15px; padding: 5px 12px; transition: all 0.2s ease; opacity: 0.8; width: 100%; margin-top: 5px; outline: none; `; // 添加输入框焦点效果 emojiSearchInput.addEventListener('focus', function() { this.style.opacity = '1'; this.style.backgroundColor = 'rgba(46, 164, 79, 0.6)'; this.style.borderColor = 'rgba(46, 164, 79, 0.6)'; }); emojiSearchInput.addEventListener('blur', function() { if (!this.value) { this.style.opacity = '0.8'; this.style.backgroundColor = 'rgba(0, 0, 0, 0.2)'; this.style.borderColor = 'rgba(255, 255, 255, 0.2)'; } }); // 添加输入框悬停效果 emojiSearchInput.addEventListener('mouseenter', function() { this.style.opacity = '1'; }); emojiSearchInput.addEventListener('mouseleave', function() { if (!this.matches(':focus') && !this.value) { this.style.opacity = '0.8'; } }); emojiSearchContainer.appendChild(emojiSearchInput); // 创建结果显示区域 const emojiResultsContainer = document.createElement('div'); emojiResultsContainer.className = 'ns-quick-emoji-results'; emojiResultsContainer.style.cssText = ` display: none; position: absolute; right: -400px; top: -150px; width: 360px; height: 300px; background: white; border-radius: 8px; border: 1px solid var(--ns-border-color); padding: 15px; z-index: 1000; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); max-height: 450px; overflow-y: auto; background-color: var(--bs-body-bg, white); color: var(--bs-body-color, black); `; // 添加结果容器 emojiSearchContainer.appendChild(emojiResultsContainer); // 将表情包搜索容器添加到快捷回复容器 quickReplyContainer.appendChild(emojiSearchContainer); // 处理搜索表情包的功能 emojiSearchInput.addEventListener('keydown', async (e) => { if (e.key === 'Enter') { const query = emojiSearchInput.value.trim(); if (!query) return; // 显示"正在搜索"提示 emojiResultsContainer.innerHTML = '
正在搜索表情包...
'; emojiResultsContainer.style.display = 'block'; // 搜索表情包 const response = await searchEmojis(query); // 显示结果 if (response.error || response.data.length === 0) { emojiResultsContainer.innerHTML = `
${response.error || '未找到相关表情包'}
`; return; } // 清空结果容器 emojiResultsContainer.innerHTML = ''; // 创建表情包结果布局 const emojiGrid = document.createElement('div'); emojiGrid.style.cssText = ` display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between; `; // 添加表情包元素 response.data.forEach(emoji => { const emojiItem = document.createElement('div'); emojiItem.className = 'ns-emoji-item'; emojiItem.style.cssText = ` cursor: pointer; border: 1px solid #eee; border-radius: 4px; overflow: hidden; width: 100px; height: 100px; display: flex; align-items: center; justify-content: center; background-color: #f8f8f8; transition: transform 0.2s ease, box-shadow 0.2s ease; `; // 为暗色模式调整样式 if (document.body.classList.contains('dark-layout')) { emojiItem.style.backgroundColor = '#2f3349'; emojiItem.style.borderColor = '#434968'; } // 添加鼠标悬停效果 emojiItem.addEventListener('mouseenter', function() { this.style.transform = 'scale(1.05)'; this.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.1)'; }); emojiItem.addEventListener('mouseleave', function() { this.style.transform = 'scale(1)'; this.style.boxShadow = 'none'; }); const img = document.createElement('img'); img.src = emoji.url; img.setAttribute('data-url', emoji.url); img.setAttribute('title', `${emoji.width}x${emoji.height} ${(emoji.size/1024).toFixed(1)}KB`); img.style.cssText = ` max-width: 95%; max-height: 95%; object-fit: contain; `; // 添加加载错误处理 img.onerror = function() { // 图片加载失败时显示错误提示 this.onerror = null; this.src = 'data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22100%25%22%20height%3D%22100%25%22%3E%3Ctext%20x%3D%2250%25%22%20y%3D%2250%25%22%20font-size%3D%2210%22%20text-anchor%3D%22middle%22%20dominant-baseline%3D%22middle%22%3E图片加载失败%3C%2Ftext%3E%3C%2Fsvg%3E'; }; emojiItem.appendChild(img); // 点击表情包插入到评论编辑器 emojiItem.addEventListener('click', () => { // 获取iframe文档对象 const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; // 找到评论编辑器 const editor = iframeDoc.querySelector('.CodeMirror'); if (editor && editor.CodeMirror) { // 插入表情包Markdown到编辑器 const imgUrl = emoji.url; const markdownImg = `![${query}](${imgUrl})`; const cursor = editor.CodeMirror.getCursor(); editor.CodeMirror.replaceRange(markdownImg, cursor); editor.CodeMirror.focus(); // 找到提交按钮并点击 const submitBtn = iframeDoc.querySelector('.md-editor .submit.btn'); if (submitBtn) { submitBtn.click(); } } else { // 如果找不到编辑器,提示用户 alert('找不到评论编辑器,请手动评论'); } // 隐藏结果 emojiResultsContainer.style.display = 'none'; }); emojiGrid.appendChild(emojiItem); }); emojiResultsContainer.appendChild(emojiGrid); } }); // 点击页面其他区域关闭结果框 document.addEventListener('click', (e) => { if (!emojiSearchContainer.contains(e.target)) { emojiResultsContainer.style.display = 'none'; } }); // 将快捷回复容器添加到页面 container.appendChild(quickReplyContainer); // 将信息卡片添加到容器中 container.appendChild(sidebarInfo); // 创建简单信息容器用于加载界面 const infoContainer = document.createElement('div'); infoContainer.style.cssText = ` display: flex; flex-direction: column; align-items: center; width: 100%; max-width: 600px; padding: 10px 20px 20px; margin-bottom: 20px; text-align: center; `; // 直接复制头像元素,保留原有类名和样式,放在第一行居中 if (domElements.avatarElement) { const avatarContainer = document.createElement('div'); avatarContainer.style.cssText = ` display: flex; justify-content: center; margin-bottom: 15px; width: 100%; `; const avatarClone = domElements.avatarElement.cloneNode(true); avatarContainer.appendChild(avatarClone); infoContainer.appendChild(avatarContainer); } // 添加标题,放在第二行居中 if (domElements.title) { const titleElement = document.createElement('div'); titleElement.textContent = domElements.title; titleElement.style.cssText = ` font-size: 18px; font-weight: bold; margin: 0 0 15px 0; text-align: center; color: var(--ns-card-text-color); width: 100%; `; infoContainer.appendChild(titleElement); } // 用户名和帖子信息,放在第三行居中 const infoWrapper = document.createElement('div'); infoWrapper.style.cssText = ` display: flex; flex-direction: column; align-items: center; width: 100%; margin-bottom: 20px; `; // 直接复制用户名元素,保留原有类名和样式 if (domElements.userElement) { const usernameContainer = document.createElement('div'); usernameContainer.style.cssText = ` display: flex; justify-content: center; width: 100%; margin-bottom: 5px; `; const usernameClone = domElements.userElement.cloneNode(true); usernameContainer.appendChild(usernameClone); infoWrapper.appendChild(usernameContainer); } // 直接复制帖子信息元素,保留原有类名和样式 if (domElements.infoElement) { const infoElementContainer = document.createElement('div'); infoElementContainer.style.cssText = ` display: flex; justify-content: center; width: 100%; `; const infoClone = domElements.infoElement.cloneNode(true); infoElementContainer.appendChild(infoClone); infoWrapper.appendChild(infoElementContainer); } infoContainer.appendChild(infoWrapper); // 创建加载指示器 const loader = document.createElement('div'); loader.className = 'ns-loader'; loader.style.cssText = ` width: 40px; height: 40px; margin: 100px 0; border: 2px solid var(--ns-loader-border); border-top: 2px solid #2ea44f; border-radius: 50%; animation: spin 1s linear infinite; `; infoContainer.appendChild(loader); loaderContainer.appendChild(infoContainer); } else { // 如果没有元素信息,只显示加载指示器 const loader = document.createElement('div'); loader.className = 'ns-loader'; loader.style.cssText = ` width: 40px; height: 40px; border: 2px solid var(--ns-loader-border); border-top: 2px solid #2ea44f; border-radius: 50%; animation: spin 1s linear infinite; `; loaderContainer.appendChild(loader); } // 创建关闭按钮 const closeBtn = document.createElement('button'); closeBtn.className = 'ns-close-btn'; closeBtn.innerHTML = '✕'; closeBtn.title = 'ESC'; // 添加悬停提示,显示ESC快捷键 closeBtn.onclick = function(e) { e.stopPropagation(); // 防止事件传递到container closeIframe(); }; // 创建iframe const iframe = document.createElement('iframe'); iframe.className = 'ns-iframe'; iframe.src = url; // 防止滚动穿透 iframe.addEventListener('load', function() { try { // 尝试阻止iframe内部滚动穿透到父页面 const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; const iframeBody = iframeDoc.body; // 在iframe中滚动到底部或顶部时,阻止继续滚动影响父页面 iframeDoc.addEventListener('wheel', function(e) { const scrollingElement = iframeDoc.scrollingElement || iframeBody; const scrollTop = scrollingElement.scrollTop; const scrollHeight = scrollingElement.scrollHeight; const clientHeight = scrollingElement.clientHeight; // 如果已经滚动到底部,并且继续向下滚动 if (scrollTop + clientHeight >= scrollHeight && e.deltaY > 0) { e.preventDefault(); } // 如果已经滚动到顶部,并且继续向上滚动 if (scrollTop <= 0 && e.deltaY < 0) { e.preventDefault(); } }, { passive: false }); } catch (error) { console.error('无法阻止iframe滚动穿透:', error); } }); // iframe加载完成后处理页面内容 iframe.onload = function() { try { // 获取iframe文档对象 const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; // 添加关闭表情包结果框的点击监听 iframeDoc.addEventListener('click', function() { // 如果表情包结果容器存在,点击时隐藏它 const emojiResults = document.querySelector('.ns-quick-emoji-results'); if (emojiResults) { emojiResults.style.display = 'none'; } }); // 移除header和footer const header = iframeDoc.querySelector('header'); const footer = iframeDoc.querySelector('footer'); if (header) header.style.display = 'none'; if (footer) footer.style.display = 'none'; // 移除右侧面板 const rightPanel = iframeDoc.getElementById('nsk-right-panel-container'); if (rightPanel) rightPanel.style.display = 'none'; // 检测iframe内的主题并应用相同主题 const isDarkMode = document.body.classList.contains('dark-layout'); const iframeIsDark = iframeDoc.body.classList.contains('dark-layout'); // 如果主题不一致,同步iframe内部主题与父页面 if (isDarkMode !== iframeIsDark) { if (isDarkMode) { iframeDoc.body.classList.add('dark-layout'); iframeDoc.body.classList.remove('light-layout'); } else { iframeDoc.body.classList.add('light-layout'); iframeDoc.body.classList.remove('dark-layout'); } } // 添加自定义样式到iframe内部 const styleElement = iframeDoc.createElement('style'); styleElement.textContent = ` /* 隐藏可能的导航和页脚 */ header, .header, #header, footer, .footer, #footer, nav, .nav, #nav, .site-header, .site-footer, .main-header, .main-footer, .page-header, .page-footer, #nsk-right-panel-container { display: none !important; } /* 调整主要内容区域 */ body { padding-top: 0 !important; margin-top: 0 !important; } /* 让内容区域占满整个空间 */ .container, .main-content, .content, #content, .page-content, .site-content, main, .main, #main { padding-top: 10px !important; margin-top: 0 !important; max-width: 100% !important; } /* 调整文章内容宽度,右侧面板被移除后 */ .post-detail-card { width: 100% !important; max-width: 100% !important; } /* 强制设置nsk-container的margin为0 */ .nsk-container { margin: 0 !important; } /* 平滑滚动效果 */ html { scroll-behavior: smooth; } /* 自定义滚动条样式 */ ::-webkit-scrollbar { width: 6px; height: 6px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background: rgba(128, 128, 128, 0.35); border-radius: 3px; } ::-webkit-scrollbar-thumb:hover { background: rgba(128, 128, 128, 0.5); } /* 深色模式滚动条 */ body.dark-layout ::-webkit-scrollbar-thumb { background: rgba(180, 180, 180, 0.35); } body.dark-layout ::-webkit-scrollbar-thumb:hover { background: rgba(180, 180, 180, 0.5); } `; iframeDoc.head.appendChild(styleElement); // 应用自定义滚动条样式到主文档和iframe iframeDoc.documentElement.classList.add('ns-custom-scrollbar'); iframeDoc.body.classList.add('ns-custom-scrollbar'); // 应用自定义滚动条到主要内容区域 const mainContainers = iframeDoc.querySelectorAll('.container, .main-content, .content, #content, .page-content, .site-content, main, .main, #main, .post-detail-card, .comment-container'); mainContainers.forEach(container => { container.classList.add('ns-custom-scrollbar'); }); // 添加回到顶部和底部按钮 const toTopBtn = document.createElement('button'); toTopBtn.className = 'ns-to-top-btn'; toTopBtn.innerHTML = '↑'; toTopBtn.title = '回到顶部'; toTopBtn.onclick = () => { iframeDoc.documentElement.scrollTop = 0; }; const toBottomBtn = document.createElement('button'); toBottomBtn.className = 'ns-to-bottom-btn'; toBottomBtn.innerHTML = '↓'; toBottomBtn.title = '到达底部'; toBottomBtn.onclick = () => { iframeDoc.documentElement.scrollTop = iframeDoc.documentElement.scrollHeight; }; // 添加发表评论按钮 const toCommentBtn = document.createElement('button'); toCommentBtn.className = 'ns-to-comment-btn'; toCommentBtn.innerHTML = '💬'; toCommentBtn.title = '发表评论'; toCommentBtn.onclick = () => { // 创建或显示浮动评论框 toggleFloatingCommentBox(iframeDoc); }; wrapper.appendChild(toTopBtn); wrapper.appendChild(toBottomBtn); wrapper.appendChild(toCommentBtn); // 滚动时显示/隐藏按钮 let scrollTimer; const handleScroll = () => { // 清除之前的定时器 clearTimeout(scrollTimer); const scrollTop = iframeDoc.documentElement.scrollTop; const scrollHeight = iframeDoc.documentElement.scrollHeight; const clientHeight = iframeDoc.documentElement.clientHeight; // 如果滚动位置超过100px,显示回到顶部按钮,否则隐藏 if (scrollTop > 100) { toTopBtn.classList.add('ns-btn-show'); } else { toTopBtn.classList.remove('ns-btn-show'); } // 如果距离底部超过200px,显示回到底部按钮,否则隐藏 if (scrollHeight - scrollTop - clientHeight > 200) { toBottomBtn.classList.add('ns-btn-show'); } else { toBottomBtn.classList.remove('ns-btn-show'); } // 检查原始评论区是否在可视范围内 const commentEditor = iframeDoc.querySelector('.md-editor:not(.ns-fixed-editor)'); if (commentEditor) { const editorRect = commentEditor.getBoundingClientRect(); // 判断评论区是否在可视范围内(完全或部分可见) const isVisible = (editorRect.top < clientHeight && editorRect.bottom > 0) && !commentEditor.classList.contains('ns-fixed-editor'); // 如果评论区可见,隐藏评论按钮;否则显示评论按钮 if (isVisible) { toCommentBtn.classList.remove('ns-btn-show'); } else { toCommentBtn.classList.add('ns-btn-show'); } } else { // 如果找不到评论区,始终显示评论按钮 toCommentBtn.classList.add('ns-btn-show'); } }; // 初始检查滚动位置 handleScroll(); // 监听滚动事件 iframeDoc.addEventListener('scroll', handleScroll); // 添加表情包搜索功能到评论框 addEmojiSearchToCommentBox(iframeDoc); // 处理翻页链接,拦截点击实现无刷新翻页 setupPagination(iframeDoc, iframe); // 处理完成后移除加载指示器并显示iframe wrapper.removeChild(loaderContainer); iframe.style.opacity = 1; // 只在窗口宽度大于800px时才显示左侧信息卡片和导航卡片 if (window.innerWidth > 800) { // 显示左侧信息卡片(仅在iframe加载完成后) const sidebarInfo = container.querySelector('.ns-sidebar-info'); if (sidebarInfo) { sidebarInfo.style.display = 'flex'; } // 显示前后帖子导航卡片 const prevNavCard = container.querySelector('.ns-post-nav-card.prev'); if (prevNavCard) { prevNavCard.style.display = 'flex'; } const nextNavCard = container.querySelector('.ns-post-nav-card.next'); if (nextNavCard) { nextNavCard.style.display = 'flex'; } // 显示快捷回复按钮 const quickReplyBtn = container.querySelector('.ns-quick-reply'); if (quickReplyBtn) { quickReplyBtn.style.display = 'flex'; } } // 监听iframe内部主题变化并同步到外部UI const iframeObserver = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.attributeName === 'class') { // 检查iframe内的主题 const iframeIsDark = iframeDoc.body.classList.contains('dark-layout'); const parentIsDark = document.body.classList.contains('dark-layout'); // 如果主题不一致,同步父页面主题与iframe if (iframeIsDark !== parentIsDark) { if (iframeIsDark) { document.body.classList.add('dark-layout'); document.body.classList.remove('light-layout'); } else { document.body.classList.add('light-layout'); document.body.classList.remove('dark-layout'); } // 应用新主题 applyTheme(); } } }); }); // 开始观察iframe内body的class变化 iframeObserver.observe(iframeDoc.body, { attributes: true }); } catch (error) { console.error('无法修改iframe内容:', error); // 出错时也显示iframe,确保用户能看到内容 wrapper.removeChild(loaderContainer); iframe.style.opacity = 1; // 即使出错也显示左侧信息卡片 const sidebarInfo = container.querySelector('.ns-sidebar-info'); if (sidebarInfo) { sidebarInfo.style.display = 'flex'; } // 即使出错也显示前后帖子导航卡片 const prevNavCard = container.querySelector('.ns-post-nav-card.prev'); if (prevNavCard) { prevNavCard.style.display = 'flex'; } const nextNavCard = container.querySelector('.ns-post-nav-card.next'); if (nextNavCard) { nextNavCard.style.display = 'flex'; } } }; // 组装元素 wrapper.appendChild(closeBtn); wrapper.appendChild(loaderContainer); // 先添加加载指示器容器 wrapper.appendChild(iframe); container.appendChild(wrapper); document.body.appendChild(container); // 点击遮罩层关闭iframe container.addEventListener('click', function(e) { // 只有点击遮罩层本身才关闭,点击iframe内部不触发 if (e.target === container) { closeIframe(); } }); // 阻止iframe包装器的点击事件冒泡 wrapper.addEventListener('click', function(e) { e.stopPropagation(); }); // 关闭iframe的函数 function closeIframe() { document.body.removeChild(container); document.removeEventListener('keydown', escListener); // 恢复父页面滚动 document.body.style.overflow = originalBodyOverflow; } // 按ESC键关闭iframe function escListener(e) { if (e.key === 'Escape') { closeIframe(); } } document.addEventListener('keydown', escListener); // 加载新帖子的函数 - 移到openInIframe内部以便访问container变量 function loadNewPost(url, currentDomElements) { // 获取当前的postMap和postOrder const postMap = currentDomElements.postMap; const postOrder = currentDomElements.postOrder; if (!postMap || !postOrder) return; // 获取新帖子的信息 const newPostInfo = postMap.get(url); if (!newPostInfo) return; const newPostIndex = newPostInfo.index; const newPostElement = newPostInfo.element; if (!newPostElement) return; // 获取新帖子的详细信息 const postLink = newPostElement.querySelector('.post-title a[href^="/post-"]'); if (!postLink) return; const postTitle = postLink.textContent.trim(); const avatarImg = newPostElement.querySelector('.avatar-normal, img.avatar'); const userElement = newPostElement.querySelector('.author-name, .post-username, .username'); const postInfoElement = newPostElement.querySelector('.post-info, .info'); // 获取新帖子的前后帖子信息 let prevPost = null; let nextPost = null; // 获取前一篇帖子 if (newPostIndex > 0) { const prevUrl = postOrder[newPostIndex - 1]; const prevInfo = postMap.get(prevUrl); if (prevInfo) { prevPost = { url: prevUrl, title: prevInfo.title }; } } // 获取后一篇帖子 if (newPostIndex < postOrder.length - 1) { const nextUrl = postOrder[newPostIndex + 1]; const nextInfo = postMap.get(nextUrl); if (nextInfo) { nextPost = { url: nextUrl, title: nextInfo.title }; } } // 更新左侧信息卡片 const sidebarInfo = container.querySelector('.ns-sidebar-info'); if (sidebarInfo) { // 临时隐藏侧边栏,避免旧内容闪烁 sidebarInfo.style.display = 'none'; // 清空现有内容 sidebarInfo.innerHTML = ''; // 添加帖子标题 if (postTitle) { const titleElement = document.createElement('div'); titleElement.className = 'title'; titleElement.textContent = postTitle; titleElement.style.cssText = ` font-size: 18px; font-weight: bold; margin: 0 0 15px 0; text-align: center; color: var(--ns-card-text-color); width: 100%; `; sidebarInfo.appendChild(titleElement); } // 添加头像 if (avatarImg) { const avatarContainer = document.createElement('div'); avatarContainer.className = 'avatar-container'; // 克隆原始头像并添加样式 const avatarClone = avatarImg.cloneNode(true); avatarContainer.appendChild(avatarClone); sidebarInfo.appendChild(avatarContainer); } // 添加用户名和其他信息 if (userElement) { const userInfo = document.createElement('div'); userInfo.className = 'user-info'; const usernameClone = userElement.cloneNode(true); userInfo.appendChild(usernameClone); sidebarInfo.appendChild(userInfo); } // 添加帖子信息 if (postInfoElement) { const postInfo = document.createElement('div'); postInfo.className = 'post-info'; const infoClone = postInfoElement.cloneNode(true); postInfo.appendChild(infoClone); sidebarInfo.appendChild(postInfo); } } // 更新前后帖子导航卡片 // 移除旧的导航卡片 const oldPrevCard = container.querySelector('.ns-post-nav-card.prev'); if (oldPrevCard) { container.removeChild(oldPrevCard); } const oldNextCard = container.querySelector('.ns-post-nav-card.next'); if (oldNextCard) { container.removeChild(oldNextCard); } // 添加新的前一篇导航卡片(如果有) if (prevPost) { const prevNav = document.createElement('div'); prevNav.className = 'ns-post-nav-card prev'; prevNav.innerHTML = ` 上一篇 `; prevNav.setAttribute('data-url', prevPost.url); prevNav.addEventListener('click', function() { loadNewPost(this.getAttribute('data-url'), { postMap: postMap, postOrder: postOrder }); }); container.appendChild(prevNav); } // 添加新的下一篇导航卡片(如果有) if (nextPost) { const nextNav = document.createElement('div'); nextNav.className = 'ns-post-nav-card next'; nextNav.innerHTML = ` 下一篇 `; nextNav.setAttribute('data-url', nextPost.url); nextNav.addEventListener('click', function() { loadNewPost(this.getAttribute('data-url'), { postMap: postMap, postOrder: postOrder }); }); container.appendChild(nextNav); } // 显示加载指示器 const newLoaderContainer = document.createElement('div'); newLoaderContainer.className = 'ns-loader-container'; newLoaderContainer.style.cssText = ` position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; background-color: var(--ns-loader-bg); z-index: 10; `; // 添加帖子信息到加载指示器,与初始加载时保持一致 if (postTitle || avatarImg || userElement || postInfoElement) { // 创建简单信息容器用于加载界面 const infoContainer = document.createElement('div'); infoContainer.style.cssText = ` display: flex; flex-direction: column; align-items: center; width: 100%; max-width: 600px; padding: 10px 20px 20px; margin-bottom: 20px; text-align: center; `; // 添加头像元素,放在第一行居中 if (avatarImg) { const avatarContainer = document.createElement('div'); avatarContainer.style.cssText = ` display: flex; justify-content: center; margin-bottom: 15px; width: 100%; `; const avatarClone = avatarImg.cloneNode(true); avatarContainer.appendChild(avatarClone); infoContainer.appendChild(avatarContainer); } // 添加标题,放在第二行居中 if (postTitle) { const titleElement = document.createElement('div'); titleElement.textContent = postTitle; titleElement.style.cssText = ` font-size: 18px; font-weight: bold; margin: 0 0 15px 0; text-align: center; color: var(--ns-card-text-color); width: 100%; `; infoContainer.appendChild(titleElement); } // 用户名和帖子信息,放在第三行居中 const infoWrapper = document.createElement('div'); infoWrapper.style.cssText = ` display: flex; flex-direction: column; align-items: center; width: 100%; margin-bottom: 20px; `; // 添加用户名元素 if (userElement) { const usernameContainer = document.createElement('div'); usernameContainer.style.cssText = ` display: flex; justify-content: center; width: 100%; margin-bottom: 5px; `; const usernameClone = userElement.cloneNode(true); usernameContainer.appendChild(usernameClone); infoWrapper.appendChild(usernameContainer); } // 添加帖子信息元素 if (postInfoElement) { const infoElementContainer = document.createElement('div'); infoElementContainer.style.cssText = ` display: flex; justify-content: center; width: 100%; `; const infoClone = postInfoElement.cloneNode(true); infoElementContainer.appendChild(infoClone); infoWrapper.appendChild(infoElementContainer); } infoContainer.appendChild(infoWrapper); // 创建加载指示器 const loader = document.createElement('div'); loader.className = 'ns-loader'; loader.style.cssText = ` width: 40px; height: 40px; margin: 100px 0; border: 2px solid var(--ns-loader-border); border-top: 2px solid #2ea44f; border-radius: 50%; animation: spin 1s linear infinite; `; infoContainer.appendChild(loader); newLoaderContainer.appendChild(infoContainer); } else { // 如果没有帖子信息,只显示加载指示器 const loader = document.createElement('div'); loader.className = 'ns-loader'; loader.style.cssText = ` width: 40px; height: 40px; border: 2px solid var(--ns-loader-border); border-top: 2px solid #2ea44f; border-radius: 50%; animation: spin 1s linear infinite; `; newLoaderContainer.appendChild(loader); } // 更新iframe的src iframe.style.opacity = 0; wrapper.appendChild(newLoaderContainer); iframe.src = url; // iframe加载完成后,移除加载指示器并显示左侧信息卡片 iframe.onload = function() { try { // 原有的iframe加载完成处理代码... const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; // 移除header和footer const header = iframeDoc.querySelector('header'); const footer = iframeDoc.querySelector('footer'); if (header) header.style.display = 'none'; if (footer) footer.style.display = 'none'; // 移除右侧面板 const rightPanel = iframeDoc.getElementById('nsk-right-panel-container'); if (rightPanel) rightPanel.style.display = 'none'; // 添加自定义样式到iframe内部 const styleElement = iframeDoc.createElement('style'); styleElement.textContent = ` /* 隐藏可能的导航和页脚 */ header, .header, #header, footer, .footer, #footer, nav, .nav, #nav, .site-header, .site-footer, .main-header, .main-footer, .page-header, .page-footer, #nsk-right-panel-container { display: none !important; } /* 调整主要内容区域 */ body { padding-top: 0 !important; margin-top: 0 !important; } /* 让内容区域占满整个空间 */ .container, .main-content, .content, #content, .page-content, .site-content, main, .main, #main { padding-top: 10px !important; margin-top: 0 !important; max-width: 100% !important; } /* 调整文章内容宽度,右侧面板被移除后 */ .post-detail-card { width: 100% !important; max-width: 100% !important; } /* 强制设置nsk-container的margin为0 */ .nsk-container { margin: 0 !important; } /* 平滑滚动效果 */ html { scroll-behavior: smooth; } /* 自定义滚动条样式 */ ::-webkit-scrollbar { width: 6px; height: 6px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background: rgba(128, 128, 128, 0.35); border-radius: 3px; } ::-webkit-scrollbar-thumb:hover { background: rgba(128, 128, 128, 0.5); } /* 深色模式滚动条 */ body.dark-layout ::-webkit-scrollbar-thumb { background: rgba(180, 180, 180, 0.35); } body.dark-layout ::-webkit-scrollbar-thumb:hover { background: rgba(180, 180, 180, 0.5); } `; iframeDoc.head.appendChild(styleElement); // 应用自定义滚动条样式到主文档和iframe iframeDoc.documentElement.classList.add('ns-custom-scrollbar'); iframeDoc.body.classList.add('ns-custom-scrollbar'); // 应用自定义滚动条到主要内容区域 const mainContainers = iframeDoc.querySelectorAll('.container, .main-content, .content, #content, .page-content, .site-content, main, .main, #main, .post-detail-card, .comment-container'); mainContainers.forEach(container => { container.classList.add('ns-custom-scrollbar'); }); // 添加表情包搜索功能到评论框 addEmojiSearchToCommentBox(iframeDoc); // 处理翻页链接,拦截点击实现无刷新翻页 setupPagination(iframeDoc, iframe); // 处理完成后移除加载指示器并显示iframe wrapper.removeChild(newLoaderContainer); iframe.style.opacity = 1; // 只在窗口宽度大于800px时才显示左侧信息卡片和导航卡片 if (window.innerWidth > 800) { // 显示左侧信息卡片 if (sidebarInfo) { sidebarInfo.style.display = 'flex'; } // 显示前后帖子导航卡片 const prevNavCard = container.querySelector('.ns-post-nav-card.prev'); if (prevNavCard) { prevNavCard.style.display = 'flex'; } const nextNavCard = container.querySelector('.ns-post-nav-card.next'); if (nextNavCard) { nextNavCard.style.display = 'flex'; } // 显示快捷回复按钮 const quickReplyBtn = container.querySelector('.ns-quick-reply'); if (quickReplyBtn) { quickReplyBtn.style.display = 'flex'; } } } catch (error) { console.error('无法修改iframe内容:', error); // 出错时也显示iframe,确保用户能看到内容 wrapper.removeChild(newLoaderContainer); iframe.style.opacity = 1; // 即使出错也显示左侧信息卡片 if (sidebarInfo) { sidebarInfo.style.display = 'flex'; } // 即使出错也显示前后帖子导航卡片 const prevNavCard = container.querySelector('.ns-post-nav-card.prev'); if (prevNavCard) { prevNavCard.style.display = 'flex'; } const nextNavCard = container.querySelector('.ns-post-nav-card.next'); if (nextNavCard) { nextNavCard.style.display = 'flex'; } } }; } } // 添加表情包搜索功能到评论框 function addEmojiSearchToCommentBox(doc) { // 监听评论框加载 const checkCommentBox = setInterval(() => { const commentBox = doc.querySelector('.md-editor'); if (commentBox) { clearInterval(checkCommentBox); // 找到表情选择区域 const expressionArea = commentBox.querySelector('.expression'); if (!expressionArea) return; // 检查是否已经存在搜索框,避免重复添加 const existingSearchContainer = expressionArea.parentNode.querySelector('.ns-emoji-search'); if (existingSearchContainer) return; // 创建表情包搜索容器 const searchContainer = doc.createElement('div'); searchContainer.className = 'ns-emoji-search'; searchContainer.style.position = 'relative'; searchContainer.style.display = 'flex'; // 直接显示 // 创建搜索输入框 const searchInput = doc.createElement('input'); searchInput.type = 'text'; searchInput.placeholder = '搜索表情包...'; // 创建结果显示区域 const resultsContainer = doc.createElement('div'); resultsContainer.className = 'ns-emoji-results'; resultsContainer.style.display = 'none'; // 创建调试信息区域 const debugContainer = doc.createElement('div'); debugContainer.className = 'ns-debug-info'; debugContainer.style.display = 'none'; // 组装元素 searchContainer.appendChild(searchInput); searchContainer.appendChild(resultsContainer); searchContainer.appendChild(debugContainer); // 将搜索容器直接添加到expression元素后面 expressionArea.parentNode.insertBefore(searchContainer, expressionArea.nextSibling); // 获取编辑器实例 const editorArea = commentBox.querySelector('#code-mirror-editor'); let cmEditor = null; // 尝试获取CodeMirror编辑器实例 if (editorArea) { const cmElement = editorArea.querySelector('.CodeMirror'); if (cmElement && cmElement.CodeMirror) { cmEditor = cmElement.CodeMirror; } } // 回车键搜索 searchInput.addEventListener('keydown', async (e) => { if (e.key === 'Enter') { const query = searchInput.value.trim(); if (!query) return; // 显示"正在搜索"提示 resultsContainer.innerHTML = '
正在搜索表情包...
'; resultsContainer.style.display = 'flex'; // 搜索表情包 const response = await searchEmojis(query); // 显示结果 if (response.error || response.data.length === 0) { resultsContainer.innerHTML = `
${response.error || '未找到相关表情包'}
`; return; } // 清空结果容器 resultsContainer.innerHTML = ''; // 创建表情包结果布局 const emojiGrid = document.createElement('div'); emojiGrid.style.cssText = ` display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between; `; // 添加表情包元素 response.data.forEach(emoji => { const emojiItem = document.createElement('div'); emojiItem.className = 'ns-emoji-item'; const img = document.createElement('img'); img.src = emoji.url; img.setAttribute('data-url', emoji.url); img.setAttribute('title', `${emoji.width}x${emoji.height} ${(emoji.size/1024).toFixed(1)}KB`); // 添加加载错误处理 img.onerror = function() { // 图片加载失败时显示错误提示 this.onerror = null; this.src = 'data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22100%25%22%20height%3D%22100%25%22%3E%3Ctext%20x%3D%2250%25%22%20y%3D%2250%25%22%20font-size%3D%2210%22%20text-anchor%3D%22middle%22%20dominant-baseline%3D%22middle%22%3E图片加载失败%3C%2Ftext%3E%3C%2Fsvg%3E'; }; emojiItem.appendChild(img); // 点击表情包插入到编辑器 emojiItem.addEventListener('click', () => { const imgUrl = emoji.url; // 使用搜索关键词作为图片alt文本,而不是固定的"表情包" const markdownImg = `![${query}](${imgUrl})`; // 如果找到了CodeMirror编辑器,则插入到编辑器中 if (cmEditor) { const cursor = cmEditor.getCursor(); cmEditor.replaceRange(markdownImg, cursor); cmEditor.focus(); } else { // 找不到编辑器,尝试使用剪贴板 try { navigator.clipboard.writeText(markdownImg).then(() => { alert('已复制表情包Markdown到剪贴板,请粘贴到评论框'); }); } catch (err) { console.error('无法复制到剪贴板:', err); alert('无法自动插入表情包,请手动复制: ' + markdownImg); } } // 隐藏结果 resultsContainer.style.display = 'none'; }); emojiGrid.appendChild(emojiItem); }); resultsContainer.appendChild(emojiGrid); } }); // 点击页面其他区域关闭结果框 doc.addEventListener('click', (e) => { if (!searchContainer.contains(e.target)) { resultsContainer.style.display = 'none'; } }); } }, 500); } // 设置翻页功能 function setupPagination(iframeDoc, iframe) { // 检查是否已添加无限滚动标记,防止重复添加 if (iframeDoc.querySelector('.ns-infinite-scroll-active')) { return; } // 给文档添加无限滚动标记 const infiniteScrollMark = iframeDoc.createElement('div'); infiniteScrollMark.className = 'ns-infinite-scroll-active'; infiniteScrollMark.style.display = 'none'; iframeDoc.body.appendChild(infiniteScrollMark); // 添加加载状态指示器 const loadingIndicator = iframeDoc.createElement('div'); loadingIndicator.className = 'ns-comment-loading-indicator'; loadingIndicator.innerHTML = `
正在加载更多评论...
`; loadingIndicator.style.display = 'none'; // 找到评论容器 const commentContainer = iframeDoc.querySelector('.comment-container'); if (commentContainer) { // 添加加载指示器到评论容器末尾 commentContainer.appendChild(loadingIndicator); // 当前正在加载的状态标记 let isLoading = false; // 没有更多评论的标记 let noMoreComments = false; // 监听滚动事件 iframeDoc.addEventListener('scroll', function() { // 如果正在加载或已经没有更多评论,则不处理 if (isLoading || noMoreComments) return; const commentList = commentContainer.querySelector('ul.comments'); if (!commentList) return; // 计算滚动位置,判断是否接近底部 const scrollTop = iframeDoc.documentElement.scrollTop || iframeDoc.body.scrollTop; const scrollHeight = iframeDoc.documentElement.scrollHeight || iframeDoc.body.scrollHeight; const clientHeight = iframeDoc.documentElement.clientHeight || iframeDoc.body.clientHeight; // 当滚动到距离底部200px时触发加载 if (scrollHeight - scrollTop - clientHeight < 200) { loadNextPage(); } }); // 加载下一页评论 function loadNextPage() { // 获取下一页链接 const nextPageLink = commentContainer.querySelector('.pager-next'); if (!nextPageLink || !nextPageLink.href) { noMoreComments = true; return; } isLoading = true; loadingIndicator.style.display = 'block'; fetch(nextPageLink.href) .then(response => { if (!response.ok) throw new Error('网络响应不正常'); return response.text(); }) .then(htmlText => { // 解析HTML const parser = new DOMParser(); const newDoc = parser.parseFromString(htmlText, 'text/html'); // 获取新页面的评论列表 const newCommentList = newDoc.querySelector('.comment-container ul.comments'); if (!newCommentList) throw new Error('无法找到评论列表'); // 获取当前评论列表 const currentCommentList = commentContainer.querySelector('ul.comments'); if (!currentCommentList) throw new Error('无法找到当前评论列表'); // 获取新评论并添加到当前列表 const newComments = Array.from(newCommentList.children); newComments.forEach(comment => { // 检查评论ID是否已存在,避免重复添加 const commentId = comment.getAttribute('data-comment-id'); if (!commentId || !currentCommentList.querySelector(`[data-comment-id="${commentId}"]`)) { currentCommentList.appendChild(comment.cloneNode(true)); } }); // 处理新加载评论中的评论菜单挂载点 fixCommentMenus(iframeDoc); // 更新分页控件 updatePagination(newDoc); // 处理引用和回复按钮 setupCommentButtons(iframeDoc); // 更新URL(但不刷新页面) if (iframe.contentWindow.history && iframe.contentWindow.history.replaceState) { iframe.contentWindow.history.replaceState({}, '', nextPageLink.href); } // 检查是否有下一页 const hasNextPage = newDoc.querySelector('.pager-next'); if (!hasNextPage) { noMoreComments = true; // 移除底部分页控件,因为已经加载了所有评论 const bottomPager = commentContainer.querySelector('.post-bottom-pager'); if (bottomPager) { bottomPager.style.display = 'none'; } } }) .catch(error => { console.error('加载下一页评论失败:', error); }) .finally(() => { isLoading = false; loadingIndicator.style.display = 'none'; }); } // 更新分页控件 function updatePagination(newDoc) { // 获取新页面的顶部和底部分页控件 const newTopPager = newDoc.querySelector('.post-top-pager'); const newBottomPager = newDoc.querySelector('.post-bottom-pager'); // 获取当前页面的顶部和底部分页控件 const curTopPager = commentContainer.querySelector('.post-top-pager'); const curBottomPager = commentContainer.querySelector('.post-bottom-pager'); // 更新顶部分页控件 if (newTopPager && curTopPager) { curTopPager.innerHTML = newTopPager.innerHTML; } // 更新底部分页控件 if (newBottomPager && curBottomPager) { curBottomPager.innerHTML = newBottomPager.innerHTML; } } } // 获取所有分页链接 - 保留原有的点击处理,作为备选 const paginationLinks = iframeDoc.querySelectorAll('.nsk-pager a'); if (paginationLinks.length === 0) return; // 拦截所有分页链接点击事件 paginationLinks.forEach(link => { link.addEventListener('click', async function(e) { e.preventDefault(); // 显示加载状态 const pageContent = iframeDoc.querySelector('.comment-container'); if (pageContent) { // 创建加载指示器 const loadingIndicator = iframeDoc.createElement('div'); loadingIndicator.style.cssText = ` position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); display: flex; justify-content: center; align-items: center; z-index: 1000; `; const spinner = iframeDoc.createElement('div'); spinner.style.cssText = ` width: 40px; height: 40px; border: 4px solid var(--ns-loader-border); border-top: 4px solid #2ea44f; border-radius: 50%; animation: spin 1s linear infinite; `; // 添加动画样式 const animStyle = iframeDoc.createElement('style'); animStyle.textContent = ` @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } `; iframeDoc.head.appendChild(animStyle); loadingIndicator.appendChild(spinner); // 设置相对定位以便于放置加载指示器 if (window.getComputedStyle(pageContent).position === 'static') { pageContent.style.position = 'relative'; } pageContent.appendChild(loadingIndicator); } const targetUrl = this.href; try { // 使用fetch异步获取新页面内容 const response = await fetch(targetUrl); if (!response.ok) throw new Error('网络响应不正常'); const htmlText = await response.text(); // 创建临时DOM解析HTML const parser = new DOMParser(); const newDoc = parser.parseFromString(htmlText, 'text/html'); // 提取主要内容区域 const newContent = newDoc.querySelector('.comment-container'); if (!newContent) throw new Error('无法找到评论内容'); // 获取当前评论容器 const currentContent = iframeDoc.querySelector('.comment-container'); if (currentContent) { // 替换内容 currentContent.innerHTML = newContent.innerHTML; // 更新页面URL(但不刷新页面) if (iframe.contentWindow.history && iframe.contentWindow.history.pushState) { iframe.contentWindow.history.pushState({}, '', targetUrl); } // 重新绑定新页面中的分页链接 setupPagination(iframeDoc, iframe); // 移除评论区内可能存在的旧表情搜索框,避免重复添加 const oldSearchContainers = iframeDoc.querySelectorAll('.ns-emoji-search'); oldSearchContainers.forEach(container => { if (container && container.parentNode) { container.parentNode.removeChild(container); } }); // 添加表情包搜索功能到新页面的评论框 addEmojiSearchToCommentBox(iframeDoc); // 处理引用和回复按钮 setupCommentButtons(iframeDoc); // 翻页后滚动到顶部 iframeDoc.documentElement.scrollTop = 0; // 触发滚动事件,以便更新按钮状态 const scrollEvent = new Event('scroll'); iframeDoc.dispatchEvent(scrollEvent); } else { throw new Error('无法找到当前评论容器'); } } catch (error) { console.error('异步加载页面失败:', error); // 加载失败时回退到传统导航方式 iframe.src = targetUrl; } // 删除加载指示器 const loadingIndicator = iframeDoc.querySelector('.comment-container > div[style*="position: absolute"]'); if (loadingIndicator) { loadingIndicator.parentNode.removeChild(loadingIndicator); } }); }); } // 设置评论按钮功能(引用和回复) function setupCommentButtons(iframeDoc) { // 获取所有引用和回复按钮 const quoteButtons = iframeDoc.querySelectorAll('.comment-menu .menu-item:has(svg[href="#quote"])'); const replyButtons = iframeDoc.querySelectorAll('.comment-menu .menu-item:has(svg[href="#back"])'); // 为引用按钮添加事件 quoteButtons.forEach(button => { button.addEventListener('click', function(e) { // 找到对应的评论内容 const commentItem = this.closest('.content-item'); if (!commentItem) return; // 获取评论ID和作者 const commentId = commentItem.getAttribute('data-comment-id'); const authorElement = commentItem.querySelector('.author-name'); const author = authorElement ? authorElement.textContent : '用户'; // 获取评论内容 const contentElement = commentItem.querySelector('.post-content'); const content = contentElement ? contentElement.textContent.trim() : ''; // 找到编辑器并插入引用 const editor = iframeDoc.querySelector('.CodeMirror'); if (editor && editor.CodeMirror) { const quote = `> **${author}** 说:\n${content.split('\n').map(line => '> ' + line).join('\n')}\n\n`; editor.CodeMirror.replaceSelection(quote); editor.CodeMirror.focus(); // 滚动到编辑器 const editorElement = iframeDoc.querySelector('.md-editor'); if (editorElement) { editorElement.scrollIntoView({ behavior: 'smooth', block: 'center' }); } } }); }); // 为回复按钮添加事件 replyButtons.forEach(button => { button.addEventListener('click', function(e) { // 找到对应的评论项 const commentItem = this.closest('.content-item'); if (!commentItem) return; // 获取作者名 const authorElement = commentItem.querySelector('.author-name'); const author = authorElement ? authorElement.textContent : '用户'; // 找到编辑器并插入@ const editor = iframeDoc.querySelector('.CodeMirror'); if (editor && editor.CodeMirror) { editor.CodeMirror.replaceSelection(`@${author} `); editor.CodeMirror.focus(); // 滚动到编辑器 const editorElement = iframeDoc.querySelector('.md-editor'); if (editorElement) { editorElement.scrollIntoView({ behavior: 'smooth', block: 'center' }); } } }); }); } // 当DOM加载完成后初始化 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } // 添加一个新函数,用于创建和显示浮动评论框 function showFloatingCommentBox(iframeDoc) { // 检查是否已存在浮动评论框 let floatingBox = iframeDoc.querySelector('.ns-floating-comment-box'); let backdrop = iframeDoc.querySelector('.ns-comment-backdrop'); // 如果不存在,创建浮动评论框 if (!floatingBox) { // 创建背景遮罩 backdrop = iframeDoc.createElement('div'); backdrop.className = 'ns-comment-backdrop'; iframeDoc.body.appendChild(backdrop); // 创建浮动评论框 floatingBox = iframeDoc.createElement('div'); floatingBox.className = 'ns-floating-comment-box'; // 创建评论框头部(标题和关闭按钮) const header = iframeDoc.createElement('div'); header.className = 'ns-floating-comment-header'; const title = iframeDoc.createElement('div'); title.className = 'ns-floating-comment-title'; title.textContent = '发表评论'; const closeBtn = iframeDoc.createElement('div'); closeBtn.className = 'ns-floating-comment-close'; closeBtn.innerHTML = '×'; closeBtn.onclick = () => { floatingBox.classList.remove('active'); backdrop.classList.remove('active'); }; header.appendChild(title); header.appendChild(closeBtn); floatingBox.appendChild(header); // 查找页面中的评论编辑器 const originalEditor = iframeDoc.querySelector('.md-editor'); if (originalEditor) { // 克隆评论编辑器到浮动框 const editorClone = originalEditor.cloneNode(true); // 处理克隆的编辑器中的事件和交互 // 设置提交评论按钮的点击事件 const submitBtn = editorClone.querySelector('.submit.btn'); if (submitBtn) { submitBtn.onclick = (e) => { // 获取原始提交按钮并触发点击 const originalSubmitBtn = originalEditor.querySelector('.submit.btn'); if (originalSubmitBtn) { // 将浮动编辑器中的内容复制到原始编辑器 // 这里需要特殊处理CodeMirror编辑器 try { const textContent = editorClone.querySelector('textarea')?.value; if (textContent) { // 找到原编辑器中的CodeMirror实例 const cmElement = originalEditor.querySelector('.CodeMirror'); if (cmElement && cmElement.CodeMirror) { // 在原编辑器中设置内容 cmElement.CodeMirror.setValue(textContent); } } // 点击原始提交按钮 originalSubmitBtn.click(); // 关闭浮动框 floatingBox.classList.remove('active'); backdrop.classList.remove('active'); } catch (e) { console.error('无法提交评论:', e); } } }; } floatingBox.appendChild(editorClone); // 添加表情包搜索框 addEmojiSearchToCommentBox(floatingBox); } else { // 没有找到评论编辑器,显示提示信息 const message = iframeDoc.createElement('div'); message.style.padding = '20px'; message.style.textAlign = 'center'; message.style.color = 'var(--ns-card-secondary-text)'; message.textContent = '未找到评论编辑器,请尝试滚动到页面底部'; floatingBox.appendChild(message); } // 添加浮动评论框到文档 iframeDoc.body.appendChild(floatingBox); // 点击背景遮罩关闭评论框 backdrop.onclick = () => { floatingBox.classList.remove('active'); backdrop.classList.remove('active'); }; } // 显示评论框 setTimeout(() => { backdrop.classList.add('active'); floatingBox.classList.add('active'); // 尝试让编辑器获得焦点 const textarea = floatingBox.querySelector('textarea'); if (textarea) { textarea.focus(); } }, 50); } // 添加一个切换浮动评论框显示/隐藏的函数 function toggleFloatingCommentBox(iframeDoc) { let originalEditor = iframeDoc.querySelector('.md-editor'); // 如果没有找到评论编辑器,直接返回 if (!originalEditor) { console.log('未找到评论编辑器'); return; } // 判断编辑器是否已经是固定状态 if (originalEditor.classList.contains('ns-fixed-editor')) { // 如果是,取消固定 unfixEditor(); } else { // 如果不是,设置为固定 fixEditor(); } // 设置为固定定位 function fixEditor() { // 创建占位符(如果不存在) let editorPlaceholder = iframeDoc.getElementById('ns-editor-placeholder'); if (!editorPlaceholder) { editorPlaceholder = iframeDoc.createElement('div'); editorPlaceholder.id = 'ns-editor-placeholder'; editorPlaceholder.className = 'ns-editor-placeholder'; editorPlaceholder.textContent = '评论编辑器已固定在视图中...'; // 插入占位符 originalEditor.parentNode.insertBefore(editorPlaceholder, originalEditor.nextSibling); } // 显示占位符 editorPlaceholder.style.display = 'block'; // 将编辑器设置为固定定位 originalEditor.classList.add('ns-fixed-editor'); // 尝试让编辑器获得焦点 try { const cmEditor = originalEditor.querySelector('.CodeMirror'); if (cmEditor && cmEditor.CodeMirror) { setTimeout(() => { cmEditor.CodeMirror.focus(); cmEditor.CodeMirror.refresh(); }, 100); } } catch (e) { console.error('无法使编辑器获得焦点:', e); } // 添加ESC键监听 iframeDoc.addEventListener('keydown', escKeyHandler); } // 取消固定定位 function unfixEditor() { // 移除fixed类 originalEditor.classList.remove('ns-fixed-editor'); // 隐藏占位符 const editorPlaceholder = iframeDoc.getElementById('ns-editor-placeholder'); if (editorPlaceholder) { editorPlaceholder.style.display = 'none'; } // 移除ESC键监听 iframeDoc.removeEventListener('keydown', escKeyHandler); } // ESC键处理函数 function escKeyHandler(e) { if (e.key === 'Escape' && originalEditor.classList.contains('ns-fixed-editor')) { unfixEditor(); } } } // 添加新函数修复加载的评论菜单 function fixCommentMenus(doc) { // 查找所有需要处理的评论菜单挂载点 const menuMounts = doc.querySelectorAll('.comment-menu-mount'); if (menuMounts.length === 0) return; menuMounts.forEach(mount => { // 获取所在的评论项 const commentItem = mount.closest('.content-item'); if (!commentItem) return; // 创建评论菜单 const commentMenu = doc.createElement('div'); commentMenu.className = 'comment-menu'; commentMenu.setAttribute('data-v-372de460', ''); // 简化后只保留引用和回复功能 // 添加引用选项 const quoteBtn = doc.createElement('div'); quoteBtn.className = 'menu-item'; quoteBtn.setAttribute('data-v-372de460', ''); quoteBtn.innerHTML = ` 引用 `; // 添加引用功能 quoteBtn.addEventListener('click', function() { // 找到对应的评论内容 const contentElement = commentItem.querySelector('.post-content'); const authorElement = commentItem.querySelector('.author-name'); if (contentElement && authorElement) { const content = contentElement.textContent.trim(); const author = authorElement.textContent.trim(); // 找到编辑器并插入引用 const editor = doc.querySelector('.CodeMirror'); if (editor && editor.CodeMirror) { const quote = `> **${author}** 说:\n${content.split('\n').map(line => '> ' + line).join('\n')}\n\n`; editor.CodeMirror.replaceSelection(quote); editor.CodeMirror.focus(); // 滚动到编辑器 const editorElement = doc.querySelector('.md-editor'); if (editorElement) { editorElement.scrollIntoView({ behavior: 'smooth', block: 'center' }); } } } }); commentMenu.appendChild(quoteBtn); // 添加回复选项 const replyBtn = doc.createElement('div'); replyBtn.className = 'menu-item'; replyBtn.setAttribute('data-v-372de460', ''); replyBtn.innerHTML = ` 回复 `; // 添加回复功能 replyBtn.addEventListener('click', function() { const authorElement = commentItem.querySelector('.author-name'); if (authorElement) { const author = authorElement.textContent.trim(); // 找到编辑器并插入@ const editor = doc.querySelector('.CodeMirror'); if (editor && editor.CodeMirror) { editor.CodeMirror.replaceSelection(`@${author} `); editor.CodeMirror.focus(); // 滚动到编辑器 const editorElement = doc.querySelector('.md-editor'); if (editorElement) { editorElement.scrollIntoView({ behavior: 'smooth', block: 'center' }); } } } }); commentMenu.appendChild(replyBtn); // 替换原始的挂载点 mount.parentNode.replaceChild(commentMenu, mount); }); } })();