您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Load symbols from BarsikSymbols.json and allow inserting them into the chat with a click. Improved and draggable menu
// ==UserScript== // @name Drawaria Symbols Loader Menu // @namespace http://tampermonkey.net/ // @version 1.0 // @description Load symbols from BarsikSymbols.json and allow inserting them into the chat with a click. Improved and draggable menu // @author YouTubeDrawaria, Barsik Hacker // @match https://drawaria.online/* // @grant none // @license MIT // @icon https://www.google.com/s2/favicons?sz=64&domain=drawaria.online // ==/UserScript== (function() { 'use strict'; const SYM_URL = "https://raw.githubusercontent.com/NuevoMundoOficial/DrawariaWordList/main/BarsikSymbols.json"; const PAGE_SIZE = 30; // Número de símbolos por página let allSymbols = []; // Almacena todos los símbolos cargados let currentPage = 0; let symLoaderBox; // Referencia al cuadro principal de la UI // Variables para la funcionalidad de arrastre let isDragging = false; let offsetX, offsetY; /** * Crea y añade la interfaz de usuario al DOM. * Incluye estilos CSS y la estructura HTML básica. */ function createUI() { // --- Estilos CSS --- const style = document.createElement('style'); style.textContent = ` #symLoaderBox { position: fixed; top: 60px; right: 20px; background: #2b2b2b; /* Fondo oscuro */ color: #e0e0e0; /* Texto claro */ z-index: 9999; /* Asegura que esté por encima de otros elementos */ border-radius: 10px; padding: 15px; width: 280px; /* Ancho ligeramente mayor */ font-size: 15px; box-shadow: 0 4px 18px rgba(0, 0, 0, 0.4); /* Sombra suave */ font-family: 'Arial', sans-serif; border: 1px solid #444; /* Borde sutil */ cursor: grab; /* Cursor para indicar que es arrastrable */ } #symLoaderHeader { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; padding-bottom: 5px; border-bottom: 1px solid #3a3a3a; /* Separador */ cursor: grab; /* Cursor para indicar que el header es arrastrable */ } #symLoaderHeader span { font-size: 18px; font-weight: bold; color: #fff; } #symLoaderBox button { margin: 0 2px; padding: 5px 9px; font-size: 17px; vertical-align: middle; border-radius: 5px; border: none; background: #444; color: #fff; cursor: pointer; transition: background 0.2s ease, transform 0.1s ease; /* Transiciones suaves */ } #symLoaderBox button:hover { background: #666; transform: translateY(-1px); /* Efecto de "levantar" */ } #symLoaderBox button:active { transform: translateY(0); } #symLoaderDL { background: #3a7bd5; /* Color distintivo para descargar */ } #symLoaderDL:hover { background: #2a6bc5; } #symLoaderClose { background: #d32f2f; /* Rojo para cerrar */ } #symLoaderClose:hover { background: #c31f1f; } #symLoaderSymbols { max-height: 280px; /* Altura máxima para el scroll */ overflow-y: auto; word-break: break-all; /* Rompe palabras largas */ white-space: normal; padding-right: 5px; /* Espacio para la barra de desplazamiento */ margin-bottom: 10px; } /* Estilos de la barra de desplazamiento (para navegadores Webkit como Chrome, Safari) */ #symLoaderSymbols::-webkit-scrollbar { width: 8px; } #symLoaderSymbols::-webkit-scrollbar-track { background: #333; border-radius: 10px; } #symLoaderSymbols::-webkit-scrollbar-thumb { background: #666; border-radius: 10px; } #symLoaderSymbols::-webkit-scrollbar-thumb:hover { background: #888; } .symBtn { /* Estilo para los botones de símbolos individuales */ display: inline-block; background: #555; color: #fff; padding: 4px 8px; margin: 3px; border-radius: 4px; cursor: pointer; font-size: 16px; transition: background 0.15s ease, transform 0.05s ease; user-select: none; /* Previene la selección de texto */ } .symBtn:hover { background: #777; transform: scale(1.02); } .symBtn:active { transform: scale(1.0); } #symLoaderPager { display: flex; justify-content: center; align-items: center; margin-top: 5px; padding-top: 5px; border-top: 1px solid #3a3a3a; /* Separador */ } #symLoaderPager .pager-button { /* Clase para los botones de paginación */ background: #007bff; color: #fff; padding: 3px 8px; margin: 0 5px; font-size: 15px; border-radius: 4px; transition: background 0.2s ease; } #symLoaderPager .pager-button:hover { background: #0056b3; } #symLoaderPager .pager-button:disabled { background: #555; cursor: not-allowed; } #symLoaderPager span { font-size: 15px; color: #bbb; } `; document.head.appendChild(style); // --- Estructura HTML --- symLoaderBox = document.createElement('div'); symLoaderBox.id = 'symLoaderBox'; symLoaderBox.innerHTML = ` <div id="symLoaderHeader"> <span>Drawaria Symbols</span> <div> <button id="symLoaderDL">💾</button> <button id="symLoaderClose">❌</button> </div> </div> <div id="symLoaderSymbols"> Cargando símbolos... </div> <div id="symLoaderPager"> <!-- Los botones de paginación se insertarán aquí --> </div> `; document.body.appendChild(symLoaderBox); // --- Event Listeners --- document.getElementById('symLoaderClose').onclick = () => symLoaderBox.remove(); document.getElementById('symLoaderDL').onclick = downloadJSON; // Delegación de eventos para los botones de símbolos (eficiente para muchos botones) document.getElementById('symLoaderBox').addEventListener('click', e => { if (e.target.classList.contains('symBtn')) { insertToChat(e.target.dataset.symbol); } }); // --- Draggable functionality --- const symLoaderHeader = document.getElementById('symLoaderHeader'); symLoaderHeader.addEventListener('mousedown', (e) => { isDragging = true; // Calcular el desplazamiento del cursor dentro del elemento offsetX = e.clientX - symLoaderBox.getBoundingClientRect().left; offsetY = e.clientY - symLoaderBox.getBoundingClientRect().top; symLoaderBox.style.cursor = 'grabbing'; // Cambiar cursor al arrastrar // Prevenir la selección de texto durante el arrastre symLoaderBox.style.userSelect = 'none'; }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; // Calcular la nueva posición del elemento let newLeft = e.clientX - offsetX; let newTop = e.clientY - offsetY; // Opcional: Limitar el arrastre dentro de la ventana const maxX = window.innerWidth - symLoaderBox.offsetWidth; const maxY = window.innerHeight - symLoaderBox.offsetHeight; newLeft = Math.max(0, Math.min(newLeft, maxX)); newTop = Math.max(0, Math.min(newTop, maxY)); symLoaderBox.style.left = `${newLeft}px`; symLoaderBox.style.top = `${newTop}px`; }); document.addEventListener('mouseup', () => { isDragging = false; symLoaderBox.style.cursor = 'grab'; // Restaurar cursor symLoaderBox.style.userSelect = 'auto'; // Habilitar selección de texto }); } /** * Rellena el contenedor de símbolos con los símbolos de la página actual. * Siempre usa `allSymbols` ya que no hay filtro. * @param {number} page - El número de página a mostrar (0-indexado). */ function populateSymbols(page = 0) { if (!allSymbols || allSymbols.length === 0) { fillSymbols('No hay símbolos disponibles.'); updatePager(0, 0, 0); // Actualiza la paginación a "sin páginas" return; } currentPage = page; const wrap = document.getElementById('symLoaderSymbols'); wrap.innerHTML = ''; // Limpia los símbolos anteriores let start = page * PAGE_SIZE; let end = Math.min(start + PAGE_SIZE, allSymbols.length); const fragment = document.createDocumentFragment(); // Para mejor rendimiento al añadir muchos elementos for (let i = start; i < end; i++) { const symbol = allSymbols[i]; const button = document.createElement('button'); button.classList.add('symBtn'); button.dataset.symbol = symbol; // Almacena el símbolo en un atributo de datos button.textContent = symbol; fragment.appendChild(button); } wrap.appendChild(fragment); updatePager(page, allSymbols.length, PAGE_SIZE); } /** * Actualiza los botones y la información de la paginación. * @param {number} currentPage - La página actual (0-indexada). * @param {number} totalSymbols - El número total de símbolos disponibles. * @param {number} pageSize - El número de símbolos por página. */ function updatePager(currentPage, totalSymbols, pageSize) { const pager = document.getElementById('symLoaderPager'); pager.innerHTML = ''; // Limpia la paginación existente if (totalSymbols <= pageSize) { return; // No se necesita paginación si hay una sola página o menos } const totalPages = Math.ceil(totalSymbols / pageSize); // Botón "Anterior" const prevButton = document.createElement('button'); prevButton.classList.add('pager-button'); prevButton.textContent = '<'; prevButton.disabled = currentPage === 0; // Deshabilitar si es la primera página prevButton.onclick = () => populateSymbols(currentPage - 1); pager.appendChild(prevButton); // Información de la página (ej: "1/5") const pageInfo = document.createElement('span'); pageInfo.textContent = `${currentPage + 1}/${totalPages}`; pager.appendChild(pageInfo); // Botón "Siguiente" const nextButton = document.createElement('button'); nextButton.classList.add('pager-button'); nextButton.textContent = '>'; nextButton.disabled = currentPage >= totalPages - 1; // Deshabilitar si es la última página nextButton.onclick = () => populateSymbols(currentPage + 1); pager.appendChild(nextButton); } /** * Rellena el contenedor de símbolos con un mensaje de estado. * @param {string} msg - El mensaje a mostrar. */ function fillSymbols(msg) { document.getElementById('symLoaderSymbols').textContent = msg; } /** * Descarga los símbolos cargados como un archivo JSON. */ function downloadJSON() { const a = document.createElement('a'); // Convierte el array a JSON con indentación para que sea legible a.href = 'data:application/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(allSymbols, null, 2)); a.download = 'BarsikSymbols.json'; a.click(); } /** * Inserta el texto dado en el campo de entrada del chat. * Se actualizó el selector para el chatbox de Drawaria. * @param {string} txt - El texto a insertar. */ function insertToChat(txt) { const chatInput = document.getElementById('chatbox_textinput'); // Selector actualizado if (!chatInput) { alert('No se ha encontrado el input de chat con ID "chatbox_textinput".'); return; } chatInput.value = txt; // Dispara un evento 'input' para asegurar que frameworks como React/Vue detecten el cambio chatInput.dispatchEvent(new Event('input', { bubbles: true })); // Opcional: enviar el mensaje (descomenta la siguiente línea, ¡bajo tu responsabilidad!) // document.querySelector('.chat__message-form button')?.click(); } /** * Carga los símbolos desde la URL especificada. */ async function loadSymbols() { fillSymbols("Cargando símbolos..."); // Mostrar mensaje de carga try { const response = await fetch(SYM_URL); if (!response.ok) { throw new Error(`Error HTTP! estado: ${response.status}`); } const obj = await response.json(); // Soporta si el JSON es un array directamente o un objeto con una propiedad 'symbols' allSymbols = Array.isArray(obj) ? obj : obj.symbols ?? []; if (allSymbols.length === 0) { fillSymbols("No se encontraron símbolos en el archivo JSON o el formato es incorrecto."); } else { populateSymbols(0); // Carga la página inicial de símbolos } } catch (e) { console.error("Error al cargar símbolos:", e); fillSymbols(`Error al cargar símbolos: ${e.message}. Por favor, intenta recargar la página.`); } } // Inicializa la interfaz de usuario y carga los símbolos al iniciar el script createUI(); loadSymbols(); })();