Universal-Markdown-Copy

自由选择网页区域并复制为 Markdown 格式

目前为 2025-03-11 提交的版本。查看 最新版本

// ==UserScript==
// @name         Universal-Markdown-Copy
// @namespace    http://tampermonkey.net/
// @version      1.2.0
// @description  自由选择网页区域并复制为 Markdown 格式
// @author       shenfangda
// @match        https://*.shenfangda.cn/*
// @grant        GM_setClipboard
// @license      MIT
// ==/UserScript==


(function() {
    'use strict';

    // 添加调试日志函数
    const log = (msg) => console.log(`[Markdown-Copy] ${msg}`);

    // 样式定义
    const STYLES = `
        .markdown-copy-btn {
            position: fixed;
            top: 10px;
            right: 10px;
            z-index: 9999;
            padding: 8px 16px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
            transition: all 0.3s;
        }
        .markdown-copy-btn:hover {
            background-color: #45a049;
            transform: scale(1.05);
        }
        .selection-box {
            position: absolute;
            border: 2px dashed #4CAF50;
            background-color: rgba(76, 175, 80, 0.1);
            z-index: 9998;
            pointer-events: none;
        }
    `;

    // 初始化样式
    const styleSheet = document.createElement('style');
    styleSheet.textContent = STYLES;
    document.head.appendChild(styleSheet);
    log('样式已加载');

    // 创建按钮
    const copyBtn = document.createElement('button');
    copyBtn.className = 'markdown-copy-btn';
    copyBtn.textContent = '选择区域复制 Markdown';
    document.body.appendChild(copyBtn);
    log('按钮已添加');

    let isSelecting = false;
    let startX, startY;
    let selectionBox = null;

    // HTML 转 Markdown
    function htmlToMarkdown(element) {
        let markdown = '';

        function processNode(node) {
            if (node.nodeType === Node.TEXT_NODE) {
                return node.textContent.trim();
            }
            if (node.nodeType !== Node.ELEMENT_NODE) return '';

            let result = '';
            const tag = node.tagName.toLowerCase();

            if (/h[1-6]/.test(tag)) {
                const level = parseInt(tag[1]);
                result += '#'.repeat(level) + ' ' + node.textContent.trim() + '\n\n';
            } else if (tag === 'p') {
                result += node.textContent.trim() + '\n\n';
            } else if (tag === 'ul' || tag === 'ol') {
                const items = Array.from(node.children).filter(child => child.tagName.toLowerCase() === 'li');
                items.forEach(item => {
                    result += (tag === 'ul' ? '- ' : '1. ') + item.textContent.trim() + '\n';
                });
                result += '\n';
            } else if (tag === 'pre' || tag === 'code') {
                result += '```\n' + node.textContent.trim() + '\n```\n\n';
            } else {
                node.childNodes.forEach(child => {
                    result += processNode(child);
                });
            }
            return result;
        }

        if (element) {
            markdown = processNode(element);
        }
        return markdown.trim();
    }

    // 获取选择区域内容
    function getSelectedContent(x1, y1, x2, y2) {
        const elements = document.elementsFromPoint((x1 + x2) / 2, (y1 + y2) / 2);
        for (let el of elements) {
            if (el.tagName.toLowerCase() !== 'body' && el.tagName.toLowerCase() !== 'html') {
                const content = htmlToMarkdown(el);
                log(`选择区域内容:${content.substring(0, 50)}...`);
                return content;
            }
        }
        return '';
    }

    // 点击按钮切换选择模式
    copyBtn.addEventListener('click', () => {
        if (!isSelecting) {
            isSelecting = true;
            copyBtn.textContent = '正在选择... (再次点击取消)';
            document.body.style.cursor = 'crosshair';
            log('进入选择模式');
        } else {
            resetSelection();
            log('取消选择模式');
        }
    });

    // 鼠标事件
    document.addEventListener('mousedown', (e) => {
        if (!isSelecting || e.target === copyBtn) return;

        startX = e.clientX;
        startY = e.clientY;

        if (selectionBox) selectionBox.remove();
        selectionBox = document.createElement('div');
        selectionBox.className = 'selection-box';
        document.body.appendChild(selectionBox);
        log(`选择开始:(${startX}, ${startY})`);
    });

    document.addEventListener('mousemove', (e) => {
        if (!isSelecting || !selectionBox) return;

        const currentX = e.clientX;
        const currentY = e.clientY;

        const left = Math.min(startX, currentX);
        const top = Math.min(startY, currentY);
        const width = Math.abs(currentX - startX);
        const height = Math.abs(currentY - startY);

        selectionBox.style.left = `${left}px`;
        selectionBox.style.top = `${top}px`;
        selectionBox.style.width = `${width}px`;
        selectionBox.style.height = `${height}px`;
    });

    document.addEventListener('mouseup', (e) => {
        if (!isSelecting || !selectionBox) return;

        const endX = e.clientX;
        const endY = e.clientY;

        const markdownContent = getSelectedContent(startX, startY, endX, endY);
        if (markdownContent) {
            try {
                GM_setClipboard(markdownContent);
                alert('Markdown 已复制到剪贴板!');
                log('复制成功');
            } catch (err) {
                alert('复制失败,请检查控制台');
                log(`复制失败:${err.message}`);
            }
        } else {
            alert('未检测到有效内容,请重新选择');
            log('未找到有效内容');
        }

        resetSelection();
    });

    // 重置选择状态
    function resetSelection() {
        isSelecting = false;
        copyBtn.textContent = '选择区域复制 Markdown';
        document.body.style.cursor = 'default';
        if (selectionBox) {
            selectionBox.remove();
            selectionBox = null;
        }
    }

    // Esc 键取消
    document.addEventListener('keydown', (e) => {
        if (e.key === 'Escape' && isSelecting) {
            resetSelection();
            log('通过 Esc 键取消选择');
        }
    });

    // 初始化检查
    window.addEventListener('load', () => {
        log(`脚本已加载于 ${window.location.href}`);
    });
})();

QingJ © 2025

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