您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
双击文本框的文字,可以复制内容到剪贴板。方便复制内容粘贴到其他页面。
// ==UserScript== // @name 简道云文本框内容复制助手Pro // @namespace https://www.jiandaoyun.com/copy // @version 4.1.2 // @description 双击文本框的文字,可以复制内容到剪贴板。方便复制内容粘贴到其他页面。 // @author 偶然好看 // @license MIT // @match https://www.jiandaoyun.com/* // @grant GM_setClipboard // @run-at document-end // ==/UserScript== (function() { 'use strict'; // 综合配置系统 const CONFIG = { TARGETS: [ 'div.fx-form-content-disabled span', '.subform-cell .fx-form-content-disabled span', 'input[type="text"]:not([readonly])', 'textarea:not([readonly])', '.input-inner input', '[data-editable="true"]' ], ROUTE_MARKERS: ['.router-link-active', '.tab-header-active'], RETRY: { MAX: 5, INTERVAL: 800 }, STYLES: { cursor: 'pointer', rippleColor: 'rgba(24, 144, 255, 0.3)', inputRipple: '#1890ff33' } }; const state = { activeRoute: null, observer: null, retryCount: 0, processing: false }; // 新增缺失的函数 function tagElement(element) { if (!element.dataset.superCopy) { element.dataset.superCopy = 'true'; element.style.pointerEvents = 'auto'; console.debug('[Tag] 元素标记完成:', element); } } function init() { if (window.__superCopy) return; window.__superCopy = true; injectMasterStyles(); setupGlobalHandlers(); startRouteWatcher(); performDeepScan(); console.info('[Master] 脚本已激活'); } function injectMasterStyles() { const style = document.createElement('style'); style.textContent = ` [data-super-copy] { cursor: ${CONFIG.STYLES.cursor} !important; user-select: text !important; -webkit-user-select: text !important; position: relative !important; } .super-ripple { position: absolute; background: ${CONFIG.STYLES.rippleColor}; border-radius: 50%; animation: superRipple 0.6s ease-out; transform: scale(0); pointer-events: none; } @keyframes superRipple { to { transform: scale(8); opacity: 0; } } `; document.head.prepend(style); } function setupGlobalHandlers() { document.addEventListener('dblclick', event => { const target = event.target.closest(CONFIG.TARGETS.join(',')); target && processCopy(target, event); }, true); } async function processCopy(element, event) { if (state.processing) return; state.processing = true; try { let text = element.textContent.trim() || element.value; // 新增处理千分符的逻辑 const thousandSeparatorRegex = /^\d{1,3}(,\d{3})*\.\d{2}$/; if (thousandSeparatorRegex.test(text)) { text = text.replace(/,/g, ''); } await GM_setClipboard(text); showFeedback(element, event); console.log('[Success] 复制成功:', text); } catch (err) { console.error('[Error] 复制失败:', err); } finally { state.processing = false; } } function showFeedback(element, event) { const ripple = document.createElement('div'); const rect = element.getBoundingClientRect(); Object.assign(ripple.style, { left: `${event.clientX - rect.left}px`, top: `${event.clientY - rect.top}px`, }); ripple.className = 'super-ripple'; element.appendChild(ripple); setTimeout(() => ripple.remove(), 600); } function startRouteWatcher() { const checkRoute = () => { const routeSign = document.querySelector(CONFIG.ROUTE_MARKERS)?.innerHTML; if (routeSign !== state.activeRoute) { state.activeRoute = routeSign; performDeepScan(true); } requestAnimationFrame(checkRoute); }; checkRoute(); } function performDeepScan(force = false) { if (state.retryCount >= CONFIG.RETRY.MAX && !force) return; // 修复点:使用统⼀的tagElement函数 document.querySelectorAll(CONFIG.TARGETS.join(',')) .forEach(tagElement); if (!state.observer) { state.observer = new MutationObserver(mutations => { mutations.forEach(({ addedNodes }) => { addedNodes.forEach(node => { if (node.nodeType === 1) { node.querySelectorAll(CONFIG.TARGETS.join(',')) .forEach(tagElement); // 使用已定义的函数 } }); }); }); state.observer.observe(document, { childList: true, subtree: true }); } if (!document.querySelector(CONFIG.TARGETS) && !force) { state.retryCount++; setTimeout(performDeepScan, CONFIG.RETRY.INTERVAL); } else { state.retryCount = 0; } } // 安全启动 if (document.readyState === 'complete') init(); else window.addEventListener('load', init); })();