Warning: fopen(/www/sites/update.greasyfork.icu/index/store/temp/c7c1a7fef3814512c7541d41bd3c707a.js): failed to open stream: No space left on device in /www/sites/update.greasyfork.icu/index/scriptControl.php on line 65
// ==UserScript==
// @name NodeSeek一键复制代码块
// @namespace https://www.nodeseek.com/space/3444
// @version 2025-04-19
// @description 用于在 NodeSeek 论坛一键复制代码块
// @license MIT
// @author Anya
// @match https://www.nodeseek.com/*
// @icon https://www.nodeseek.com/static/image/favicon/android-chrome-192x192.png
// @grant none
// @downloadURL https://update.greasyfork.icu/scripts/533312/NodeSeek%E4%B8%80%E9%94%AE%E5%A4%8D%E5%88%B6%E4%BB%A3%E7%A0%81%E5%9D%97.user.js
// @updateURL https://update.greasyfork.icu/scripts/533312/NodeSeek%E4%B8%80%E9%94%AE%E5%A4%8D%E5%88%B6%E4%BB%A3%E7%A0%81%E5%9D%97.meta.js
// ==/UserScript==
(function() {
'use strict';
// 样式注入:为复制按钮设置位置和外观
const style = document.createElement('style');
style.textContent = `
.tm-copy-btn {
position: absolute;
top: 8px;
right: 8px;
padding: 2px 8px;
font-size: 12px;
background: #4CAF50;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
z-index: 1000;
opacity: 0.8;
transition: opacity 0.2s;
}
.tm-copy-btn:hover {
opacity: 1;
}
pre.tm-copy-wrapper {
position: relative !important;
}
`;
document.head.appendChild(style);
// 给单个 添加复制按钮
function addCopyBtn(pre) {
if (pre.classList.contains('tm-copy-wrapper')) return; // 已处理过
const code = pre.querySelector('code');
if (!code) return;
pre.classList.add('tm-copy-wrapper');
const btn = document.createElement('button');
btn.className = 'tm-copy-btn';
btn.textContent = '复制';
btn.addEventListener('click', () => {
// 复制 code 内的纯文本
const text = code.innerText;
navigator.clipboard.writeText(text).then(() => {
btn.textContent = '已复制';
setTimeout(() => { btn.textContent = '复制'; }, 2000);
}).catch(err => {
console.error('复制失败:', err);
btn.textContent = '失败';
setTimeout(() => { btn.textContent = '复制'; }, 2000);
});
});
pre.appendChild(btn);
}
// 扫描页面中所有符合条件的 pre
function scanAndAttach() {
document.querySelectorAll('pre').forEach(addCopyBtn);
}
// 页面初次加载时运行一次
scanAndAttach();
// 针对动态添加的 ,使用 MutationObserver
const observer = new MutationObserver(mutations => {
for (const m of mutations) {
for (const node of m.addedNodes) {
if (!(node instanceof HTMLElement)) continue;
// 如果直接是 ,或包含若干
if (node.matches('pre')) {
addCopyBtn(node);
} else {
node.querySelectorAll?.('pre').forEach(addCopyBtn);
}
}
}
});
observer.observe(document.body, { childList: true, subtree: true });
})();