Greasy Fork

Greasy Fork is available in English.

页面编辑功能

alt + z : 编辑文本 ; alt + x : 结束编辑文本 ; alt + c : 编辑块 ; alt + z : 结束编辑块

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         页面编辑功能
// @namespace    www.leizingyiu.net
// @author       leizingyiu
// @include      *://*/*
// @license      GNU AGPLv3
// @version      20250812
// @grant        none
// @description  alt + z : 编辑文本 ; alt + x : 结束编辑文本 ; alt + c : 编辑块 ; alt + z : 结束编辑块
// ==/UserScript==

(function () {
    'use strict';

    const show = hint;
    const print = console.log;

    const config = {
        "z": editTrue,
        "x": editFalse,

        "c": editDomStart,
        "v": editDomEnd,
    };

    function editTrue() {
        document.querySelectorAll("*").forEach(el => {
            el.setAttribute("contenteditable", true);
        });
        show("✅ 页面已设置为可编辑");
    }

    function editFalse() {
        document.querySelectorAll("*").forEach(el => {
            el.setAttribute("contenteditable", false);
        });
        show("✅ 页面已设置为不可编辑");
    }

    function editDomStart() {
        let selected = null;
        let styleTag = document.createElement('style');
        styleTag.id = 'dom-selection-style';
        styleTag.innerHTML = `
      .selected {
        outline: 2px solid rgba(0, 123, 255, 0.7)!important;
        box-shadow: 0 0 8px 2px rgba(0, 123, 255, 0.7);
        cursor: pointer;
      }
    `;
        document.head.appendChild(styleTag);

        const selectElement = (el) => {
            if (!el) return;
            if (selected) selected.classList.remove('selected');
            selected = el;
            selected.classList.add('selected');
            //selected.scrollIntoView({ behavior: 'smooth', block: 'center' });
        };

        const onMouseEnter = (e) => {
            if (e.target === document.body || e.target === document.documentElement) return;
            if (selected) selected.classList.remove('selected');
            selected = e.target;
            selected.classList.add('selected');
        };

        const onMouseOut = (e) => {
            if (e.target === selected) {
                selected.classList.remove('selected');
                selected = null;
            }
        };

        const onKeyDown = (e) => {
            if (!selected) return;

            let newSelected = null;
            switch (e.key) {
                case 'w':
                    if (selected.parentElement && selected.parentElement !== document.body && selected.parentElement !== document.documentElement) {
                        newSelected = selected.parentElement;
                    }
                    break;
                case 's':
                    if (selected.children && selected.children.length > 0) {
                        newSelected = selected.children[0];
                    }
                    break;
                case 'a':
                    if (selected.previousElementSibling) {
                        newSelected = selected.previousElementSibling;
                    }
                    break;
                case 'd':
                    if (selected.nextElementSibling) {
                        newSelected = selected.nextElementSibling;
                    }
                    break;
                case 'Enter':
                    e.preventDefault();
                    if (selected && selected.parentNode) {
                        const clone = selected.cloneNode(true);
                        selected.parentNode.insertBefore(clone, selected.nextSibling);
                    }
                    break;
                case 'Backspace':
                    e.preventDefault();
                    if (selected && selected.parentNode) {
                        let toRemove = selected;
                        let newFocus = selected.nextElementSibling || selected.previousElementSibling || selected.parentElement;
                        toRemove.parentNode.removeChild(toRemove);
                        selected = null;
                        if (newFocus && newFocus !== document.body && newFocus !== document.documentElement) {
                            selectElement(newFocus);
                        }
                    }
                    break;
            }

            if (newSelected) {
                e.preventDefault();
                selectElement(newSelected);
            }
        };

        document.body.addEventListener('mouseenter', onMouseEnter, true);
        document.body.addEventListener('mouseout', onMouseOut, true);
        document.addEventListener('keydown', onKeyDown);

        // 给 stop 函数用来解绑事件和清理
        window.__domSelectorStop = () => {
            document.body.removeEventListener('mouseenter', onMouseEnter, true);
            document.body.removeEventListener('mouseout', onMouseOut, true);
            document.removeEventListener('keydown', onKeyDown);
            if (selected) {
                selected.classList.remove('selected');
                selected = null;
            }
            styleTag.remove();
            window.__domSelectorStop = null;
        };

        show("✅ 已进入页面部件编辑状态,现在可以对高亮部分操作,按 enter 复制,按 backspace 移除");
    }

    function editDomEnd() {
        if (typeof window.__domSelectorStop === 'function') {
            window.__domSelectorStop();
            show("✅ 已结束页面部件编辑状态");

        }
    }

    window.addEventListener("keydown", (e) => {
        print(e);
        if (e.altKey && !e.shiftKey && !e.ctrlKey && !e.metaKey) {

            if (e.code.startsWith("Key")) {
                const keyChar = e.code.slice(3).toLowerCase();
                if (config[keyChar]) {
                    e.preventDefault();
                    config[keyChar]();
                }
            }
        }
    });

    function hint(content, duration = 1000) {
        // 创建toast元素
        const toast = document.createElement('div');
        toast.textContent = content;

        // 设置样式
        Object.assign(toast.style, {
            position: 'fixed',
            bottom: '30px',
            left: '50%',
            transform: 'translateX(-50%)',
            background: 'rgba(0, 0, 0, 0.7)',
            color: 'white',
            padding: '10px 20px',
            borderRadius: '4px',
            fontSize: '14px',
            zIndex: 9999,
            opacity: '0',
            transition: 'opacity 0.3s ease',
            pointerEvents: 'none', // 不阻挡鼠标事件
        });

        // 添加到页面
        document.body.appendChild(toast);

        // 触发显示动画
        requestAnimationFrame(() => {
            toast.style.opacity = '1';
        });

        // 定时关闭
        setTimeout(() => {
            toast.style.opacity = '0';
            // 动画结束后移除元素
            toast.addEventListener('transitionend', () => {
                toast.remove();
            }, { once: true });
        }, duration);
    }
})();