Anti-UI Purge Library

Prevents specified DOM elements from being destroyed by page state changes

Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greasyfork.org/scripts/584836/1863342/Anti-UI%20Purge%20Library.js

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Violentmonkey installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Violentmonkey installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Userscripts installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey installieren.

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

(Ich habe bereits einen Benutzerstil Verwaltung, ich möchte ihn installieren!)

// ==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);