Skip to content

在Firefox+微信公众号文章页面上会导致自动复制脚本失效 #229

@YandLiu

Description

@YandLiu

一个很神奇的bug:
选中某个关键词,按下Ctrl+`快捷键用扩展高亮后,自动复制脚本就失效了
换其他页面就没这个问题
用Edge浏览器也没有这个问题
示例页面:https://mp.weixin.qq.com/s/pSY5rKVpuFxZokgFhPHf5g
Windows 11, Firefox 141 (至少13x以来都有这个问题)

我用的自动复制脚本

// ==UserScript==
// @name         AutoCopy
// @name:zh-CN   自动复制
// @namespace    https://github.com/YandLiu/
// @version      20250715
// @description  选中自动复制
// @author       YandLiu
// @include      *
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addValueChangeListener
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAABpElEQVR4nO3Vv2uUQRDG8c/ebSMWqay0trATAxrUSi1S2AiWFoJYpNCgoBjURsHWJKeNRfAvsDgFixQqKdPZ2ViEiCJYBOQu8f1hEXO59713j7MUfLZ6d2a/O8vMO0OzDnin9Ku2Mjvuaw07xgSAYEVXe2indMhj92zpKJLnBhF8MDeye9hn6zbN70eRiqCw02Bra3up8BBLu1FEBxsBucXqW4csz0ULe4jorSCMuPU89boRELDMHiI6Y8V65bbCUTccc70RkaOwKLOg0IkyXa9qTjOu2LAs6NZuD86hrdTyxRNTkUqqdhXlHrngGRVEZsMpJwex9DxIZSHYclesIb65LCoHgIs66UJq6btDBZHZrPh8V6YBOX66LbOkTGckBYimBW2FVTNeuOZNyrFJ236Yl4NSy5SbVm1PDvhodqgyMledTdRlAtDzqfL9tfkwUtyaRkv9LwFj9B/w7wPycXOhqlJ0yZHKPChMi5MCiM47XhsopbVJAUHfrYbmN/EToN+02eLPfz9OYyZhFJzW1Jn3lTsxaKQjCkp52jy45r1ZvSbTb9M0d4PBozGZAAAAAElFTkSuQmCC
// ==/UserScript==

// (function () {
//     'use strict';



const STORAGE_KEY = '__autoCopyEnabled';
let enabled = GM_getValue(STORAGE_KEY, true);


// 创建悬浮按钮
var button = document.createElement('button');
button.textContent = '📋';
Object.assign(button.style, {
    position: 'fixed',
    bottom: '10px',
    right: '10px',
    zIndex: 9999,
    padding: '5px 5px',
    fontSize: '14px',
    backgroundColor: enabled ? 'rgba(76, 175, 80, 0.3)' : 'rgba(244, 67, 54, 0.3)',
    color: 'white',
    border: 'none',
    borderRadius: '10px',
    cursor: 'pointer',
});
// 阻止在iframe中显示
if (window.top !== window.self) return;
else document.body.appendChild(button);

// 监听按钮点击
button.addEventListener('click', async () => {
    enabled = !enabled;
    await GM_setValue(STORAGE_KEY, enabled);
    updateButton();
});

// 跨标签页同步
GM_addValueChangeListener(STORAGE_KEY, (name, oldVal, newVal) => {
    enabled = newVal;
    updateButton();
});

function updateButton () {
    button.style.backgroundColor = enabled ? 'rgba(76, 175, 80, 0.3)' : 'rgba(244, 67, 54, 0.3)';
}

let mouseDownTarget;
window.onmousedown = function (e) {
    mouseDownTarget = e.target;
};

// 记录双击事件
let lastClickTime = 0;
let doubleClickThreshold = 300; // 双击阈值(毫秒)

window.addEventListener('mouseup', (e) => {
    const now = Date.now();
    const isDoubleClick = (now - lastClickTime) < doubleClickThreshold;
    lastClickTime = now;

    // 延迟处理,给浏览器时间更新选中范围
    setTimeout(() => {
        if (!inTextBox() && enabled) {
            copySelection(isDoubleClick);
        }
    }, isDoubleClick ? 50 : 0); // 双击时增加延迟
});

function copySelection (isDoubleClick) {
    try {
        // 获取用户当前选中的HTML内容
        const selection = document.getSelection();

        // 检查是否有选中内容
        if (!selection || selection.isCollapsed || selection.rangeCount === 0) return;
        const range = selection.getRangeAt(0);

        // 创建临时容器
        const tempDiv = document.createElement('div');
        tempDiv.appendChild(range.cloneContents());

        // 清理临时容器中的脚本和事件
        sanitizeContent(tempDiv);

        // 获取选中内容的 HTML 代码和文本
        const htmlContent = tempDiv.innerHTML;
        const textContent = selection.toString();

        // 检查内容是否有效
        if (!htmlContent.trim() || !textContent.trim()) return;

        // 创建剪贴板项
        const htmlBlob = new Blob([htmlContent], {type: 'text/html'});
        const textBlob = new Blob([textContent], {type: 'text/plain'});
        const clipboardItem = new ClipboardItem({
            'text/html': htmlBlob,
            'text/plain': textBlob
        });

        // 写入剪贴板
        navigator.clipboard.write([clipboardItem]).catch(err => {
            console.error('自动复制失败:', err);
            // 回退方案
            document.execCommand('copy');
        });
    } catch (error) {
        console.error('自动复制过程出错:', error);
    }
}


// 清理临时容器中的潜在危险内容
function sanitizeContent (element) {
    // 移除所有脚本标签
    const scripts = element.querySelectorAll('script');
    scripts.forEach(script => script.remove());

    // 移除所有事件属性
    const allElements = element.querySelectorAll('*');
    allElements.forEach(el => {
        for (let attr of el.attributes) {
            if (attr.name.startsWith('on')) {
                el.removeAttribute(attr.name);
            }
        }
    });
}


// 检测是否在文本框/编辑器中
function inTextBox () {
    const generalElements = ['textarea, input, *[contenteditable="true"]'];
    let targets = [];

    // 收集常规文本输入元素
    generalElements.forEach(selector => {
        document.querySelectorAll(selector).forEach(el => {
            targets.push(el);
        });
    });

    // 特定网站的特殊处理
    const siteSpecificRules = {
        'mail.google.com': 'div[aria-label= "Message Body"]',
        'outlook.live.com': '#editorParent_1'
    };

    for (const [hostname, selector] of Object.entries(siteSpecificRules)) {
        if (document.location.hostname.includes(hostname)) {
            document.querySelectorAll(selector).forEach(el => {
                targets.push(el);
            });
        }
    }

    // 检查点击目标是否在这些元素内
    return targets.some(target => target.contains(mouseDownTarget));
}
// })();

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions