// ==UserScript== // @name 论文万能助手 · 免费划词改写 // @namespace https://jzlw.chat/ // @version 0.9.8 // @description 论文万能助手:任意网页划词改写。选中一段中文或英文,侧边面板或划词气泡即可换一种说法重写:降低查重率(降重)换说法、降低与原文的雷同程度;也可按降 AI 味做降AIGC,把机翻腔、套话改成更像人写的。腾讯文档、飞书、石墨、WPS 云文档里写初稿时,读到某段想换说法:选中 → 填进面板 → 看结果 → 满意就替换或复制。学校论文系统、教务页也能用;嫌烦可在本站隐藏。免登录免费试用,降重、改写、辅助、检测额度分开,面板页脚能看到剩余量,游客按本机标识按日计数,用完可第二天再来,注册登录后可用积分继续。还能做 AIGC检测:对当前段落给出模型返回的 AIGC 率、判定和一句话说明,只转述结果,不出正式报告。翻译、解释、总结可中英互译、把这段话讲通俗、压成要点,这三样是参考信息,不会当成正文去替换。支持上传 Word(.docx)试用文档开头,常见上限 5MB。更多里还有强力改写(降重加降 AI 味一起做)和英文改写。单次字数上限以面板为准。夜间模式未选过时跟随系统。侧边工具栏默认可贴右侧,设置里可改到左侧。适合润色自己写的文字,改完请自己读一遍再提交。 // @description:en Paper all-in-one assistant: select text on any page and rewrite it inline to paraphrase, reduce similarity, or lower AI-like wording. Free to try, no login. Similarity rewrite, AI-tone rewrite, helpers, and AIGC detection use separate daily quotas. Also AIGC detection (model rate and a short note; not an official report), translate, explain, summarize, and a Word trial. Extra modes: stronger and English rewrite. Night mode can follow the system. Please read the result before submitting. // @author 极致论文 // @license MIT // @match *://*/* // @noframes // @connect jzlw.chat // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @grant GM_registerMenuCommand // @run-at document-idle // @icon https://a.jzlw.my/upload/icon_1774847597_8221.gif // @antifeature:zh-CN tracking 使用改写功能时会上报匿名使用统计:脚本本地生成的随机设备编号,以及事件名(首次使用 / 改写 / 上传 / 额度用完 / 点击注册链接);首次使用那一次会附带当前站点域名。不上报你选中或上传的正文内容,不读取 Cookie。未激活的站点不发任何请求。 // @antifeature tracking When you use the rewrite feature, anonymous usage stats are sent to the author's server: a random device id generated locally by the script, plus event names (first-use / rewrite / upload / quota-exhausted / cta-click). The first-use event also includes the current site's hostname. The text you select or upload is never included, and no cookies are read. Sites where the script is not activated send nothing. // ==/UserScript== (function () { 'use strict'; const USE_PROD = true; const API_PROD = 'https://jzlw.chat/v1/guest'; function resolveApiBase() { try { const forced = typeof window !== 'undefined' && window.LRW_API_BASE; if (typeof forced === 'string' && forced.trim()) { return forced.replace(/\/$/, ''); } } catch (e) {} return API_PROD; } const CONFIG = { apiBase: resolveApiBase(), siteUrl: 'https://jzlw.chat/', inviteCode: '6666', brand: '论文万能助手', version: '0.9.8', maxSelection: 1500, aigcMaxSelection: 600, plagiarismMaxSelection: 600, cooldownSeconds: 8, assistCooldownSeconds: 3, detectCooldownSeconds: 20 }; document.querySelectorAll('#lrw-host').forEach(function (el) { el.remove(); }); const ACTIONS = [ { id: 'plagiarism', kind: 'rewrite', name: '降低查重率', run: '改写', out: '改写结果', copy: '复制结果', desc: '换说法、重排句子,降低与原文雷同。单次最多 600 字' }, { id: 'aigc', kind: 'rewrite', name: '降低 AIGC', run: '改写', out: '改写结果', copy: '复制结果', desc: '降 AIGC 率 · 改写,单次最多 600 字' }, { id: 'aigc_strong', kind: 'rewrite', primary: false, name: '强力改写', run: '改写', icon: 'bolt', out: '改写结果', copy: '复制结果', desc: '降 AI 改写 · 中文强力档。降重和降 AI 味一起做,改得更狠' }, { id: 'aigc_en', kind: 'rewrite', primary: false, name: '英文改写', run: '改写', icon: 'world', out: '改写结果', copy: '复制结果', desc: '降 AI 改写 · 英文标准档(英文仅此档)。按英文论文写法重写' }, { id: 'translate', kind: 'assist', name: '翻译', run: '翻译', icon: 'lang', out: '译文', copy: '复制译文', desc: '中英互译,方向自动判断' }, { id: 'explain', kind: 'assist', name: '解释', run: '解释', icon: 'bulb', out: '讲解', copy: '复制讲解', desc: '把这段话讲通俗,专业术语单独说明' }, { id: 'summary', kind: 'assist', name: '总结', run: '总结', icon: 'list', out: '要点', copy: '复制要点', desc: '压成几条要点,方便快速过一遍' }, { id: 'detect', kind: 'detect', name: 'AIGC 检测', run: '检测', icon: 'gauge', out: '检测结果', copy: '复制检测结果', desc: '独立检测。给出 AIGC 率、判定和一句话说明' } ]; const PRIMARY_ACTIONS = ACTIONS.filter((a) => a.kind === 'rewrite' && a.primary !== false); const MENU_ACTIONS = ACTIONS.filter((a) => PRIMARY_ACTIONS.indexOf(a) === -1); const MORE_TITLE = '更多功能:' + MENU_ACTIONS.map((a) => a.name).join(' / '); const DEFAULT_ACTION = ACTIONS[0].id; let detectEnabled = null; function detectIsOff() { return detectEnabled === false; } const MODES = ACTIONS.filter((a) => a.kind === 'rewrite'); const DEFAULT_MODE = MODES[0].id; function actionInfo(id) { return ACTIONS.filter((a) => a.id === id)[0] || ACTIONS[0]; } function currentAction() { const saved = GM.get('action', '') || GM.get('mode', ''); if (!ACTIONS.some((a) => a.id === saved)) return DEFAULT_ACTION; if (saved === 'detect' && detectIsOff()) return DEFAULT_ACTION; return saved; } function currentMode() { const saved = GM.get('mode', ''); return MODES.some((m) => m.id === saved) ? saved : DEFAULT_MODE; } function modeInfo(id) { return MODES.filter((m) => m.id === id)[0] || MODES[0]; } function rememberAction(id) { if (!ACTIONS.some((a) => a.id === id)) return; GM.set('action', id); if (actionInfo(id).kind === 'rewrite') GM.set('mode', id); } const DEFAULT_SITES = [ 'jzlw.chat', 'paperpass.com', 'paperyy.com', 'checkcopy.com', 'cnki.net', 'wanfangdata.com.cn', 'cqvip.com', 'kdocs.cn', 'docs.qq.com', 'shimo.im', 'feishu.cn', 'larksuite.com', 'yuque.com', 'note.youdao.com', 'office.com', 'officeapps.live.com', 'sharepoint.com', 'localhost', '127.0.0.1' ]; function readList(key) { try { const raw = GM.get(key, '[]'); const arr = JSON.parse(raw); return Array.isArray(arr) ? arr : []; } catch (e) { return []; } } function hostMatches(host, site) { return host === site || host.endsWith('.' + site); } function siteState() { const host = location.hostname; if (readList('disabled_sites').some((s) => hostMatches(host, s))) return 'off'; if (readList('enabled_sites').some((s) => hostMatches(host, s))) return 'user'; if (DEFAULT_SITES.some((s) => hostMatches(host, s))) return 'default'; return 'auto'; } function toggleSite(on) { const host = location.hostname; const enabled = readList('enabled_sites').filter((s) => s !== host); const disabled = readList('disabled_sites').filter((s) => s !== host); if (on) { enabled.push(host); } else { disabled.push(host); } GM.set('enabled_sites', JSON.stringify(enabled)); GM.set('disabled_sites', JSON.stringify(disabled)); location.reload(); } const QUOTA_CODES = ['quota_chars', 'quota_calls', 'quota_ip', 'budget_exhausted']; const DETECT_QUOTA_CODES = QUOTA_CODES.concat(['upstream_busy']); function isQuotaCode(code, kind) { const list = kind === 'detect' ? DETECT_QUOTA_CODES : QUOTA_CODES; return list.indexOf(code) !== -1; } const DETECT_FAIL_MSG = { disabled: '免费通道当前未开放', detect_disabled: 'AIGC 检测暂未开放,请稍后再试', not_configured: '服务暂时不可用,请稍后再试', bad_client: '客户端标识无效,请刷新页面后重试', empty_text: '请先选中需要检测的文字', too_long: '选中的文字超过了单次检测上限,请少选一点再试', too_fast: '操作太频繁,请稍后再试', quota_ip: '当前网络今日检测次数已用完,换个网络或明天再来', too_many_clients: '当前网络今日新增用户过多,请稍后再试', busy: '当前排队人数较多,请稍后再试', upstream_timeout: '检测超时,请稍后重试', upstream_error: '服务暂时不可用,请稍后再试', error: '服务暂时不可用,请稍后再试' }; const REWRITE_FAIL_MSG = { disabled: '免费通道当前未开放', not_configured: '服务暂时繁忙,请稍后重试', bad_client: '客户端标识无效,请刷新页面后重试', empty_text: '请先选中需要改写的文字', too_long: '选中的文字超过了单次上限,请少选一点再试', too_fast: '操作太频繁,请稍后再试', quota_ip: '当前网络今日额度已用完,换个网络或明天再来', too_many_clients: '当前网络今日新增用户过多,请稍后再试', busy: '当前排队人数较多,请稍后再试', empty_result: '改写失败,请稍后重试', error: '服务暂时繁忙,请稍后重试' }; function looksLikeInternalError(msg) { return /GUEST_|XYZ|AIGC_|PLAGIARISM|traceback|Traceback|Exception|Error:/i.test( String(msg || '')); } function safeFailMessage(res, kind, fallback) { const code = res && res.code; const table = kind === 'detect' ? DETECT_FAIL_MSG : REWRITE_FAIL_MSG; if (code && table[code]) return table[code]; const raw = res && res.message; if (raw && !looksLikeInternalError(raw)) return raw; return fallback || (kind === 'detect' ? '检测失败' : '改写失败'); } function ctaUrl(source) { const track = 'from=userscript&v=' + CONFIG.version + '&src=' + encodeURIComponent(source) + '&cid=' + encodeURIComponent(clientId()); return CONFIG.siteUrl + '?' + track + '#/register?invite=' + encodeURIComponent(CONFIG.inviteCode); } const GM = { get(key, fallback) { try { if (typeof GM_getValue === 'function') return GM_getValue(key, fallback); } catch (e) { } const raw = localStorage.getItem('lrw_' + key); return raw === null ? fallback : raw; }, set(key, value) { try { if (typeof GM_setValue === 'function') return GM_setValue(key, value); } catch (e) { } localStorage.setItem('lrw_' + key, value); }, request(opts) { if (typeof GM_xmlhttpRequest === 'function') { GM_xmlhttpRequest(opts); return; } fetch(opts.url, { method: opts.method || 'GET', headers: opts.headers || {}, body: opts.data }) .then(async (r) => opts.onload && opts.onload({ status: r.status, responseText: await r.text() })) .catch((e) => opts.onerror && opts.onerror(e)); } }; function api(path, body) { return new Promise((resolve, reject) => { const isGet = body === undefined; GM.request({ method: isGet ? 'GET' : 'POST', url: CONFIG.apiBase + path, headers: { 'Content-Type': 'application/json' }, data: isGet ? undefined : JSON.stringify(body), onload: (res) => { try { resolve(JSON.parse(res.responseText)); } catch (e) { reject(new Error('返回格式异常')); } }, onerror: () => reject(new Error('网络请求失败')) }); }); } function stat(event, source, detail) { return api('/stat', { event: event, client_id: clientId(), source: source || location.hostname, detail: detail || '' }).catch(() => {}); } function apiUpload(path, formData) { return new Promise((resolve, reject) => { GM.request({ method: 'POST', url: CONFIG.apiBase + path, data: formData, onload: (res) => { try { resolve(JSON.parse(res.responseText)); } catch (e) { reject(new Error('返回格式异常')); } }, onerror: () => reject(new Error('上传失败,请检查网络')) }); }); } function clientId() { let id = GM.get('client_id', ''); if (!id) { id = 'd' + Date.now().toString(36) + Math.random().toString(36).slice(2, 10); GM.set('client_id', id); } return id; } function markInstalled() { if (GM.get('installed', '')) return; GM.set('installed', String(Date.now())); stat('install'); } const CSS = ` :host { all: initial; position: fixed; z-index: 2147483645; left: 0; top: 0; width: 0; height: 0; overflow: visible; pointer-events: none; --p-paper-00: #FFFFFF; --p-paper-05: #F9FAF8; --p-paper-10: #F4F5F3; --p-paper-20: #EDEEEB; --p-paper-30: #E7E8E4; --p-paper-40: #D4D7D0; --p-paper-50: #8E948D; --p-ink-90: #1B211E; --p-ink-70: #3C423E; --p-ink-60: #565C57; --p-ink-50: #666D67; --p-coal-00: #111413; --p-coal-05: #181B19; --p-coal-20: #262B28; --p-coal-30: #2A2F2C; --p-coal-40: #3A403C; --p-coal-50: #6A716C; --p-chalk-90: #E8EBE7; --p-chalk-70: #C4C9C5; --p-chalk-60: #A9B0AB; --p-chalk-50: #8B928D; --p-green-70: #0A5740; --p-green-60: #0E6B4F; --p-green-30: #C3DED3; --p-green-10: #EBF4F0; --p-green-45: #4FC79E; --p-green-75: #25453A; --p-green-85: #12241D; --p-green-95: #0B1410; --p-red-60: #A62A21; --p-red-10: #FCEDEB; --p-red-45: #F08A7E; --p-red-85: #2A1512; --c-surface: var(--p-paper-00); --c-surface-soft: var(--p-paper-05); --c-surface-sunken: var(--p-paper-10); --c-surface-hover: var(--p-paper-20); --c-text: var(--p-ink-90); --c-text-strong: var(--p-ink-70); --c-text-muted: var(--p-ink-60); --c-text-meta: var(--p-ink-50); --c-text-on-accent: #FFFFFF; --c-line-hairline: var(--p-paper-30); --c-line-control: var(--p-paper-50); --c-line-edge: var(--p-paper-40); --c-accent: var(--p-green-60); --c-accent-press: var(--p-green-70); --c-accent-line: var(--p-green-30); --c-accent-wash: var(--p-green-10); --c-danger: var(--p-red-60); --c-danger-wash: var(--p-red-10); --c-focus: var(--p-green-60); --c-detect-surface: var(--c-surface-soft); --c-detect-ink: var(--c-text); --c-detect-muted: var(--c-text-muted); --c-detect-meta: var(--c-text-meta); --c-detect-track: var(--c-surface-hover); --c-detect-ring: var(--p-green-45); --c-detect-ai: var(--c-danger); --detect-card-bg: var(--c-detect-surface); --detect-ring-stroke: var(--c-detect-ring); --detect-bar-fill: var(--c-detect-ring); --detect-bar-track: var(--c-detect-track); --detect-card-shadow: 0 3px 4px 0 rgb(23 30 27 / .03); --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, "PingFang SC", "HarmonyOS Sans SC", "Source Han Sans SC", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif; --font-num: ui-monospace, "Segoe UI", "Cascadia Mono", "Segoe UI Mono", Consolas, monospace; --fs-read: 15px; --lh-read: 1.85; --fs-lead: 17px; --lh-lead: 1.55; --fs-base: 14px; --fs-label: 12px; --fs-meta: 12px; --fs-micro: 11px; --ls-label: .02em; --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px; --sp-6: 24px; --r-xs: 4px; --r-sm: 8px; --r-md: 12px; --r-full: 999px; --sh-dock: -1px 0 0 0 var(--c-line-edge), -6px 0 14px -6px rgb(23 30 27 / .10); --sh-float: 0 0 0 .5px rgb(23 30 27 / .10), 0 1px 2px rgb(23 30 27 / .05), 0 12px 32px -8px rgb(23 30 27 / .14); --sh-quiet: 0 0 0 .5px rgb(23 30 27 / .09), 0 2px 8px -2px rgb(23 30 27 / .10); --sh-chip: 0 0 0 1px rgb(255 255 255 / .16), 0 2px 6px rgb(0 0 0 / .24), 0 8px 20px -6px rgb(0 0 0 / .28); --mo-fast: 150ms; --mo-base: 180ms; --mo-slow: 220ms; --mo-ease: cubic-bezier(0, 0, .2, 1); --z-ball: 2147483645; --z-chip: 2147483646; --z-panel: 2147483647; --i-alert: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 12a9 9 0 1 0 18 0a9 9 0 0 0-18 0m9-4v4m0 4h.01'/%3E%3C/svg%3E"); --i-check: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12l5 5L20 7'/%3E%3C/svg%3E"); } @media (prefers-color-scheme: dark) { :host:not(.theme-light) { --c-surface: #161618; --c-surface-soft: #161618; --c-surface-sunken: #070707; --c-surface-hover: #1E1E22; --c-text: #F5F5F5; --c-text-strong: #D0D2DC; --c-text-muted: #B5B7C8; --c-text-meta: #9A9CAE; --c-text-on-accent: var(--p-green-95); --c-line-hairline: #1E2027; --c-line-control: #363843; --c-line-edge: #26272F; --c-accent: var(--p-green-45); --c-accent-press: #6FD8B4; --c-accent-line: var(--p-green-75); --c-accent-wash: var(--p-green-85); --c-danger: var(--p-red-45); --c-danger-wash: var(--p-red-85); --c-focus: var(--p-green-45); --sh-dock: -1px 0 0 0 var(--c-line-edge), -6px 0 14px -6px rgb(0 0 0 / .34); --sh-float: 0 0 0 .5px rgb(255 255 255 / .09), 0 1px 2px rgb(0 0 0 / .30), 0 12px 32px -8px rgb(0 0 0 / .44); --sh-quiet: 0 0 0 .5px rgb(255 255 255 / .08), 0 2px 8px -2px rgb(0 0 0 / .40); --detect-card-shadow: none; color-scheme: dark; } :host(.side-left):not(.theme-light) { --sh-dock: 1px 0 0 0 var(--c-line-edge), 6px 0 14px -6px rgb(0 0 0 / .34); } :host:not(.theme-light) .box.detect.detect-card { background: var(--c-surface); } } :host(.theme-dark) { --c-surface: #161618; --c-surface-soft: #161618; --c-surface-sunken: #070707; --c-surface-hover: #1E1E22; --c-text: #F5F5F5; --c-text-strong: #D0D2DC; --c-text-muted: #B5B7C8; --c-text-meta: #9A9CAE; --c-text-on-accent: var(--p-green-95); --c-line-hairline: #1E2027; --c-line-control: #363843; --c-line-edge: #26272F; --c-accent: var(--p-green-45); --c-accent-press: #6FD8B4; --c-accent-line: var(--p-green-75); --c-accent-wash: var(--p-green-85); --c-danger: var(--p-red-45); --c-danger-wash: var(--p-red-85); --c-focus: var(--p-green-45); --sh-dock: -1px 0 0 0 var(--c-line-edge), -6px 0 14px -6px rgb(0 0 0 / .34); --sh-float: 0 0 0 .5px rgb(255 255 255 / .09), 0 1px 2px rgb(0 0 0 / .30), 0 12px 32px -8px rgb(0 0 0 / .44); --sh-quiet: 0 0 0 .5px rgb(255 255 255 / .08), 0 2px 8px -2px rgb(0 0 0 / .40); --detect-card-shadow: none; color-scheme: dark; } :host(.theme-dark.side-left) { --sh-dock: 1px 0 0 0 var(--c-line-edge), 6px 0 14px -6px rgb(0 0 0 / .34); } :host(.theme-dark) .box.detect.detect-card { background: var(--c-surface); } * { box-sizing: border-box; font-family: var(--font-ui); } .num { font-family: var(--font-num); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; } .rt { overflow-wrap: anywhere; word-break: normal; line-break: strict; text-align: left; } .num { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; } .ic { width: 16px; height: 16px; flex: none; display: block; overflow: visible; transition: color var(--mo-base) var(--mo-ease), opacity var(--mo-base) var(--mo-ease), transform .35s cubic-bezier(.34, 1.56, .64, 1); } .ic path { transition: stroke-opacity var(--mo-base) var(--mo-ease), opacity var(--mo-base) var(--mo-ease); } @keyframes lucide-stroke-hover { 0% { stroke-dashoffset: 40; } 100% { stroke-dashoffset: 0; } } :where(button, a, textarea, input, [tabindex]):focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; } .rail, .panel, .bubble, .hint, .toast, .dlg, .menu, .pop { pointer-events: auto; } .bubble { position: fixed; z-index: var(--z-chip); display: inline-flex; align-items: center; gap: 2px; min-height: 34px; height: auto; padding: 4px; border-radius: var(--r-full); background: var(--p-ink-90); color: #fff; user-select: none; overflow: visible; box-shadow: var(--sh-chip); animation: pop var(--mo-base) var(--mo-ease); } .bubble > button { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px 6px; min-height: 26px; height: auto; padding: 4px 10px; border: 0; border-radius: var(--r-full); background: transparent; color: #fff; font-size: 13px; font-weight: 500; line-height: 1.2; white-space: nowrap; cursor: pointer; overflow: visible; transition: background var(--mo-fast) var(--mo-ease); } .bubble > button .pro { color: var(--p-green-45); background: rgb(255 255 255 / .10); border-color: rgb(255 255 255 / .18); } .bubble > button:hover { background: rgb(255 255 255 / .15); } .bubble > button:active { transform: translateY(1px); } .bubble > button .ic { width: 15px; height: 15px; color: var(--p-green-45); } .bubble > button:hover .ic { color: #fff; } .bubble > button .brand { width: 17px; height: 17px; display: block; object-fit: contain; } .bubble > button .brand-fallback { display: inline-flex; } .bubble > .more { padding: 0 7px; } .bubble > .more .ic { width: 16px; height: 16px; color: var(--p-chalk-60); } .bubble > .more:hover .ic { color: #fff; } .bubble > .sep { width: 1px; height: 16px; margin: 0 3px; background: rgb(255 255 255 / .2); } @keyframes pop { from { opacity: 0; transform: translateY(4px) scale(.96); } } .pop { display: none; position: absolute; right: 0; top: calc(100% + 6px); z-index: 3; min-width: 214px; padding: var(--sp-1); border-radius: var(--r-sm); background: var(--c-surface); box-shadow: var(--sh-float); animation: pop var(--mo-fast) var(--mo-ease); } .pop.open { display: block; } .pop.up { top: auto; bottom: calc(100% + 6px); } .pop .pi { display: flex; align-items: flex-start; gap: 9px; width: 100%; padding: 8px 10px; border: 0; border-radius: var(--r-xs); cursor: pointer; background: none; color: var(--c-text); text-align: left; } .pop .pi:hover { background: var(--c-surface-hover); } .pop .pi .ic { width: 16px; height: 16px; margin-top: 2px; color: var(--c-text-meta); overflow: visible; } .pop .pi:hover .ic { transform: scale(1.18) rotate(-6deg); } .pop .pi .ic path { stroke-dasharray: 60; stroke-dashoffset: 0; } .pop .pi:hover .ic path { animation: lucide-stroke-hover .5s ease-out forwards; } .pop .pi b { display: flex; align-items: center; flex-wrap: wrap; gap: 5px; font-size: 13px; font-weight: 600; line-height: 1.5; overflow: visible; } .pop .pi .pro { flex: none; } .pop .pi em { display: block; margin-top: 1px; font-style: normal; font-size: var(--fs-micro); line-height: 1.5; color: var(--c-text-meta); overflow-wrap: anywhere; white-space: normal; } .pop .pi.on { background: var(--c-accent-wash); } .pop .pi.on b, .pop .pi.on .ic { color: var(--c-accent); } .pop .pi[disabled] { cursor: not-allowed; background: none; } .pop .pi[disabled] b, .pop .pi[disabled] .ic { color: var(--c-text-meta); } .pop-cap { padding: 7px 10px 3px; font-size: var(--fs-micro); line-height: 1.4; letter-spacing: .04em; color: var(--c-text-meta); font-weight: 600; } .pop-cap:not(:first-child) { margin-top: 4px; padding-top: 8px; border-top: 1px solid var(--c-line-hairline); } .hint { position: fixed; z-index: var(--z-chip); max-width: 268px; padding: 11px 13px; border-radius: var(--r-sm); background: var(--p-ink-90); color: var(--p-chalk-90); font-size: 12.5px; line-height: 1.7; overflow-wrap: anywhere; box-shadow: var(--sh-chip); animation: pop var(--mo-base) var(--mo-ease); } .hint b { color: var(--p-green-45); font-weight: 600; } .toast { position: fixed; left: 50%; bottom: 30px; transform: translateX(-50%); z-index: var(--z-panel); max-width: 340px; padding: 11px 16px; border-radius: var(--r-sm); background: var(--p-ink-90); color: var(--p-chalk-90); font-size: 13px; line-height: 1.6; box-shadow: var(--sh-chip); animation: toastin var(--mo-base) var(--mo-ease); } @keyframes toastin { from { opacity: 0; transform: translate(-50%, 6px); } } .dlg { position: fixed; inset: 0; z-index: var(--z-panel); } .dlg-mask { position: absolute; inset: 0; background: color-mix(in srgb, var(--p-ink-90) 36%, transparent); } .dlg-box { position: absolute; left: 50%; top: 12%; transform: translateX(-50%); width: 360px; max-width: calc(100vw - 32px); max-height: min(78vh, 560px); overflow-y: auto; background: var(--c-surface); color: var(--c-text); border-radius: var(--r-md); box-shadow: var(--sh-float); padding: 18px 18px 14px; animation: rise var(--mo-slow) var(--mo-ease); } .dlg-title { font-size: var(--fs-lead); font-weight: 600; color: var(--c-text-strong); margin: 0 0 8px; } .dlg-ver { margin: -4px 0 12px; font-size: var(--fs-meta); line-height: 1.5; color: var(--c-text-meta); font-variant-numeric: tabular-nums; } .dlg-box p { margin: 0 0 16px; font-size: var(--fs-base); line-height: 1.65; color: var(--c-text-muted); } .dlg-actions { display: flex; justify-content: flex-end; gap: 8px; } .dlg-row { display: flex; gap: 10px; align-items: flex-start; padding: 10px 0; cursor: pointer; } .dlg-row + .dlg-row { border-top: 1px solid var(--c-line-hairline); } .dlg-row > span { flex: 1; min-width: 0; } .dlg-row b { display: block; font-size: var(--fs-base); color: var(--c-text-strong); font-weight: 600; } .dlg-row small { display: block; margin-top: 4px; font-size: var(--fs-meta); color: var(--c-text-muted); line-height: 1.55; overflow-wrap: anywhere; white-space: normal; } .dlg-row input { margin-top: 3px; accent-color: var(--c-accent); } .dlg-row.dlg-side { cursor: default; } .side-seg { display: flex; gap: 2px; padding: 2px; margin-top: 8px; border-radius: var(--r-sm); background: var(--c-surface-sunken); width: fit-content; } .side-seg button { padding: 4px 12px; border: 0; border-radius: var(--r-xs); cursor: pointer; background: transparent; color: var(--c-text-muted); font-size: 12px; line-height: 1.4; } .side-seg button.on { background: var(--c-surface); color: var(--c-accent); font-weight: 600; } button.act.danger { color: var(--c-danger); border-color: var(--c-danger); background: var(--c-danger-wash); } button.act.danger:hover { background: var(--c-danger-wash); } .panel { position: fixed; z-index: var(--z-panel); width: 560px; max-width: calc(100vw - 32px); background: var(--c-surface); color: var(--c-text); border-radius: var(--r-md); overflow: hidden; box-shadow: var(--sh-float); animation: rise var(--mo-slow) var(--mo-ease); } @keyframes rise { from { opacity: 0; transform: translateY(8px); } } @keyframes settle { from { opacity: 0; transform: translateY(3px); } } .hd { position: relative; flex: none; display: flex; align-items: center; gap: var(--sp-2); padding: 11px var(--sp-4); cursor: move; background: var(--c-surface); border-bottom: 1px solid var(--c-line-hairline); } .hd .mark { width: 22px; height: 22px; flex: none; border-radius: var(--r-xs); display: grid; place-items: center; overflow: hidden; } .hd .mark .brand { width: 22px; height: 22px; display: block; object-fit: contain; } .hd .mark .brand-fallback { width: 100%; height: 100%; border-radius: var(--r-xs); display: grid; place-items: center; background: var(--c-accent-wash); color: var(--c-accent); } .hd .mark .ic { width: 14px; height: 14px; } .hd .hd-name { flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; } .hd .title { min-width: 0; font-size: var(--fs-base); font-weight: 600; line-height: 1.4; letter-spacing: .01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .hd .ver { flex: none; font-size: var(--fs-meta); font-weight: 500; line-height: 1.4; color: var(--c-text-meta); font-variant-numeric: tabular-nums; letter-spacing: .02em; } .pro { flex: none; display: inline-block; padding: 0 5px; border-radius: 3px; font-size: 10px; font-weight: 600; line-height: 16px; letter-spacing: .04em; color: var(--c-accent); background: var(--c-surface-sunken); border: 1px solid var(--c-line-hairline); vertical-align: 1px; white-space: nowrap; } .pro[hidden] { display: none !important; } .icon-btn { width: 26px; height: 26px; flex: none; padding: 0; border: 0; border-radius: var(--r-xs); cursor: pointer; background: transparent; color: var(--c-text-meta); display: grid; place-items: center; transition: background var(--mo-base) var(--mo-ease), color var(--mo-base) var(--mo-ease); } .icon-btn:hover { background: var(--c-surface-hover); color: var(--c-text); } .icon-btn .ic { width: 15px; height: 15px; opacity: .78; overflow: visible; } .icon-btn:hover .ic { opacity: 1; transform: scale(1.18) rotate(-6deg); } .icon-btn .ic path { stroke-dasharray: 60; stroke-dashoffset: 0; } .icon-btn:hover .ic path { animation: lucide-stroke-hover .5s ease-out forwards; } .menu { display: none; position: absolute; right: var(--sp-3); top: calc(100% - 4px); z-index: 2; min-width: 132px; padding: var(--sp-1); border-radius: var(--r-sm); background: var(--c-surface); box-shadow: var(--sh-float); } .menu.open { display: block; } .menu .mi { display: block; width: 100%; padding: 8px 10px; border: 0; border-radius: var(--r-xs); cursor: pointer; background: none; color: var(--c-text-strong); font-size: 13px; line-height: 1.5; text-align: left; transition: background var(--mo-base) var(--mo-ease), color var(--mo-base) var(--mo-ease); } .menu .mi:hover { background: var(--c-surface-hover); color: var(--c-text); } .bd { padding: var(--sp-4); max-height: 62vh; overflow: auto; } .label { display: flex; align-items: baseline; gap: var(--sp-2); margin-bottom: 6px; font-size: var(--fs-label); font-weight: 600; letter-spacing: var(--ls-label); color: var(--c-text-muted); } .label .n { font-weight: 400; color: var(--c-text-meta); font-variant-numeric: tabular-nums; } .label.accent { color: var(--c-accent); } .notice { display: flex; align-items: flex-start; gap: var(--sp-2); margin-bottom: var(--sp-3); padding: 9px 10px; border-radius: var(--r-sm); border: 1px solid var(--c-line-hairline); background: var(--c-surface-sunken); font-size: var(--fs-meta); line-height: 1.65; color: var(--c-text-muted); } .notice > .ic { width: 14px; height: 14px; flex: none; margin-top: 2px; color: var(--c-text-meta); } .notice .msg { flex: 1; min-width: 0; overflow-wrap: anywhere; white-space: pre-wrap; } .notice .nx { flex: none; padding: 0; border: 0; background: none; cursor: pointer; color: var(--c-text-meta); line-height: 0; border-radius: var(--r-xs); } .notice .nx:hover { color: var(--c-text); background: var(--c-surface-hover); } .notice .nx .ic { width: 13px; height: 13px; opacity: .78; } .notice .nx:hover .ic { opacity: 1; transform: scale(1.1); } .modes { position: relative; display: flex; align-items: stretch; gap: 2px; padding: 3px; border-radius: var(--r-sm); background: var(--c-surface-sunken); overflow: visible; } .modes .mode { flex: 1 1 0; min-width: 0; padding: 6px 4px; border: 0; border-radius: var(--r-xs); cursor: pointer; background: transparent; color: var(--c-text-muted); font-size: 13px; line-height: 1.3; white-space: normal; display: inline-flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 3px 4px; overflow: visible; transition: background var(--mo-fast) var(--mo-ease), color var(--mo-fast) var(--mo-ease); } .modes .mode .mode-txt { white-space: nowrap; } .modes .mode .pro { padding: 0 4px; font-size: 10px; line-height: 15px; position: relative; z-index: 1; } .modes .mode:hover { color: var(--c-text); } .modes .mode.on { background: var(--c-surface); color: var(--c-accent); font-weight: 600; } .modes .mode.more { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; gap: 4px; padding: 7px 9px; } .modes .mode.more .ic { width: 14px; height: 14px; opacity: .75; } .modes .mode.more:hover .ic { opacity: 1; transform: scale(1.18) rotate(-6deg); } .modes .mode.more .ic path { stroke-dasharray: 60; stroke-dashoffset: 0; } .modes .mode.more:hover .ic path { animation: lucide-stroke-hover .5s ease-out forwards; } .mode-tip { margin: 7px 0 var(--sp-3); font-size: var(--fs-meta); line-height: 1.6; color: var(--c-text-meta); overflow-wrap: anywhere; } .lang-pick { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2); margin: -4px 0 var(--sp-3); overflow: visible; } .lang-pick[hidden] { display: none; } .lang-label { flex: none; font-size: var(--fs-micro); color: var(--c-text-meta); } .lang-pick .pro { margin-right: 2px; } .lang-seg { display: flex; gap: 2px; padding: 2px; border-radius: var(--r-sm); background: var(--c-surface-sunken); } .lang-seg button { padding: 4px 10px; border: 0; border-radius: var(--r-xs); cursor: pointer; background: transparent; color: var(--c-text-muted); font-size: 12px; line-height: 1.4; transition: background var(--mo-base) var(--mo-ease), color var(--mo-base) var(--mo-ease); } .lang-seg button.on { background: var(--c-surface); color: var(--c-accent); font-weight: 600; } .box { border: 0; border-radius: var(--r-sm); padding: 12px 14px; font-size: var(--fs-read); line-height: var(--lh-read); white-space: pre-wrap; overflow-wrap: anywhere; word-break: normal; line-break: strict; max-height: 190px; overflow: auto; background: var(--c-surface-sunken); color: var(--c-text-muted); } .box.result { background: var(--c-accent-wash); color: var(--c-text); animation: settle var(--mo-base) var(--mo-ease); } .box.assist { background: var(--c-surface-sunken); color: var(--c-text); animation: settle var(--mo-base) var(--mo-ease); } .box.detect.detect-card { position: relative; overflow: hidden; max-height: none; white-space: normal; padding: 12px; border-radius: var(--r-md); background: linear-gradient(135deg, var(--c-accent-wash), var(--c-surface)); color: var(--c-detect-ink); border: 1px solid var(--c-line-hairline); box-shadow: var(--detect-card-shadow); animation: detect-in var(--mo-slow) var(--mo-ease); } @keyframes detect-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } } .detect-card__row, .detect-card__note { position: relative; z-index: 2; } .detect-card::after { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none; background: linear-gradient(105deg, transparent 35%, rgb(79 199 158 / .22) 50%, transparent 65%); transform: translateX(-100%); animation: detect-shimmer 1.2s var(--mo-ease) .5s 1; } .detect-card:hover::after { animation: detect-shimmer .7s var(--mo-ease) 1; } @keyframes detect-shimmer { to { transform: translateX(100%); } } .detect-card__row { display: grid; grid-template-columns: 92px 1fr; gap: 12px; align-items: center; } .detect-card__meter { position: relative; width: 92px; height: 92px; } .detect-card__svg { display: block; width: 92px; height: 92px; transform: rotate(-90deg); } .detect-card__track, .detect-card__arc { fill: none; stroke-width: 7; stroke-linecap: round; } .detect-card__track { stroke: var(--c-detect-track); } .detect-card__arc { stroke: var(--detect-ring-stroke); stroke-dasharray: 226.2; stroke-dashoffset: 226.2; animation: detect-arc var(--mo-slow) var(--mo-ease) forwards; } @keyframes detect-arc { to { stroke-dashoffset: var(--detect-offset, 226.2); } } .detect-card__read { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; pointer-events: none; } .detect-card__pct { font-size: 22px; font-weight: 700; line-height: 1; letter-spacing: -.03em; color: var(--c-text); } .detect-card__unit { font-size: 10px; margin-top: 2px; color: var(--c-detect-meta); } .detect-card__bars { display: flex; flex-direction: column; justify-content: center; gap: 10px; min-width: 0; } .detect-card__bar { display: grid; grid-template-columns: 1fr auto; gap: 2px 8px; } .detect-card__k { font-size: var(--fs-micro); line-height: 1.4; color: var(--c-detect-muted); } .detect-card__v { font-size: var(--fs-micro); line-height: 1.4; color: var(--c-detect-ink); } .detect-card__bar .detect-card__track { grid-column: 1 / -1; height: 4px; border-radius: var(--r-xs); overflow: hidden; background: var(--detect-bar-track); } .detect-card__fill { display: block; height: 100%; width: 100%; border-radius: inherit; background: var(--detect-bar-fill); transform: scaleX(0); transform-origin: left center; transition: transform var(--mo-slow) var(--mo-ease); } .detect-card__bar:nth-child(2) .detect-card__fill { transition-delay: 40ms; } .detect-card__bar:nth-child(3) .detect-card__fill { transition-delay: 80ms; } .detect-card__note { margin: 10px 0 0; font-size: 11px; line-height: 1.6; color: var(--c-detect-meta); } .box.detect.ai .detect-card__arc, .box.detect.is-ai .detect-card__arc { stroke: var(--c-detect-ai); } .box.detect.ai .detect-card__pct, .box.detect.is-ai .detect-card__pct { color: var(--c-detect-ai); } .box.detect.ai .detect-card__fill, .box.detect.is-ai .detect-card__fill { background: var(--c-detect-ai); } @media (max-width: 360px) { .detect-card__row { grid-template-columns: 1fr; } .detect-card__meter { margin: 0 auto; } } .assist-note { display: flex; align-items: flex-start; gap: 6px; margin-top: 7px; font-size: var(--fs-micro); line-height: 1.6; color: var(--c-text-meta); } .assist-note .ic { width: 13px; height: 13px; margin-top: 2px; } .metric { display: flex; align-items: flex-start; gap: 6px; margin-top: 7px; font-size: var(--fs-micro); line-height: 1.6; color: var(--c-text-meta); } .metric .ic { width: 13px; height: 13px; margin-top: 2px; flex: none; } .metric b { color: var(--c-text); font-weight: 600; font-variant-numeric: tabular-nums; } .metric .why { display: block; } .to-detect { display: inline-flex; align-items: center; margin-top: 8px; padding: 0; border: 0; background: none; cursor: pointer; font-size: var(--fs-meta); line-height: 1.6; color: var(--c-accent); } .to-detect:hover { text-decoration: underline; } .bar + .metric { margin-top: 0; margin-bottom: var(--sp-4); } .gap { height: var(--sp-3); } .skeleton span { display: block; height: 11px; border-radius: var(--r-xs); margin-bottom: 9px; background: linear-gradient(90deg, var(--c-surface-sunken) 25%, var(--c-surface-hover) 37%, var(--c-surface-sunken) 63%); background-size: 400% 100%; animation: shimmer 1.3s ease infinite; } .skeleton span:nth-child(2) { width: 92%; } .skeleton span:nth-child(3) { width: 78%; } @keyframes shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } } .err { display: flex; align-items: flex-start; gap: var(--sp-2); padding: 11px 12px; border-radius: var(--r-sm); background: var(--c-danger-wash); color: var(--c-danger); font-size: 13px; line-height: 1.65; } .err::before { content: ""; flex: none; width: 15px; height: 15px; margin-top: 2px; background: currentColor; -webkit-mask: var(--i-alert) center / contain no-repeat; mask: var(--i-alert) center / contain no-repeat; } .upsell { padding: var(--sp-4); border-radius: var(--r-sm); background: var(--c-surface-sunken); border: 1px solid var(--c-accent-line); } .upsell .ttl { font-size: var(--fs-lead); line-height: var(--lh-lead); font-weight: 600; color: var(--c-text); margin-bottom: 4px; } .upsell .sub { font-size: var(--fs-meta); line-height: 1.7; color: var(--c-text-muted); margin-bottom: var(--sp-3); } .upsell ul { list-style: none; margin: 0 0 var(--sp-4); padding: 0; } .upsell li { position: relative; padding: 3px 0 3px 23px; font-size: 13px; line-height: 1.75; color: var(--c-text-muted); } .upsell li::before { content: ""; position: absolute; left: 0; top: 8px; width: 15px; height: 15px; background: var(--c-accent); -webkit-mask: var(--i-check) center / contain no-repeat; mask: var(--i-check) center / contain no-repeat; } .upsell a.go { display: inline-block; padding: 9px 18px; border-radius: var(--r-sm); background: var(--c-accent); color: var(--c-text-on-accent); font-size: var(--fs-base); font-weight: 500; text-decoration: none; transition: background var(--mo-base) var(--mo-ease), transform var(--mo-fast) var(--mo-ease); } .upsell a.go:hover { background: var(--c-accent-press); } .upsell a.go:active { transform: translateY(1px); } .upsell .later { display: block; margin-top: 10px; font-size: var(--fs-micro); color: var(--c-text-meta); } .rail { position: fixed; z-index: var(--z-ball); right: 0; top: 50%; transform: translateY(-50%); display: flex; flex-direction: column; gap: 2px; padding: 6px 4px; background: var(--c-surface); color: var(--c-text-strong); border: 1px solid var(--c-line-edge); border-right: 0; border-radius: var(--r-md) 0 0 var(--r-md); box-shadow: var(--sh-float); pointer-events: auto; transition: right var(--mo-slow) var(--mo-ease), left var(--mo-slow) var(--mo-ease); } .rail.quiet { color: var(--c-text-meta); box-shadow: var(--sh-quiet); } .rail.quiet:hover, .rail.quiet.open { color: var(--c-text-strong); box-shadow: var(--sh-float); } .rail button { width: 32px; height: 32px; padding: 0 8px; overflow: hidden; white-space: nowrap; display: flex; align-items: center; justify-content: flex-start; gap: 0; border: 0; border-radius: var(--r-sm); background: transparent; color: inherit; cursor: pointer; font: inherit; font-size: 13px; line-height: 1; transition: width var(--mo-base) var(--mo-ease), gap var(--mo-base) var(--mo-ease), background var(--mo-fast) var(--mo-ease), color var(--mo-fast) var(--mo-ease); } .rail button:hover { background: var(--c-surface-hover); color: var(--c-text); } .rail button .ic { opacity: .72; overflow: visible; } .rail button:hover .ic { opacity: 1; transform: scale(1.18) rotate(-6deg); } .rail button .ic path { stroke-opacity: .82; stroke-dasharray: 60; stroke-dashoffset: 0; } .rail button:hover .ic path { stroke-opacity: 1; animation: lucide-stroke-hover .5s ease-out forwards; } .rail button[data-go="settings"] .ic { transition: transform .4s ease, opacity var(--mo-base) var(--mo-ease); } .rail button[data-go="settings"]:hover .ic { transform: rotate(-180deg); animation: none; } .rail button[data-go="settings"]:hover .ic path { animation: none; } .rail.open button { width: 148px; gap: 8px; } .rail button span { opacity: 0; transform: translateX(-4px); transition: opacity var(--mo-fast) var(--mo-ease), transform var(--mo-fast) var(--mo-ease); } .rail.open button span { opacity: 1; transform: none; } .rail .sep { height: 1px; margin: 4px 2px; background: var(--c-line-hairline); } .rail .quit { color: var(--c-text-meta); } .rail.shift { right: 400px; } .rail-tip { position: fixed; z-index: var(--z-chip); right: 169px; top: 50%; transform: translateY(-50%); max-width: 230px; padding: 10px 12px; border-radius: var(--r-sm); background: var(--p-ink-90); color: var(--p-chalk-90); font-size: 12.5px; line-height: 1.7; box-shadow: var(--sh-chip); pointer-events: none; } .rail-tip b { color: var(--p-green-45); font-weight: 600; } :host(.side-left) { --sh-dock: 1px 0 0 0 var(--c-line-edge), 6px 0 14px -6px rgb(23 30 27 / .10); } :host(.side-left) .rail { right: auto; left: 0; border-right: 1px solid var(--c-line-edge); border-left: 0; border-radius: 0 var(--r-md) var(--r-md) 0; } :host(.side-left) .rail.shift { left: 400px; right: auto; } :host(.side-left) .rail-tip { right: auto; left: 169px; } :host(.side-left) .rail .quit .ic { transform: scaleX(-1); } :host(.side-left) .rail .quit:hover .ic { transform: scaleX(-1) scale(1.18) rotate(-6deg); } .drop { border: 1px dashed var(--c-line-control); border-radius: var(--r-sm); padding: 26px 16px; text-align: center; cursor: pointer; background: var(--c-surface-soft); transition: border-color var(--mo-base) var(--mo-ease), background var(--mo-base) var(--mo-ease); } .drop:hover, .drop.over { border-color: var(--c-accent); background: var(--c-accent-wash); } .drop .ic { width: 28px; height: 28px; margin: 0 auto 10px; color: var(--c-accent); opacity: .85; } .drop:hover .ic { opacity: 1; transform: scale(1.06); } .drop .m { font-size: var(--fs-base); font-weight: 500; color: var(--c-text); } .drop .s { font-size: var(--fs-meta); color: var(--c-text-muted); margin-top: 6px; line-height: 1.75; overflow-wrap: anywhere; } .drop .s2 { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 5px; margin-top: 9px; font-size: var(--fs-micro); line-height: 1.5; color: var(--c-text-meta); overflow-wrap: anywhere; } .drop .s2 .ic { width: 13px; height: 13px; margin: 0; color: var(--c-text-meta); } .docmeta { font-size: var(--fs-meta); line-height: 1.8; color: var(--c-text-muted); margin-bottom: var(--sp-2); } .docmeta b { color: var(--c-text); font-weight: 600; } .back { display: inline-flex; align-items: center; gap: 4px; color: var(--c-accent); cursor: pointer; text-decoration: none; font-size: var(--fs-meta); } .back:hover { text-decoration: underline; } .bar { height: 4px; border-radius: var(--r-xs); background: var(--c-surface-hover); overflow: hidden; margin-bottom: var(--sp-4); } .bar i { display: block; height: 100%; border-radius: var(--r-xs); background: var(--c-accent); } .pair { margin-bottom: var(--sp-3); } .pair .o, .pair .n { padding: 10px 12px; border-radius: var(--r-sm); font-size: 14px; line-height: 1.8; white-space: pre-wrap; overflow-wrap: anywhere; word-break: normal; line-break: strict; } .pair .o { background: var(--c-surface-sunken); color: var(--c-text-muted); } .pair .n { background: var(--c-accent-wash); color: var(--c-text); margin-top: var(--sp-1); } .pair .tag { display: block; font-size: var(--fs-micro); font-weight: 600; color: var(--c-text-meta); margin-bottom: 2px; } .pair .n .tag { color: var(--c-accent); } .hist { margin-top: var(--sp-4); } .hist-cap { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2); margin-bottom: var(--sp-2); font-size: var(--fs-label); font-weight: 600; letter-spacing: var(--ls-label); color: var(--c-text-muted); } .hist-cap em { font-style: normal; font-weight: 400; font-size: var(--fs-micro); color: var(--c-text-meta); } .hrow { display: flex; align-items: flex-start; gap: 10px; padding: 11px 0; border-bottom: 1px solid var(--c-line-hairline); } .hrow:last-child { border-bottom: 0; } .hrow > .ic { width: 15px; height: 15px; margin-top: 3px; color: var(--c-text-meta); } .hrow .info { flex: 1; min-width: 0; } .hrow .fn { font-size: 13px; line-height: 1.5; color: var(--c-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .hrow .meta { margin-top: 3px; font-size: var(--fs-micro); line-height: 1.5; color: var(--c-text-meta); font-variant-numeric: tabular-nums; } .hrow .meta .st { color: var(--c-accent); font-weight: 600; } .hrow .ops { display: flex; gap: 2px; flex: none; } .empty { text-align: center; padding: 34px 12px; color: var(--c-text-meta); } .empty .ic { width: 26px; height: 26px; margin: 0 auto 10px; color: var(--c-line-control); } .empty .t { font-size: var(--fs-lead); line-height: var(--lh-lead); color: var(--c-text-muted); } .empty .s { font-size: var(--fs-meta); line-height: 1.7; margin-top: 6px; } .locked { display: flex; gap: var(--sp-2); margin-top: var(--sp-3); } .locked button { flex: 1; display: flex; align-items: center; justify-content: center; gap: 6px; padding: 9px 8px; border-radius: var(--r-sm); cursor: pointer; border: 1px solid var(--c-line-control); background: var(--c-surface); color: var(--c-text-muted); font-size: 13px; line-height: 1.4; } .locked button:hover { background: var(--c-surface-hover); color: var(--c-text); } .locked .ic { width: 14px; height: 14px; } .ft { flex: none; padding: 10px var(--sp-4) 12px; background: var(--c-surface-sunken); border-top: 1px solid var(--c-line-hairline); } .ft-actions { display: flex; align-items: flex-start; gap: var(--sp-2); flex-wrap: wrap; } .ft .quota { flex: 1 1 100%; min-width: 0; font-size: var(--fs-meta); line-height: 1.65; color: var(--c-text-meta); font-variant-numeric: tabular-nums; overflow: visible; white-space: normal; overflow-wrap: anywhere; } .ft .xp { flex: 1 1 100%; min-width: 0; margin-top: 2px; padding: 6px 8px; border-radius: 6px; background: var(--c-surface); border: 1px solid var(--c-line-hairline); } .ft .xp[hidden] { display: none; } .ft .xp.off { opacity: .5; } .ft .xp-hd { font-size: var(--fs-micro); font-weight: 600; line-height: 1.4; color: var(--c-text-muted); } .ft .xp-bd, .ft .xp-sub { font-size: var(--fs-micro); line-height: 1.55; color: var(--c-text-meta); overflow-wrap: anywhere; } .ft .xp-sub { margin-top: 2px; font-variant-numeric: tabular-nums; } .xp-row { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 6px; margin-top: 4px; font-size: var(--fs-micro); line-height: 1.55; color: var(--c-text-meta); } .xp-row .xp-name { color: var(--c-text-muted); font-weight: 600; } .xp-row .xp-name .pro { margin-left: 4px; vertical-align: 1px; } .ft-btns { display: flex; flex: 1 1 100%; gap: var(--sp-2); flex-wrap: wrap; justify-content: flex-end; align-items: center; } .ft .cta { display: flex; align-items: flex-start; gap: 6px; margin-top: 9px; font-size: var(--fs-meta); line-height: 1.55; color: var(--c-text-muted); text-decoration: none; overflow-wrap: anywhere; } .ft .cta b { color: var(--c-accent); font-weight: 600; } .ft .cta:hover b { text-decoration: underline; } .ft .cta .ic { width: 14px; height: 14px; color: var(--c-accent); } .privacy { display: flex; align-items: flex-start; gap: 6px; margin-top: 7px; font-size: var(--fs-micro); line-height: 1.55; color: var(--c-text-meta); overflow-wrap: anywhere; } .privacy .ic { width: 13px; height: 13px; } button.act { padding: 8px 15px; border-radius: var(--r-sm); border: 1px solid var(--c-line-control); background: var(--c-surface); color: var(--c-text-strong); font-size: var(--fs-base); line-height: 1.4; cursor: pointer; transition: background var(--mo-base) var(--mo-ease), border-color var(--mo-base) var(--mo-ease), color var(--mo-base) var(--mo-ease), opacity var(--mo-base) var(--mo-ease), transform var(--mo-fast) var(--mo-ease); } button.act:hover { background: var(--c-surface-hover); } button.act:active:not(:disabled) { transform: translateY(1px); } button.act.primary { background: var(--c-accent); border-color: var(--c-accent); color: var(--c-text-on-accent); font-weight: 500; } button.act.primary:hover { background: var(--c-accent-press); border-color: var(--c-accent-press); } button.act:disabled, button.act:disabled:hover { opacity: 1; cursor: not-allowed; background: var(--c-surface-sunken); border-color: var(--c-line-control); color: var(--c-text-meta); } .panel.dock { top: 0; right: 0; left: auto; width: 400px; max-width: 92vw; height: 100vh; display: flex; flex-direction: column; border-radius: 0; box-shadow: var(--sh-dock); animation: slidein var(--mo-slow) var(--mo-ease); } @keyframes slidein { from { opacity: 0; transform: translateX(26px); } } :host(.side-left) .panel.dock { right: auto; left: 0; animation-name: slidein-left; } @keyframes slidein-left { from { opacity: 0; transform: translateX(-26px); } } :host(.side-left) .dock .hd [data-close] .ic { transform: scaleX(-1); } .dock .hd { cursor: default; } .tabs { display: flex; flex: none; gap: 2px; padding: 0 var(--sp-3); background: var(--c-surface); border-bottom: 1px solid var(--c-line-hairline); } .tabs .tab { position: relative; padding: 9px 12px 10px; border: 0; background: none; cursor: pointer; color: var(--c-text-muted); font-size: 13px; line-height: 1.4; border-radius: var(--r-xs) var(--r-xs) 0 0; transition: color var(--mo-fast) var(--mo-ease), background var(--mo-fast) var(--mo-ease); } .tabs .tab:hover { color: var(--c-text); background: var(--c-surface-hover); } .tabs .tab.on { color: var(--c-text); font-weight: 600; } .tabs .tab::after { content: ""; position: absolute; left: 8px; right: 8px; bottom: -1px; height: 2px; border-radius: 2px 2px 0 0; background: var(--c-accent); transform: scaleX(0); transform-origin: center bottom; transition: transform var(--mo-base) var(--mo-ease); } .tabs .tab.on::after { transform: scaleX(1); } .dock .bd { flex: 1; max-height: none; padding: var(--sp-4) var(--sp-4) var(--sp-5); } .dock .pane { display: none; } .dock[data-tab="text"] .pane[data-pane="text"], .dock[data-tab="upload"] .pane[data-pane="upload"], .dock[data-tab="history"] .pane[data-pane="history"] { display: block; } .sec { margin: 0; } .sec-hd { margin: 0 0 var(--sp-3); font-size: var(--fs-label); font-weight: 600; letter-spacing: var(--ls-label); color: var(--c-text); line-height: 1.45; } .sec-hd em { display: block; margin-top: 4px; font-style: normal; font-weight: 400; font-size: var(--fs-meta); line-height: 1.65; color: var(--c-text-muted); overflow-wrap: anywhere; } .ta { width: 100%; min-height: 140px; resize: vertical; border: 1px solid var(--c-line-control); border-radius: var(--r-sm); padding: 11px 12px; font-family: var(--font-ui); font-size: var(--fs-read); line-height: var(--lh-read); color: var(--c-text); background: var(--c-surface); overflow-wrap: anywhere; word-break: normal; } .ta::placeholder { color: var(--c-text-meta); } .ta:focus { outline: 2px solid var(--c-focus); outline-offset: 1px; border-color: transparent; } .row { display: flex; align-items: center; gap: var(--sp-2); margin-top: 10px; } .row .cnt { flex: 1; font-size: var(--fs-meta); color: var(--c-text-meta); font-variant-numeric: tabular-nums; } .row .cnt.over { color: var(--c-danger); font-weight: 600; } .dock .ft [data-again], .dock .ft [data-copy], .dock .ft [data-copyall] { display: none; } .dock[data-tab="text"] .ft [data-again], .dock[data-tab="text"] .ft [data-copy], .dock[data-tab="upload"] .ft [data-copyall] { display: block; } .dock .ft [data-cta-text], .dock .ft [data-cta-upload] { display: none; } .dock[data-tab="text"] .ft [data-cta-text] { display: flex; } .dock[data-tab="upload"] .ft [data-cta-upload], .dock[data-tab="history"] .ft [data-cta-upload] { display: flex; } .panel[data-kind="assist"] .ft [data-again] { display: none; } .panel[data-kind="detect"] .ft [data-again] { display: none; } .dock .drop { padding: 22px 14px; } .dock .hist { margin-top: 0; } .dock .box { max-height: none; } .dock [data-stage] [data-hist] { display: none; } @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; } .rail button span { transform: none !important; } .rail button .ic, .rail button:hover .ic, .icon-btn .ic, .icon-btn:hover .ic, .drop .ic, .drop:hover .ic, .modes .mode.more .ic, .modes .mode.more:hover .ic, .notice .nx .ic, .notice .nx:hover .ic, .pop .pi .ic, .pop .pi:hover .ic, .rail button[data-go="settings"] .ic, .rail button[data-go="settings"]:hover .ic { transform: none !important; opacity: 1 !important; animation: none !important; } .ic path, .rail button:hover .ic path, .icon-btn:hover .ic path, .pop .pi:hover .ic path { animation: none !important; stroke-dashoffset: 0 !important; } :host(.side-left) .rail .quit .ic, :host(.side-left) .rail .quit:hover .ic { transform: scaleX(-1) !important; opacity: 1 !important; } .skeleton span { animation: none !important; background: var(--c-surface-hover) !important; } .detect-card, .detect-card__arc, .detect-card__fill, .detect-card::after { animation: none !important; transition: none !important; } .detect-card__arc { stroke-dashoffset: var(--detect-offset); } .detect-card__fill { transform: scaleX(var(--detect-p, 0)); } } @media (forced-colors: active) { .panel, .rail, .rail-tip, .bubble, .hint, .toast, .menu, .pop, .dlg, .dlg-mask, .dlg-box { border: 1px solid CanvasText; } .box.result { border: 1px solid Highlight; } .box.assist { border: 1px solid CanvasText; } .modes .mode.on { border: 1px solid Highlight; } } `; const ICONS = { replace: 'M3 4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1zm12 12a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1zm6-5V8a2 2 0 0 0-2-2h-6l3 3m0-6l-3 3M3 13v3a2 2 0 0 0 2 2h6l-3-3m0 6l3-3', x: 'M18 6L6 18M6 6l12 12', dots: 'M4 12a1 1 0 1 0 2 0a1 1 0 1 0-2 0m7 0a1 1 0 1 0 2 0a1 1 0 1 0-2 0m7 0a1 1 0 1 0 2 0a1 1 0 1 0-2 0', dotsv: 'M11 5a1 1 0 1 0 2 0a1 1 0 1 0-2 0m0 7a1 1 0 1 0 2 0a1 1 0 1 0-2 0m0 7a1 1 0 1 0 2 0a1 1 0 1 0-2 0', lang: 'M4 5h7M9 3v2c0 4.418-2.239 8-5 8M5 9c0 2.144 2.952 3.908 6.7 4M12 20l4-9l4 9M19.1 18h-6.2', bulb: 'M3 12h1M12 3v1M20 12h1M4.6 5.6l.7.7M17.4 5.6l-.7.7M9 16a5 5 0 1 1 6 0a3.5 3.5 0 0 0-1 3a2 2 0 0 1-4 0a3.5 3.5 0 0 0-1-3M9.7 17h4.6', list: 'M9 6h11M9 12h11M9 18h11M5 6h.01M5 12h.01M5 18h.01', bolt: 'M13 3v7h6l-8 11v-7H5l8-11', sparkle: 'M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9zM18 15l.8 2.2L21 18l-2.2.8L18 21l-.8-2.2L15 18l2.2-.8z', world: 'M3 12a9 9 0 1 0 18 0a9 9 0 0 0-18 0M3.6 9h16.8M3.6 15h16.8M11.5 3a17 17 0 0 0 0 18M12.5 3a17 17 0 0 1 0 18', gauge: 'M13.45 11.55l2.05-2.05M6.4 20a9 9 0 1 1 11.2 0zM11 12a1 1 0 1 0 2 0a1 1 0 1 0-2 0', info: 'M3 12a9 9 0 1 0 18 0a9 9 0 0 0-18 0M12 9h.01M11 12h1v4h1', collapse: 'm7 7l5 5l-5 5m6-10l5 5l-5 5', upload: 'M14 3v4a1 1 0 0 0 1 1h4M17 21H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7l5 5v11a2 2 0 0 1-2 2m-5-10v6M9.5 13.5L12 11l2.5 2.5', file: 'M14 3v4a1 1 0 0 0 1 1h4M17 21H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7l5 5v11a2 2 0 0 1-2 2M9 9h1m-1 4h6m-6 4h6', eye: 'M10 12a2 2 0 1 0 4 0a2 2 0 0 0-4 0M21 12q-3.6 6-9 6t-9-6q3.6-6 9-6t9 6', trash: 'M4 7h16m-10 4v6m4-6v6M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2l1-12M9 7V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3', lock: 'M5 13a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2zM11 16a1 1 0 1 0 2 0a1 1 0 0 0-2 0m-3-5V7a4 4 0 1 1 8 0v4', shield: 'M12 3a12 12 0 0 0 8.5 3A12 12 0 0 1 12 21A12 12 0 0 1 3.5 6A12 12 0 0 0 12 3M11 11a1 1 0 1 0 2 0a1 1 0 1 0-2 0m1 1v2.5', settings: 'M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 0 0-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 0 0-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 0 0-2.573-1.066c1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 0 0-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 0 0 1.066-2.573c-.94-1.543.826 3.31 2.37-2.37c1 .608 2.296.07 2.572-1.065M9 12a3 3 0 1 0 6 0a3 3 0 0 0-6 0', arrow: 'M5 12h14m-4 4l4-4m-4-4l4 4', moon: 'M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z', sun: [ 'M12 8a4 4 0 1 0 0 8a4 4 0 1 0 0-8', 'M12 2v2', 'M12 20v2', 'M2 12h2', 'M20 12h2', 'M4.93 4.93l1.41 1.41', 'M17.66 17.66l1.41 1.41', 'M6.34 17.66l-1.41 1.41', 'M19.07 4.93l-1.41 1.41' ] }; function ic(name) { const spec = ICONS[name]; const ds = Array.isArray(spec) ? spec : [spec]; const paths = ds.map(function (d) { return ''; }).join(''); return ''; } var BRAND_LOGO = 'data:image/webp;base64,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'; function brandMark(cls) { return ''; } function wireBrandFallback(scope) { if (!scope) return; scope.querySelectorAll('img.brand').forEach(function (img) { img.addEventListener('error', function () { var span = document.createElement('span'); span.className = img.className.replace('brand', 'brand-fallback'); span.innerHTML = ic('replace'); if (img.parentNode) img.parentNode.replaceChild(span, img); }, { once: true }); }); } function closePops(except) { if (!root) return false; let closed = false; root.querySelectorAll('[data-pop].open').forEach((pop) => { if (pop === except) return; pop.classList.remove('open', 'up'); const btn = pop.parentNode && pop.parentNode.querySelector('[data-pop-btn]'); if (btn) btn.setAttribute('aria-expanded', 'false'); closed = true; }); return closed; } function prefOn(key, defaultOn) { return GM.get(key, defaultOn ? '1' : '0') === '1'; } function setPref(key, on) { GM.set(key, on ? '1' : '0'); } function autorunOnSelect() { return prefOn('autorun_on_select', false); } function setAutorunOnSelect(on) { setPref('autorun_on_select', on); } function showSelectionBubble() { return prefOn('show_bubble', true); } function setShowSelectionBubble(on) { setPref('show_bubble', on); if (!on) hideBubble(); } function hotkeyEnabled() { return prefOn('hotkey_enabled', true); } function setHotkeyEnabled(on) { setPref('hotkey_enabled', on); } function saveHistoryOn() { return prefOn('save_history', true); } function setSaveHistoryOn(on) { setPref('save_history', on); } function noSelectHint() { return prefOn('no_select_hint', true); } function setNoSelectHint(on) { setPref('no_select_hint', on); } function railDimOther() { return prefOn('rail_dim_other_v2', false); } function setRailDimOther(on) { setPref('rail_dim_other_v2', on); applyRailQuiet(); } function autoCopyOnSuccess() { return prefOn('auto_copy', false); } function setAutoCopyOnSuccess(on) { setPref('auto_copy', on); } function darkModeStored() { const raw = GM.get('dark_mode', ''); if (raw === '1') return true; if (raw === '0') return false; return null; } function prefersDark() { try { return !!(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches); } catch (e) { return false; } } function darkModeOn() { const stored = darkModeStored(); return stored === null ? prefersDark() : stored; } function setDarkMode(on) { setPref('dark_mode', on); applyDarkMode(); } function themeBtnLabel(on) { return on ? '日间模式' : '夜间模式'; } function syncThemeButtons() { if (!root) return; const on = darkModeOn(); const label = themeBtnLabel(on); const iconHtml = ic(on ? 'sun' : 'moon'); root.querySelectorAll('[data-theme], [data-go="theme"]').forEach((btn) => { btn.title = label; btn.setAttribute('aria-label', label); btn.setAttribute('aria-pressed', String(on)); const svg = btn.querySelector('.ic'); if (svg) { const wrap = document.createElement('div'); wrap.innerHTML = iconHtml; svg.replaceWith(wrap.firstChild); } const span = btn.querySelector('span'); if (span) span.textContent = label; }); const box = root.querySelector('[data-pref="dark_mode"]'); if (box) box.checked = on; } function applyDarkMode() { if (!host) return; const on = darkModeOn(); host.classList.toggle('theme-dark', on); host.classList.toggle('theme-light', !on); syncThemeButtons(); } try { const mq = window.matchMedia('(prefers-color-scheme: dark)'); const onScheme = function () { if (darkModeStored() === null) applyDarkMode(); }; if (mq.addEventListener) mq.addEventListener('change', onScheme); else if (mq.addListener) mq.addListener(onScheme); } catch (e) { } function panelSide() { return GM.get('panel_side', 'right') === 'left' ? 'left' : 'right'; } function setPanelSide(side) { GM.set('panel_side', side === 'left' ? 'left' : 'right'); applyPanelSide(); } function applyPanelSide() { if (!host) return; host.classList.toggle('side-left', panelSide() === 'left'); } function applyRailQuiet() { const rail = root && root.querySelector('.rail'); if (!rail) return; rail.classList.toggle('quiet', railDimOther() && siteState() === 'auto'); } function closeDialogs() { if (!root) return false; const dlg = root.querySelector('[data-dlg]'); if (!dlg) return false; dlg.remove(); return true; } function openDlg(html) { if (!root) mount(); closeDialogs(); closePops(); const wrap = document.createElement('div'); wrap.className = 'dlg'; wrap.setAttribute('data-dlg', ''); wrap.innerHTML = html; const mask = wrap.querySelector('[data-dlg-mask]'); if (mask) mask.addEventListener('click', closeDialogs); const cancel = wrap.querySelector('[data-dlg-cancel]'); if (cancel) cancel.addEventListener('click', closeDialogs); root.appendChild(wrap); return wrap; } function confirmHideSite() { const wrap = openDlg( '
' + '' ); wrap.querySelector('[data-dlg-ok]').addEventListener('click', () => toggleSite(false)); } function openSettings() { const rows = [ { key: 'dark_mode', on: darkModeOn(), set: setDarkMode, title: '夜间模式', hint: '整块面板改成暗色。默认跟随系统;你点过一次之后就按你选的来,刷新仍在。' }, { key: 'autorun_on_select', on: autorunOnSelect(), set: setAutorunOnSelect, title: '点功能立刻执行', hint: '默认关掉。划词、快捷键或切换功能时,先把文字填进输入框,你可以改完再点「改写」。打开后恢复旧行为:点气泡 / 切功能立刻发请求。' }, { key: 'show_bubble', on: showSelectionBubble(), set: setShowSelectionBubble, title: '划词弹出工具条', hint: '选中一段文字后,在选区旁边弹出降重 / 翻译等快捷按钮。关掉后只保留侧边工具栏和快捷键。' }, { key: 'hotkey_enabled', on: hotkeyEnabled(), set: setHotkeyEnabled, title: '快捷键 Alt+D', hint: '选中文字后按 Alt+D,跳过气泡直接打开侧边面板。关掉后快捷键无效。' }, { key: 'save_history', on: saveHistoryOn(), set: setSaveHistoryOn, title: '保存处理记录', hint: '上传整篇 Word 后把对照结果存在本机浏览器。关掉后不再写入,已有记录仍可查看和删除。' }, { key: 'no_select_hint', on: noSelectHint(), set: setNoSelectHint, title: '选不中时弹出提示', hint: '拖选一段却拿不到文字(画布、PDF、iframe 编辑器)时,在鼠标旁提示去上传 Word。关掉后不再弹这条。' }, { key: 'rail_dim_other_v2', on: railDimOther(), set: setRailDimOther, title: '非推荐站点弱化工具栏', hint: '默认关闭。打开后,不在推荐名单里的网站侧边工具栏用更淡的颜色,鼠标靠近才实体化。关掉则所有网站都按正常颜色显示。' }, { key: 'auto_copy', on: autoCopyOnSuccess(), set: setAutoCopyOnSuccess, title: '改写完成后自动复制', hint: '默认关掉。点「改写」成功后自动把结果放进剪贴板。打开后不用再点「复制」。检测结果不自动复制。' } ]; const body = rows.map((r) => ( '' )).join(''); const side = panelSide(); const sideRow = '
' + '' + '面板位置' + '侧边工具栏和停靠面板一起贴左或贴右。默认右侧,刷新后仍保留。' + '' + '' + '' + '' + '' + '
'; const wrap = openDlg( '
' + '' ); const byKey = {}; rows.forEach((r) => { byKey[r.key] = r.set; }); wrap.querySelectorAll('[data-pref]').forEach((box) => { box.addEventListener('change', () => { const fn = byKey[box.getAttribute('data-pref')]; if (fn) fn(box.checked); }); }); wrap.querySelectorAll('[data-side]').forEach((btn) => { btn.addEventListener('click', () => { setPanelSide(btn.getAttribute('data-side')); wrap.querySelectorAll('[data-side]').forEach((b) => { b.classList.toggle('on', b === btn); }); }); }); } function togglePop(btn, pop) { const open = !pop.classList.contains('open'); closePops(pop); pop.classList.toggle('open', open); btn.setAttribute('aria-expanded', String(open)); if (!open) return; pop.classList.remove('up'); const box = pop.getBoundingClientRect(); if (box.bottom > window.innerHeight - 8 && box.height < window.innerHeight - 16) { pop.classList.add('up'); } } function versionLabel() { return 'v' + CONFIG.version; } function headerHtml(title, closeIcon, closeLabel) { return '
' + '' + brandMark() + '' + '' + '' + title + '' + '' + versionLabel() + '' + '' + '' + '' + '' + '' + '
'; } function bindFooterCta(panel) { panel.querySelectorAll('[data-cta]').forEach((a) => { a.addEventListener('click', () => stat('cta_click', a.getAttribute('data-cta'))); }); } function bindHeader(panel) { wireBrandFallback(panel); bindFooterCta(panel); const themeBtn = panel.querySelector('[data-theme]'); if (themeBtn) { themeBtn.addEventListener('click', (e) => { e.stopPropagation(); setDarkMode(!darkModeOn()); }); } syncThemeButtons(); const more = panel.querySelector('[data-more]'); const menu = panel.querySelector('[data-menu]'); if (!more || !menu) return; more.addEventListener('click', (e) => { e.stopPropagation(); togglePop(more, menu); }); const setBtn = menu.querySelector('[data-settings]'); if (setBtn) setBtn.addEventListener('click', () => { closePops(); openSettings(); }); menu.querySelector('[data-hide-site]').addEventListener('click', () => { closePops(); confirmHideSite(); }); } function actionOff(a) { return a.kind === 'detect' && detectIsOff(); } function actionIsPro() { return false; } function proTagHtml() { return ''; } function actionNameHtml(name) { return '' + name + ''; } function popItemHtml(a, cur) { const off = actionOff(a); return ''; } function popHtml(cur) { const xyz = MENU_ACTIONS.filter((a) => a.kind !== 'assist'); const assist = MENU_ACTIONS.filter((a) => a.kind === 'assist'); return ''; } function syncDetectItems(scope) { if (!scope) return; const off = detectIsOff(); scope.querySelectorAll('[data-act="detect"]').forEach((btn) => { btn.disabled = off; if (off) btn.setAttribute('aria-disabled', 'true'); else btn.removeAttribute('aria-disabled'); if (off) btn.classList.remove('on'); const em = btn.querySelector('em'); if (em) em.textContent = off ? 'AIGC 检测暂未开放' : actionInfo('detect').desc; }); } function setDetectEnabled(on) { const next = on === null ? null : !!on; if (detectEnabled === next) return; detectEnabled = next; if (panelEl) syncActions(); if (bubbleEl) { syncDetectItems(bubbleEl); syncProTags(bubbleEl); } } function actionsHtml() { const cur = currentAction(); const info = actionInfo(cur); const onMenu = !PRIMARY_ACTIONS.some((a) => a.id === cur); return '
' + PRIMARY_ACTIONS.map((a) => '' ).join('') + '' + popHtml(cur) + '
' + '
' + info.desc + '
' + ''; } function displayedAction() { const has = panelEl && panelEl.querySelector('[data-out] [data-res]'); return has && lastRunAction ? lastRunAction : currentAction(); } function syncOutLabel() { if (!panelEl) return; const info = actionInfo(displayedAction()); panelEl.querySelectorAll('[data-out-label]').forEach((el) => { el.textContent = info.out; el.classList.toggle('accent', info.kind === 'rewrite'); }); } function syncCopyLabel() { if (!panelEl) return; const label = actionInfo(displayedAction()).copy; panelEl.querySelectorAll('[data-copy]').forEach((b) => { if (b.getAttribute('data-flash') === '1') return; b.textContent = label; }); } function syncActions() { if (!panelEl) return; const cur = currentAction(); const info = actionInfo(cur); panelEl.setAttribute('data-kind', info.kind); panelEl.querySelectorAll('[data-act]').forEach((b) => { const on = b.getAttribute('data-act') === cur; b.classList.toggle('on', on); if (b.hasAttribute('aria-pressed')) b.setAttribute('aria-pressed', String(on)); }); const onMenu = !PRIMARY_ACTIONS.some((a) => a.id === cur); panelEl.querySelectorAll('.mode.more').forEach((b) => { b.classList.toggle('on', onMenu); }); panelEl.querySelectorAll('[data-more-label]').forEach((s) => { s.textContent = onMenu ? info.name : '更多'; }); panelEl.querySelectorAll('[data-mode-tip]').forEach((t) => { t.textContent = info.desc; }); panelEl.querySelectorAll('[data-rewrite]').forEach((b) => { b.textContent = info.run; }); syncDetectItems(panelEl); syncDetectLangPick(); syncProTags(panelEl); syncOutLabel(); syncCopyLabel(); paintCooldown(); countInput(); renderQuota(); } function syncModes() { syncActions(); } function bindActions(panel) { panel.querySelectorAll('[data-act]').forEach((btn) => { btn.addEventListener('click', () => { const id = btn.getAttribute('data-act'); closePops(); if (id === currentAction()) return; rememberAction(id); syncActions(); if (!autorunOnSelect()) return; const done = panelEl && panelEl.querySelector('[data-out] [data-res]'); if (done && panelSource && !running && remainCooldown(actionInfo(id).kind) <= 0) { run(panelSource, id); } }); }); panel.querySelectorAll('[data-lang]').forEach((btn) => { btn.addEventListener('click', () => { setDetectLangChoice(btn.getAttribute('data-lang')); syncDetectLangPick(); }); }); const more = panel.querySelector('.mode.more[data-pop-btn]'); const pop = more && more.parentNode.querySelector('[data-pop]'); if (more && pop) { more.addEventListener('click', (e) => { e.stopPropagation(); togglePop(more, pop); }); } } function bindModes(panel) { bindActions(panel); } let host = null; let root = null; let bubbleEl = null; let panelEl = null; let lastSelection = ''; let lastRange = null; let panelSource = ''; let lastRunAction = ''; let running = false; function pinHostOnTop() { if (!host || !document.body) return; if (host.parentNode !== document.body || document.body.lastElementChild !== host) { document.body.appendChild(host); } } function mount() { if (host && host.isConnected) return; if (!document.body) { throw new Error('页面 body 未就绪'); } document.querySelectorAll('#lrw-host').forEach(function (el) { el.remove(); }); host = document.createElement('div'); host.id = 'lrw-host'; host.setAttribute('style', 'position:fixed;left:0;top:0;width:0;height:0;overflow:visible;z-index:2147483645;pointer-events:none;'); root = host.attachShadow({ mode: 'open' }); const style = document.createElement('style'); style.textContent = CSS; root.appendChild(style); document.body.appendChild(host); applyPanelSide(); applyDarkMode(); setTimeout(pinHostOnTop, 800); } function hideBubble() { if (bubbleEl) { bubbleEl.remove(); bubbleEl = null; } } const CANVAS_EDITORS = ['docs.qq.com', 'kdocs.cn']; let hintShown = false; function isCanvasEditor() { return CANVAS_EDITORS.some((s) => hostMatches(location.hostname, s)); } function showHint(html, x, y) { if (!noSelectHint()) return; if (hintShown) return; hintShown = true; mount(); const tip = document.createElement('div'); tip.className = 'hint'; tip.innerHTML = html; tip.style.left = Math.max(8, Math.min(x, window.innerWidth - 280)) + 'px'; tip.style.top = Math.max(8, Math.min(y, window.innerHeight - 90)) + 'px'; tip.addEventListener('click', () => tip.remove()); root.appendChild(tip); setTimeout(() => tip.remove(), 6000); } function showNoSelectionHint(x, y) { showHint(isCanvasEditor() ? '本站正文是画在画布上的,无法直接选中
请从右侧工具栏点上传整篇 Word。' : '这里的文字选不中(多半是画布或 PDF 渲染的)。
请从右侧工具栏点上传整篇 Word。', x, y); } function isInteractive(el) { if (!el || typeof el.closest !== 'function') return false; return !!el.closest('input,textarea,select,button,a,label,[role="button"],' + '[role="slider"],[draggable="true"],[contenteditable="true"]'); } function looksLikeEditorFrame(el) { try { const doc = el.contentDocument; if (doc && (doc.designMode === 'on' || (doc.body && doc.body.isContentEditable))) return true; } catch (e) { } const sig = ((el.id || '') + ' ' + (el.className || '') + ' ' + (el.getAttribute('title') || '')).toLowerCase(); return /ueditor|tinymce|\bmce\b|edui|ckeditor|richtext|editor/.test(sig); } function watchEditorFrames() { window.addEventListener('blur', () => { setTimeout(() => { const ae = document.activeElement; if (!ae || ae.tagName !== 'IFRAME' || !looksLikeEditorFrame(ae)) return; const box = ae.getBoundingClientRect(); showHint('这个编辑器的正文在 iframe 里,划词读不到选区。
' + '请从右侧工具栏点上传整篇 Word。', box.left + 12, box.top + 12); }, 0); }); } function currentSelection() { const ae = document.activeElement; if (ae && (ae.tagName === 'TEXTAREA' || (ae.tagName === 'INPUT' && /^(text|search)$/i.test(ae.type || '')))) { const start = ae.selectionStart; const end = ae.selectionEnd; if (typeof start === 'number' && typeof end === 'number' && end > start) { return { text: String(ae.value).substring(start, end).trim(), kind: 'input', el: ae, start: start, end: end }; } } const sel = window.getSelection(); const text = sel ? String(sel).trim() : ''; if (!text) return null; let range = null; try { range = sel.getRangeAt(0); } catch (e) { range = null; } return { text: text, kind: 'dom', range: range }; } function showBubble(x, y) { mount(); hideBubble(); bubbleEl = document.createElement('div'); bubbleEl.className = 'bubble'; bubbleEl.setAttribute('role', 'toolbar'); bubbleEl.setAttribute('aria-label', CONFIG.brand); bubbleEl.innerHTML = PRIMARY_ACTIONS.map((a, i) => '' ).join('') + '' + '' + popHtml(currentAction()); wireBrandFallback(bubbleEl); bubbleEl.addEventListener('mousedown', (e) => e.preventDefault()); const more = bubbleEl.querySelector('[data-pop-btn]'); const pop = bubbleEl.querySelector('[data-pop]'); more.addEventListener('click', (e) => { e.stopPropagation(); togglePop(more, pop); }); bubbleEl.querySelectorAll('[data-act]').forEach((btn) => { btn.addEventListener('click', () => { closePops(); hideBubble(); openPanel(lastSelection, btn.getAttribute('data-act')); }); }); syncProTags(bubbleEl); root.appendChild(bubbleEl); const box = bubbleEl.getBoundingClientRect(); bubbleEl.style.left = Math.max(8, Math.min(x, window.innerWidth - box.width - 8)) + 'px'; bubbleEl.style.top = Math.max(8, Math.min(y, window.innerHeight - box.height - 8)) + 'px'; } function closePanel() { stopAgainCooldown(); if (panelEl) { panelEl.remove(); panelEl = null; } panelSource = ''; lastRunAction = ''; syncRail(); } function openPanel(text, actionId) { if (actionId) rememberAction(actionId); closePops(); hideBubble(); ensureDock(); if (panelEl) syncActions(); setTab('text'); const ta = panelEl && panelEl.querySelector('[data-input]'); if (ta) { ta.value = String(text || '').slice(0, inputLimit() || CONFIG.maxSelection); countInput(); try { ta.focus(); } catch (e) {} } if (autorunOnSelect()) runFromInput(); } function enableDrag(el, handle) { let sx = 0, sy = 0, ox = 0, oy = 0, dragging = false; handle.addEventListener('mousedown', (e) => { if (e.target && e.target.closest && e.target.closest('button')) return; dragging = true; sx = e.clientX; sy = e.clientY; ox = el.offsetLeft; oy = el.offsetTop; e.preventDefault(); }); document.addEventListener('mousemove', (e) => { if (!dragging) return; el.style.left = (ox + e.clientX - sx) + 'px'; el.style.top = (oy + e.clientY - sy) + 'px'; }); document.addEventListener('mouseup', () => { dragging = false; }); } let quotaStamp = 0; const quotaCache = { rewrite: null, assist: null, detect: null, plagiarism: null }; let quotaNote = '额度查询中…'; function isNativeAigcRewrite(act) { return !!(act && act.id === 'aigc'); } function isNativePlagiarismRewrite(act) { return !!(act && act.id === 'plagiarism'); } function quotaBucket(act) { if (isNativePlagiarismRewrite(act)) return 'plagiarism'; return (act && act.kind) || 'rewrite'; } function nativeAigcLimit() { const rewriteQ = quotaCache.rewrite; const detectQ = quotaCache.detect; const fromRewrite = rewriteQ ? parseInt(rewriteQ.aigc_max_chars_per_call, 10) : 0; const fromDetect = detectQ ? parseInt(detectQ.aigc_max_chars_per_call, 10) : 0; if (fromRewrite > 0) return fromRewrite; if (fromDetect > 0) return fromDetect; return CONFIG.aigcMaxSelection || 600; } function detectLimit() { return nativeAigcLimit(); } function plagiarismLimit() { const plagQ = quotaCache.plagiarism; const fromPlag = plagQ ? parseInt(plagQ.max_chars_per_call, 10) : 0; if (fromPlag > 0) return fromPlag; const rewriteQ = quotaCache.rewrite; const fromRewrite = rewriteQ ? parseInt(rewriteQ.plagiarism_max_chars_per_call, 10) : 0; if (fromRewrite > 0) return fromRewrite; return CONFIG.plagiarismMaxSelection || 600; } function rewriteLimit() { const q = quotaCache.rewrite; const n = q ? parseInt(q.max_chars_per_call, 10) : 0; return n > 0 ? n : CONFIG.maxSelection; } function rewriteViaXyz() { return false; } function rewriteLimitFor(act) { if (isNativePlagiarismRewrite(act)) return plagiarismLimit(); if (isNativeAigcRewrite(act)) return nativeAigcLimit(); return rewriteLimit(); } function inputLimit() { const act = actionInfo(currentAction()); if (act.kind === 'detect' || isNativeAigcRewrite(act)) return nativeAigcLimit(); if (isNativePlagiarismRewrite(act)) return plagiarismLimit(); if (act.kind === 'rewrite') return rewriteLimit(); return CONFIG.maxSelection; } function quotaKind() { if (!panelEl) return 'rewrite'; if (isDock() && panelEl.getAttribute('data-tab') !== 'text') return 'rewrite'; if (!panelEl.querySelector('[data-act]')) return 'rewrite'; return quotaBucket(actionInfo(currentAction())); } function quotaText(txt) { const el = panelEl && panelEl.querySelector('[data-quota]'); if (el) el.textContent = txt; } function experienceOn() { return false; } function experienceLimit() { return nativeAigcLimit(); } function renderProTag() { syncProTags(root); } function syncProTags(scope) { const box = scope || root; if (!box) return; box.querySelectorAll('[data-pro-tag]').forEach((el) => { el.hidden = true; }); } function renderExperience() { renderProTag(); const box = panelEl && panelEl.querySelector('[data-xp]'); if (!box) return; box.hidden = true; box.classList.add('off'); box.textContent = ''; } function renderQuota() { if (!panelEl) return; const kind = quotaKind(); const q = quotaCache[kind]; if (q) { if (kind === 'detect') { quotaText('检测额度 剩余 ' + q.remain_calls + ' / ' + q.daily_calls + ' 次'); } else { const label = kind === 'assist' ? '辅助额度' : (kind === 'plagiarism' ? '降重额度' : '改写额度'); quotaText(label + ' 剩余 ' + q.remain_chars + ' / ' + q.daily_chars + ' 字'); } } else if (kind === 'detect') { quotaText(detectIsOff() ? 'AIGC 检测暂未开放' : quotaNote); } else if (kind === 'plagiarism') { quotaText('降重额度独立,不占改写额度'); } else { quotaText(kind === 'assist' ? '翻译 / 解释 / 总结额度独立,不占改写额度' : quotaNote); } renderExperience(); } function setQuota(q, kind) { if (!q) return; quotaStamp += 1; quotaCache[kind || 'rewrite'] = q; renderQuota(); updateDetectBars(); } function quotaTitle(res, insufficient) { const remain = (res && res.quota && res.quota.remain_chars) || 0; if (res && res.code === 'quota_chars' && remain > 0) return insufficient; return (res && res.message) || '今日免费额度已用完'; } function renderNotice(text) { if (!panelEl) return; const bd = panelEl.querySelector('.bd'); if (!bd) return; const old = bd.querySelector('[data-notice]'); if (old) old.remove(); const msg = String(text == null ? '' : text).trim(); if (!msg) return; if (GM.get('notice_seen', '') === msg) return; const el = document.createElement('div'); el.className = 'notice'; el.setAttribute('data-notice', ''); el.innerHTML = ic('info') + '' + ''; el.querySelector('.msg').textContent = msg; el.querySelector('[data-notice-x]').addEventListener('click', () => { GM.set('notice_seen', msg); el.remove(); }); bd.insertBefore(el, bd.firstChild); } function refreshQuota() { const panel = panelEl; const stamp = quotaStamp; quotaNote = '额度查询中…'; api('/quota?client_id=' + encodeURIComponent(clientId())).then((res) => { if (panelEl !== panel || quotaStamp !== stamp) return; if (res && res.success && (res.quotas || res.quota)) { const buckets = res.quotas || {}; setQuota(buckets.rewrite || res.quota, 'rewrite'); setQuota(buckets.assist, 'assist'); setQuota(buckets.detect, 'detect'); setQuota(buckets.plagiarism, 'plagiarism'); setDetectEnabled(true); countInput(); } else { quotaNote = res && res.code === 'disabled' ? '免费通道未开放' : '额度暂不可用'; renderQuota(); } renderNotice(res && res.notice); }).catch(() => { if (panelEl !== panel || quotaStamp !== stamp) return; quotaNote = '额度暂不可用'; renderQuota(); }); } const cooldownEnd = { rewrite: 0, assist: 0, detect: 0, plagiarism: 0 }; let againTimer = null; function remainCooldown(kind) { return Math.max(0, Math.ceil((cooldownEnd[kind] - Date.now()) / 1000)); } function stopAgainCooldown() { if (againTimer) { clearInterval(againTimer); againTimer = null; } } function paintCooldown() { const btn = panelEl && panelEl.querySelector('[data-again]'); if (!btn) { stopAgainCooldown(); return; } if (running) { btn.disabled = true; return; } const againKind = quotaKind() === 'plagiarism' ? 'plagiarism' : 'rewrite'; const left = remainCooldown(againKind); btn.textContent = left > 0 ? '再来一版 ' + left + 's' : '再来一版'; btn.disabled = left > 0; if (left > 0) { if (!againTimer) againTimer = setInterval(paintCooldown, 1000); } else { stopAgainCooldown(); } } function noteCooldown(kind, seconds) { cooldownEnd[kind] = Date.now() + Math.max(0, Math.ceil(seconds || 0)) * 1000; paintCooldown(); } function startAgainCooldown(seconds) { noteCooldown('rewrite', seconds); } const COOLDOWN_KEY = { assist: 'assistCooldownSeconds', detect: 'detectCooldownSeconds', rewrite: 'cooldownSeconds', plagiarism: 'cooldownSeconds' }; function cooldownFor(kind) { return CONFIG[COOLDOWN_KEY[kind] || 'cooldownSeconds']; } function learnCooldown(message, startedAt, kind) { const key = COOLDOWN_KEY[kind] || 'cooldownSeconds'; const m = /(\d+)\s*秒/.exec(message || ''); if (!m) return CONFIG[key]; const wait = parseInt(m[1], 10); const waited = startedAt ? (Date.now() - startedAt) / 1000 : 0; const real = Math.min(Math.ceil(waited + wait), 120); if (real > CONFIG[key]) CONFIG[key] = real; return wait; } let toastTimer = null; function toast(msg) { mount(); const old = root.querySelector('.toast'); if (old) old.remove(); clearTimeout(toastTimer); const el = document.createElement('div'); el.className = 'toast'; el.textContent = msg; root.appendChild(el); toastTimer = setTimeout(() => el.remove(), 3600); } function copyText(text) { if (window.isSecureContext && navigator.clipboard && navigator.clipboard.writeText) { return navigator.clipboard.writeText(text).catch(() => legacyCopy(text)); } return legacyCopy(text); } function legacyCopy(text) { return new Promise((resolve, reject) => { const ta = document.createElement('textarea'); ta.value = text; ta.setAttribute('readonly', ''); ta.style.cssText = 'position:fixed;top:0;left:-9999px;opacity:0;'; document.body.appendChild(ta); const sel = window.getSelection(); const prev = sel && sel.rangeCount ? sel.getRangeAt(0) : null; let ok = false; try { ta.select(); ta.setSelectionRange(0, ta.value.length); ok = document.execCommand('copy'); } catch (e) { ok = false; } ta.remove(); if (sel && prev) { try { sel.removeAllRanges(); sel.addRange(prev); } catch (e) { } } if (ok) resolve(); else reject(new Error('copy_denied')); }); } function copyInto(btn, label, text) { if (!btn || !text) return; const flash = (msg, hold) => { btn.setAttribute('data-flash', '1'); btn.textContent = msg; setTimeout(() => { btn.removeAttribute('data-flash'); btn.textContent = label; syncCopyLabel(); }, hold); }; copyText(text).then(() => flash('已复制', 1400)).catch(() => { flash('复制失败', 2600); toast('浏览器拒绝了自动复制(本页不是 HTTPS 时常见),请手动选中结果按 Ctrl+C'); }); } function copyResult() { const out = panelEl && panelEl.querySelector('[data-out] [data-res]'); if (!out) return; copyInto(panelEl.querySelector('[data-copy]'), actionInfo(displayedAction()).copy, out.getAttribute('data-copy-text') || out.textContent); } const lastSuccessAt = { rewrite: 0, assist: 0, detect: 0, plagiarism: 0 }; function detectLang(text) { return /[\u4e00-\u9fff\u3400-\u4dbf]/.test(text) ? 'cn' : 'en'; } const DETECT_LANG_NAME = { cn: '中文', en: '英文' }; function detectLangChoice() { const v = GM.get('detect_lang', ''); return v === 'en' || v === 'cn' ? v : ''; } function setDetectLangChoice(lang) { if (lang === 'cn' || lang === 'en') GM.set('detect_lang', lang); } function shownDetectLang() { const ta = panelEl && panelEl.querySelector('[data-input]'); return detectLangChoice() || detectLang((ta && ta.value) || panelSource || ''); } function resolveDetectLang(text) { return detectLangChoice() || detectLang(text); } function syncDetectLangPick() { if (!panelEl) return; const pick = panelEl.querySelector('[data-lang-pick]'); if (!pick) return; const on = currentAction() === 'detect' && !detectIsOff(); pick.hidden = !on; if (!on) return; const lang = shownDetectLang(); pick.querySelectorAll('[data-lang]').forEach((b) => { b.classList.toggle('on', b.getAttribute('data-lang') === lang); }); } const DETECT_RING = 226.2; function currentInputChars() { const ta = panelEl && panelEl.querySelector('[data-input]'); return ta ? String(ta.value || '').length : 0; } function quotaBarPair(q, remainKey, dailyKey, unit) { if (q && q[dailyKey] != null && q[dailyKey] !== '') { const remain = Number(q[remainKey]); const daily = Number(q[dailyKey]); const safeRemain = isFinite(remain) ? remain : 0; const safeDaily = isFinite(daily) ? daily : 0; return { text: safeRemain + ' / ' + safeDaily + ' ' + unit, p: safeDaily > 0 ? Math.max(0, Math.min(1, safeRemain / safeDaily)) : 0 }; } return { text: '查询中', p: 0 }; } function fillDetectBars(card) { if (!card) return; const charsEl = card.querySelector('[data-detect-chars]'); const detectEl = card.querySelector('[data-detect-q-detect]'); const rewriteEl = card.querySelector('[data-detect-q-rewrite]'); const fills = card.querySelectorAll('.detect-card__fill'); const lim = detectLimit() || 600; const chars = currentInputChars(); const charP = lim > 0 ? Math.max(0, Math.min(1, chars / lim)) : 0; if (charsEl) charsEl.textContent = chars + ' / ' + lim; const detectPair = quotaBarPair(quotaCache.detect, 'remain_calls', 'daily_calls', '次'); const rewritePair = quotaBarPair(quotaCache.rewrite, 'remain_chars', 'daily_chars', '字'); if (detectEl) detectEl.textContent = detectPair.text; if (rewriteEl) rewriteEl.textContent = rewritePair.text; const ps = [charP, detectPair.p, rewritePair.p]; fills.forEach(function (el, i) { const p = ps[i] == null ? 0 : ps[i]; el.style.setProperty('--detect-p', String(p)); el.style.transform = 'scaleX(' + p + ')'; }); } function updateDetectBars() { if (!panelEl) return; const card = panelEl.querySelector('.detect-card[data-res]'); if (card) fillDetectBars(card); } function renderDetect(out, res) { const r = (res && res.result) || {}; const rawScore = (res && res.score != null) ? res.score : r.ai_percent; if (rawScore == null || rawScore === '') { out.innerHTML = ''; return; } const pct = Math.max(0, Math.min(100, Number(rawScore))); if (!isFinite(pct)) { out.innerHTML = ''; return; } const shown = Math.round(pct); const label = String((res && res.label) || '').toLowerCase(); const isAi = label === 'ai' || Number(r.prediction) === 1; const isMixed = label === 'mixed'; const summary = String((res && res.summary) || '').trim(); const lang = String(r.lang || res.lang || ''); const langName = DETECT_LANG_NAME[lang] || lang; const unit = lang === 'en' ? '检测词数' : '检测字数'; const verdict = isMixed ? '模型判定:混合' : (isAi ? '模型判定:AI 生成' : '模型判定:人工撰写'); const words = Number((res && res.word_count) || r.word_count) || 0; const meta = (summary ? summary + ' · ' : '') + unit + ' ' + words + (langName ? ' · ' + langName : ''); const offset = (DETECT_RING * (1 - pct / 100)).toFixed(1); const mods = (isAi ? ' ai is-ai' : '') + (isMixed ? ' is-mixed' : ''); out.innerHTML = '
' + '
' + '' + '
' + '
' + '本次字数' + '' + '
' + '
' + '
' + '检测额度' + '' + '
' + '
' + '
' + '改写额度' + '' + '
' + '
' + '
' + '
' + '

