// ==UserScript== // @name 万能复制插件(预览 + 历史 + 美观提示) // @namespace http://tampermonkey.net/ // @version 10.0 // @description Ctrl+点击或长按复制网页内容,附带来源 + 高亮 + 音效 + 弹窗预览 + 历史记录 // @author You // @match *://*/* // @grant GM_setClipboard // @grant GM_registerMenuCommand // @require https://cdn.jsdelivr.net/npm/sweetalert2@11 // @downloadURL none // ==/UserScript== (function () { 'use strict'; const allowTags = ['div', 'span', 'p', 'pre', 'code', 'td', 'input', 'textarea', 'li']; const ignoreTags = ['button', 'a', 'script', 'style', 'footer', 'nav']; const copyHistory = []; let lastRightClickedEl = null; function playSound() { const audio = new Audio("data:audio/wav;base64,UklGRigAAABXQVZFZm10IBAAAAABAAEAESsAACJWAAACABAAZGF0YYAAAAA="); audio.play().catch(() => {}); } function highlight(el) { const prev = el.style.backgroundColor; el.style.transition = 'background-color 0.3s'; el.style.backgroundColor = '#ffe08a'; setTimeout(() => el.style.backgroundColor = prev, 1500); } function showTip(text) { Swal.fire({ toast: true, position: 'top-end', showConfirmButton: false, timer: 1800, background: '#28a745', color: 'white', icon: 'success', title: text }); } function preview(text) { const panel = document.createElement('div'); panel.style.cssText = ` position: fixed; bottom: 20px; left: 20px; background: white; color: black; padding: 10px; max-width: 400px; max-height: 200px; overflow: auto; border: 1px solid #aaa; box-shadow: 0 0 10px rgba(0,0,0,0.3); border-radius: 6px; z-index: 100000; font-family: monospace; white-space: pre-wrap; `; panel.textContent = text; document.body.appendChild(panel); setTimeout(() => panel.remove(), 5000); } function getText(el) { const tag = el.tagName.toLowerCase(); if (tag === 'input' || tag === 'textarea') return el.value.trim(); return el.innerText?.trim() || el.textContent?.trim() || ''; } function isCopyable(el) { const tag = el.tagName.toLowerCase(); if (ignoreTags.includes(tag)) return false; return allowTags.includes(tag); } function appendSource(text) { const url = window.location.href; const title = document.title; return `${text}\n\n【来源】${title}\n${url}`; } function copyWithSource(text) { if (!text || !text.trim()) return; const finalText = appendSource(text.trim()); if (navigator.clipboard) { navigator.clipboard.writeText(finalText).then(() => { playSound(); preview(finalText); showTip('✅ 已复制(附带来源)'); }).catch(() => { GM_setClipboard(finalText); showTip('✅ 兼容复制成功'); }); } else { GM_setClipboard(finalText); showTip('✅ 复制成功'); } copyHistory.unshift(finalText); if (copyHistory.length > 10) copyHistory.pop(); } document.addEventListener('click', (e) => { if (!e.ctrlKey) return; let el = e.target; while (el && el !== document.body) { if (isCopyable(el)) { const text = getText(el); if (text) { copyWithSource(text); highlight(el); break; } } el = el.parentElement; } }); let timer = null; document.addEventListener('mousedown', (e) => { let el = e.target; while (el && el !== document.body) { if (isCopyable(el)) { timer = setTimeout(() => { const text = getText(el); if (text) { copyWithSource(text); highlight(el); } }, 600); break; } el = el.parentElement; } }); document.addEventListener('mouseup', () => clearTimeout(timer)); document.addEventListener('mouseleave', () => clearTimeout(timer)); document.addEventListener('contextmenu', (e) => { lastRightClickedEl = e.target; }); GM_registerMenuCommand('📋 复制右键目标内容', () => { if (!lastRightClickedEl) return showTip('无记录'); let el = lastRightClickedEl; while (el && el !== document.body) { if (isCopyable(el)) { const text = getText(el); if (text) { copyWithSource(text); highlight(el); return; } } el = el.parentElement; } showTip('无可复制内容'); }); GM_registerMenuCommand('📑 查看复制历史', () => { const html = copyHistory.slice(0, 5).map((item, idx) => { return `
${idx + 1}.
${item}
`; }).join('
'); Swal.fire({ title: '📋 最近复制记录', html: html || '暂无记录', width: 600, confirmButtonText: '关闭', customClass: { popup: 'swal2-noanimation', } }); }); })();