AI网站公式复制Latex

支持Claude、DeepSeek、Google Gemini等网站的公式复制,包括点击复制、选择复制和按钮复制,格式化为$和$$包裹的LaTeX

// ==UserScript==
// @name         AI网站公式复制Latex
// @namespace    http://tampermonkey.net/
// @version      0.9
// @description  支持Claude、DeepSeek、Google Gemini等网站的公式复制,包括点击复制、选择复制和按钮复制,格式化为$和$$包裹的LaTeX
// @license      MIT
// @author       fanxing
// @match        *://demo.fuclaude.oaifree.com/*
// @match        *://claude.ai/*
// @match        *://*.zhihu.com/*
// @match        *://*.wikipedia.org/*
// @match        *://*.chatgpt.com/*
// @match        *://*.x.liaox.ai/*
// @match        *://*.moonshot.cn/*
// @match        *://*.stackexchange.com/*
// @match        *://*.oi-wiki.org/*
// @match        *://*.luogu.com/*
// @match        *://*.doubao.com/*
// @match        *://*.deepseek.com/*
// @match        *://chat.deepseek.com/*
// @match        *://aistudio.google.com/*
// @match        *://gemini.google.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    console.log('公式复制格式调整脚本已加载');
    console.log('当前网站:', window.location.href);
    console.log('浏览器剪贴板API支持:', {
        clipboard: !!navigator.clipboard,
        writeText: !!(navigator.clipboard && navigator.clipboard.writeText),
        write: !!(navigator.clipboard && navigator.clipboard.write),
        ClipboardItem: !!window.ClipboardItem
    });

    // 安全检查:确保脚本只加载一次
    if (window.formulaScriptLoaded) {
        console.log('脚本已经加载过,跳过重复加载');
        return;
    }
    window.formulaScriptLoaded = true;

    // 创建样式
    const style = document.createElement('style');
    style.textContent = `
        .formula-toast {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background-color: #333;
            color: white;
            padding: 12px 20px;
            border-radius: 4px;
            z-index: 10000;
            font-family: Arial, sans-serif;
            font-size: 14px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
            transition: opacity 0.3s, transform 0.3s;
            opacity: 0;
            transform: translateY(20px);
        }
        .formula-toast.show {
            opacity: 1;
            transform: translateY(0);
        }
        .formula-toast.success {
            background-color: #4caf50;
        }
        .formula-toast.error {
            background-color: #f44336;
        }
        .formula-toast.info {
            background-color: #2196F3;
        }

        /* LaTeX提示框样式 */
        .latex-tooltip {
            position: fixed;
            background-color: #333;
            color: #fff;
            padding: 8px 12px;
            border-radius: 4px;
            font-size: 12px;
            z-index: 10001;
            display: none;
            opacity: 0;
            transition: opacity 0.2s;
            max-width: 350px;
            word-break: break-all;
            white-space: pre-wrap;
            box-shadow: 0 2px 8px rgba(0,0,0,0.4);
            font-family: monospace;
            pointer-events: none;
        }

        /* 复制成功提示 */
        .latex-copy-success {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 10px 20px;
            border-radius: 4px;
            font-size: 14px;
            z-index: 10002;
            transition: opacity 0.2s;
            opacity: 1;
        }

        /* 高亮样式 */
        .formula-hover {
            cursor: pointer !important;
            box-shadow: 0 0 0 1px #007bff !important;
            background-color: rgba(0, 123, 255, 0.1) !important;
        }
    `;
    document.head.appendChild(style);

    // 创建提示框元素
    const tooltip = document.createElement('div');
    tooltip.classList.add('latex-tooltip');
    document.body.appendChild(tooltip);

    // 声明全局变量
    let tooltipTimeout;
    let activeFormulaElement = null;

    // Gemini专用:KaTeX Hook系统
    const allKatexGemini = {};
    let isGeminiKatexHooked = false;

    // Gemini专用:Hook KaTeX render方法
    function hookKatexRender(katexObj) {
        if (!katexObj || typeof katexObj.render !== 'function') {
            console.warn('katex.render not found, skipping hook');
            return false;
        }

        const originalRender = katexObj.render;
        katexObj.render = new Proxy(originalRender, {
            apply: function(target, thisArg, args) {
                let result = target.apply(thisArg, args);
                if (args.length >= 2) {
                    const latexStr = args[0];
                    const element = args[1];
                    const katexHtml = element.querySelector('.katex-html');
                    if (element instanceof Element && katexHtml !== null) {
                        allKatexGemini[katexHtml.outerHTML] = latexStr;
                        console.log('Gemini KaTeX记录:', latexStr);
                    }
                }
                return result;
            }
        });
        console.log('Successfully hooked katex.render for Gemini');
        return true;
    }

    // Gemini专用:设置KaTeX Hook
    function setupGeminiKatexHook() {
        if (isGeminiKatexHooked) return;

        // 1. 检查现有katex
        if (window.katex) {
            isGeminiKatexHooked = hookKatexRender(window.katex);
            return;
        }

        // 2. 监听katex赋值
        let originalKatex = window.katex;
        Object.defineProperty(window, 'katex', {
            set: function(newKatex) {
                console.log('Detected katex assignment for Gemini, hooking render...');
                originalKatex = newKatex;
                if (!isGeminiKatexHooked) {
                    isGeminiKatexHooked = hookKatexRender(originalKatex);
                }
                return originalKatex;
            },
            get: function() {
                return originalKatex;
            },
            configurable: true
        });
    }

    // Gemini专用:处理选择复制时的KaTeX替换
    function katexReplaceWithTexGemini(fragment) {
        const katexHtml = fragment.querySelectorAll('.katex-html');
        for (let i = 0; i < katexHtml.length; i++) {
            const element = katexHtml[i];
            const texSource = document.createElement('annotation');
            
            if (element.outerHTML && allKatexGemini[element.outerHTML]) {
                const latexStr = allKatexGemini[element.outerHTML];
                
                // 判断是否为显示模式(块级公式)
                const isDisplayMode = element.closest('.katex-display') || 
                                     element.closest('.math-block');
                
                if (isDisplayMode) {
                    texSource.textContent = `\n$$\n${latexStr}\n$$\n`;
                } else {
                    texSource.textContent = `$${latexStr}$`;
                }

                if (element.replaceWith) {
                    element.replaceWith(texSource);
                } else if (element.parentNode) {
                    element.parentNode.replaceChild(texSource, element);
                }
            }
        }
        return fragment;
    }

    // Gemini专用:查找包含节点的最近KaTeX元素
    function closestKatex(node) {
        const element = (node instanceof Element ? node : node.parentElement);
        return element && element.closest('.katex');
    }

    // 显示Toast提示函数
    function showToast(message, type = 'success', duration = 3000) {
        // 移除现有的toast,避免重叠
        const existingToast = document.querySelector('.formula-toast');
        if (existingToast) {
            existingToast.remove();
        }

        // 创建新的toast
        const toast = document.createElement('div');
        toast.className = `formula-toast ${type}`;
        toast.textContent = message;
        document.body.appendChild(toast);

        // 显示toast
        setTimeout(() => {
            toast.classList.add('show');
        }, 10);

        // 设置自动消失
        setTimeout(() => {
            toast.classList.remove('show');
            setTimeout(() => {
                toast.remove();
            }, 300);
        }, duration);
    }

    // 显示复制成功提示
    function showCopySuccessTooltip() {
        const copyTooltip = document.createElement("div");
        copyTooltip.className = "latex-copy-success";
        copyTooltip.innerText = "已复制LaTeX公式";
        document.body.appendChild(copyTooltip);
        setTimeout(() => {
            copyTooltip.style.opacity = "0";
            setTimeout(() => {
                document.body.removeChild(copyTooltip);
            }, 200);
        }, 1000);
    }

    // 设置剪贴板为纯文本
    async function setClipboardToPlainText(text) {
        console.log('开始设置剪贴板,文本长度:', text.length);

        // 方法1:使用ClipboardItem(更可靠的纯文本格式)
        try {
            if (navigator.clipboard && window.ClipboardItem) {
                const blob = new Blob([text], { type: 'text/plain' });
                const data = new ClipboardItem({
                    'text/plain': blob
                });

                await navigator.clipboard.write([data]);
                console.log('已成功将内容设置为纯文本格式到剪贴板(方法1)');
                return true;
            }
        } catch (err) {
            console.error('ClipboardItem方法失败:', err);
        }

        // 方法2:使用writeText(备用方法)
        try {
            if (navigator.clipboard && navigator.clipboard.writeText) {
                await navigator.clipboard.writeText(text);
                console.log('已成功使用writeText设置剪贴板(方法2)');
                return true;
            }
        } catch (err) {
            console.error('writeText方法失败:', err);
        }

        // 方法3:使用传统的execCommand(最后备用)
        try {
            const textArea = document.createElement('textarea');
            textArea.value = text;
            textArea.style.position = 'fixed';
            textArea.style.left = '-999999px';
            textArea.style.top = '-999999px';
            document.body.appendChild(textArea);
            textArea.focus();
            textArea.select();

            const successful = document.execCommand('copy');
            document.body.removeChild(textArea);

            if (successful) {
                console.log('已成功使用execCommand设置剪贴板(方法3)');
                return true;
            }
        } catch (err) {
            console.error('execCommand方法失败:', err);
        }

        console.error('所有剪贴板方法都失败了');
        return false;
    }

    // 隐藏提示框的函数
    function hideTooltip() {
        tooltip.style.display = 'none';
        tooltip.style.opacity = '0';
        if (activeFormulaElement) {
            activeFormulaElement.classList.remove('formula-hover');
            activeFormulaElement = null;
        }
    }

    // 全局点击和滚动事件强制隐藏提示框
    document.addEventListener('click', function(e) {
        // 检查点击是否在公式上,如果不是,隐藏提示框
        if (activeFormulaElement && !activeFormulaElement.contains(e.target)) {
            hideTooltip();
        }
    });

    document.addEventListener('scroll', hideTooltip);
    window.addEventListener('resize', hideTooltip);

    // 获取对象和公式方法
    function getTarget(url) {
        let target = { elementSelector: '', getLatexString: null, isDisplayMode: null }

        // 检查元素是否是公式块
        function isDisplayModeFormula(element) {
            // Claude
            if (element.classList.contains('math-display') ||
                element.closest('.math-display') !== null) {
                return true;
            }

            // KaTeX相关网站
            if (element.classList.contains('katex-display') ||
                element.closest('.katex-display') !== null) {
                return true;
            }

            // DeepSeek
            if (element.closest('.ds-markdown-math') !== null) {
                return true;
            }

            // Google AI Studio - 检查ms-katex元素是否为块级公式
            if (element.tagName === 'MS-KATEX' && !element.classList.contains('inline')) {
                return true;
            }
            if (element.closest('ms-katex') && !element.closest('ms-katex').classList.contains('inline')) {
                return true;
            }

            return false;
        }

        // 格式化latex
        function formatLatex(input, isDisplayMode) {
            if (!input) return null;

            // 清理可能的多余字符
            input = input.trim();
            while (input.endsWith(' ') || input.endsWith('\\')) {
                input = input.slice(0, -1).trim();
            }

            // 如果输入已经有$或$$包裹,先去除
            if (input.startsWith('$') && input.endsWith('$')) {
                // 判断是否是$$公式块
                if (input.startsWith('$$') && input.endsWith('$$')) {
                    input = input.slice(2, -2).trim();
                } else {
                    input = input.slice(1, -1).trim();
                }
            }

            // 额外剥离 \( ... \) 与 \[ ... \] 定界,兼容豆包等站点
            if ((input.startsWith('\\(') && input.endsWith('\\)')) ||
                (input.startsWith('\\[') && input.endsWith('\\]'))) {
                // \( ... \) 或 \[ ... \]
                input = input.slice(2, -2).trim();
            }

            // 根据显示模式添加适当的分隔符
            if (isDisplayMode) {
                return '\n$$\n' + input + '\n$$\n';
            } else {
                return '$' + input + '$';
            }
        }

        // Claude.ai
        if (url.includes('claude.ai') || url.includes('fuclaude.oaifree.com')) {
            target.elementSelector = 'span.katex, span.math-inline, span.math-display, div.math-display';
            target.getLatexString = (element) => {
                const annotation = element.querySelector('annotation[encoding="application/x-tex"]');
                const isDisplay = isDisplayModeFormula(element);
                return annotation ? formatLatex(annotation.textContent, isDisplay) : null;
            };
            target.isDisplayMode = isDisplayModeFormula;
            return target;
        }
        // DeepSeek
        else if (url.includes('deepseek.com')) {
            target.elementSelector = 'span.katex';
            target.getLatexString = (element) => {
                const annotation = element.querySelector('annotation[encoding="application/x-tex"]');
                // 检查是否是公式块
                const isDisplay = isDisplayModeFormula(element);
                return annotation ? formatLatex(annotation.textContent, isDisplay) : null;
            };
            target.isDisplayMode = isDisplayModeFormula;
            return target;
        }
        // Google Gemini
        else if (url.includes('gemini.google.com')) {
            target.elementSelector = 'span.katex, span.katex-html, .katex-html, span.math-inline, div.math-block span.katex, span.math-display, div.math-block, .math-inline, .math-display';
            target.getLatexString = (element) => {
                // 使用Gemini的hook数据
                const katexHtml = element.classList.contains('katex-html') ? element : element.querySelector('.katex-html');
                if (katexHtml && allKatexGemini[katexHtml.outerHTML]) {
                    const latexStr = allKatexGemini[katexHtml.outerHTML];
                    const isDisplay = isDisplayModeFormula(element);
                    return formatLatex(latexStr, isDisplay);
                }
                return null;
            };
            target.isDisplayMode = isDisplayModeFormula;
            return target;
        }
        // Google AI Studio
        else if (url.includes('aistudio.google.com')) {
            target.elementSelector = 'ms-katex, span.katex, span.math-inline, span.math-display, div.math-display';
            target.getLatexString = (element) => {
                const annotation = element.querySelector('annotation[encoding="application/x-tex"]');
                const isDisplay = isDisplayModeFormula(element);
                return annotation ? formatLatex(annotation.textContent, isDisplay) : null;
            };
            target.isDisplayMode = isDisplayModeFormula;
            return target;
        }
        // 豆包
        else if (url.includes('doubao.com')) {
            target.elementSelector = 'span.container-rkuXQi, span.katex, span.math-inline, span.math-display';
            target.getLatexString = (element) => {
                // 优先从最近的容器读取 data-custom-copy-text(兼容事件绑定在 .katex 等子节点的情况)
                const container = element.closest('.container-rkuXQi') || element;
                const customCopyText = container.getAttribute('data-custom-copy-text') || element.getAttribute('data-custom-copy-text');
                if (customCopyText) {
                    // 显示模式:优先依据是否存在 .katex-display,其次依据容器/元素的行内/块级标记
                    const isDisplay = !!(container.querySelector('.katex-display') || element.closest('.katex-display')) ||
                                      container.classList.contains('math-display') ||
                                      (!container.classList.contains('math-inline') && !element.classList.contains('math-inline'));
                    return formatLatex(customCopyText, isDisplay);
                }
                
                // 回退到标准annotation方法
                const annotation = element.querySelector('annotation[encoding="application/x-tex"]');
                const isDisplay = isDisplayModeFormula(element);
                return annotation ? formatLatex(annotation.textContent, isDisplay) : null;
            };
            target.isDisplayMode = (element) => !!(element.querySelector && element.querySelector('.katex-display')) ||
                                               !!element.closest('.katex-display') ||
                                               element.classList.contains('math-display') ||
                                               !element.classList.contains('math-inline');
            return target;
        }
        // 知乎
        else if (url.includes('zhihu.com')) {
            target.elementSelector = 'span.ztext-math';
            target.getLatexString = (element) => {
                const isDisplay = element.classList.contains('ztext-math-block');
                return formatLatex(element.getAttribute('data-tex'), isDisplay);
            };
            target.isDisplayMode = (element) => element.classList.contains('ztext-math-block');
            return target;
        }
        // 默认KaTeX检测
        target.elementSelector = 'span.katex, span.math';
        target.getLatexString = (element) => {
            const annotation = element.querySelector('annotation[encoding="application/x-tex"]');
            const isDisplay = isDisplayModeFormula(element);
            return annotation ? formatLatex(annotation.textContent, isDisplay) : null;
        };
        target.isDisplayMode = isDisplayModeFormula;
        return target;
    }

    // 重构:直接处理DOM fragment,避免Trusted Types问题
    function processFormulaContentFromFragment(fragment) {
        if (!fragment) return '';

        console.log('处理选中的DOM fragment开始');

        // 克隆fragment以避免修改原始选择
        const workingFragment = fragment.cloneNode(true);

        // 创建临时容器来处理fragment
        const tempDiv = document.createElement('div');
        tempDiv.appendChild(workingFragment);

        return processFormulaFromElement(tempDiv);
    }

    // 新函数:直接从DOM元素处理公式,完全避免HTML字符串操作
    function processFormulaFromElement(element) {
        console.log('开始处理元素中的公式');

        // 找出所有KaTeX公式,包括Google AI Studio的ms-katex和豆包的container-rkuXQi
        const allFormulas = element.querySelectorAll('.katex, .math-inline, .math-display, .katex-display, ms-katex, .container-rkuXQi');
        console.log(`找到 ${allFormulas.length} 个公式元素`);

        // 打印找到的公式元素信息
        allFormulas.forEach((formula, index) => {
            console.log(`公式 ${index + 1}:`, {
                tagName: formula.tagName,
                className: formula.className,
                hasAnnotation: !!formula.querySelector('annotation[encoding="application/x-tex"]')
            });
        });

        // 处理每个公式
        allFormulas.forEach((formula, index) => {
            try {
                console.log(`处理公式 ${index + 1}`);
                
                let latexContent = null;
                let isDisplayMode = false;
                
                // 豆包:优先使用data-custom-copy-text属性
                const customCopyText = formula.getAttribute('data-custom-copy-text');
                if (customCopyText) {
                    latexContent = customCopyText;
                    isDisplayMode = formula.classList.contains('math-display') || 
                                   !formula.classList.contains('math-inline');
                } else {
                    // 其他网站:查找annotation元素
                    const annotation = formula.querySelector('annotation[encoding="application/x-tex"]');
                    if (annotation && annotation.textContent) {
                        latexContent = annotation.textContent;
                        // 判断是否是公式块
                        isDisplayMode = formula.classList.contains('math-display') ||
                                      formula.classList.contains('katex-display') ||
                                      formula.closest('.math-display') !== null ||
                                      formula.closest('.katex-display') !== null ||
                                      formula.closest('.ds-markdown-math') !== null ||
                                      (formula.tagName === 'MS-KATEX' && !formula.classList.contains('inline')) ||
                                      (formula.closest('ms-katex') && !formula.closest('ms-katex').classList.contains('inline'));
                    }
                }

                // 如果找到了LaTeX内容
                if (latexContent) {
                    // 创建替换内容
                    let replacementText;
                    if (isDisplayMode) {
                        replacementText = '\n$$\n' + latexContent.trim() + '\n$$\n';
                    } else {
                        replacementText = '$' + latexContent.trim() + '$';
                    }

                    // 替换公式元素
                    const textNode = document.createTextNode(replacementText);

                    // 找到最合适的父节点进行替换
                    let targetNode = formula;
                    if (formula.closest('.katex-display')) {
                        targetNode = formula.closest('.katex-display');
                    } else if (formula.closest('.math-display')) {
                        targetNode = formula.closest('.math-display');
                    } else if (formula.closest('.ds-markdown-math')) {
                        targetNode = formula.closest('.ds-markdown-math');
                    } else if (formula.closest('.container-rkuXQi')) {
                        targetNode = formula.closest('.container-rkuXQi');
                    } else if (formula.tagName === 'MS-KATEX') {
                        targetNode = formula;
                    } else if (formula.closest('ms-katex')) {
                        targetNode = formula.closest('ms-katex');
                    }

                    if (targetNode.parentNode) {
                        targetNode.parentNode.replaceChild(textNode, targetNode);
                    }
                }
            } catch (e) {
                console.error('处理公式时出错:', e);
            }
        });

        // 返回处理后的文本内容
        let result;
        try {
            result = element.textContent || element.innerText || '';
        } catch (e) {
            console.error('获取文本内容失败:', e);
            // 如果连textContent都无法访问,尝试手动提取
            result = extractTextFromElement(element);
        }
        console.log('处理后的文本:', result);
        return result;
    }

    // 辅助函数:安全地从元素中提取文本
    function extractTextFromElement(element) {
        let text = '';
        try {
            // 递归遍历所有子节点
            for (let node of element.childNodes) {
                if (node.nodeType === Node.TEXT_NODE) {
                    text += node.textContent || '';
                } else if (node.nodeType === Node.ELEMENT_NODE) {
                    text += extractTextFromElement(node);
                }
            }
        } catch (e) {
            console.error('手动文本提取也失败:', e);
            return '';
        }
        return text;
    }

    // 为公式元素添加事件处理
    function setupFormulaHandlers() {
        const target = getTarget(window.location.href);
        if (!target) return;

        const formulaElements = document.querySelectorAll(target.elementSelector);
        if (formulaElements.length === 0) return;

        console.log(`找到 ${formulaElements.length} 个公式元素,添加事件处理器`);

        formulaElements.forEach(element => {
            // 防止重复添加
            if (element.hasAttribute('data-formula-handled')) return;

            // 为了处理嵌套元素,检查父元素是否已经处理过
            let parent = element.parentElement;
            while (parent) {
                if (parent.hasAttribute('data-formula-handled')) return;
                parent = parent.parentElement;
            }

            // 标记为已处理
            element.setAttribute('data-formula-handled', 'true');

            // 检查元素是否包含有效的LaTeX内容
            let hasValidLatex = false;
            
            if (window.location.href.includes('gemini.google.com')) {
                // Gemini:检查hook数据
                const katexHtml = element.classList.contains('katex-html') ? element : element.querySelector('.katex-html');
                hasValidLatex = katexHtml && allKatexGemini[katexHtml.outerHTML];
            } else if (window.location.href.includes('doubao.com')) {
                // 豆包:检查data-custom-copy-text属性
                hasValidLatex = !!element.getAttribute('data-custom-copy-text') || 
                               !!element.querySelector('annotation[encoding="application/x-tex"]');
            } else {
                // 其他网站:检查annotation元素
                const annotation = element.querySelector('annotation[encoding="application/x-tex"]');
                hasValidLatex = !!annotation;
            }
            
            if (!hasValidLatex) return;

            // 鼠标进入事件
            element.addEventListener('mouseenter', function() {
                clearTimeout(tooltipTimeout);

                // 设置活动元素
                if (activeFormulaElement) {
                    activeFormulaElement.classList.remove('formula-hover');
                }

                activeFormulaElement = element;
                element.classList.add('formula-hover');

                // 准备显示LaTeX提示
                tooltipTimeout = setTimeout(function() {
                    const latexString = target.getLatexString(element);
                    if (latexString) {
                        tooltip.textContent = latexString;

                        // 计算位置
                        const rect = element.getBoundingClientRect();
                        tooltip.style.display = 'block';
                        tooltip.style.opacity = '0';

                        // 确保提示框不会超出视窗
                        let leftPos = rect.left;
                        if (leftPos + 350 > window.innerWidth) {
                            leftPos = window.innerWidth - 350;
                        }
                        if (leftPos < 10) leftPos = 10;

                        // 在元素上方或下方显示
                        if (rect.top > 100) {
                            tooltip.style.top = `${rect.top - tooltip.offsetHeight - 5}px`;
                        } else {
                            tooltip.style.top = `${rect.bottom + 5}px`;
                        }

                        tooltip.style.left = `${leftPos}px`;
                        tooltip.style.opacity = '0.9';
                    }
                }, 300);
            });

            // 鼠标离开事件
            element.addEventListener('mouseleave', function() {
                clearTimeout(tooltipTimeout);
                element.classList.remove('formula-hover');

                tooltipTimeout = setTimeout(function() {
                    if (activeFormulaElement === element) {
                        hideTooltip();
                    }
                }, 100);
            });

            // 点击事件 - 复制公式
            element.addEventListener('click', function(e) {
                const latexString = target.getLatexString(element);
                if (latexString) {
                    navigator.clipboard.writeText(latexString).then(() => {
                        showCopySuccessTooltip();
                        console.log(`已复制公式: ${latexString}`);
                    }).catch(err => {
                        console.error('复制公式失败:', err);
                        showToast('复制公式失败: ' + err.message, 'error');
                    });

                    // 阻止事件冒泡
                    e.stopPropagation();
                    e.preventDefault();
                }
            });
        });
    }

    // 监听复制事件(用户使用Ctrl+C或右键复制)
    document.addEventListener('copy', async function(e) {
        console.log('复制事件触发');

        // 检查是否有选中的内容
        const selection = window.getSelection();
        if (!selection || selection.isCollapsed) {
            console.log('没有选中内容,跳过处理');
            return;
        }

        console.log('选中文本:', selection.toString());

        // 获取选中的DOM内容(直接处理DOM,避免Trusted Types错误)
        const range = selection.getRangeAt(0);
        const fragment = range.cloneContents();

        // 直接检查DOM fragment中是否有公式元素
        const tempDiv = document.createElement('div');
        tempDiv.appendChild(fragment.cloneNode(true));

        // 直接在DOM中检测公式元素
        const formulaElements = tempDiv.querySelectorAll('.katex, .math-inline, .math-display, .katex-display, ms-katex, .katex-html, .container-rkuXQi');
        const hasFormula = formulaElements.length > 0;

        console.log('找到公式元素数量:', formulaElements.length);
        console.log('是否包含公式:', hasFormula);

        if (hasFormula) {
            console.log('检测到选中内容包含公式,开始处理...');

            try {
                e.preventDefault(); // 阻止默认复制行为
                e.stopPropagation(); // 阻止事件冒泡

                let processedText;
                
                // Gemini网站特殊处理
                if (window.location.href.includes('gemini.google.com')) {
                    console.log('使用Gemini专用复制逻辑');
                    
                    // 扩展选择范围到完整的katex元素
                    const startKatex = closestKatex(range.startContainer);
                    if (startKatex) {
                        range.setStartBefore(startKatex);
                    }
                    
                    const endKatex = closestKatex(range.endContainer);
                    if (endKatex) {
                        range.setEndAfter(endKatex);
                    }
                    
                    // 重新获取扩展后的fragment
                    const expandedFragment = range.cloneContents();
                    
                    // 使用Gemini专用的替换函数
                    katexReplaceWithTexGemini(expandedFragment);
                    processedText = expandedFragment.textContent;
                    
                    // 阻止Gemini的默认处理
                    e.stopImmediatePropagation();
                } else {
                    // 其他网站使用原有逻辑
                    processedText = processFormulaContentFromFragment(fragment);
                }
                
                console.log('处理后的文本:', processedText);

                // 设置到剪贴板
                const success = await setClipboardToPlainText(processedText);

                if (success) {
                    showToast('已格式化选中的公式内容', 'success');
                    console.log('复制成功');
                } else {
                    // 备用复制方法
                    try {
                        await navigator.clipboard.writeText(processedText);
                        showToast('已格式化选中的公式内容(备用方法)', 'success');
                        console.log('备用复制方法成功');
                    } catch (fallbackError) {
                        console.error('备用复制方法也失败:', fallbackError);
                        showToast('复制失败,请手动复制。处理后的内容已打印到控制台', 'error');
                        console.log('请手动复制以下内容:', processedText);
                    }
                }
            } catch (error) {
                console.error('处理复制事件时出错:', error);
                showToast('处理复制事件时出错: ' + error.message, 'error');
            }
        }
    }, { capture: true, passive: false });

    // 处理按钮点击事件
    function handleButtonClick() {
        console.log('复制按钮被点击');

        setTimeout(async function() {
            try {
                const text = await navigator.clipboard.readText();

                // 统一规范化三种常见定界:$$...$$, \[...\], \(...\)
                let modifiedText = text;
                let matchCount = 0;

                // $$...$$ → 换行块级
                modifiedText = modifiedText.replace(/\$\$(.*?)\$\$/gs, (m, f) => {
                    matchCount++;
                    return `\n$$\n${f.trim()}\n$$\n`;
                });

                // \[...\] → 换行块级(避免与 $$ 已替换的重复,这里直接处理剩余)
                modifiedText = modifiedText.replace(/\\\[(.*?)\\\]/gs, (m, f) => {
                    matchCount++;
                    return `\n$$\n${f.trim()}\n$$\n`;
                });

                // \(...\) → 行内
                modifiedText = modifiedText.replace(/\\\((.*?)\\\)/gs, (m, f) => {
                    matchCount++;
                    return `$${f.trim()}$`;
                });

                if (matchCount > 0) {
                    const success = await setClipboardToPlainText(modifiedText);
                    if (success) {
                        showToast(`已格式化 ${matchCount} 个公式`, 'success');
                    } else {
                        showToast('写入纯文本格式到剪贴板失败', 'error');
                    }
                }
            } catch (err) {
                console.error('处理剪贴板失败:', err);
                showToast('处理剪贴板失败', 'error');
            }
        }, 100);
    }

    // 查找并监听复制按钮
    function setupButtonListener() {
        // 查找所有可能的复制按钮
        const copyButtons = document.querySelectorAll('button[data-testid="action-bar-copy"], button:has(svg[data-testid="action-bar-copy"])');

        // DeepSeek特定按钮
        if (window.location.href.includes('deepseek.com')) {
            const deepseekButtons = document.querySelectorAll('button.copy-btn, button:has(svg[data-icon="copy"])');
            if (deepseekButtons.length > 0) {
                deepseekButtons.forEach(button => {
                    button.removeEventListener('click', handleButtonClick);
                    button.addEventListener('click', handleButtonClick);
                });
            }
        }

        // 豆包特定按钮
        if (window.location.href.includes('doubao.com')) {
            const doubaoButtons = document.querySelectorAll('button[data-testid="message_action_copy"]');
            if (doubaoButtons.length > 0) {
                doubaoButtons.forEach(button => {
                    button.removeEventListener('click', handleButtonClick);
                    button.addEventListener('click', handleButtonClick);
                });
                console.log(`找到 ${doubaoButtons.length} 个豆包复制按钮,添加监听器`);
            }
        }

        if (copyButtons.length > 0) {
            console.log(`找到 ${copyButtons.length} 个复制按钮,添加监听器`);

            copyButtons.forEach(button => {
                button.removeEventListener('click', handleButtonClick);
                button.addEventListener('click', handleButtonClick);
            });
        }
    }

    // 页面加载和DOM变化时初始化功能
    function initialize() {
        setupButtonListener();
        setupFormulaHandlers();
    }

    // Gemini专用延迟初始化逻辑
    function initializeForGemini() {
        let retryCount = 0;
        const maxRetries = 3;
        const baseDelay = 1000; // 1秒基础延迟

        function attemptInitialization() {
            console.log(`Gemini初始化尝试 ${retryCount + 1}/${maxRetries}`);

            // 首先设置KaTeX Hook
            setupGeminiKatexHook();

            // 检查是否有对话容器存在
            const conversationContainer = document.querySelector('.response-container, message-content, .model-response-text');

            if (conversationContainer || retryCount >= maxRetries) {
                initialize();

                // 为Gemini对话容器添加特殊监听
                if (conversationContainer) {
                    const geminiObserver = new MutationObserver(function() {
                        // 确保hook依然有效
                        if (!isGeminiKatexHooked) {
                            setupGeminiKatexHook();
                        }
                        setTimeout(initialize, 500); // 短延迟后重新初始化
                    });
                    geminiObserver.observe(conversationContainer, { childList: true, subtree: true });
                }
                return;
            }

            retryCount++;
            const delay = baseDelay * retryCount; // 递增延迟
            setTimeout(attemptInitialization, delay);
        }

        attemptInitialization();
    }

    // 页面加载完成后初始化
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', function() {
            if (window.location.href.includes('gemini.google.com')) {
                initializeForGemini();
            } else {
                initialize();
            }
        });
    } else {
        if (window.location.href.includes('gemini.google.com')) {
            initializeForGemini();
        } else {
            initialize();
        }
    }

    // 使用MutationObserver监视DOM变化
    const observer = new MutationObserver(function(mutations) {
        let needsSetup = false;

        mutations.forEach(function(mutation) {
            if (mutation.addedNodes && mutation.addedNodes.length > 0) {
                needsSetup = true;
            }
            // 针对Gemini添加属性变化监听
            if (mutation.type === 'attributes' &&
                (mutation.attributeName === 'class' || mutation.attributeName === 'data-formula-handled')) {
                needsSetup = true;
            }
        });

        if (needsSetup) {
            initialize();
        }
    });

    // 开始观察文档体的变化,针对Gemini增强监听
    const observerConfig = {
        childList: true,
        subtree: true,
        attributes: true,
        attributeFilter: ['class', 'data-formula-handled']
    };
    observer.observe(document.body, observerConfig);

    // 添加安全定时器,定期重新扫描页面上的公式
    setInterval(initialize, 5000);

    // 添加调试辅助函数
    window.debugFormulaScript = function() {
        console.log('=== 公式复制脚本调试信息 ===');
        console.log('脚本版本: 0.9 (豆包网站新增支持)');
        console.log('当前网站:', window.location.href);
        console.log('支持的网站:', ['Claude', 'DeepSeek', '知乎', 'Google AI Studio', 'Google Gemini', '豆包', '等等']);

        const target = getTarget(window.location.href);
        console.log('当前网站配置:', target);

        const formulas = document.querySelectorAll(target.elementSelector);
        console.log(`页面上找到 ${formulas.length} 个公式元素`);

        formulas.forEach((formula, index) => {
            const latex = target.getLatexString(formula);
            console.log(`公式 ${index + 1}:`, latex);
        });

        // Gemini特殊调试信息
        if (window.location.href.includes('gemini.google.com')) {
            console.log('=== Gemini特殊调试信息 ===');
            console.log('KaTeX Hook状态:', isGeminiKatexHooked);
            console.log('已记录的KaTeX映射数量:', Object.keys(allKatexGemini).length);
            const containers = document.querySelectorAll('.response-container, message-content, .model-response-text');
            console.log(`找到 ${containers.length} 个对话容器`);
            const mathBlocks = document.querySelectorAll('div.math-block');
            console.log(`找到 ${mathBlocks.length} 个数学块容器`);
            const katexHtmlElements = document.querySelectorAll('.katex-html');
            console.log(`找到 ${katexHtmlElements.length} 个katex-html元素`);
            
            // 显示已记录的KaTeX映射
            console.log('KaTeX映射详情:');
            Object.entries(allKatexGemini).forEach(([html, latex], index) => {
                console.log(`  ${index + 1}. ${latex}`);
            });
        }

        // 豆包特殊调试信息
        if (window.location.href.includes('doubao.com')) {
            console.log('=== 豆包特殊调试信息 ===');
            const doubaoContainers = document.querySelectorAll('.container-rkuXQi');
            console.log(`找到 ${doubaoContainers.length} 个豆包公式容器`);
            const copyButtons = document.querySelectorAll('button[data-testid="message_action_copy"]');
            console.log(`找到 ${copyButtons.length} 个豆包复制按钮`);
            
            // 显示豆包公式的data-custom-copy-text属性
            console.log('豆包公式data-custom-copy-text属性:');
            doubaoContainers.forEach((container, index) => {
                const customText = container.getAttribute('data-custom-copy-text');
                if (customText) {
                    console.log(`  ${index + 1}. ${customText}`);
                }
            });
        }

        console.log('如果复制不工作,请检查浏览器控制台的错误信息');
        console.log('=== 调试信息结束 ===');
    };

    // 在页面上显示初始化成功提示
    showToast('公式复制格式调整脚本已加载', 'info', 2000);

    // 如果是Google AI Studio,显示特殊提示
    if (window.location.href.includes('aistudio.google.com')) {
        setTimeout(() => {
            showToast('Google AI Studio适配已启用,控制台输入debugFormulaScript()查看调试信息', 'info', 4000);
        }, 2500);
    }

    // 如果是Google Gemini,显示特殊提示
    if (window.location.href.includes('gemini.google.com')) {
        setTimeout(() => {
            showToast('Google Gemini适配已启用,支持动态加载内容,控制台输入debugFormulaScript()查看调试信息', 'info', 4000);
        }, 2500);
    }

    // 如果是豆包,显示特殊提示
    if (window.location.href.includes('doubao.com')) {
        setTimeout(() => {
            showToast('豆包适配已启用,支持data-custom-copy-text属性,控制台输入debugFormulaScript()查看调试信息', 'info', 4000);
        }, 2500);
    }
})();