// ==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);
})();