Greasy Fork

Greasy Fork is available in English.

剪贴板历史记录助手

在页面右侧显示剪贴板历史记录

当前为 2024-12-05 提交的版本,查看 最新版本

// ==UserScript==
// @name         剪贴板历史记录助手
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  在页面右侧显示剪贴板历史记录
// @author       Your name
// @match        *://*/*
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_setClipboard
// @run-at       document-end
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    if (window.hasRunClipboardHelper) return;
    window.hasRunClipboardHelper = true;

    GM_addStyle(`
        #clipboard-panel {
            position: fixed !important;
            right: 0 !important;
            top: 20% !important;
            width: 250px !important;
            max-height: 60vh !important;
            background: #fff !important;
            border: 1px solid #ccc !important;
            border-radius: 4px 0 0 4px !important;
            padding: 10px !important;
            box-shadow: -2px 2px 10px rgba(0,0,0,0.1) !important;
            z-index: 2147483647 !important;
            overflow-y: auto !important;
            font-family: system-ui, -apple-system, sans-serif !important;
            box-sizing: border-box !important;
            transition: all 0.3s ease !important;
        }

        #clipboard-panel.hidden {
            transform: translateX(235px) !important;
        }

        #clipboard-panel.hidden:hover {
            transform: translateX(230px) !important;
        }

        #clipboard-panel::before {
            content: "📋" !important;
            position: absolute !important;
            left: 10px !important;
            top: 50% !important;
            transform: translateY(-50%) !important;
            font-size: 20px !important;
            opacity: 0 !important;
            transition: opacity 0.3s ease !important;
            cursor: pointer !important;
        }

        #clipboard-panel.hidden::before {
            opacity: 1 !important;
        }

        #clipboard-panel.hidden .clipboard-controls,
        #clipboard-panel.hidden #clipboard-list {
            visibility: hidden !important;
        }

        .clipboard-controls {
            display: flex !important;
            justify-content: flex-end !important;
            gap: 8px !important;
            margin-bottom: 10px !important;
            transition: opacity 0.3s ease !important;
        }

        .clipboard-btn {
            padding: 4px 8px !important;
            border: 1px solid #ddd !important;
            border-radius: 3px !important;
            background: #f5f5f5 !important;
            cursor: pointer !important;
            font-size: 12px !important;
        }

        .clipboard-item {
            padding: 8px !important;
            border: 1px solid #eee !important;
            margin-bottom: 5px !important;
            cursor: pointer !important;
            border-radius: 4px !important;
            font-size: 14px !important;
            line-height: 1.4 !important;
            background: #fff !important;
            white-space: nowrap !important;
            overflow: hidden !important;
            text-overflow: ellipsis !important;
        }

        .clipboard-item:hover {
            background: #f5f5f5 !important;
            white-space: normal !important;
            word-break: break-all !important;
        }

        .clipboard-item.pinned {
            border-left: 3px solid #4CAF50 !important;
            background: #f8fff8 !important;
        }
    `);

    // 创建面板
    const panel = document.createElement('div');
    panel.id = 'clipboard-panel';
    panel.innerHTML = `
        <div class="clipboard-controls">
            <button class="clipboard-btn" id="clear-history">清空</button>
            <button class="clipboard-btn" id="hide-panel"></button>
        </div>
        <div id="clipboard-list"></div>
    `;
    document.body.appendChild(panel);

    // 初始化数据
    let clipboardHistory = GM_getValue('clipboardHistory', []);
    let pinnedItems = GM_getValue('pinnedItems', []);
    const maxHistoryItems = 10;

    // 更新面板显示
    function updatePanel() {
        const listElement = document.getElementById('clipboard-list');
        const allItems = [
            ...pinnedItems.map(text => ({ text, pinned: true })),
            ...clipboardHistory
                .filter(text => !pinnedItems.includes(text))
                .map(text => ({ text, pinned: false }))
        ];

        listElement.innerHTML = allItems
            .map((item, index) => `
                <div class="clipboard-item ${item.pinned ? 'pinned' : ''}"
                     data-index="${index}"
                     title="${item.text}">
                    ${item.pinned ? '📌 ' : ''}${item.text}
                </div>
            `)
            .join('');

        // 根据是否有记录来设置点击外部自动隐藏
        if (allItems.length === 0) {
            // 无记录时添加点击外部自动隐藏
            if (!window.clipboardAutoHideHandler) {
                window.clipboardAutoHideHandler = (e) => {
                    if (!panel.contains(e.target) && !panel.classList.contains('hidden')) {
                        panel.classList.add('hidden');
                    }
                };
                document.addEventListener('click', window.clipboardAutoHideHandler);
            }
        } else {
            // 有记录时移除点击外部自动隐藏
            if (window.clipboardAutoHideHandler) {
                document.removeEventListener('click', window.clipboardAutoHideHandler);
                window.clipboardAutoHideHandler = null;
            }
        }

        // 添加事件监听
        document.querySelectorAll('.clipboard-item').forEach(item => {
            item.addEventListener('click', () => {
                const text = allItems[item.dataset.index].text;
                GM_setClipboard(text, 'text');
                item.style.backgroundColor = '#e6ffe6';
                setTimeout(() => {
                    item.style.backgroundColor = '';
                }, 500);
            });

            item.addEventListener('contextmenu', (e) => {
                e.preventDefault();
                const text = allItems[item.dataset.index].text;
                const isPinned = pinnedItems.includes(text);
                if (isPinned) {
                    pinnedItems = pinnedItems.filter(t => t !== text);
                } else {
                    pinnedItems.unshift(text);
                }
                GM_setValue('pinnedItems', pinnedItems);
                updatePanel();
            });
        });
    }

    // 事件监听
    document.getElementById('hide-panel').addEventListener('click', () => {
        panel.classList.add('hidden');
    });

    panel.addEventListener('click', (e) => {
        if (panel.classList.contains('hidden')) {
            e.stopPropagation();
            panel.classList.remove('hidden');
        }
    });

    document.getElementById('clear-history').addEventListener('click', () => {
        clipboardHistory = [];
        pinnedItems = [];
        GM_setValue('clipboardHistory', clipboardHistory);
        GM_setValue('pinnedItems', pinnedItems);
        updatePanel();
    });

    // 监听复制事件
    document.addEventListener('copy', () => {
        setTimeout(() => {
            const selection = window.getSelection().toString().trim();
            if (selection && !clipboardHistory.includes(selection)) {
                clipboardHistory.unshift(selection);
                if (clipboardHistory.length > maxHistoryItems) {
                    clipboardHistory.pop();
                }
                GM_setValue('clipboardHistory', clipboardHistory);
                updatePanel();
            }
        }, 100);
    });

    // 初始化显示
    updatePanel();
})();