好友
阅读权限10
听众
最后登录1970-1-1
|
本帖最后由 Main91 于 2026-3-23 14:54 编辑
AirScript脚本编写调试的时候日志不好复制,所以用AI写了个篡改猴的JS脚本,自动添加复制按钮,一键复制日志
方便将日志发给AI
[JavaScript] 纯文本查看 复制代码 // ==UserScript==
// @name 金山文档 WPS云文档- AirScript添加复制运行日志按钮
// @namespace https://github.com/your-name/kdocs-copy-log
// @version 3.3.0
// @description 将复制按钮完美嵌入运行日志面板,利用原生 Flex 布局完美贴合并垂直居中,还原原生按钮间距,自动单行排版
// @author You
// @match https://www.kdocs.cn/*
// @match https://kdocs.cn/*
// @grant GM_setClipboard
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
// ===================== 原生风格图标 (SVG) =====================
const COPY_SVG = `<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="5.25" y="5.25" width="9" height="9" rx="1.5" stroke="#333" stroke-width="1.2" fill="none"/>
<path d="M10.75 5.25V3.25C10.75 2.42157 10.0784 1.75 9.25 1.75H3.25
C2.42157 1.75 1.75 2.42157 1.75 3.25V9.25
C1.75 10.0784 2.42157 10.75 3.25 10.75H5.25"
stroke="#333" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
</svg>`;
const CHECK_SVG = `<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 8.5L6.5 12L13 4" stroke="#52c41a" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>`;
// ===================== 注入样式到 iframe =====================
function injectIframeStyle(doc) {
if (doc.getElementById('db-copy-log-style')) return;
const style = doc.createElement('style');
style.id = 'db-copy-log-style';
style.textContent = `
#db-copy-log-btn {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
#db-copy-log-btn .copy-tooltip {
display: none;
position: absolute;
bottom: -30px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.75);
color: #fff;
font-size: 12px;
padding: 4px 8px;
border-radius: 4px;
white-space: nowrap;
pointer-events: none;
z-index: 99999;
font-weight: normal;
line-height: 1;
}
#db-copy-log-btn .copy-tooltip.show {
display: block;
}
`;
doc.head.appendChild(style);
}
// ============ 格式化日志内容 ============
function formatLogText(rawText) {
if (!rawText) return '';
const lines = rawText.split('\n').map(l => l.trim()).filter(l => l !== '');
const timeRegex = /^\d{2}:\d{2}:\d{2}(?:\.\d{3})?$/;
const logs = [];
let currentLog = [];
for (const line of lines) {
if (timeRegex.test(line)) {
if (currentLog.length > 0) logs.push(currentLog.join(' '));
currentLog = [line];
} else {
if (currentLog.length > 0) {
currentLog.push(line);
}
}
}
if (currentLog.length > 0) logs.push(currentLog.join(' '));
const uniqueLogs = [...new Set(logs)];
return uniqueLogs.join('\n');
}
// ============ 提取日志文本 ============
function extractLogText() {
try {
const iframe = document.getElementById('db_script_ide');
if (!iframe || !iframe.contentDocument) return '';
const doc = iframe.contentDocument;
const knownContainer = doc.querySelector('.logArea');
if (knownContainer && knownContainer.innerText.trim()) {
return formatLogText(knownContainer.innerText);
}
const candidates = doc.querySelectorAll('div, pre, code, ul, section, main');
let bestElement = null;
let maxTimeCount = 0;
const timeRegexGlobal = /^\d{2}:\d{2}:\d{2}(?:\.\d{3})?$/gm;
for (const el of candidates) {
const text = el.innerText || '';
const matches = text.match(timeRegexGlobal);
const timeCount = matches ? matches.length : 0;
if (timeCount > 0) {
if (timeCount > maxTimeCount) {
maxTimeCount = timeCount;
bestElement = el;
} else if (timeCount === maxTimeCount && bestElement) {
if (text.length < bestElement.innerText.length) {
bestElement = el;
}
}
}
}
if (bestElement) {
return formatLogText(bestElement.innerText);
}
} catch (e) {
console.warn('[复制日志] 无法访问 iframe:', e);
}
return '';
}
// ============ 复制到剪贴板 ============
function copyToClipboard(text) {
if (typeof GM_setClipboard === 'function') {
GM_setClipboard(text, 'text');
return;
}
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).catch(() => fallbackCopy(text));
return;
}
fallbackCopy(text);
}
function fallbackCopy(text) {
const ta = document.createElement('textarea');
ta.value = text;
ta.style.cssText = 'position:fixed;left:-9999px;top:-9999px';
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
}
// ============ 注入按钮 ============
function tryInject() {
const iframe = document.getElementById('db_script_ide');
if (!iframe || !iframe.contentDocument) return;
const doc = iframe.contentDocument;
if (doc.getElementById('db-copy-log-btn')) return;
const headers = doc.querySelectorAll('.header');
let logHeader = null;
for (const h of headers) {
if (h.innerText.includes('运行日志')) {
logHeader = h;
break;
}
}
if (!logHeader) return;
const closeBtn = logHeader.querySelector('button.close');
if (!closeBtn) return;
injectIframeStyle(doc);
const btn = doc.createElement('button');
btn.id = 'db-copy-log-btn';
btn.type = 'button';
btn.className = 'kd-button kd-button-light kd-button-lg kd-button-icon';
btn.title = '复制运行日志';
// ── 【还原官方紧凑间距】 ──
btn.style.width = '32px';
btn.style.height = '32px';
btn.style.marginLeft = 'auto'; // 依然负责把关闭按钮顶到最右侧
btn.style.marginRight = '0px'; // ❗ 设为0,完全依赖原生按钮自带的内边距,达到无缝贴合效果
btn.innerHTML = `
<i class="kd-icon kd-icon-pro" style="line-height: 0;">
${COPY_SVG}
</i>
<span class="copy-tooltip">已复制!</span>
`;
closeBtn.parentElement.insertBefore(btn, closeBtn);
btn.addEventListener('click', () => {
let logText = extractLogText();
if (!logText) {
logText = '(未获取到运行日志内容,请确保面板已输出日志)';
}
copyToClipboard(logText);
const iconContainer = btn.querySelector('i');
const tooltip = btn.querySelector('.copy-tooltip');
iconContainer.innerHTML = CHECK_SVG;
tooltip.classList.add('show');
setTimeout(() => {
iconContainer.innerHTML = COPY_SVG;
tooltip.classList.remove('show');
}, 1500);
});
}
// ============ 轮询监听 ============
setInterval(() => {
tryInject();
}, 1000);
})(); |
-
免费评分
-
查看全部评分
|
发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。 |
|
|
|
|
|