Trump Text Styler

Makes instances of "trump" more prominent on webpages

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Trump Text Styler
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Makes instances of "trump" more prominent on webpages
// @author       Ethan
// @match        *://*/*
// @grant        none
// @run-at       document-idle
// @license     MIT
// ==/UserScript==

(function() {
    'use strict';

    // Flag to prevent processing our own mutations
    let isProcessing = false;
    
    // Custom attribute to mark elements we've already processed
    const PROCESSED_ATTR = 'data-trump-processed';

    function isEditable(node) {
        const editableTags = ['INPUT', 'TEXTAREA'];
        
        // Check if node itself is editable
        if (editableTags.includes(node?.tagName) || node?.isContentEditable) {
            return true;
        }
        
        // Check if node is inside an editable element
        let parent = node?.parentNode;
        while (parent) {
            if (editableTags.includes(parent.tagName) || parent.isContentEditable) {
                return true;
            }
            parent = parent.parentNode;
        }
        
        return false;
    }

    function styleTrump(node) {
        // Skip if not a valid node
        if (!node) return;
        
        // Skip if already processed
        if (node.nodeType === Node.ELEMENT_NODE && 
            node.getAttribute && 
            node.getAttribute(PROCESSED_ATTR) === 'true') {
            return;
        }
        
        // First check if node is inside an editable element
        if (isEditable(node)) {
            return;
        }
        
        if (node.nodeType === Node.TEXT_NODE) {
            const text = node.textContent;
            const regex = /\b(trump)\b/gi;
            
            if (regex.test(text)) {
                // Temporarily disable observer
                isProcessing = true;
                
                const span = document.createElement('span');
                span.innerHTML = text.replace(regex, '<b style="font-size: 1.2em;">$1</b>');
                span.setAttribute(PROCESSED_ATTR, 'true');
                
                if (node.parentNode) {
                    node.parentNode.replaceChild(span, node);
                }
                
                // Re-enable observer after a small delay
                setTimeout(() => {
                    isProcessing = false;
                }, 0);
            }
        } else if (node.nodeType === Node.ELEMENT_NODE) {
            // Mark this element as processed
            if (node.setAttribute) {
                node.setAttribute(PROCESSED_ATTR, 'true');
            }
            
            // Process children
            if (node.childNodes && node.childNodes.length > 0) {
                // Safe copy of childNodes to avoid modification during iteration
                Array.from(node.childNodes).forEach(child => styleTrump(child));
            }
        }
    }

    // Wait for the DOM to be fully loaded
    window.addEventListener('DOMContentLoaded', () => {
        // Process initial page after a small delay
        setTimeout(() => {
            styleTrump(document.body);
        }, 500);
    });
    
    // For pages where DOMContentLoaded might have already fired
    if (document.readyState === 'complete' || document.readyState === 'interactive') {
        setTimeout(() => {
            styleTrump(document.body);
        }, 500);
    }

    const observer = new MutationObserver(mutations => {
        // Skip processing if we're already handling mutations
        if (isProcessing) return;
        
        mutations.forEach(mutation => {
            if (mutation.addedNodes && mutation.addedNodes.length > 0) {
                mutation.addedNodes.forEach(node => {
                    // Only process if it's a DOM node and not already processed
                    if (node.nodeType && 
                        !(node.nodeType === Node.ELEMENT_NODE && 
                          node.getAttribute && 
                          node.getAttribute(PROCESSED_ATTR) === 'true') &&
                        !isEditable(node)) {
                        styleTrump(node);
                    }
                });
            }
        });
    });

    // Start observing with a delay to let the page load first
    setTimeout(() => {
        observer.observe(document.body, { 
            childList: true, 
            subtree: true 
        });
    }, 1000);
})();