Anti-UI Purge Library

Prevents specified DOM elements from being destroyed by page state changes

Questo script non dovrebbe essere installato direttamente. È una libreria per altri script da includere con la chiave // @require https://update.greasyfork.org/scripts/584836/1863342/Anti-UI%20Purge%20Library.js

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name         Anti-UI Purge Library
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Prevents specified DOM elements from being destroyed by page state changes
// @author       Gemini
// @grant        none
// ==/UserScript==

(function(win) {
    'use strict';

    const protectedIDs = new Set();
    const protectedElements = new Map();

    // ==========================================
    // 1. NATIVE METHOD HOOKING (Proactive Defense)
    // ==========================================
    
    // Hook removeChild to intercept direct removal attempts
    const originalRemoveChild = Node.prototype.removeChild;
    Node.prototype.removeChild = function(child) {
        if (child && child.id && protectedIDs.has(child.id)) {
            console.warn(`[Anti-Purge] Blocked attempt to remove protected element: #${child.id}`);
            return child; // Pretend it was removed successfully
        }
        return originalRemoveChild.apply(this, arguments);
    };

    // Hook replaceChild
    const originalReplaceChild = Node.prototype.replaceChild;
    Node.prototype.replaceChild = function(newChild, oldChild) {
        if (oldChild && oldChild.id && protectedIDs.has(oldChild.id)) {
            console.warn(`[Anti-Purge] Blocked attempt to replace protected element: #${oldChild.id}`);
            // Insert the new child, but keep the old protected child
            this.insertBefore(newChild, oldChild);
            return oldChild;
        }
        return originalReplaceChild.apply(this, arguments);
    };

    // Hook innerHTML to catch blanket wipes (e.g., document.body.innerHTML = '')
    const originalInnerHTML = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
    Object.defineProperty(Element.prototype, 'innerHTML', {
        set: function(value) {
            // Find if any protected elements are currently inside this container
            const elementsToSave = [];
            protectedIDs.forEach(id => {
                const el = this.querySelector(`#${id}`);
                if (el) elementsToSave.push(el);
            });

            // Allow the wipe
            originalInnerHTML.set.call(this, value);

            // Re-append the protected elements immediately
            elementsToSave.forEach(el => {
                this.appendChild(el);
                console.warn(`[Anti-Purge] Restored #${el.id} after innerHTML wipe.`);
            });
        },
        get: originalInnerHTML.get
    });

    // ==========================================
    // 2. MUTATION OBSERVER (Reactive Fallback)
    // ==========================================
    
    const observer = new MutationObserver((mutations) => {
        mutations.forEach(mutation => {
            mutation.removedNodes.forEach(node => {
                if (node.nodeType === Node.ELEMENT_NODE) {
                    // Check if the node itself is protected
                    if (protectedIDs.has(node.id)) {
                        document.body.appendChild(protectedElements.get(node.id));
                        console.warn(`[Anti-Purge] Observer restored orphaned element: #${node.id}`);
                    } 
                    // Check if the removed node *contained* our protected element
                    else {
                        protectedIDs.forEach(id => {
                            if (node.querySelector(`#${id}`)) {
                                document.body.appendChild(protectedElements.get(id));
                                console.warn(`[Anti-Purge] Observer restored element #${id} from purged parent container.`);
                            }
                        });
                    }
                }
            });
        });
    });

    win.addEventListener('DOMContentLoaded', () => {
        observer.observe(document.body, { childList: true, subtree: true });
    });

    // ==========================================
    // 3. EXPORTED API
    // ==========================================
    
    win.AntiPurge = {
        /**
         * Registers an element to be protected from DOM deletion.
         * @param {HTMLElement} element - The DOM node to protect. Must have a unique ID.
         */
        protect: function(element) {
            if (!element.id) {
                console.error('[Anti-Purge] Element must have an ID to be protected.');
                return;
            }
            protectedIDs.add(element.id);
            protectedElements.set(element.id, element);
            console.log(`[Anti-Purge] Now protecting: #${element.id}`);
        },

        /**
         * Unregisters an element, allowing normal deletion.
         * @param {string} id - The ID of the element to release.
         */
        release: function(id) {
            protectedIDs.delete(id);
            protectedElements.delete(id);
            console.log(`[Anti-Purge] Released protection for: #${id}`);
        }
    };

})(typeof unsafeWindow !== 'undefined' ? unsafeWindow : window);