Greasy Fork is available in English.
Дискорд эмоджики в тунио, теперь лучше
// ==UserScript==// @name Discord Emojis for Toonio// @namespace DiscordEmojisConverter// @version 1.1.03// @description Дискорд эмоджики в тунио, теперь лучше// @author Vika4ernaya// @match https://toonio.ru/*// @match https://*.toonio.ru/*// @icon https://www.google.com/s2/favicons?sz=64&domain=toonio.ru// @grant none// @license MIT// ==/UserScript==// Добавляем функцию для установки пакаfunction installPack() {const hash = window.location.hash.slice(1);if (!hash) return;try {const packData = JSON.parse(atob(hash));const { pack, emojis } = packData;// Получаем текущие паки и эмодзиconst currentPacks = storage.get('demoji_packs');const currentEmojis = storage.get('demoji_emojis');// Проверяем, существует ли уже пак с таким IDconst existingPack = currentPacks.find(p => p.id === pack.id);if (existingPack) {if (!confirm(`Пак "${pack.name}" уже существует. Хотите обновить его?`)) {return;}// Удаляем старые эмодзи пакаconst newEmojis = currentEmojis.filter(e => e.packId !== pack.id);storage.set('demoji_emojis', [...newEmojis, ...emojis]);// Обновляем информацию о пакеconst newPacks = currentPacks.map(p => p.id === pack.id ? pack : p);storage.set('demoji_packs', newPacks);} else {// Добавляем новый пак и его эмодзиstorage.set('demoji_packs', [...currentPacks, pack]);storage.set('demoji_emojis', [...currentEmojis, ...emojis]);}alert(`Пак "${pack.name}" успешно ${existingPack ? 'обновлен' : 'установлен'}!`);// Очищаем хэш из URLwindow.location.hash = '';// Обновляем менюupdateDemojiMenu();} catch (error) {console.error('Ошибка установки пака:', error);alert('Ошибка при установке пака. Неверный формат данных.');}}// Добавляем проверку URL при загрузке страницыdocument.addEventListener('DOMContentLoaded', () => {if (window.location.hash.startsWith('#')) {installPack();}});const storage = {get: (key) => JSON.parse(localStorage.getItem(key) || '[]'),set: (key, value) => localStorage.setItem(key, JSON.stringify(value)),};// Создание UI для эмодзиfunction createDemojiUI() {const formatContainer = document.querySelector(".send .format");const editorFormatCont = document.querySelector("#save .format");if (!formatContainer && !editorFormatCont) return;// Создаем кнопкуconst demojiButton = document.createElement("a");demojiButton.id = "discordDemojiBtn";demojiButton.title = "Discord эмодзи";demojiButton.style.width = "24px";demojiButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" style="fill: white;"><path d="M 18.90625 7 C 18.90625 7 12.539063 7.4375 8.375 10.78125 C 8.355469 10.789063 8.332031 10.800781 8.3125 10.8125 C 7.589844 11.480469 7.046875 12.515625 6.375 14 C 5.703125 15.484375 4.992188 17.394531 4.34375 19.53125 C 3.050781 23.808594 2 29.058594 2 34 C 1.996094 34.175781 2.039063 34.347656 2.125 34.5 C 3.585938 37.066406 6.273438 38.617188 8.78125 39.59375 C 11.289063 40.570313 13.605469 40.960938 14.78125 41 C 15.113281 41.011719 15.429688 40.859375 15.625 40.59375 L 18.0625 37.21875 C 20.027344 37.683594 22.332031 38 25 38 C 27.667969 38 29.972656 37.683594 31.9375 37.21875 L 34.375 40.59375 C 34.570313 40.859375 34.886719 41.011719 35.21875 41 C 36.394531 40.960938 38.710938 40.570313 41.21875 39.59375 C 43.726563 38.617188 46.414063 37.066406 47.875 34.5 C 47.960938 34.347656 48.003906 34.175781 48 34 C 48 29.058594 46.949219 23.808594 45.65625 19.53125 C 45.007813 17.394531 44.296875 15.484375 43.625 14 C 42.953125 12.515625 42.410156 11.480469 41.6875 10.8125 C 41.667969 10.800781 41.644531 10.789063 41.625 10.78125 C 37.460938 7.4375 31.09375 7 31.09375 7 C 31.019531 6.992188 30.949219 6.992188 30.875 7 C 30.527344 7.046875 30.234375 7.273438 30.09375 7.59375 C 30.09375 7.59375 29.753906 8.339844 29.53125 9.40625 C 27.582031 9.09375 25.941406 9 25 9 C 24.058594 9 22.417969 9.09375 20.46875 9.40625 C 20.246094 8.339844 19.90625 7.59375 19.90625 7.59375 C 19.734375 7.203125 19.332031 6.964844 18.90625 7 Z M 18.28125 9.15625 C 18.355469 9.359375 18.40625 9.550781 18.46875 9.78125 C 16.214844 10.304688 13.746094 11.160156 11.4375 12.59375 C 11.074219 12.746094 10.835938 13.097656 10.824219 13.492188 C 10.816406 13.882813 11.039063 14.246094 11.390625 14.417969 C 11.746094 14.585938 12.167969 14.535156 12.46875 14.28125 C 17.101563 11.410156 22.996094 11 25 11 C 27.003906 11 32.898438 11.410156 37.53125 14.28125 C 37.832031 14.535156 38.253906 14.585938 38.609375 14.417969 C 38.960938 14.246094 39.183594 13.882813 39.175781 13.492188 C 39.164063 13.097656 38.925781 12.746094 38.5625 12.59375 C 36.253906 11.160156 33.785156 10.304688 31.53125 9.78125 C 31.59375 9.550781 31.644531 9.359375 31.71875 9.15625 C 32.859375 9.296875 37.292969 9.894531 40.3125 12.28125 C 40.507813 12.460938 41.1875 13.460938 41.8125 14.84375 C 42.4375 16.226563 43.09375 18.027344 43.71875 20.09375 C 44.9375 24.125 45.921875 29.097656 45.96875 33.65625 C 44.832031 35.496094 42.699219 36.863281 40.5 37.71875 C 38.5 38.496094 36.632813 38.84375 35.65625 38.9375 L 33.96875 36.65625 C 34.828125 36.378906 35.601563 36.078125 36.28125 35.78125 C 38.804688 34.671875 40.15625 33.5 40.15625 33.5 C 40.570313 33.128906 40.605469 32.492188 40.234375 32.078125 C 39.863281 31.664063 39.226563 31.628906 38.8125 32 C 38.8125 32 37.765625 32.957031 35.46875 33.96875 C 34.625 34.339844 33.601563 34.707031 32.4375 35.03125 C 32.167969 35 31.898438 35.078125 31.6875 35.25 C 29.824219 35.703125 27.609375 36 25 36 C 22.371094 36 20.152344 35.675781 18.28125 35.21875 C 18.070313 35.078125 17.8125 35.019531 17.5625 35.0625 C 16.394531 34.738281 15.378906 34.339844 14.53125 33.96875 C 12.234375 32.957031 11.1875 32 11.1875 32 C 10.960938 31.789063 10.648438 31.699219 10.34375 31.75 C 9.957031 31.808594 9.636719 32.085938 9.53125 32.464844 C 9.421875 32.839844 9.546875 33.246094 9.84375 33.5 C 9.84375 33.5 11.195313 34.671875 13.71875 35.78125 C 14.398438 36.078125 15.171875 36.378906 16.03125 36.65625 L 14.34375 38.9375 C 13.367188 38.84375 11.5 38.496094 9.5 37.71875 C 7.300781 36.863281 5.167969 35.496094 4.03125 33.65625 C 4.078125 29.097656 5.0625 24.125 6.28125 20.09375 C 6.90625 18.027344 7.5625 16.226563 8.1875 14.84375 C 8.8125 13.460938 9.492188 12.460938 9.6875 12.28125 C 12.707031 9.894531 17.140625 9.296875 18.28125 9.15625 Z M 18.5 21 C 15.949219 21 14 23.316406 14 26 C 14 28.683594 15.949219 31 18.5 31 C 21.050781 31 23 28.683594 23 26 C 23 23.316406 21.050781 21 18.5 21 Z M 31.5 21 C 28.949219 21 27 23.316406 27 26 C 27 28.683594 28.949219 31 31.5 31 C 34.050781 31 36 28.683594 36 26 C 36 23.316406 34.050781 21 31.5 21 Z M 18.5 23 C 19.816406 23 21 24.265625 21 26 C 21 27.734375 19.816406 29 18.5 29 C 17.183594 29 16 27.734375 16 26 C 16 24.265625 17.183594 23 18.5 23 Z M 31.5 23 C 32.816406 23 34 24.265625 34 26 C 34 27.734375 32.816406 29 31.5 29 C 30.183594 29 29 27.734375 29 26 C 29 24.265625 30.183594 23 31.5 23 Z"></path></svg>`;// Создаем менюconst demojiMenu = document.createElement("div");demojiMenu.id = "discordDemojiMenu";demojiMenu.className = "discordDemojis";demojiMenu.style.display = 'none';demojiMenu.innerHTML = `<style>.discordDemojis {background: #292929;padding: 3px;max-width: 530px;display: none;position: absolute;top: 130px;left: 196px;z-index: 99;border-radius: 5px;}.toons_picker_relative .discordDemojis {top: inherit;bottom: 0;}.format {grid-template-columns: repeat(6, 24px) 1fr !important;}.discordDemojis > .demoji-content {max-height: 105px;overflow-y: auto;width: 35px;height: 30px;display: inline-block;margin: 5px;padding: 5px;background-color: #0003;border-radius: 3px;cursor: pointer;}.discordDemoji {width: 40px;height: 40px;cursor: pointer;transition: all 0.1s ease-in-out;border: 2px solid #0000;opacity: 0.7;}.discordDemoji:hover {border: 2px solid #7289da;opacity: 1;border-radius: 4px;}.demoji-header {display: flex;gap: 10px;margin-bottom: 10px;padding: 5px;}.demoji_search {flex: 1;display: flex;align-items: center;background: #0003;padding: 5px;border-radius: 3px;}.demoji_search input {background: transparent;border: none;color: white;margin-left: 5px;width: 100%;}.demoji_search input:focus {outline: none;}.demoji_notfound {display: none;text-align: center;padding: 10px;color: white;}#demojiArea {overflow-y: scroll;height: 260px;scroll-behavior: smooth;}.pack-header{font-family: Fira Sans, sans-serif;padding: 5px;cursor: pointer;user-select: none;color: white;display: flex;align-items: center;gap: 5px;}.pack-header img{width: 30px;height: 30px;vertical-align: middle;}.pack-header .arrow {margin-left: auto;transition: transform 0.2s ease;}.pack-collapsed .pack-header .arrow {transform: rotate(-90deg);}.pack-emojis {overflow: hidden;transition: all 0.2s ease-in-out;padding: 5px;}.pack-collapsed .pack-emojis {height: 0 !important;padding: 0 5px !important;}.pack-icons-sidebar {display: flex;flex-direction: column;gap: 5px;padding: 5px;background: #1e1e1e;border-radius: 4px;}.pack-icon {margin-top: 5px;width: 40px;height: 40px;cursor: pointer;border-radius: 4px;transition: all 0.2s ease;border: 2px solid #0000;opacity: 0.7;border-radius: 4px;}.pack-icon:hover {border: 2px solid #7289da;opacity: 1;}.pack-icon.active {opacity: 1;background: #7289da33;}.packs-content {flex: 1;}.demoji-content-area{display: flex;flex-direction: row;gap: 10px;height: 300px;overflow: hidden;overflow-x: auto;scroll-behavior: smooth;padding: 5px;width: 502px;}</style><div class="demoji-content-area"><div class="pack-icons-sidebar" id="packIconsSidebar"></div><div class="packs-content"><div class="demoji-header"><div class="demoji_search"><span class="fas fa-search fa-fw"></span><input type="text" placeholder="Искать эмодзи" id="demojiSearchInput"></div><div class="demoji-controls"><a id="addDiscordDemojiBtn" class="add-emoji-btn" title="Добавить эмодзи"><span class="far fa-plus fa-fw icon"></span></a><a id="addPackBtn" class="add-emoji-btn" title="Добавить пак"><span class="far fa-folder-plus fa-fw icon"></span></a><a id="importPackBtn" class="add-emoji-btn" title="Импортировать пак"><span class="far fa-upload fa-fw icon"></span></a><a id="aboutDiscordDemoji" class="add-emoji-btn" title="Как пользоваться"><span class="far fa-question fa-fw"></span></a></div></div><div id="demojiArea"></div><div class="demoji_notfound" id="demojiNotFound"><h3>Ничего не найдено</h3></div></div></div>`;// Добавляем кнопку в .formatif (editorFormatCont) {editorFormatCont.appendChild(demojiButton);} else {formatContainer.appendChild(demojiButton);}demojiMenu.querySelector('#addPackBtn').addEventListener('click', showAddPackDialog);// Добавляем меню в .emoji_holderif (document.querySelector(".emoji_holder")) {document.querySelector(".emoji_holder").appendChild(demojiMenu);} else if (document.querySelector(".toons_picker_relative")) {document.querySelector(".toons_picker_relative").appendChild(demojiMenu);} else if (editorFormatCont) {demojiMenu.classList.add("descr");document.querySelector(".tpicker.descr").insertAdjacentElement('afterend', demojiMenu);} else {console.error("Не удалось найти контейнер для Discord эмодзи меню");return;}// Обработчики событийdocument.getElementById('discordDemojiBtn').addEventListener('click', toggleDemojiMenu);document.getElementById('addDiscordDemojiBtn').addEventListener('click', showAddDemojiDialog);document.getElementById('aboutDiscordDemoji').addEventListener('click', showDemojiHelp);document.getElementById('demojiSearchInput').addEventListener('input', searchDemojis);document.getElementById('importPackBtn').addEventListener('click', importPack);// Закрытие меню при клике вне егоdocument.addEventListener('click', (e) => {const menu = document.getElementById('discordDemojiMenu');const btn = document.getElementById('discordDemojiBtn');if (!menu.contains(e.target) && !btn.contains(e.target)) {menu.style.display = 'none';}});updateDemojiMenu();}function toggleDemojiMenu() {const menu = document.getElementById('discordDemojiMenu');menu.style.display = menu.style.display === 'none' ? 'block' : 'none';}function searchDemojis(event) {const searchText = event.target.value.toLowerCase();const demojiArea = document.getElementById('demojiArea');const notFoundMessage = document.getElementById('demojiNotFound');const packs = storage.get('demoji_packs');const emojis = storage.get('demoji_emojis');const filteredEmojis = searchText ?emojis.filter(emoji =>emoji.name.toLowerCase().includes(searchText) ||packs.find(p => p.id === emoji.packId)?.name.toLowerCase().includes(searchText)) : emojis;if (filteredEmojis.length === 0) {demojiArea.style.display = 'none';notFoundMessage.style.display = 'block';} else {demojiArea.style.display = 'block';notFoundMessage.style.display = 'none';// Группируем эмодзи по пакамconst groupedEmojis = {};filteredEmojis.forEach(emoji => {if (!groupedEmojis[emoji.packId]) {groupedEmojis[emoji.packId] = [];}groupedEmojis[emoji.packId].push(emoji);});// Отображаем эмодзи по пакамdemojiArea.innerHTML = packs.sort((a, b) => a.order - b.order).map(pack => {if (!groupedEmojis[pack.id]) return '';return `<div class="pack-container"><div class="pack-header" data-pack-header="${pack.id}"><div class="pack-header-content" onclick="if(!event.target.parentElement.classList.contains('pack-buttons') &&!event.target.parentElement.parentElement.classList.contains('pack-buttons')) togglePack('${pack.id}')"><img src="${pack.icon}"oncontextmenu="editPackIcon('${pack.id}', event)"title="ПКМ чтобы изменить иконку"><span oncontextmenu="editPackName('${pack.id}', event)"title="ПКМ чтобы изменить название">${pack.name}</span><span class="arrow"><i class="fas fa-chevron-down"></i></span><div class="pack-buttons"><button class="pack-btn add-emoji-btn" onclick="addEmojiToPackK('${pack.id}')" title="Добавить эмодзи в пак"><i class="fas fa-plus"></i></button><button class="pack-btn share-pack-btn" onclick="exportPack('${pack.id}')" title="Экспортировать пак"><i class="fas fa-download"></i></button><button class="pack-btn delete-pack-btn" onclick="deletePack('${pack.id}')" title="Удалить пак"><i class="fas fa-trash-alt"></i></button></div></div></div><div class="pack-emojis">${groupedEmojis[pack.id].map(emoji => `<imgsrc="https://cdn.discordapp.com/emojis/${emoji.id}.${emoji.animated ? 'gif' : 'webp'}"alt=":${emoji.name}:"title=":${emoji.name}:"class="discordDemoji"data-id="${emoji.id}"onclick="T.AddText('<${emoji.animated ? 'a' : ''}:${emoji.name}:${emoji.id}'>, ${document.querySelector(".send .format") ? "false" : "true"})"onmousedown="handleDemojiMouseDown(event, '${emoji.id}')">`).join('')}</div></div>`;}).join('');}}function updateDemojiMenu() {const demojiArea = document.getElementById('demojiArea');const packIconsSidebar = document.getElementById('packIconsSidebar');const packs = storage.get('demoji_packs');const emojis = storage.get('demoji_emojis');const searchText = document.getElementById('demojiSearchInput').value.toLowerCase();// Обновляем сайдбар с иконкамиpackIconsSidebar.innerHTML = packs.sort((a, b) => a.order - b.order).map(pack => `<imgsrc="${pack.icon}"class="pack-icon"data-pack-id="${pack.id}"title="${pack.name}"onclick="scrollToPack('${pack.id}')">`).join('');const filteredEmojis = searchText ?emojis.filter(emoji =>emoji.name.toLowerCase().includes(searchText) ||packs.find(p => p.id === emoji.packId)?.name.toLowerCase().includes(searchText)) : emojis;if (filteredEmojis.length === 0) {demojiArea.style.display = 'none';document.getElementById('demojiNotFound').style.display = 'block';return;}demojiArea.style.display = 'block';document.getElementById('demojiNotFound').style.display = 'none';// Группируем эмодзи по пакамconst groupedEmojis = {};filteredEmojis.forEach(emoji => {if (!groupedEmojis[emoji.packId]) {groupedEmojis[emoji.packId] = [];}groupedEmojis[emoji.packId].push(emoji);});// Отображаем эмодзи по пакамdemojiArea.innerHTML = packs.sort((a, b) => a.order - b.order).map(pack => {const packEmojis = groupedEmojis[pack.id] || [];// Сортируем эмодзи: сначала статические, потом анимированныеconst sortedEmojis = packEmojis.sort((a, b) => {if (a.animated === b.animated) {return a.name.localeCompare(b.name); // Сортировка по имени внутри каждой группы}return a.animated ? 1 : -1; // Анимированные идут после статических});return `<div class="pack-container"><div class="pack-header" data-pack-header="${pack.id}"><div class="pack-header-content" onclick="if(!event.target.parentElement.classList.contains('pack-buttons') &&!event.target.parentElement.parentElement.classList.contains('pack-buttons')) togglePack('${pack.id}')"><img src="${pack.icon}"oncontextmenu="editPackIcon('${pack.id}', event)"title="ПКМ чтобы изменить иконку"><span oncontextmenu="editPackName('${pack.id}', event)"title="ПКМ чтобы изменить название">${pack.name}</span><span class="arrow"><i class="fas fa-chevron-down"></i></span><div class="pack-buttons"><button class="pack-btn add-emoji-btn" onclick="addEmojiToPackK('${pack.id}')" title="Добавить эмодзи в пак"><i class="fas fa-plus"></i></button><button class="pack-btn share-pack-btn" onclick="exportPack('${pack.id}')" title="Экспортировать пак"><i class="fas fa-download"></i></button><button class="pack-btn delete-pack-btn" onclick="deletePack('${pack.id}')" title="Удалить пак"><i class="fas fa-trash-alt"></i></button></div></div></div><div class="pack-emojis">${packEmojis.length > 0 ?packEmojis.map(emoji => `<imgsrc="https://cdn.discordapp.com/emojis/${emoji.id}.${emoji.animated ? 'gif' : 'webp'}"alt=":${emoji.name}:"title=":${emoji.name}:"class="discordDemoji"data-id="${emoji.id}"onclick="T.AddText('<${emoji.animated ? 'a' : ''}:${emoji.name}:${emoji.id}>', ${document.querySelector(".send .format") ? "false" : "true"})"onmousedown="handleDemojiMouseDown(event, '${emoji.id}')">`).join(''): '<div class="no-emojis-message">В этом паке пока нет эмодзи</div>'}</div></div>`;}).join('');}function showAddDemojiDialog() {const packs = storage.get('demoji_packs');if (packs.length === 0) {alert('Сначала создайте хотя бы один пак!');return;}const packId = prompt(`Выберите ID пака для добавления:\n${packs.map(p => `${p.id}: ${p.name}`).join('\n')}`);if (!packId || !packs.find(p => p.id === packId)) {alert('Неверный ID пака!');return;}addEmojiToPackK(packId)}function addEmojiToPackK(packId) {const input = prompt('Вставьте ID Discord эмодзи (можно несколько через пробел)\nФорматы: id или id:name');if (!input) return;const items = input.split(/\s+/).filter(item => item.length > 0);items.forEach(item => {let id, name;if (item.includes(':')) {[id, name] = item.split(':');} else {id = item;name = id.slice(0, 4);}if (!/^\d+$/.test(id)) {alert(`Неверный формат ID эмодзи: ${id}`);return;}checkAndAddEmoji(id, name, packId);});}// Проверка и добавление эмодзиfunction checkAndAddEmoji(id, name, packId) {const img = new Image();img.onload = function () {addEmojiToPack(id, name, packId, true);};img.onerror = function () {const staticImg = new Image();staticImg.onload = function () {addEmojiToPack(id, name, packId, false);};staticImg.onerror = function () {alert(`Эмодзи с ID ${id} не найден!`);};staticImg.src = `https://cdn.discordapp.com/emojis/${id}.webp`;};img.src = `https://cdn.discordapp.com/emojis/${id}.gif`;}// Добавление эмодзи в пакfunction addEmojiToPack(id, name, packId, animated) {const emojis = storage.get('demoji_emojis') || [];emojis.push({id: id,name: name,packId: packId,animated: animated});storage.set('demoji_emojis', emojis);updateDemojiMenu();}function showDemojiHelp() {alert(`Как пользоваться Discord эмодзи📦 Управление паками• Добавить пак: нажмите кнопку "+" в верхнем меню• Удалить пак: нажмите кнопку корзины в заголовке пака• Поделиться паком: нажмите кнопку "экспорт" в заголовке пака• Установить пак: нажмите кнопку "импорт" в верхнем меню и выберите файл😀 Управление эмодзи• Добавить эмодзи: нажмите "+" в заголовке пака и вставьте ссылку или ID эмодзи• Использовать эмодзи: кликните левой кнопкой мыши по эмодзи• Переименовать эмодзи: нажмите среднюю кнопку мыши (колесико)• Удалить эмодзи: нажмите правую кнопку мыши🔍 Поиск• Используйте поисковую строку для поиска по имени эмодзи или названию пака• Поиск работает в реальном времени💡 Дополнительно• Паки можно сворачивать/разворачивать, кликнув по заголовку• Быстрая навигация по пакам доступна через боковую панель• Для добавления эмодзи из Discord, скопируйте ID эмодзи (\\:emoji:)• Поддерживаются как статические, так и анимированные эмодзи⚠️ Важно• Эмодзи сохраняются локально в вашем браузере• При очистке данных браузера, все сохраненные эмодзи будут удалены• Рекомендуется периодически экспортировать паки для создания резервной копии`);}window.removeDiscordDemoji = function (demojiId) {if (confirm('Удалить этот эмодзи?')) {const emojis = storage.get('demoji_emojis');const newEmojis = emojis.filter(e => e.id !== demojiId);storage.set('demoji_emojis', newEmojis);updateDemojiMenu();}};// Конвертация эмодзи в комментарияхfunction convertDiscordDemojis(element) {if (!element) return;element.innerHTML = element.innerHTML.replace(/<(a?):(\w+):(\d+)>|<(a?):(\w+):(\d+)>/g,(match, animated1, name1, id1, animated2, name2, id2) => {const animated = animated1 || animated2;const name = name1 || name2;const id = id1 || id2;const extension = animated ? 'gif' : 'webp';return `<img src="https://cdn.discordapp.com/emojis/${id}.${extension}"alt=":${name}:"class="discord-demoji"style=""data-demoji-id="${id}"data-demoji-name="${name}"data-demoji-animated="${!!animated}"oncontextmenu="copyEmojiInfo(event, '${id}', '${name}')">`;});}// Обработка существующих комментариевfunction processExistingComments() {const comments = document.querySelectorAll('div.comment_data > p');comments.forEach(convertDiscordDemojis);const desc = document.querySelectorAll(".description:not(textarea)");desc.forEach(convertDiscordDemojis);const toonName = document.querySelectorAll(".content.divided.watch .info h1");toonName.forEach(convertDiscordDemojis);const smallToonName = document.querySelectorAll(".toon_data .name a");smallToonName.forEach(convertDiscordDemojis);}// Наблюдатель за новыми комментариямиconst observer = new MutationObserver((mutations) => {mutations.forEach((mutation) => {mutation.addedNodes.forEach((node) => {if (node.nodeType === 1) {const comments = node.querySelectorAll('div.comment_data > p');const desc = node.querySelectorAll(".description:not(textarea)");const toonName = node.querySelectorAll(".content.divided.watch .info h1");const smallToonName = node.querySelectorAll(".toon_data .name a");comments.forEach(convertDiscordDemojis);desc.forEach(convertDiscordDemojis);toonName.forEach(convertDiscordDemojis);smallToonName.forEach(convertDiscordDemojis);}});});});// Инициализацияfunction init() {try {const additionalStyles = `.no-emojis-message {padding: 10px;text-align: center;color: #666;font-family: 'Pangolin', sans-serif;border-radius: 4px;margin: 5px;}.discord-demoji{width: 40px;height: 40px;vertical-align: middle;}.toon_data .discord-demoji{width: 20px !important;height: 20px !important;}.pack-header {display: flex;justify-content: space-between;align-items: center;padding: 5px;border-radius: 4px;}.pack-container{background: #2f3136;}.pack-header-content {display: grid;grid-template-columns: auto 1fr 1fr auto;gap: 10px;align-items: center;width: 100%;}.pack-header-content span {opacity: 0.7;transition: all 0.2s ease;}.pack-header-content:hover span {opacity: 1;}.add-emoji-btn {background: transparent;border: none;color: #b9bbbe;padding: 5px;cursor: pointer;border-radius: 4px;transition: all 0.2s ease;width: 100%;item-align: center;text-align: center;}.add-emoji-btn span{margin: 0;}.add-emoji-btn:hover {color: white;background: #40444b;}.pack-buttons {display: flex;gap: 5px;margin-left: auto;}.pack-btn {background: transparent;border: none;color: #b9bbbe;padding: 5px;cursor: pointer;border-radius: 4px;transition: all 0.2s ease;display: flex;align-items: center;justify-content: center;width: 28px;height: 28px;}.pack-btn:hover {color: white;background: #40444b;}.share-pack-btn {color: #b9bbbe;}.share-pack-btn:hover {color: #00b0f4;}.pack-header-content img {width: 24px;height: 24px;border-radius: 4px;}.delete-pack-btn {color: #b9bbbe;}.delete-pack-btn:hover {color: #ed4245;background: rgba(237, 66, 69, 0.1);}.emoji-copy-notification {position: fixed;background: #36393f;color: white;padding: 8px 12px;border-radius: 4px;font-size: 14px;z-index: 9999;pointer-events: none;animation: fadeInOut 1.5s ease forwards;transform: translate(-50%, -100%);margin-top: -10px;box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);font-family: 'Pangolin', sans-serif;}@keyframes fadeInOut {0% {opacity: 0;transform: translate(-50%, -90%);}15% {opacity: 1;transform: translate(-50%, -100%);}85% {opacity: 1;transform: translate(-50%, -100%);}100% {opacity: 0;transform: translate(-50%, -90%);}}`;document.querySelector('style').textContent += additionalStyles;} catch { }processExistingComments();if (document.querySelector("#comment_form") || document.querySelector(".sender") || document.querySelector("iframe#draw")) {createDemojiUI();}observer.observe(document.body, {childList: true,subtree: true});}// Запуск после загрузки страницыif (document.readyState === 'loading') {document.addEventListener('DOMContentLoaded', init);} else {init();}// Добавляем глобальную функцию для обработки нажатий мышиwindow.handleDemojiMouseDown = function (event, demojiId) {event.preventDefault();console.log(event.button)if (event.button === 1) { // Средняя кнопка мышиrenameDemoji(demojiId);} else if (event.button === 2) { // Правая кнопка мышиremoveDiscordDemoji(demojiId);}};function renameDemoji(demojiId) {console.log(demojiId);const emojis = storage.get('demoji_emojis');const emoji = emojis.find(e => e.id === demojiId);if (!emoji) return;const newName = prompt('Введите новое имя для эмодзи:', emoji.name);if (newName && newName.trim()) {emoji.name = newName.trim();storage.set('demoji_emojis', emojis);updateDemojiMenu();}}function showAddPackDialog() {const packName = prompt('Введите название пака:');if (!packName) return;const packIcon = prompt('Вставьте URL иконки пака:');if (!packIcon) return;const packs = storage.get('demoji_packs');const newPack = {id: Date.now().toString(),name: packName,icon: packIcon,order: packs.length // Для сортировки паков};packs.push(newPack);storage.set('demoji_packs', packs);updateDemojiMenu();alert('Пак успешно создан!\nID пака: ' + newPack.id);}window.togglePack = togglePack;// Добавляем стили// Добавляем в глобальную область видимостиwindow.addEmojiToPackK = addEmojiToPackK;function togglePack(packId) {const packContainer = document.querySelector(`[data-pack-header="${packId}"]`).closest('.pack-container');const emojisContainer = packContainer.querySelector('.pack-emojis');// Сохраняем текущее состояниеconst isCollapsed = packContainer.classList.contains('pack-collapsed');if (!isCollapsed) {// Сворачиваемconst currentHeight = emojisContainer.offsetHeight;emojisContainer.style.height = currentHeight + 'px';// Форсируем reflowemojisContainer.offsetHeight;packContainer.classList.add('pack-collapsed');} else {// РазворачиваемemojisContainer.style.transition = 'none';packContainer.classList.remove('pack-collapsed');const targetHeight = emojisContainer.scrollHeight;packContainer.classList.add('pack-collapsed');emojisContainer.style.height = '0px';// Форсируем reflowemojisContainer.offsetHeight;emojisContainer.style.transition = '';packContainer.classList.remove('pack-collapsed');emojisContainer.style.height = targetHeight + 'px';}// Очищаем высоту после анимацииemojisContainer.addEventListener('transitionend', function handler() {if (!packContainer.classList.contains('pack-collapsed')) {emojisContainer.style.height = '';}emojisContainer.removeEventListener('transitionend', handler);});}function scrollToPack(packId) {const packElement = document.querySelector(`[data-pack-header="${packId}"]`);if (packElement) {// Обновляем активную иконкуdocument.querySelectorAll('.pack-icon').forEach(icon => {icon.classList.remove('active');});document.querySelector(`.pack-icon[data-pack-id="${packId}"]`).classList.add('active');// Прокручиваем к пакуconst demojiArea = document.getElementById('demojiArea');const packTop = packElement.offsetTop;demojiArea.scrollTo({top: packTop,behavior: 'smooth'});// Разворачиваем пак, если он свёрнутconst packContainer = packElement.closest('.pack-container');if (packContainer.classList.contains('pack-collapsed')) {togglePack(packId);}}}// Добавляем в глобальную область видимостиwindow.scrollToPack = scrollToPack;window.deletePack = deletePack;// Добавляем функцию удаления пакаfunction deletePack(packId) {const packs = storage.get('demoji_packs');const pack = packs.find(p => p.id === packId);if (!pack) return;if (!confirm(`Вы уверены, что хотите удалить пак "${pack.name}"?\nВсе эмодзи пака также будут удалены.`)) {return;}// Удаляем пакconst newPacks = packs.filter(p => p.id !== packId);storage.set('demoji_packs', newPacks);// Удаляем все эмодзи пакаconst emojis = storage.get('demoji_emojis');const newEmojis = emojis.filter(e => e.packId !== packId);storage.set('demoji_emojis', newEmojis);updateDemojiMenu();alert(`Пак "${pack.name}" успешно удален!`);}// Добавляем в глобальную область видимостиwindow.deletePack = deletePack;// Функция экспорта пакаfunction exportPack(packId) {const packs = storage.get('demoji_packs');const emojis = storage.get('demoji_emojis');const pack = packs.find(p => p.id === packId);const packEmojis = emojis.filter(e => e.packId === packId);if (!pack || !packEmojis.length) {alert('Ошибка: пак не найден или пуст');return;}const packData = {pack: pack,emojis: packEmojis};const blob = new Blob([JSON.stringify(packData)], { type: 'application/json' });const url = URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = `${pack.name}_pack.json`;document.body.appendChild(a);a.click();document.body.removeChild(a);URL.revokeObjectURL(url);}// Функция импорта пакаfunction importPack() {const input = document.createElement('input');input.type = 'file';input.accept = '.json';input.onchange = function (e) {const file = e.target.files[0];const reader = new FileReader();reader.onload = function (e) {try {const packData = JSON.parse(e.target.r###lt);const { pack, emojis } = packData;// Получаем текущие паки и эмодзиconst currentPacks = storage.get('demoji_packs');const currentEmojis = storage.get('demoji_emojis');// Проверяем, существует ли уже пак с таким IDconst existingPack = currentPacks.find(p => p.id === pack.id);if (existingPack) {if (!confirm(`Пак "${pack.name}" уже существует. Заменить?`)) {return;}// Удаляем старые эмодзи пакаconst newEmojis = currentEmojis.filter(e => e.packId !== pack.id);storage.set('demoji_emojis', [...newEmojis, ...emojis]);// Обновляем пакconst newPacks = currentPacks.map(p => p.id === pack.id ? pack : p);storage.set('demoji_packs', newPacks);} else {// Добавляем новый пак и его эмодзиstorage.set('demoji_packs', [...currentPacks, pack]);storage.set('demoji_emojis', [...currentEmojis, ...emojis]);}updateDemojiMenu();alert(`Пак "${pack.name}" успешно импортирован!`);} catch (error) {console.error('Ошибка импорта пака:', error);alert('Ошибка при импорте пака. Неверный формат файла.');}};reader.readAsText(file);};input.click();}window.exportPack = exportPack;function editPackName(packId, event) {event.preventDefault(); // Предотвращаем стандартное контекстное менюconst packs = storage.get('demoji_packs');const pack = packs.find(p => p.id === packId);if (!pack) return;const newName = prompt('Введите новое название пака:', pack.name);if (newName && newName.trim()) {pack.name = newName.trim();storage.set('demoji_packs', packs);updateDemojiMenu();}}function editPackIcon(packId, event) {event.preventDefault(); // Предотвращаем стандартное контекстное менюconst packs = storage.get('demoji_packs');const pack = packs.find(p => p.id === packId);if (!pack) return;const newIcon = prompt('Вставьте новый URL иконки пака:', pack.icon);if (newIcon && newIcon.trim()) {pack.icon = newIcon.trim();storage.set('demoji_packs', packs);updateDemojiMenu();}}// Добавьте в глобальную область видимостиwindow.editPackName = editPackName;window.editPackIcon = editPackIcon;// Добавьте функцию для копирования в буфер обменаfunction copyEmojiInfo(event, emojiId, emojiName) {event.preventDefault(); // Предотвращаем стандартное контекстное менюconst emojiInfo = `${emojiId}:${emojiName}`;navigator.clipboard.writeText(emojiInfo).then(() => {// Создаем временное уведомлениеconst notification = document.createElement('div');notification.className = 'emoji-copy-notification';notification.textContent = 'Информация скопирована';// Позиционируем уведомление возле курсораnotification.style.left = `${event.pageX}px`;notification.style.top = `${event.pageY}px`;document.body.appendChild(notification);setTimeout(() => {notification.remove();}, 1500);});}window.copyEmojiInfo = copyEmojiInfo;