Desbloquea los textos artísticos, previene popups, copia al portapapeles sin notificaciones, sin afectar el scroll, y elimina "@Facemojikeyboard" del texto.
// ==UserScript==
// @name Desbloquear Facemojikeyboard
// @namespace http://tampermonkey.net/
// @version 1.3.1
// @description Desbloquea los textos artísticos, previene popups, copia al portapapeles sin notificaciones, sin afectar el scroll, y elimina "@Facemojikeyboard" del texto.
// @author YouTubeDrawaria
// @match https://www.facemojikeyboard.com/text-art-collection
// @grant none
// @license MIT
// @icon https://cdn.facemojikeyboard.com/website/favicon.png
// ==/UserScript==
(function() {
'use strict';
// Cadena a eliminar de los textos
const STRING_TO_REMOVE = '@Facemojikeyboard';
/**
* Copia el texto dado al portapapeles. Sin notificaciones.
* @param {string} text El texto a copiar.
*/
function copyTextToClipboard(text) {
// Eliminar la cadena no deseada antes de copiar
const cleanedText = text.replace(new RegExp(STRING_TO_REMOVE, 'g'), '').trim();
if (navigator.clipboard) {
navigator.clipboard.writeText(cleanedText).catch(err => {
console.error('No se pudo copiar el texto usando navigator.clipboard: ', err);
fallbackCopyTextToClipboard(cleanedText);
});
} else {
fallbackCopyTextToClipboard(cleanedText);
}
}
/**
* Fallback para copiar texto al portapapeles usando un textarea temporal.
* @param {string} text El texto a copiar.
*/
function fallbackCopyTextToClipboard(text) {
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
textarea.style.left = '-9999px';
textarea.style.top = '-9999px';
document.body.appendChild(textarea);
textarea.focus();
textarea.select();
try {
document.execCommand('copy');
} catch (err) {
console.error('No se pudo copiar el texto con execCommand: ', err);
}
document.body.removeChild(textarea);
}
/**
* Aplica las modificaciones a los elementos de arte de texto (eliminar candado, hacer seleccionable, añadir listener de copia).
*/
function applyModifications() {
const textArtWrappers = document.querySelectorAll('.emojiwrapper-list-tool__wrapper');
textArtWrappers.forEach(item => {
// 1. Elimina el icono de candado si existe
const lockIcon = item.querySelector('img.lock');
if (lockIcon) {
lockIcon.remove();
}
// 2. Asegura que el texto sea seleccionable
item.style.userSelect = 'text';
item.style.webkitUserSelect = 'text';
item.style.mozUserSelect = 'text';
item.style.msUserSelect = 'text';
// 3. Añade un listener de clic para copiar texto y prevenir popups
if (!item.dataset.listenerAdded) {
item.addEventListener('click', function(event) {
event.preventDefault();
event.stopPropagation();
const textSpan = this.querySelector('span');
if (textSpan && textSpan.textContent) {
copyTextToClipboard(textSpan.textContent.trim());
}
}, { capture: true });
item.dataset.listenerAdded = 'true';
}
});
}
/**
* Oculta elementos específicos de pop-up y asegura que el scroll no esté bloqueado.
* Se usa `!important` para asegurar la anulación de estilos existentes.
*/
function hideSpecificPopupsAndRestoreScroll() {
const popper = document.querySelector('.el-popper.tooltip-popper-class');
if (popper) {
popper.style.setProperty('display', 'none', 'important');
popper.setAttribute('aria-hidden', 'true');
}
const modal = document.querySelector('.dialog-container.default-modal');
if (modal) {
modal.style.setProperty('display', 'none', 'important');
}
document.body.style.setProperty('overflow', 'auto', 'important');
document.documentElement.style.setProperty('overflow', 'auto', 'important');
}
// --- Lógica de Ejecución y Observación ---
// 1. Añadir reglas CSS globales para ocultar los popups de forma persistente
// y asegurar que el scroll siempre funcione.
function addGlobalCSSRules() {
const style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = `
/* Ocultar los popups de información/descarga */
.el-popper.tooltip-popper-class,
.dialog-container.default-modal {
display: none !important;
}
/* Asegurar que el scroll siempre funcione */
body, html {
overflow: auto !important;
}
`;
document.head.appendChild(style);
}
addGlobalCSSRules();
// 2. Ejecutar las modificaciones iniciales y ocultar popups al cargar la página
applyModifications();
hideSpecificPopupsAndRestoreScroll();
// 3. Observar cambios en el DOM para manejar contenido cargado dinámicamente y nuevos popups
const observer = new MutationObserver((mutationsList, observer) => {
let needsModifications = false;
let needsPopupHiding = false;
for (const mutation of mutationsList) {
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) { // Solo si es un elemento HTML
if (node.classList.contains('emojiwrapper-list-tool') || node.querySelector('.emojiwrapper-list-tool__wrapper')) {
needsModifications = true;
}
if (node.classList.contains('el-popper') || node.classList.contains('dialog-container')) {
needsPopupHiding = true;
}
}
});
} else if (mutation.type === 'attributes' && (mutation.target === document.body || mutation.target === document.documentElement) && mutation.attributeName === 'style') {
if (mutation.target.style.overflow === 'hidden') {
needsPopupHiding = true;
}
}
}
if (needsModifications) {
applyModifications();
}
if (needsPopupHiding) {
hideSpecificPopupsAndRestoreScroll();
}
});
observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style'] });
observer.observe(document.documentElement, { attributes: true, attributeFilter: ['style'] });
})();