Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Torn Chat Emoji+
- // @namespace http://tampermonkey.net/
- // @version 1.2
- // @description Adds a categorized emoji menu with dark mode, favorites and configurable button emoji.
- // @author HeyItzWerty [3626448]
- // @match https://www.torn.com/*
- // @grant none
- // ==/UserScript==
- (function() {
- 'use strict';
- // --- STORAGE KEYS ---
- const FAVORITES_KEY = 'torn_emoji_plus_favorites';
- const CUSTOM_KEY = 'torn_emoji_plus_custom';
- const DARK_MODE_KEY = 'torn_emoji_plus_dark_mode';
- const BUTTON_EMOJI_KEY = 'torn_emoji_plus_button_emoji';
- let favorites = JSON.parse(localStorage.getItem(FAVORITES_KEY)) || [];
- let customEmojis = JSON.parse(localStorage.getItem(CUSTOM_KEY)) || [];
- let isDarkMode = localStorage.getItem(DARK_MODE_KEY) === 'true';
- let fixedButtonEmoji = localStorage.getItem(BUTTON_EMOJI_KEY) || '๐';
- let isSelectingButtonEmoji = false;
- const emojiCategories = {
- 'โญ Favorites': favorites,
- 'โจ My Custom Emojis': customEmojis,
- '๐ Smileys & Emotion': ['๐','๐','๐','๐','๐','๐ ','๐','๐คฃ','๐ฅฒ','๐ฅน','๐','๐','๐','๐','๐','๐','๐ฅฐ','๐','๐','๐','๐','๐คช','๐คจ','๐ง','๐ค','๐','๐ฅธ','๐คฉ','๐ฅณ','๐','๐','๐','๐','๐','๐','๐','โน๏ธ','๐ฃ','๐','๐ซ','๐ฉ','๐ฅบ','๐ข','๐ญ','๐ค','๐ ','๐ก','๐คฌ','๐คฏ','๐ณ','๐ฅต','๐ฅถ','๐ฑ','๐จ','๐ฐ','๐ฅ','๐','๐ซฃ','๐ค','๐ซก','๐ค','๐ซข','๐คญ','๐คซ','๐คฅ','๐ถ','๐ถโ๐ซ๏ธ','๐','๐','๐ฌ','๐','๐ฏ','๐ฆ','๐ง','๐ฎ','๐ฒ','๐ฅฑ','๐ด','๐คค','๐ช','๐ต','๐ตโ๐ซ','๐ซฅ','๐ค','๐ฅด','๐คข','๐คฎ','๐คง','๐ท','๐ค','๐ค','๐ค','๐ค ','๐คก','๐ฉ','๐ป','๐','๐บ','๐ธ','๐น','๐ป','๐ผ','๐ฝ','๐','๐ฟ','๐พ'],
- '๐ People & Body': ['๐','๐ค','๐๏ธ','โ','๐','๐','๐ค','๐ค','โ๏ธ','๐ค','๐ซฐ','๐ค','๐ค','๐ค','๐','๐','๐','๐','๐','โ๏ธ','๐','๐','โ','๐','๐ค','๐ค','๐','๐','๐','๐คฒ','๐ค','๐','โ๏ธ','๐ ','๐คณ','๐ช','๐ฆพ','๐ฆฟ','๐ฆต','๐ฆถ','๐','๐ฆป','๐','๐ง ','๐ซ','๐ซ','๐ฆท','๐ฆด','๐','๐๏ธ','๐ ','๐','๐ซฆ','๐ถ','๐ง','๐ง','๐ฆ','๐ฉ','๐ง','๐จ','๐ต','๐ง','๐ด','๐ฎโโ๏ธ','๐ฎ','๐ทโโ๏ธ','๐ท','๐ต๏ธโโ๏ธ','๐ต๏ธ','๐ฉโโ๏ธ','๐งโโ๏ธ','๐จโโ๏ธ','๐ฉโ๐','๐งโ๐','๐จโ๐','๐ฉโ๐ซ','๐งโ๐ซ','๐จโ๐ซ','๐ฉโโ๏ธ','๐งโโ๏ธ','๐จโโ๏ธ','๐ฉโ๐พ','๐งโ๐พ','๐จโ๐พ','๐ฉโ๐ณ','๐งโ๐ณ','๐จโ๐ณ','๐ฉโ๐ง','๐งโ๐ง','๐จโ๐ง','๐ฉโ๐ป','๐งโ๐ป','๐จโ๐ป','๐ฉโ๐ค','๐งโ๐ค','๐จโ๐ค','๐ฉโ๐จ','๐งโ๐จ','๐จโ๐จ','๐ฉโ๐','๐งโ๐','๐จโ๐','๐ธ','๐คด','๐ฆธโโ๏ธ','๐ฆธ','๐ฆนโโ๏ธ','๐ฆน','๐ ','๐คถ','๐งโโ๏ธ','๐ง','๐งโโ๏ธ','๐ง','๐งโโ๏ธ','๐ง','๐งโโ๏ธ','๐ง','๐งโโ๏ธ','๐ง','๐งโโ๏ธ','๐ง','๐งโโ๏ธ','๐ง','๐ผ','๐คฐ','๐คฑ','๐โโ๏ธ','๐','๐โโ๏ธ','๐','๐ โโ๏ธ','๐ ','๐โโ๏ธ','๐','๐โโ๏ธ','๐','๐คฆโโ๏ธ','๐คฆ','๐คทโโ๏ธ','๐คท','๐โโ๏ธ','๐','๐โโ๏ธ','๐','๐โโ๏ธ','๐','๐โโ๏ธ','๐','๐','๐บ','๐โโ๏ธ','๐','๐ถโโ๏ธ','๐ถ','๐ซ','๐ฃ๏ธ','๐ค','๐ฅ'],
- '๐ป Animals': ['๐ต','๐','๐ฆ','๐ฆง','๐ถ','๐','๐ฆฎ','๐โ๐ฆบ','๐ฉ','๐บ','๐ฆ','๐ฆ','๐ฑ','๐','๐โโฌ','๐ฆ','๐ฏ','๐ ','๐','๐ด','๐','๐ฆ','๐ฆ','๐ฆ','๐ฆฌ','๐ฎ','๐','๐','๐','๐ท','๐','๐','๐ฝ','๐','๐','๐','๐ช','๐ซ','๐ฆ','๐ฆ','๐','๐ฆฃ','๐ฆ','๐ฆ','๐ญ','๐','๐','๐น','๐ฐ','๐','๐ฟ๏ธ','๐ฆซ','๐ฆ','๐ฆ','๐ป','๐ปโโ๏ธ','๐จ','๐ผ','๐ฆฅ','๐ฆฆ','๐ฆจ','๐ฆ','๐ฆก','๐พ','๐ฆ','๐','๐','๐ฃ','๐ค','๐ฅ','๐ฆ','๐ง','๐๏ธ','๐ฆ ','๐ฆ','๐ฆข','๐ฆ','๐ฆค','๐ชถ','๐ธ','๐','๐ข','๐ฆ','๐','๐ฒ','๐','๐ณ','๐','๐ฌ','๐ฆญ','๐','๐ ','๐ก','๐ฆ','๐','๐','๐','๐ฆ','๐','๐','๐','๐ชฒ','๐','๐ฆ','๐ชณ','๐ท๏ธ','๐ธ๏ธ','๐ฆ','๐ฆ','๐ชฐ','๐ชฑ'],
- '๐ณ Nature': ['๐','๐ธ','๐ฎ','๐ต๏ธ','๐น','๐ฅ','๐บ','๐ป','๐ผ','๐ท','๐ฑ','๐ชด','๐ฒ','๐ณ','๐ด','๐ชต','๐ต','๐พ','๐ฟ','โ๏ธ','๐','๐','๐','๐','๐','๐','๐','๐','๐','๐','๐','๐','๐','๐','๐','๐','โญ','๐','๐ซ','โจ','โ๏ธ','โ๏ธ','๐ค๏ธ','โ ','๐ฅ๏ธ','๐ฆ๏ธ','โ๏ธ','๐ง๏ธ','โ๏ธ','๐ฉ๏ธ','โก','๐ฅ','๐ฅ','โ๏ธ','๐จ๏ธ','โ๏ธ','โ','๐ฌ๏ธ','๐จ','๐ช๏ธ','๐ซ๏ธ','๐','๐ง','๐ฆ'],
- '๐ Food & Drink': ['๐','๐','๐','๐','๐','๐','๐','๐ฅญ','๐','๐','๐','๐','๐','๐','๐ซ','๐ฅ','๐ ','๐ซ','๐ฅฅ','๐ฅ','๐','๐ฅ','๐ฅ','๐ฝ','๐ถ๏ธ','๐ซ','๐ฅ','๐ฅฌ','๐ฅฆ','๐ง','๐ง ','๐','๐ฅ','๐ซ','๐ฐ','๐','๐ฅ','๐ฅ','๐ซ','๐ฅจ','๐ฅฏ','๐ฅ','๐ง','๐ง','๐','๐','๐ฅฉ','๐ฅ','๐','๐','๐','๐ญ','๐ฅช','๐ฅ','๐ง','๐ฎ','๐ฏ','๐ซ','๐ฅ','๐ฅ','๐ซ','๐ฅซ','๐','๐','๐ฒ','๐','๐ฃ','๐ฑ','๐ฅ','๐ฆช','๐ค','๐','๐','๐','๐ฅ','๐ฅ ','๐ฅฎ','๐ข','๐ก','๐ง','๐จ','๐ฆ','๐ฅง','๐ง','๐ฐ','๐','๐ฎ','๐ญ','๐ฌ','๐ซ','๐ฟ','๐ฉ','๐ช','๐ฏ','๐ฅ','๐ผ','โ๏ธ','๐ซ','๐ต','๐ถ','๐พ','๐ท','๐ธ','๐น','๐บ','๐ป','๐ฅ','๐ฅ','๐ซ','๐ฅค','๐ง','๐ง','๐ง','๐ง','๐ฅข','๐ฝ๏ธ','๐ด','๐ฅ','๐บ'],
- 'โฝ Activities & Events': ['โฝ','๐','๐','โพ','๐ฅ','๐พ','๐','๐','๐ฅ','๐ฑ','๐ช','๐','๐ธ','๐','๐','๐ฅ','๐','๐ช','๐ฅ ','โณ','๐ช','๐น','๐ฃ','๐คฟ','๐ฅ','๐ฅ','๐ฝ','๐น','๐ผ','๐ท','โธ๏ธ','๐ฅ','๐ฟ','โท๏ธ','๐','๐ช','๐๏ธโโ๏ธ','๐๏ธ','๐๏ธโโ๏ธ','๐คผโโ๏ธ','๐คผ','๐คผโโ๏ธ','๐คธโโ๏ธ','๐คธ','๐คธโโ๏ธ','โน๏ธโโ๏ธ','โน๏ธ','โน๏ธโโ๏ธ','๐คบ','๐คพโโ๏ธ','๐คพ','๐คพโโ๏ธ','๐๏ธโโ๏ธ','๐๏ธ','๐๏ธโโ๏ธ','๐','๐งโโ๏ธ','๐ง','๐งโโ๏ธ','๐โโ๏ธ','๐','๐โโ๏ธ','๐โโ๏ธ','๐','๐โโ๏ธ','๐คฝโโ๏ธ','๐คฝ','๐คฝโโ๏ธ','๐ฃโโ๏ธ','๐ฃ','๐ฃโโ๏ธ','๐งโโ๏ธ','๐ง','๐งโโ๏ธ','๐ตโโ๏ธ','๐ต','๐ตโโ๏ธ','๐ดโโ๏ธ','๐ด','๐ดโโ๏ธ','๐','๐ฅ','๐ฅ','๐ฅ','๐ ','๐๏ธ','๐ต๏ธ','๐๏ธ','๐ซ','๐๏ธ','๐ช','๐คน','๐คนโโ๏ธ','๐คนโโ๏ธ','๐ญ','๐ฉฐ','๐จ','๐ฌ','๐ค','๐ง','๐ผ','๐น','๐ฅ','๐ช','๐ท','๐บ','๐ช','๐ธ','๐ช','๐ป','๐ช','๐ฒ','โ๏ธ','๐ฏ','๐ณ','๐ฎ','๐ฐ','๐งฉ','๐','๐','๐','๐','๐','๐','๐'],
- '๐ก Objects': ['โ','๐ฑ','๐ฒ','๐ป','โจ๏ธ','๐ฅ๏ธ','๐จ๏ธ','๐ฑ๏ธ','๐ฒ๏ธ','๐น๏ธ','๐ฝ','๐พ','๐ฟ','๐','๐ผ','๐ท','๐ธ','๐น','๐ฅ','๐','โ๏ธ','๐','๐ ','๐บ','๐ป','๐๏ธ','๐ก','๐ฆ','๐ฏ๏ธ','๐ฐ','๐ต','๐ด','๐ถ','๐ท','๐ช','๐ณ','๐','โ๏ธ','๐ง','๐จ','โ๏ธ','๐ ๏ธ','โ๏ธ','๐ฉ','โ๏ธ','๐งฑ','โ๏ธ','๐งฒ','โฐ๏ธ','๐ชฆ','โฑ๏ธ','๐ฎ','๐ฟ','๐งฟ','๐','๐ญ','๐ฌ','๐ณ๏ธ','๐ฉน','๐ฉบ','๐งฌ','๐ฆ ','๐งช','๐ก๏ธ','๐งน','๐งบ','๐ฝ','๐ฐ','๐ฟ','๐','๐งผ','๐ชฅ','๐งฝ','๐งฏ','๐','๐๏ธ','๐ช','๐๏ธ','๐๏ธ','๐งธ','๐ผ๏ธ','๐๏ธ','๐','โ๏ธ','๐งง','๐ซ','๐ฎ','๐ฆ','๐ท๏ธ','๐','๐','๐','๐','๐','๐','๐','๐๏ธ','๐๏ธ','๐๏ธ','๐','๐','โ๏ธ','๐๏ธ','โ๏ธ','๐๏ธ','๐๏ธ','๐','โ๏ธ','๐','๐','๐','๐','๐','๐'],
- '๐ Torn-Themed': ['๐ซ','๐ฃ','๐งจ','๐ช','๐ช','๐ก๏ธ','โ๏ธ','๐ก๏ธ','๐ฌ','๐','๐','๐ฉธ','โค๏ธโ๐ฅ','โค๏ธโ๐ฉน','๐','๐ฏ','๐ข','๐ฆ','๐','๐','๐','๐ฟ','๐น','๐บ','๐ฅ','๐ฅ','๐จ','๐ธ','โ๏ธ','๐'],
- 'โค๏ธโ Symbols & Flags': ['๐','โ๏ธ','โข๏ธ','โฃ๏ธ','๐ด','๐','๐','ใ๏ธ','ใ๏ธ','๐','๐','โ','๐ซ','โ','โญ','๐','๐','โจ๏ธ','โ๏ธ','โ','โ','โ','โผ๏ธ','โ๏ธ','โ ','โ๏ธ','โ๏ธ','โ','โ๏ธ','โช๏ธ','๐๏ธ','โก๏ธ','โฏ๏ธ','โฎ๏ธ','โฆ๏ธ','โ ๏ธ','๐ธ','โป๏ธ','โ๏ธ','๐ฑ','๐ฐ','๐ง','โฟ','๐ ฟ๏ธ','๐พ','๐ถ','๐','๐๏ธ','๐','๐ฏ','๐','๐น','๐บ','๐ถ','๐ท๏ธ','๐ธ','๐ฒ','๐ต','๐ด','๐','๐ ฑ๏ธ','๐ ฐ๏ธ','๐ พ๏ธ','๐','๐','๐','๐','๐','๐','๐','โ๏ธ','โ๏ธ','โ๏ธ','โ๏ธ','โ๏ธ','โ๏ธ','โฉ๏ธ','โช๏ธ','โคด๏ธ','โคต๏ธ','โก๏ธ','โฌ ๏ธ','โฌ๏ธ','โฌ๏ธ','โ','โ','โ','โ๏ธ','โพ๏ธ','๐ฒ','๐ฑ','โข๏ธ','ยฉ๏ธ','ยฎ๏ธ','๐','๐','๐','๐','๐','๐ด','๐ ','๐ก','๐ข','๐ต','๐ฃ','๐ค','โซ','โช','๐ฅ','๐ง','๐จ','๐ฉ','๐ฆ','๐ช','๐ซ','โฌ','โฌ','๐','๐ฉ','๐','๐ด','๐ณ๏ธ','๐ณ๏ธโ๐','๐ณ๏ธโโง๏ธ','๐ดโโ ๏ธ']
- };
- const themes = {
- light: { bg: '#f2f2f2', text: '#000', border: '#ccc', catBg: '#e9e9e9' },
- dark: { bg: '#2c2c2c', text: '#f1f1f1', border: '#555', catBg: '#222' }
- };
- const nativeTextareaValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value").set;
- function simulateUserInput(textarea, text) {
- const start = textarea.selectionStart;
- const end = textarea.selectionEnd;
- const newText = textarea.value.substring(0, start) + text + textarea.value.substring(end);
- nativeTextareaValueSetter.call(textarea, newText);
- textarea.dispatchEvent(new Event('input', { bubbles: true }));
- textarea.selectionStart = textarea.selectionEnd = start + text.length;
- textarea.focus();
- }
- function save(key, data) {
- localStorage.setItem(key, JSON.stringify(data));
- }
- function showNotification(message) {
- const notif = document.createElement('div');
- notif.textContent = message;
- Object.assign(notif.style, {
- position: 'fixed', top: '20px', right: '20px',
- background: 'rgba(0,0,0,0.7)', color: 'white',
- padding: '10px 20px', borderRadius: '5px', zIndex: 9999
- });
- document.body.appendChild(notif);
- setTimeout(() => notif.remove(), 1500);
- }
- function addEmojiButtonTo(chatContainer) {
- if (chatContainer.querySelector('.custom-emoji-button-v3')) return;
- const emojiButton = document.createElement('button');
- emojiButton.className = 'custom-emoji-button-v3';
- emojiButton.textContent = fixedButtonEmoji;
- Object.assign(emojiButton.style, {
- background: 'transparent',
- border: 'none',
- fontSize: '22px',
- cursor: 'pointer',
- height: '32px',
- width: '32px',
- marginRight: '5px'
- });
- const picker = document.createElement('div');
- Object.assign(picker.style, {
- position: 'absolute', display: 'none',
- bottom: '40px', left: '0',
- width: '300px', height: '320px',
- borderRadius: '8px', zIndex: 1001,
- boxShadow: '0 5px 15px rgba(0,0,0,0.3)',
- display: 'flex', flexDirection: 'column'
- });
- const categoryContainer = document.createElement('div');
- Object.assign(categoryContainer.style, {
- display: 'flex', flexWrap: 'wrap',
- padding: '5px', alignItems: 'center'
- });
- const emojiDisplay = document.createElement('div');
- Object.assign(emojiDisplay.style, {
- padding: '5px', flexGrow: '1', overflowY: 'auto'
- });
- picker.append(categoryContainer, emojiDisplay);
- function applyTheme() {
- const theme = isDarkMode ? themes.dark : themes.light;
- Object.assign(picker.style, {
- background: theme.bg,
- border: `1px solid ${theme.border}`,
- color: theme.text
- });
- categoryContainer.style.background = theme.catBg;
- }
- function renderEmojis(list) {
- emojiDisplay.innerHTML = '';
- const grid = document.createElement('div');
- Object.assign(grid.style, { display: 'flex', flexWrap: 'wrap' });
- list.forEach(emoji => {
- const span = document.createElement('span');
- span.textContent = emoji;
- Object.assign(span.style, {
- cursor: 'pointer', padding: '4px', fontSize: '22px'
- });
- span.addEventListener('click', () => {
- if (isSelectingButtonEmoji) {
- fixedButtonEmoji = emoji;
- localStorage.setItem(BUTTON_EMOJI_KEY, emoji);
- emojiButton.textContent = emoji;
- isSelectingButtonEmoji = false;
- showNotification(`Button emoji set to ${emoji}`);
- return;
- }
- simulateUserInput(chatContainer.querySelector('textarea.textarea___V8HsV'), emoji);
- picker.style.display = 'none';
- });
- grid.appendChild(span);
- });
- emojiDisplay.appendChild(grid);
- }
- Object.keys(emojiCategories).forEach(name => {
- const tab = document.createElement('button');
- tab.textContent = name.split(' ')[0];
- Object.assign(tab.style, {
- background: 'none', border: 'none',
- cursor: 'pointer', fontSize: '20px', padding: '5px'
- });
- tab.addEventListener('click', () => renderEmojis(emojiCategories[name]));
- categoryContainer.appendChild(tab);
- });
- const themeToggle = document.createElement('button');
- themeToggle.textContent = '๐';
- Object.assign(themeToggle.style, {
- border: '1px solid', borderRadius: '5px',
- cursor: 'pointer', fontSize: '16px',
- width: '30px', height: '30px', marginLeft: 'auto'
- });
- themeToggle.addEventListener('click', () => {
- isDarkMode = !isDarkMode;
- localStorage.setItem(DARK_MODE_KEY, isDarkMode);
- applyTheme();
- });
- const settingsBtn = document.createElement('button');
- settingsBtn.textContent = 'โ๏ธ';
- settingsBtn.title = 'Set button emoji';
- Object.assign(settingsBtn.style, {
- border: '1px solid', borderRadius: '5px',
- cursor: 'pointer', fontSize: '16px',
- width: '30px', height: '30px', marginLeft: '5px'
- });
- settingsBtn.addEventListener('click', () => {
- isSelectingButtonEmoji = true;
- showNotification('Click an emoji to set as button icon');
- });
- categoryContainer.append(themeToggle, settingsBtn);
- emojiButton.addEventListener('click', (e) => {
- e.stopPropagation();
- picker.style.display = picker.style.display === 'none' ? 'flex' : 'none';
- applyTheme();
- renderEmojis(emojiCategories['๐ Smileys & Emotion']);
- });
- chatContainer.insertBefore(emojiButton, chatContainer.querySelector('.iconWrapper___tyRRU'));
- chatContainer.appendChild(picker);
- }
- document.addEventListener('click', (e) => {
- if (!e.target.closest('.custom-emoji-picker') && !e.target.closest('.custom-emoji-button-v3')) {
- document.querySelectorAll('.custom-emoji-picker').forEach(p => p.style.display = 'none');
- }
- });
- const observer = new MutationObserver(() => {
- document.querySelectorAll('.root___WUd1h').forEach(container => addEmojiButtonTo(container));
- });
- observer.observe(document.body, { childList: true, subtree: true });
- })();
Advertisement
Add Comment
Please, Sign In to add comment