Greasy Fork

来自缓存

Greasy Fork is available in English.

HighLighter_Modern_Final

使用浏览器原生 Highlight API。不修改 DOM,不丢文字。Ctrl+左键高亮,Ctrl+右键取消。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         HighLighter_Modern_Final
// @namespace    http://tampermonkey.net/
// @version      0.9.0
// @description  使用浏览器原生 Highlight API。不修改 DOM,不丢文字。Ctrl+左键高亮,Ctrl+右键取消。
// @author       Gemini
// @match        *://*/*
// @grant        none
// @license MI
// ==/UserScript==

(function() {
    'use strict';

    // 1. 创建 CSS 样式(定义高亮外观)
    // ::highlight(my-custom-highlight) 是虚拟的,不改变 HTML 结构
    const style = document.createElement('style');
    style.textContent = `
        ::highlight(my-custom-highlight) {
            background-color: yellow;
            color: black;
        }
    `;
    document.head.appendChild(style);

    // 2. 初始化高亮集合
    let highlightRanges = new Set();

    function updateRegistry() {
        // 更新浏览器渲染的高亮范围
        CSS.highlights.set("my-custom-highlight", new Highlight(...highlightRanges));
    }

    // --- 高亮逻辑 ---
    function applyHighlight() {
        const selection = window.getSelection();
        if (selection.isCollapsed || selection.rangeCount === 0) return;

        const range = selection.getRangeAt(0).cloneRange();
        highlightRanges.add(range);
        
        updateRegistry();
        selection.removeAllRanges();
    }

    // --- 取消高亮逻辑 ---
    function removeHighlight() {
        const selection = window.getSelection();
        if (selection.rangeCount === 0) return;

        const selRange = selection.getRangeAt(0);

        // 检查当前选区是否重叠了已有的高亮范围
        highlightRanges.forEach(range => {
            // 如果两个范围有重叠,就移除旧的高亮
            if (isOverlapping(range, selRange) || selection.containsNode(range.startContainer, true)) {
                highlightRanges.delete(range);
            }
        });

        updateRegistry();
        selection.removeAllRanges();
    }

    // 判断两个 Range 是否重叠
    function isOverlapping(range1, range2) {
        return range1.compareBoundaryPoints(Range.END_TO_START, range2) < 0 &&
               range2.compareBoundaryPoints(Range.END_TO_START, range1) < 0;
    }

    // --- 事件监听 ---

    // 禁用右键菜单 (按下 Ctrl 时)
    document.addEventListener('contextmenu', (e) => {
        if (e.ctrlKey) e.preventDefault();
    });

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

        if (e.button === 0) { // 左键高亮
            setTimeout(applyHighlight, 10);
        } else if (e.button === 2) { // 右键取消
            setTimeout(removeHighlight, 10);
        }
    });

})();