结果由第三方模型给出,仅供参考,不代表任何查重或投稿系统的判定

' + '
'; const box = out.querySelector('[data-res]'); box.querySelector('.detect-card__pct').textContent = String(shown); box.querySelector('.detect-card__meter').setAttribute( 'aria-label', 'AIGC 率 ' + shown + '% · ' + verdict); const arc = box.querySelector('.detect-card__arc'); arc.style.setProperty('--detect-offset', offset); box.setAttribute('data-copy-text', 'AI 疑似度 ' + shown + '%(' + verdict + ')· ' + meta); const fills = box.querySelectorAll('.detect-card__fill'); const reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; fills.forEach(function (el) { el.style.setProperty('--detect-p', '0'); el.style.transform = 'scaleX(0)'; }); const paint = function () { fillDetectBars(box); }; if (reduce) paint(); else requestAnimationFrame(paint); } function rewriteResultText() { const box = panelEl && panelEl.querySelector('[data-out] [data-res]'); if (!box || !/\bresult\b/.test(box.className) || /\bassist\b/.test(box.className)) { return ''; } return String(box.textContent || '').trim(); } function detectFromRewrite() { const text = rewriteResultText(); if (!text) { toast('还没有改写结果'); return; } if (detectIsOff()) { toast(DETECT_FAIL_MSG.detect_disabled); return; } rememberAction('detect'); const ta = panelEl && panelEl.querySelector('[data-input]'); if (ta) { ta.value = text.slice(0, inputLimit() || CONFIG.maxSelection); countInput(); } syncActions(); run(text, 'detect'); } function attachDetectFromRewrite(out) { if (!out || detectIsOff()) return; if (out.querySelector('[data-todetect]')) return; const btn = document.createElement('button'); btn.type = 'button'; btn.className = 'to-detect'; btn.setAttribute('data-todetect', ''); btn.textContent = '用改写结果去检测'; btn.addEventListener('click', detectFromRewrite); out.appendChild(btn); } const OVERLAP_N = 8; const OVERLAP_MIN_CHARS = 20; function overlapCount(src, out, n) { const a = Array.from(String(src == null ? '' : src)); const b = Array.from(String(out == null ? '' : out)); const pool = new Set(); for (let i = 0; i + n <= a.length; i++) pool.add(a.slice(i, i + n).join('')); let hit = 0; let total = 0; for (let i = 0; i + n <= b.length; i++) { total++; if (pool.has(b.slice(i, i + n).join(''))) hit++; } return { hit: hit, total: total }; } function overlapUsable(src, out) { return Array.from(String(src == null ? '' : src)).length >= OVERLAP_MIN_CHARS && Array.from(String(out == null ? '' : out)).length >= OVERLAP_MIN_CHARS; } function overlapPairs(pairs) { let hit = 0; let total = 0; (pairs || []).forEach((p) => { if (!p || !overlapUsable(p.o, p.n)) return; const r = overlapCount(p.o, p.n, OVERLAP_N); hit += r.hit; total += r.total; }); return total ? { hit: hit, total: total } : null; } function overlapPct(r) { return Math.round((r.hit / r.total) * 1000) / 10; } function overlapNoteHtml(r, scope) { return '
' + ic('info') + '' + escapeHtml(scope || '') + '与原文仍有 ' + overlapPct(r) + '% 的长片段重合' + '连续 ' + OVERLAP_N + ' 字为一段,只与你给的原文比对,不含任何文献库' + '
'; } async function run(text, actionId) { const act = actionInfo(actionId || currentAction()); const assist = act.kind === 'assist'; const detect = act.kind === 'detect'; const out = panelEl && panelEl.querySelector('[data-out]'); const again = panelEl && panelEl.querySelector('[data-again]'); const copy = panelEl && panelEl.querySelector('[data-copy]'); if (!out || !again || !copy) return; const fail = (msg) => { out.innerHTML = '
'; out.querySelector('.err').textContent = msg; }; if (!assist && !detect) { const lim = rewriteLimitFor(act); if (lim && text.length > lim) { fail('改写单次最多 ' + lim + ' 字,当前 ' + text.length + ' 字,请少选一点再试'); return; } } if (detect) { if (detectIsOff()) { fail(DETECT_FAIL_MSG.detect_disabled); return; } const lim = detectLimit(); if (lim && text.length > lim) { fail('AIGC 检测单次最多 ' + lim + ' 字,当前 ' + text.length + ' 字,请少选一点再试'); return; } const wait = remainCooldown('detect'); if (wait > 0) { fail('检测太频繁了,请 ' + wait + ' 秒后再试'); return; } } panelSource = text; const prevRes = out.querySelector('[data-res]'); const prevIsDetect = !!(prevRes && prevRes.classList.contains('detect-card')); const prevHtml = prevIsDetect ? prevRes.outerHTML : ''; const prevText = prevRes && !prevIsDetect ? prevRes.textContent : ''; const prevCls = prevRes ? prevRes.className : 'box result'; const prevAction = lastRunAction; running = true; stopAgainCooldown(); again.disabled = true; again.textContent = '再来一版'; copy.disabled = true; out.innerHTML = '
'; const keepPrev = () => { if (prevHtml) { lastRunAction = prevAction; out.insertAdjacentHTML('beforeend', '
' + prevHtml); copy.disabled = false; syncOutLabel(); syncCopyLabel(); return; } if (!prevText) return; lastRunAction = prevAction; out.insertAdjacentHTML('beforeend', '
'); out.querySelector('[data-res]').textContent = prevText; copy.disabled = false; if (/\bresult\b/.test(prevCls) && !/\bassist\b/.test(prevCls)) { attachDetectFromRewrite(out); } syncOutLabel(); syncCopyLabel(); }; const showError = (msg) => { out.innerHTML = '
'; out.querySelector('.err').textContent = msg; keepPrev(); }; const showUpsell = (res) => { const bullets = detect ? '' : ''; out.innerHTML = '
' + '
' + '
' + (detect ? '注册极致论文,继续检测这篇论文' : '注册极致论文,把这篇论文一次处理完') + '
' + bullets + '免费注册领取额度 →' + '' + (detect ? '明天 0 点自动恢复免费检测名额' : '明天 0 点自动恢复免费额度') + '' + '
'; out.querySelector('.ttl').textContent = quotaTitle(res, '剩余额度不足本次' + act.run); out.querySelector('.go').href = ctaUrl('quota_exhausted'); out.querySelector('.go').addEventListener('click', () => { stat('cta_click', 'quota_exhausted'); }); stat('quota_exhausted', detect ? 'detect' : (assist ? 'assist' : 'selection')); keepPrev(); }; try { const bucket = quotaBucket(act); let path; let body; if (detect) { path = '/aigc_detect'; body = { text: text, client_id: clientId(), mode: 'normal', engine: 'AIGC_DETECT', lang: resolveDetectLang(text) }; } else if (assist) { path = '/assist'; body = { text: text, client_id: clientId(), mode: act.id }; } else if (isNativePlagiarismRewrite(act)) { path = '/plagiarism_rewrite'; body = { text: text, client_id: clientId(), mode: 'normal' }; } else if (isNativeAigcRewrite(act)) { path = '/aigc_rewrite'; body = { text: text, client_id: clientId(), mode: 'normal', engine: 'AIGC_REWRITE' }; } else { path = '/rewrite'; body = { text: text, client_id: clientId(), mode: act.id }; } const res = await api(path, body); if (!res.success) { if (detect && (res.code === 'detect_disabled' || res.code === 'not_configured')) { setDetectEnabled(false); } if (isQuotaCode(res.code, bucket)) { showUpsell(res); } else { showError(safeFailMessage(res, detect ? 'detect' : bucket, act.run + '失败')); } setQuota(res.quota, bucket); if (res.code === 'too_fast') { noteCooldown(bucket, learnCooldown(res.message, lastSuccessAt[bucket], bucket)); } if (detect && res.code === 'upstream_timeout') { noteCooldown('detect', cooldownFor('detect')); } return; } if (detect) { renderDetect(out, res); } else { out.innerHTML = '
'; out.querySelector('[data-res]').textContent = res.result; if (assist) { out.insertAdjacentHTML('beforeend', '
' + ic('info') + '供阅读参考,不建议直接替换论文正文
'); } else if (overlapUsable(text, res.result)) { out.insertAdjacentHTML('beforeend', overlapNoteHtml(overlapCount(text, res.result, OVERLAP_N), '')); } if (!assist) attachDetectFromRewrite(out); } const ranId = res.mode && ACTIONS.some((a) => a.id === res.mode && a.kind === act.kind) ? res.mode : act.id; lastRunAction = ranId; setQuota(res.quota, bucket); lastSuccessAt[bucket] = Date.now(); copy.disabled = false; syncOutLabel(); syncCopyLabel(); noteCooldown(bucket, cooldownFor(bucket)); if (autoCopyOnSuccess() && !detect) copyResult(); } catch (e) { showError(looksLikeInternalError(e && e.message) ? '服务暂时繁忙,请稍后重试' : ((e && e.message) || '请求失败,请稍后重试')); } finally { running = false; paintCooldown(); } } const HISTORY_MAX = 10; function readHistory() { try { const arr = JSON.parse(GM.get('history', '[]')); return Array.isArray(arr) ? arr : []; } catch (e) { return []; } } function writeHistory(list) { GM.set('history', JSON.stringify(list.slice(0, HISTORY_MAX))); } function addHistory(res) { if (!saveHistoryOn()) return; const s = res.stats; const list = readHistory(); list.unshift({ id: 'h' + Date.now().toString(36), name: res.file_name, at: Date.now(), totalChars: s.total_chars, totalParas: s.total_paragraphs, doneChars: s.processed_chars, coverage: s.coverage, aligned: !!res.aligned, merged: res.merged_result || '', pairs: (res.paragraphs || []).map((p) => ({ o: p.original, n: p.rewritten })) }); writeHistory(list); } function removeHistory(id) { writeHistory(readHistory().filter((r) => r.id !== id)); } function fmtTime(ts) { const d = new Date(ts); const p = (n) => (n < 10 ? '0' + n : '' + n); return p(d.getMonth() + 1) + '-' + p(d.getDate()) + ' ' + p(d.getHours()) + ':' + p(d.getMinutes()); } function openUploadPanel() { mount(); closePanel(); hideBubble(); panelEl = document.createElement('div'); panelEl.className = 'panel'; panelEl.style.left = Math.max(16, (window.innerWidth - 560) / 2) + 'px'; panelEl.style.top = '11vh'; panelEl.innerHTML = headerHtml(CONFIG.brand + ' · Word 试用', 'x', '关闭') + `
免登录直接用
需要整篇处理?前往极致论文${ic('arrow')} ${ic('shield')}历史与文件都只留在这台电脑上
`; panelEl.querySelector('[data-close]').addEventListener('click', closePanel); panelEl.querySelector('[data-copyall]').addEventListener('click', copyAllRewritten); bindHeader(panelEl); enableDrag(panelEl, panelEl.querySelector('.hd')); root.appendChild(panelEl); showUploadView(); } function stageEl() { return panelEl && panelEl.querySelector('[data-stage]'); } function showUploadView() { const stage = stageEl(); if (!stage) return; panelEl.querySelector('[data-copyall]').disabled = true; stage.innerHTML = '
' + ic('upload') + '
点击或拖拽 .docx 到这里
' + '
只改文档开头作试用。粘贴文字、AIGC 检测请切到「改写文本」。
' + '' + ic('shield') + '文件用完即删,服务器不保留 · 单个不超过 5MB' + '
' + '
'; bindDropZone(stage.querySelector('[data-drop]')); renderHistory(); } function renderHistory(target) { const box = target || (panelEl && panelEl.querySelector('[data-hist]')); if (!box) return; const list = readHistory(); const cap = '
上传历史 仅存本机 · 最多 ' + HISTORY_MAX + ' 条
'; if (!list.length) { box.innerHTML = cap + '
' + ic('file') + '
还没有上传记录
' + '
' + (saveHistoryOn() ? '上传一份 .docx,这里会留下改写前后的对照' : '已关闭「保存处理记录」,新的上传不会写入。可在设置里重新打开') + '
' + '
'; return; } const rows = list.map((r) => ( '
' + ic('file') + '
' + '
' + escapeHtml(r.name) + '
' + '
' + r.totalChars + ' 字 · ' + '已试用 ' + r.coverage + '% · ' + fmtTime(r.at) + '
' + '
' + '
' + '' + '' + '
' + '
' )).join(''); box.innerHTML = cap + rows; box.querySelectorAll('.hrow[data-id]').forEach((row) => { const id = row.getAttribute('data-id'); row.querySelector('[data-view]').addEventListener('click', () => { const rec = readHistory().find((x) => x.id === id); if (rec) showResultView(rec); }); row.querySelector('[data-del]').addEventListener('click', () => { removeHistory(id); renderHistory(box); }); }); } function bindDropZone(zone) { const input = document.createElement('input'); input.type = 'file'; input.accept = '.docx'; input.style.display = 'none'; zone.appendChild(input); zone.addEventListener('click', () => input.click()); input.addEventListener('change', () => { if (input.files && input.files[0]) uploadDoc(input.files[0]); }); ['dragenter', 'dragover'].forEach((ev) => zone.addEventListener(ev, (e) => { e.preventDefault(); zone.classList.add('over'); })); ['dragleave', 'drop'].forEach((ev) => zone.addEventListener(ev, (e) => { e.preventDefault(); zone.classList.remove('over'); })); zone.addEventListener('drop', (e) => { const f = e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files[0]; if (f) uploadDoc(f); }); } async function uploadDoc(file) { const stage = panelEl.querySelector('[data-stage]'); const copyAll = panelEl.querySelector('[data-copyall]'); copyAll.disabled = true; stage.innerHTML = '
正在解析并改写,请稍候…
' + '
'; try { const fd = new FormData(); fd.append('client_id', clientId()); fd.append('mode', currentMode()); fd.append('file', file, file.name); const res = await apiUpload('/upload', fd); if (!res.success) { if (isQuotaCode(res.code)) { renderDocUpsell(stage, res); } else { stage.innerHTML = '
'; stage.querySelector('.err').textContent = res.message || '处理失败'; stage.insertAdjacentHTML('beforeend', '
'); rebuildDrop(stage); } setQuota(res.quota, 'rewrite'); if (res.code === 'too_fast') { noteCooldown('rewrite', learnCooldown(res.message, lastSuccessAt.rewrite, 'rewrite')); } return; } addHistory(res); showResultView(readHistory()[0]); setQuota(res.quota, 'rewrite'); lastSuccessAt.rewrite = Date.now(); noteCooldown('rewrite', cooldownFor('rewrite')); } catch (e) { stage.innerHTML = '
'; stage.querySelector('.err').textContent = e.message || '上传失败'; } } function rebuildDrop(stage) { const zone = stage.querySelector('[data-drop]'); if (!zone) return; zone.innerHTML = ic('upload') + '
换一个文件试试
' + '
支持 .docx,不超过 5MB
'; bindDropZone(zone); } function renderDocUpsell(stage, res) { stage.innerHTML = '
' + '
' + '
注册极致论文,整篇一次处理完
' + '' + '免费注册领取额度 →' + '
'; stage.querySelector('.ttl').textContent = quotaTitle(res, '剩余额度不足以处理这篇文档'); stage.querySelector('.go').href = ctaUrl('upload_quota'); stage.querySelector('.go').addEventListener('click', () => stat('cta_click', 'upload_quota')); stat('quota_exhausted', 'docx'); } function showResultView(rec) { focusStageTab(); const stage = stageEl(); if (!stage) return; const remaining = Math.max(rec.totalChars - rec.doneChars, 0); const parts = []; parts.push('
' + '‹ 返回上传 ' + '' + escapeHtml(rec.name) + ' · 全文 ' + rec.totalChars + ' 字 / ' + rec.totalParas + ' 段 | 已免费改写 ' + rec.doneChars + ' 字(' + rec.coverage + '%)
'); parts.push('
'); const docOverlap = overlapPairs(rec.pairs); if (docOverlap) parts.push(overlapNoteHtml(docOverlap, '已改写段落')); if (rec.aligned) { (rec.pairs || []).forEach((p) => { parts.push('
' + '
原文' + escapeHtml(p.o) + '
' + '
改写' + escapeHtml(p.n) + '
' + '
'); }); } else { parts.push('
' + escapeHtml(rec.merged || '') + '
'); } if (remaining > 0) { parts.push('
' + '
还有 ' + remaining + ' 字未处理
' + '
免费版只改写文档开头部分,注册后可整篇一次跑完
' + '' + '免费注册处理整篇 →' + '
'); } parts.push('
' + '' + '' + '
'); stage.innerHTML = parts.join(''); panelEl.querySelector('[data-copyall]').disabled = false; stage.querySelector('[data-back]').addEventListener('click', showUploadView); const go = stage.querySelector('.go'); if (go) { go.href = ctaUrl('upload_remaining'); go.addEventListener('click', () => stat('cta_click', 'upload_remaining')); } stage.querySelectorAll('[data-lock]').forEach((btn) => { btn.addEventListener('click', () => showLockedNotice(btn.getAttribute('data-lock'))); }); } function showLockedNotice(kind) { const stage = stageEl(); if (!stage) return; const isCloud = kind === 'cloud'; stage.innerHTML = '
' + '
' + (isCloud ? '云端保存记录需要注册' : '整篇降重需要注册') + '
' + '
' + (isCloud ? '免费版的处理记录只存在这台电脑的浏览器里,最多 ' + HISTORY_MAX + ' 条,换设备就看不到了' : '免费版只改写文档开头部分,整篇处理请到极致论文') + '
' + '' + '免费注册 →' + '‹ 返回' + '
'; stage.querySelector('.go').href = ctaUrl('locked_' + kind); stage.querySelector('.go').addEventListener('click', () => stat('cta_click', 'locked_' + kind)); stage.querySelector('[data-back]').addEventListener('click', showUploadView); } function escapeHtml(s) { return String(s == null ? '' : s).replace(/[&<>"]/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c])); } function copyAllRewritten() { if (!panelEl) return; const scope = panelEl.querySelector('[data-stage]') || panelEl; const list = Array.from(scope.querySelectorAll('.pair .n')) .map((el) => el.textContent.replace(/^原文|^改写/, '').trim()); const merged = scope.querySelector('.box.result'); const text = list.length ? list.join('\n\n') : (merged ? merged.textContent : ''); if (!text) return; copyInto(panelEl.querySelector('[data-copyall]'), '复制全部改写', text); } function isDock() { return !!(panelEl && panelEl.classList.contains('dock')); } function syncRail() { const rail = root && root.querySelector('.rail'); if (!rail) return; rail.classList.toggle('shift', isDock()); applyRailQuiet(); } const syncBall = syncRail; function setTab(name) { if (!isDock()) return; panelEl.setAttribute('data-tab', name); panelEl.querySelectorAll('[data-tab-btn]').forEach((b) => { b.classList.toggle('on', b.getAttribute('data-tab-btn') === name); }); if (name === 'history') renderHistory(panelEl.querySelector('[data-hist-tab]')); renderQuota(); } function focusStageTab() { if (isDock()) setTab('upload'); } function countInput() { const ta = panelEl && panelEl.querySelector('[data-input]'); const cnt = panelEl && panelEl.querySelector('[data-count]'); if (!ta || !cnt) return; const n = ta.value.length; const lim = inputLimit(); cnt.textContent = lim ? (n + ' / ' + lim + ' 字') : (n + ' 字'); cnt.classList.toggle('over', lim > 0 && n > lim); if (currentAction() === 'detect' && !detectLangChoice()) syncDetectLangPick(); updateDetectBars(); } function runFromInput() { const ta = panelEl && panelEl.querySelector('[data-input]'); const out = panelEl && panelEl.querySelector('[data-out]'); if (!ta || !out) return; const text = String(ta.value || '').trim().slice(0, CONFIG.maxSelection); if (text.length < 10) { out.innerHTML = '
'; out.querySelector('.err').textContent = '至少贴 10 个字再' + actionInfo(currentAction()).run; return; } run(text); } function openMainPanel(opts) { const toggle = !opts || opts.toggle !== false; if (isDock()) { if (toggle) { closePanel(); return; } return panelEl; } mount(); closePanel(); hideBubble(); panelEl = document.createElement('div'); panelEl.className = 'panel dock'; panelEl.setAttribute('data-tab', 'text'); panelEl.innerHTML = headerHtml(CONFIG.brand, 'collapse', '收起') + `
文本改写 / 检测粘贴段落做降重、降 AI 味或 AIGC 检测。整份 Word 请切到「Word 上传」。
${actionsHtml()}
把要处理的文字贴进来
0 / ${CONFIG.maxSelection} 字
改写结果
Word 上传改写只改文档开头作试用。粘贴文字、AIGC 检测请切到「改写文本」。
Word 处理记录只记录本机上传过的文档,不含文本粘贴改写。
额度查询中…
需要更多额度?前往极致论文${ic('arrow')} 整篇 DOCX 一键降重,保留原格式 前往极致论文${ic('arrow')} ${ic('shield')}历史与文件都只留在这台电脑上
`; panelEl.querySelector('[data-close]').addEventListener('click', closePanel); bindHeader(panelEl); bindActions(panelEl); panelEl.querySelector('[data-rewrite]').addEventListener('click', runFromInput); panelEl.querySelector('[data-input]').addEventListener('input', countInput); panelEl.querySelector('[data-again]').addEventListener('click', () => { if (panelSource) run(panelSource); else runFromInput(); }); panelEl.querySelector('[data-copy]').addEventListener('click', copyResult); panelEl.querySelector('[data-copyall]').addEventListener('click', copyAllRewritten); panelEl.querySelectorAll('[data-tab-btn]').forEach((b) => { b.addEventListener('click', () => setTab(b.getAttribute('data-tab-btn'))); }); root.appendChild(panelEl); syncRail(); showUploadView(); syncActions(); refreshQuota(); return panelEl; } function ensureDock() { if (isDock()) return panelEl; return openMainPanel({ toggle: false }); } function railGo(id) { if (id === 'site') { window.open(ctaUrl('rail_site'), '_blank', 'noopener,noreferrer'); stat('cta_click', 'rail_site'); return; } if (id === 'settings') { openSettings(); return; } if (id === 'theme') { setDarkMode(!darkModeOn()); return; } if (id === 'hide') { confirmHideSite(); return; } const tab = id === 'upload' ? 'upload' : id === 'history' ? 'history' : 'text'; if (id === 'rewrite' && isDock() && panelEl.getAttribute('data-tab') === 'text') { closePanel(); return; } ensureDock(); setTab(tab); } const RAIL_ITEMS = [ { id: 'rewrite', label: '划词改写', icon: 'replace' }, { id: 'upload', label: '上传整篇 Word', icon: 'upload' }, { id: 'history', label: '处理记录', icon: 'file' }, { id: 'site', label: '打开极致论文', icon: 'sparkle' } ]; function mountRail() { mount(); if (root.querySelector('.rail')) return; const rail = document.createElement('div'); rail.className = 'rail'; rail.setAttribute('role', 'toolbar'); rail.setAttribute('aria-label', CONFIG.brand); let html = RAIL_ITEMS.map((it) => '' ).join(''); html += '
' + '' + '' + ''; rail.innerHTML = html; rail.addEventListener('mouseenter', () => { if (!rail.classList.contains('intro')) rail.classList.add('open'); }); rail.addEventListener('mouseleave', () => { if (!rail.classList.contains('intro')) rail.classList.remove('open'); }); rail.querySelectorAll('[data-go]').forEach((btn) => { btn.addEventListener('click', () => railGo(btn.getAttribute('data-go'))); }); root.appendChild(rail); applyPanelSide(); applyRailQuiet(); applyDarkMode(); introOnce(rail); } const mountBall = mountRail; function introOnce(rail) { if (GM.get('intro_shown', '')) return; GM.set('intro_shown', String(Date.now())); setTimeout(() => { if (!rail.isConnected) return; rail.classList.add('open', 'intro'); const tip = document.createElement('div'); tip.className = 'rail-tip'; tip.innerHTML = '选中论文里的段落,会就地弹出降重工具条。
' + '整篇 Word、处理记录、极致论文都在这条工具栏里。'; root.appendChild(tip); setTimeout(() => { tip.remove(); if (rail.isConnected) rail.classList.remove('open', 'intro'); }, 3600); }, 600); } let bound = false; function bindEvents() { if (bound) return; bound = true; let downX = 0; let downY = 0; let downTarget = null; document.addEventListener('mousedown', (e) => { downX = e.clientX; downY = e.clientY; downTarget = e.target; if (!root || !root.querySelector('[data-pop].open')) return; const path = (e.composedPath && e.composedPath()) || []; const inside = path.some((n) => n && n.nodeType === 1 && n.hasAttribute && (n.hasAttribute('data-pop') || n.hasAttribute('data-pop-btn'))); if (!inside) closePops(); }); document.addEventListener('mouseup', (e) => { if (host && e.composedPath().indexOf(host) >= 0) return; const dragged = Math.abs(e.clientX - downX) + Math.abs(e.clientY - downY) > 30; const onControl = isInteractive(downTarget) || isInteractive(e.target); setTimeout(() => { const picked = currentSelection(); if (!picked || picked.text.length < 10) { hideBubble(); if (dragged && !picked && (isCanvasEditor() || !onControl)) { showNoSelectionHint(e.clientX + 6, e.clientY + 14); } return; } lastSelection = picked.text.slice(0, CONFIG.maxSelection); lastRange = picked.kind === 'dom' ? picked.range : null; if (showSelectionBubble()) showBubble(e.clientX + 6, e.clientY + 14); else hideBubble(); }, 10); }); document.addEventListener('keydown', (e) => { if (e.altKey && (e.key === 'd' || e.key === 'D') && hotkeyEnabled()) { const picked = currentSelection(); if (picked && picked.text.length >= 10) { hideBubble(); openPanel(picked.text.slice(0, CONFIG.maxSelection)); } } if (e.key === 'Escape') { if (closeDialogs()) return; if (closePops()) return; hideBubble(); closePanel(); } }); } function activate() { bindEvents(); watchEditorFrames(); mountRail(); markInstalled(); } const ACTIVE = siteState() !== 'off'; if (typeof GM_registerMenuCommand === 'function') { if (ACTIVE) { GM_registerMenuCommand('改写当前选中文字', () => { const picked = currentSelection(); if (picked && picked.text.length >= 10) openPanel(picked.text.slice(0, CONFIG.maxSelection)); }); GM_registerMenuCommand('打开降重面板', openMainPanel); GM_registerMenuCommand('上传 Word 免费试用', openUploadPanel); GM_registerMenuCommand('设置', openSettings); GM_registerMenuCommand('在本站停用', confirmHideSite); } else { GM_registerMenuCommand('在本站启用论文万能助手', () => toggleSite(true)); } } function bootWarn(reason) { try { console.info('[论文万能助手] 未能挂上工具栏:' + reason); } catch (e) { } } function startWhenReady(attempt) { attempt = attempt || 0; try { if (!document.documentElement || !document.body) { if (attempt > 40) { bootWarn(document.documentElement ? '页面 body 未就绪' : '文档根节点未就绪'); return; } setTimeout(function () { startWhenReady(attempt + 1); }, 50); return; } activate(); if (!host || !host.isConnected) { bootWarn('宿主节点未写入页面'); } } catch (e) { bootWarn((e && e.message) ? e.message : '启动异常'); } } if (ACTIVE) startWhenReady(0); function dropForeignHosts() { document.querySelectorAll('#lrw-host').forEach(function (el) { if (el !== host) el.remove(); }); publishApi(); } setTimeout(dropForeignHosts, 600); try { if (location.port === '9811' || (typeof window !== 'undefined' && window.LRW_API_BASE)) { setTimeout(dropForeignHosts, 1800); } } catch (e) { } function publishApi() { window.__lrw = { openPanel, openUploadPanel, closePanel, showBubble, uploadDoc, siteState, toggleSite, activate, currentSelection, isCanvasEditor, openMainPanel, ensureDock, setTab, runFromInput, isDock, renderHistory, mountRail, syncRail, railGo, RAIL_ITEMS, mountBall, syncBall, refreshQuota, copyText, legacyCopy, quotaTitle, renderNotice, startAgainCooldown, showNoSelectionHint, looksLikeEditorFrame, currentMode, syncModes, MODES, DEFAULT_MODE, ACTIONS, PRIMARY_ACTIONS, MENU_ACTIONS, DEFAULT_ACTION, currentAction, actionInfo, rememberAction, syncActions, run, closePops, closeDialogs, confirmHideSite, openSettings, prefOn, setPref, autorunOnSelect, setAutorunOnSelect, showSelectionBubble, setShowSelectionBubble, hotkeyEnabled, setHotkeyEnabled, saveHistoryOn, setSaveHistoryOn, noSelectHint, setNoSelectHint, railDimOther, setRailDimOther, applyRailQuiet, autoCopyOnSuccess, setAutoCopyOnSuccess, darkModeOn, setDarkMode, applyDarkMode, darkModeStored, panelSide, setPanelSide, applyPanelSide, experienceOn, renderProTag, actionIsPro, syncProTags, rewriteViaXyz, quotaKind, quotaCache, quotaBucket, remainCooldown, renderQuota, renderExperience, setDetectEnabled, detectIsOff, detectLimit, plagiarismLimit, detectLang, renderDetect, updateDetectBars, isNativePlagiarismRewrite, isNativeAigcRewrite, rewriteLimitFor, safeFailMessage, detectLangChoice, setDetectLangChoice, shownDetectLang, resolveDetectLang, syncDetectLangPick, detectFromRewrite, rewriteResultText, attachDetectFromRewrite, isQuotaCode, DETECT_FAIL_MSG, REWRITE_FAIL_MSG, get detectEnabled() { return detectEnabled; }, overlapCount, overlapUsable, overlapPairs, overlapPct, overlapNoteHtml, OVERLAP_N, OVERLAP_MIN_CHARS, DEFAULT_SITES, CANVAS_EDITORS, active: ACTIVE, CONFIG }; } publishApi(); })();