LKML 內文複製器(多重備援)

一鍵複製 lkml.org 信件 <pre itemprop="articleBody"> 內的 HTML,三層備援不失敗。

当前为 2025-06-06 提交的版本,查看 最新版本

// ==UserScript==
// @name         LKML 內文複製器(多重備援)
// @namespace    https://abc0922001.github.io/lkml-userscripts
// @version      1.2
// @description  一鍵複製 lkml.org 信件 <pre itemprop="articleBody"> 內的 HTML,三層備援不失敗。
// @author       abc0922001
// @match        https://lkml.org/lkml/*
// @grant        GM_setClipboard
// @license      MIT
// ==/UserScript==

(() => {
  'use strict';

  /* ---------- 等待元素 ---------- */
  function waitForElement(selector, timeout = 5000) {
    return new Promise((resolve, reject) => {
      const hit = document.querySelector(selector);
      if (hit) return resolve(hit);

      const ob = new MutationObserver(() => {
        const el = document.querySelector(selector);
        if (el) {
          ob.disconnect();
          resolve(el);
        }
      });
      ob.observe(document.body, { childList: true, subtree: true });

      setTimeout(() => {
        ob.disconnect();
        reject(new Error(`等待元素「${selector}」超時 (${timeout}ms)`));
      }, timeout);
    });
  }

  /* ---------- 提示 ---------- */
  const showAlert = msg => window.alert(msg);

  /* ---------- 多重寫入剪貼簿 ---------- */
  async function copyToClipboard(html) {
    /* ① 原生 Clipboard API(含 text/html),成功率高 */
    try {
      await navigator.clipboard.write([
        new ClipboardItem({ 'text/html': new Blob([html], { type: 'text/html' }) })
      ]);
      showAlert('✅ 已複製 (HTML)!');
      return;
    } catch (_) { /* fall through */ }

    /* ② GM_setClipboard(Violentmonkey API)*/
    try {
      GM_setClipboard(html, { type: 'html' });
      showAlert('✅ 已複製 (GM)!');
      return;
    } catch (_) { /* fall through */ }

    /* ③ textarea + execCommand (最後保底)*/
    try {
      const ta = document.createElement('textarea');
      ta.value = html;
      ta.style.position = 'fixed';
      ta.style.left = '-9999px';
      document.body.appendChild(ta);
      ta.select();
      document.execCommand('copy');
      document.body.removeChild(ta);
      showAlert('✅ 已複製 (fallback)!');
    } catch (err) {
      showAlert(`❌ 複製失敗:${err.message}`);
    }
  }

  /* ---------- 建立按鈕 ---------- */
  function createCopyButton() {
    const button = document.createElement('button');
    button.textContent = '📋 複製內文';
    Object.assign(button.style, {
      position: 'fixed',
      top: '10px',
      right: '10px',
      zIndex: 1000,
      padding: '6px 10px',
      fontSize: '14px',
      backgroundColor: '#2b7de9',
      color: '#fff',
      border: 'none',
      borderRadius: '4px',
      cursor: 'pointer',
    });

    button.addEventListener('click', () => {
      const selector = 'pre[itemprop="articleBody"]';
      waitForElement(selector)
        .then(el => copyToClipboard(el.innerHTML))   // 保留 <br> 等 HTML 標籤
        .catch(() => showAlert('⚠️ 找不到內文區塊。'));
    });

    document.body.appendChild(button);
  }

  /* 🚀 啟動腳本 */
  createCopyButton();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址