Reddit Multi Emote Picker (WORKING)

Adds a popup emote picker with multiple emotes to Reddit comment box on right-click, inserts emote text like [emote:t5_33td5:59888](http://img)

当前为 2025-06-05 提交的版本,查看 最新版本

// ==UserScript==
// @name         Reddit Multi Emote Picker (WORKING)
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  Adds a popup emote picker with multiple emotes to Reddit comment box on right-click, inserts emote text like [emote:t5_33td5:59888](http://img)
// @author       You
// @match        https://www.reddit.com/r/*/comments/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    const baseEmoteId = 59888; // starting emote number for Clueless

    const emoteNames = [
        'Clueless',
        'Okayeg',
        'cmonBruh',
        'Copesen',
        'forsenCD',
        'forsenE',
        'tf',
        'FeelsOkayMan',
        'gachiGASM',
        'monkaOMEGA',
        'LULE',
        'OMEGALUL',
        'PagMan',
        'forsenBased',
        'Sadeg',
        'forsenAlright',
        'forsenLevel',
        'pepeLaugh',
        'forsenDespair',
        'sadE',
        'forsenMaxLevel',
        'maoE',
        'Wutface',
        'MegaLUL',
        'Docsen',
        'amongE',
        'Batchest',
        'forsenNugget',
        'LongHairMaxLevel',
        'Pewds',
        'monkaLaugh'
    ];

    const emoteBaseUrl = 'https://rarestemotes.github.io/emotes/images/';

    // Build EMOTES array with name, image src, and emote code string
    const EMOTES = emoteNames.map((name, index) => {
        // Image URL: base + name + ".png"
        const src = `${emoteBaseUrl}${name}.png`;

        // Emote code: using the ID starting at 59888 and incrementing
        const code = `[emote:t5_33td5:${baseEmoteId + index}](http://img)`;

        return { name, src, code };
    });

    let currentTarget = null;

    const picker = document.createElement('div');
    picker.id = 'customEmotePicker';
    picker.style.position = 'absolute';
    picker.style.background = '#1a1a1b';
    picker.style.border = '1px solid #555';
    picker.style.padding = '10px';
    picker.style.zIndex = 9999;
    picker.style.borderRadius = '8px';
    picker.style.boxShadow = '0 4px 12px rgba(0,0,0,0.6)';
    picker.style.display = 'none';
    picker.style.width = '220px';
    picker.style.display = 'grid';
    picker.style.gridTemplateColumns = 'repeat(5, 1fr)';
    picker.style.gap = '8px';
    picker.style.textAlign = 'center';

    EMOTES.forEach(({ name, src, code }) => {
        const emote = document.createElement('img');
        emote.src = src;
        emote.alt = name;
        emote.title = name;
        emote.style.width = '32px';
        emote.style.height = '32px';
        emote.style.cursor = 'pointer';
        emote.style.userSelect = 'none';
        emote.addEventListener('click', () => {
            if (currentTarget) {
                currentTarget.focus();

                const selection = window.getSelection();
                if (selection.rangeCount === 0) return;

                const range = selection.getRangeAt(0);
                range.deleteContents();

                const textNode = document.createTextNode(code);
                range.insertNode(textNode);

                range.setStartAfter(textNode);
                range.collapse(true);
                selection.removeAllRanges();
                selection.addRange(range);

                currentTarget.dispatchEvent(new InputEvent('input', {
                    bubbles: true,
                    cancelable: true,
                    inputType: 'insertText',
                    data: code
                }));
            }

            picker.style.display = 'none';
            currentTarget = null;
        });
        picker.appendChild(emote);
    });

    document.body.appendChild(picker);

    // Show picker on right-click inside comment box
    document.addEventListener('contextmenu', (e) => {
        const editable = e.target.closest('div[contenteditable="true"][role="textbox"]');
        if (editable) {
            e.preventDefault();
            currentTarget = editable;

            picker.style.left = `${e.pageX}px`;
            picker.style.top = `${e.pageY}px`;
            picker.style.display = 'grid';
        } else {
            picker.style.display = 'none';
            currentTarget = null;
        }
    });

    // Hide on click elsewhere
    document.addEventListener('click', () => {
        picker.style.display = 'none';
        currentTarget = null;
    });
})();