Native Image Toggler

通过原生 UI 控制当前页面图片的显示和隐藏,支持持久化设置

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name         Native Image Toggler
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  通过原生 UI 控制当前页面图片的显示和隐藏,支持持久化设置
// @author       You
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // 配置常量
    const STORAGE_KEY_PREFIX = 'img_toggle_';
    const STYLE_ID = 'native-image-toggler-style';
    const POSITION_KEY = 'img_toggle_position_';
    const UI_VISIBLE_KEY = 'img_toggle_ui_visible_';
    const DEFAULT_POSITION = { top: 10, right: 20 };

    // 获取当前域名的设置键
    const hostname = window.location.hostname;
    const storageKey = STORAGE_KEY_PREFIX + hostname;
    const positionKey = POSITION_KEY + hostname;

    // 状态:true 表示图片显示(默认),false 表示图片隐藏
    // 默认所有网站都是显示的,除非用户手动关闭
    let isImagesVisible = GM_getValue(storageKey, true);
    let uiPosition = GM_getValue(positionKey, DEFAULT_POSITION);
    let isUIVisible = GM_getValue(UI_VISIBLE_KEY, true);

    // CSS 样式:隐藏图片的样式
    const hideImageCSS = `
        img, image, picture, svg, canvas, video, iframe {
            opacity: 0 !important;
            visibility: hidden !important;
            pointer-events: none !important;
        }
        * {
            background-image: none !important;
        }
        /* 排除我们自己的 UI */
        #image-toggler-ui, #image-toggler-ui * {
            opacity: 1 !important;
            visibility: visible !important;
            pointer-events: auto !important;
            background-image: initial !important;
        }
    `;

    // CSS 样式:UI 控件的样式
    const uiCSS = `
        #image-toggler-ui {
            position: fixed;
            z-index: 2147483647; /* Max Z-Index */
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
            background-color: rgba(30, 30, 30, 0.8);
            backdrop-filter: blur(10px);
            color: #fff;
            padding: 8px;
            border-radius: 16px;
            cursor: grab;
            user-select: none;
            box-shadow: 0 4px 15px rgba(0,0,0,0.3);
            transition: transform 0.2s ease, box-shadow 0.2s ease;
            font-size: 14px;
            font-weight: 500;
            display: flex;
            align-items: center;
            gap: 8px;
            border: 1px solid rgba(255, 255, 255, 0.1);
            opacity: 0.9;
        }
        #image-toggler-ui:hover {
            opacity: 1;
            transform: translateY(2px);
            box-shadow: 0 6px 20px rgba(0,0,0,0.4);
        }
        #image-toggler-ui.dragging {
            cursor: grabbing;
            box-shadow: 0 8px 25px rgba(0,0,0,0.5);
            transform: scale(1.05);
            z-index: 2147483647;
        }
        #image-toggler-ui.hidden-mode {
            background-color: rgba(69, 105, 212, 0.9);
            border-color: rgba(69, 105, 212, 0.5);
        }
        #image-toggler-ui.visible-mode {
            background-color: rgba(69, 105, 212, 0.9);
            border-color: rgba(69, 105, 212, 0.5);
        }
        #image-toggler-icon {
            font-size: 16px;
            line-height: 1;
        }
        #image-toggler-text {
            line-height: 1;
        }
    `;

    // 初始化
    function init() {
        // 尽早应用状态(如果需要隐藏图片)
        applyState();

        // 等待 body 加载完成后创建 UI
        if (document.body) {
            setupUI();
            applyUIState();
        } else {
            document.addEventListener('DOMContentLoaded', setupUI);
            document.addEventListener('DOMContentLoaded', applyUIState);
        }

        // 注册菜单命令作为备用
        GM_registerMenuCommand("切换图片显示/隐藏", toggleImages);
        GM_registerMenuCommand("切换控件显示/隐藏", toggleUIVisibility);

        // 添加键盘快捷键 Ctrl+Shift+I
        document.addEventListener('keydown', function(e) {
            if (e.ctrlKey && e.shiftKey && e.key === 'I') {
                e.preventDefault();
                toggleImages();
            }
        });
    }

    function setupUI() {
        // 防止重复创建
        if (document.getElementById('image-toggler-ui') && document.getElementById('image-toggler-ui-top')) return;

        // 添加 UI 样式
        GM_addStyle(uiCSS);

        // 创建 UI
        createUI();
    }

    // 创建 UI 控件
    function createUI() {
        const div = document.createElement('div');
        div.id = 'image-toggler-ui';
        div.style.top = uiPosition.top + 'px';
        div.style.right = uiPosition.right + 'px';

        let isDragging = false;
        let dragOffsetX = 0;
        let dragOffsetY = 0;

        div.addEventListener('mousedown', function(e) {
            if (e.button !== 0) return;
            const rect = div.getBoundingClientRect();
            dragOffsetX = e.clientX - rect.left;
            dragOffsetY = e.clientY - rect.top;
            isDragging = true;
            div.classList.add('dragging');
            e.preventDefault();
        });

        document.addEventListener('mousemove', function(e) {
            if (!isDragging) return;
            const newLeft = e.clientX - dragOffsetX;
            const newTop = e.clientY - dragOffsetY;
            div.style.right = 'auto';
            div.style.left = newLeft + 'px';
            div.style.top = newTop + 'px';
        });

        document.addEventListener('mouseup', function(e) {
            if (!isDragging) return;
            isDragging = false;
            div.classList.remove('dragging');

            const rect = div.getBoundingClientRect();
            const finalLeft = rect.left;
            const finalTop = rect.top;

            uiPosition = { top: finalTop, right: window.innerWidth - finalLeft - rect.width };
            GM_setValue(positionKey, uiPosition);

            div.style.left = 'auto';
            div.style.right = uiPosition.right + 'px';
        });

        div.addEventListener('click', function(e) {
            if (isDragging) {
                e.preventDefault();
                e.stopPropagation();
                return;
            }
            toggleImages();
        });

        div.title = '拖动调整位置 | 点击切换图片显隐 | Ctrl+Shift+I 快捷键切换';
        document.body.appendChild(div);
        updateUI(div);

        // 创建右上角 UI
    }

    // 更新 UI 显示
    function updateUI(element) {
        const el = element || document.getElementById('image-toggler-ui');
        if (!el) return;

        // 移除旧的类
        el.classList.remove('visible-mode', 'hidden-mode');

        if (isImagesVisible) {
            el.innerHTML = '<span id="image-toggler-icon">👁️</span> <span id="image-toggler-text">显</span>';
            el.classList.add('visible-mode');
            el.title = '当前:图片显示。点击隐藏图片';
        } else {
            el.innerHTML = '<span id="image-toggler-icon">🚫</span> <span id="image-toggler-text">隐</span>';
            el.classList.add('hidden-mode');
            el.title = '当前:图片隐藏。点击显示图片';
        }
        // 不需要在这里直接设置 backgroundColor,交由 CSS 类处理
        el.style.backgroundColor = '';
    }

    // 切换状态
    function toggleImages() {
        isImagesVisible = !isImagesVisible;
        GM_setValue(storageKey, isImagesVisible);
        applyState();
        updateUI();
    }

    // 切换 UI 可见性
    function toggleUIVisibility() {
        isUIVisible = !isUIVisible;
        GM_setValue(UI_VISIBLE_KEY, isUIVisible);
        applyUIState();
    }

    // 应用 UI 可见性状态
    function applyUIState() {
        const ui = document.getElementById('image-toggler-ui');
        if (ui) {
            ui.style.display = isUIVisible ? 'flex' : 'none';
        }
    }

    // 应用状态(添加或移除 CSS)
    function applyState() {
        let styleEl = document.getElementById(STYLE_ID);

        // 确保 head 存在,通常在 document-start 时 head 也是存在的(除了极早的情况)
        // 如果 head 不存在,稍微延时重试
        if (!document.head) {
            setTimeout(applyState, 10);
            return;
        }

        if (!isImagesVisible) {
            // 如果需要隐藏图片,且样式元素不存在,则添加
            if (!styleEl) {
                styleEl = document.createElement('style');
                styleEl.id = STYLE_ID;
                styleEl.textContent = hideImageCSS;
                document.head.appendChild(styleEl);
            }
        } else {
            // 如果需要显示图片,且样式元素存在,则移除
            if (styleEl) {
                styleEl.remove();
            }
        }
    }

    // 启动
    init();

})();