Greasy Fork

Greasy Fork is available in English.

复制格式转换 (Markdown)

选中内容后,按钮智能显示在右上角,点击按钮自动复制为完整的 Markdown 格式。

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

// ==UserScript==
// @name         复制格式转换 (Markdown)
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  选中内容后,按钮智能显示在右上角,点击按钮自动复制为完整的 Markdown 格式。
// @author       KiwiFruit
// @match        *://*/*
// @grant        GM_setClipboard
// @license      MIT
// ==/UserScript==
(function () {
    'use strict';

    // 创建浮动按钮
    function createFloatingButton() {
        const button = document.createElement('button');
        button.id = 'markdownCopyButton';
        button.innerText = '复制为 Markdown 格式';
        button.style.position = 'fixed';
        button.style.top = '20px'; // 固定在右上角
        button.style.right = '20px'; // 固定在右上角
        button.style.padding = '10px 20px';
        button.style.backgroundColor = '#007bff';
        button.style.color = '#fff';
        button.style.border = 'none';
        button.style.borderRadius = '5px';
        button.style.cursor = 'pointer';
        button.style.zIndex = '9999';
        button.style.display = 'none'; // 默认隐藏
        button.style.boxShadow = '0 4px 6px rgba(0,0,0,0.1)';
        document.body.appendChild(button);
        return button;
    }

    let floatingButton = createFloatingButton();

    // 显示浮动按钮
    function showFloatingButton() {
        floatingButton.style.display = 'block';
    }

    // 隐藏浮动按钮
    function hideFloatingButton() {
        floatingButton.style.display = 'none';
    }

    // 提取选中内容
    function extractSelectedContent(range) {
        const fragment = range.cloneContents(); // 克隆选中的 DOM 内容
        const tempDiv = document.createElement('div');
        tempDiv.appendChild(fragment);

        // 提取文本内容
        const text = tempDiv.innerText.trim();

        // 提取图片
        const images = Array.from(tempDiv.querySelectorAll('img')).map(img => ({
            src: img.src,
            alt: img.alt || "Image",
        }));

        // 提取链接
        const links = Array.from(tempDiv.querySelectorAll('a')).map(a => ({
            text: a.innerText.trim() || "Link",
            href: a.href,
        }));

        return { text, images, links };
    }

    // 转换为 Markdown 格式
    function convertToMarkdown(content) {
        let markdown = '';

        // 添加文本内容
        if (content.text) {
            markdown += `${content.text}
`;
        }

        // 添加图片
        content.images.forEach(image => {
            markdown += `![${image.alt}](${image.src})
`;
        });

        // 添加链接
        content.links.forEach(link => {
            markdown += `[${link.text}](${link.href})
`;
        });

        return markdown.trim();
    }

    // 复制到剪贴板
    async function copyToClipboard(text) {
        try {
            if (typeof GM_setClipboard === 'function') {
                GM_setClipboard(text); // 使用油猴的剪贴板 API
                return true; // 成功
            } else {
                await navigator.clipboard.writeText(text);
                console.log('Markdown 已复制到剪贴板');
                return true; // 成功
            }
        } catch (err) {
            console.error('复制失败:', err);
            return false; // 失败
        }
    }

    // 显示提示信息
    function showToast(message) {
        const toast = document.createElement('div');
        toast.style.position = 'fixed';
        toast.style.bottom = '20px';
        toast.style.right = '20px';
        toast.style.padding = '10px 20px';
        toast.style.backgroundColor = '#333';
        toast.style.color = '#fff';
        toast.style.borderRadius = '5px';
        toast.style.zIndex = '9999';
        toast.style.boxShadow = '0 4px 6px rgba(0,0,0,0.1)';
        toast.innerText = message;
        document.body.appendChild(toast);

        // 自动移除提示
        setTimeout(() => {
            toast.remove();
        }, 2000); // 2秒后消失
    }

    // 监听鼠标释放事件
    document.addEventListener('mouseup', handleMouseUp);

    // 处理鼠标释放事件
    function handleMouseUp(event) {
        const selection = window.getSelection();
        if (selection && !selection.isCollapsed) {
            // 显示按钮
            showFloatingButton();

            // 绑定按钮点击事件
            floatingButton.onclick = async () => {
                try {
                    const range = selection.getRangeAt(0);
                    const selectedContent = extractSelectedContent(range);
                    const markdownContent = convertToMarkdown(selectedContent);

                    // 复制内容
                    const success = await copyToClipboard(markdownContent);
                    if (success) {
                        showToast('内容已复制为 Markdown 格式!');
                    } else {
                        showToast('复制失败,请重试!');
                    }
                } catch (err) {
                    console.error('处理内容时出错:', err);
                    showToast('处理内容时出错,请重试!');
                } finally {
                    hideFloatingButton(); // 操作完成后隐藏按钮
                }
            };
        } else {
            // 如果没有选中内容,隐藏按钮
            hideFloatingButton();
        }
    }

    // 监听页面点击事件,点击空白区域时隐藏按钮
    document.addEventListener('mousedown', (event) => {
        if (!floatingButton.contains(event.target)) {
            hideFloatingButton();
        }
    });
})();