您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在湖南大学CG平台中为每个代码块添加复制按钮
// ==UserScript== // @name 湖南大学CG平台代码块复制 // @namespace http://tampermonkey.net/ // @version 1.7 // @description 在湖南大学CG平台中为每个代码块添加复制按钮 // @author 淼畔 // @match https://cg.hnu.edu.cn/* // @grant none // @license MIT // @icon https://cg.hnu.edu.cn/images/cgicon.png // ==/UserScript== (function () { 'use strict'; // 存储已处理的代码块 const processedPre = new WeakSet(); // 初始处理可见的代码块 document.querySelectorAll('pre').forEach(pre => { if (isElementVisible(pre)) { addButtonForPre(pre); } }); // 设置监控 DOM 变化的观察器 const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { if (mutation.type === 'childList') { // 处理新增节点 mutation.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) { if (node.tagName === 'PRE' && isElementVisible(node)) { addButtonForPre(node); } node.querySelectorAll('pre').forEach(pre => { if (isElementVisible(pre)) { addButtonForPre(pre); } }); } }); } else if (mutation.type === 'attributes' && mutation.attributeName === 'style') { document.querySelectorAll('pre').forEach(pre => { if (isElementVisible(pre)) { addButtonForPre(pre); } }); } }); }); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style'] }); // 为单个代码块添加按钮 function addButtonForPre(pre) { if (processedPre.has(pre)) return; processedPre.add(pre); // 查找合适的容器元素 let container = findSuitableContainer(pre); // 检查字符长度 const text = container.textContent.trim(); const shouldNewLine = text.length > 15; let btnContainer = container; if (shouldNewLine) { const newContainer = document.createElement('div'); newContainer.style.marginTop = '4px'; pre.parentNode.insertBefore(newContainer, pre); btnContainer = newContainer; } // 添加复制按钮 createCopyButton(btnContainer, pre); } // 获取pre元素的文本内容,处理<br>换行,并替换特殊空格和非期望字符 function getPreTextContent(pre) { // 克隆节点以避免修改原始DOM const clone = pre.cloneNode(true); // 替换所有<br>为换行符 const brs = clone.querySelectorAll('br'); brs.forEach(br => { br.parentNode.replaceChild(document.createTextNode('\n'), br); }); // 获取文本内容并处理非期望字符 let text = clone.textContent.trim(); // 替换所有类型的空格字符(除换行符外)和控制字符 text = text.replace(/[^\S\n]|[\x00-\x09\x0B-\x1F\x7F-\x9F]/g, ' '); // 合并连续的空格为单个空格(不包括换行符) text = text.replace(/(?!\n) +(?!\n)/g, ' '); return text; } // 智能查找合适的容器元素 function findSuitableContainer(pre) { // 默认使用前一个元素 let candidate = pre.previousElementSibling; // 向前搜索最多5个元素 for (let i = 0; i < 5 && candidate; i++) { const isValid = ( candidate && candidate.tagName !== 'BR' && // 跳过 <br> 元素 !isEffectivelyEmpty(candidate) // 跳过空元素 ); if (isValid) { return candidate; } candidate = candidate.previousElementSibling; } // 如果没有找到合适元素,创建新容器 const container = document.createElement('div'); container.style.margin = '8px 0'; pre.parentNode.insertBefore(container, pre); return container; } // 检查元素是否实质为空 function isEffectivelyEmpty(element) { if (!element) return true; // 检查可见子元素 const hasVisibleChildren = Array.from(element.children).some(child => { return isElementVisible(child) && !isEffectivelyEmpty(child); }); // 检查文本内容 const text = element.textContent.trim(); return !hasVisibleChildren && text === ''; } // 创建复制按钮 function createCopyButton(container, preElement) { // 避免重复添加 if (container.querySelector('.hnu-copy-btn')) return; const btn = document.createElement('button'); btn.className = 'hnu-copy-btn'; btn.textContent = '复制'; btn.style.cssText = ` font-size: 12px; padding: 2px 8px; background: #f5f5f5; border: 1px solid #ddd; border-radius: 3px; cursor: pointer; color: #333; transition: all 0.3s; position: relative; z-index: 1000; `; container.appendChild(btn); btn.addEventListener('click', function () { const originalText = btn.textContent; copyToClipboard(getPreTextContent(preElement)); btn.textContent = "✓ 复制成功"; btn.style.background = "#edfae9"; btn.style.borderColor = "#4CAF50"; btn.style.color = "#4CAF50"; setTimeout(() => { btn.textContent = originalText; btn.style.background = "#f5f5f5"; btn.style.borderColor = "#ddd"; btn.style.color = "#333"; }, 400); }); } // 判断元素是否可见 function isElementVisible(el) { if (!el) return false; if (el.style && el.style.display === 'none') return false; const computedStyle = window.getComputedStyle(el); if (computedStyle.display === 'none') return false; if (computedStyle.visibility === 'hidden') return false; let parent = el.parentElement; while (parent && parent !== document.body) { const parentStyle = window.getComputedStyle(parent); if (parentStyle.display === 'none' || parentStyle.visibility === 'hidden') { return false; } parent = parent.parentElement; } return true; } // 复制到剪贴板 function copyToClipboard(text) { const textArea = document.createElement('textarea'); textArea.value = text; textArea.style.position = 'fixed'; textArea.style.opacity = '0'; // 透明但可操作 document.body.appendChild(textArea); textArea.select(); document.execCommand('copy'); document.body.removeChild(textArea); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址