Enable Copy-Paste

Force-enables copy, paste, context menu, and keyboard shortcuts by monkey-patching and piercing Shadow DOM.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name         Enable Copy-Paste
// @version      3.0
// @description  Force-enables copy, paste, context menu, and keyboard shortcuts by monkey-patching and piercing Shadow DOM.
// @description:en Force-enables copy, paste, context menu, and keyboard shortcuts by monkey-patching and piercing Shadow DOM.
// @match        *://*/*
// @grant        GM_addStyle
// @run-at       document-start
// @namespace    http://tampermonkey.net/
// @license      LGPL-2.1
// ==/UserScript==

(function() {
    'use strict';

    // 1. Define CSS rules
    const cssRule = `
        *, *::before, *::after {
            -webkit-user-select: auto !important;
            -moz-user-select: auto !important;
            -ms-user-select: auto !important;
            user-select: auto !important;
            -webkit-touch-callout: auto !important;
        }
    `;

    // 2. Inject CSS (Light DOM)
    GM_addStyle(cssRule);

    // 3. Pierce Shadow DOM
    const originalAttachShadow = Element.prototype.attachShadow;
    Element.prototype.attachShadow = function(options) {
        const shadowRoot = originalAttachShadow.call(this, options);
        const style = document.createElement('style');
        style.textContent = cssRule;
        shadowRoot.appendChild(style);
        return shadowRoot;
    };

    // 4. Block Event Listeners

    // Events to simply block
    const simpleForbiddenEvents = [
        'copy', 'paste', 'cut',
        'selectstart',
        'contextmenu',
        'dragstart'
    ];

    // Keyboard events for smart handling
    const keyboardEvents = ['keydown', 'keyup', 'keypress'];

    // Shortcut detection
    const isShortcut = (e) => {
        return (e.ctrlKey || e.metaKey) &&
               ['c', 'v', 'x', 'a', 'insert'].includes(e.key.toLowerCase());
    };

    // Override addEventListener
    const originalAddEventListener = EventTarget.prototype.addEventListener;

    EventTarget.prototype.addEventListener = function(type, listener, options) {

        if (simpleForbiddenEvents.includes(type)) {
            console.log(`[Anti-Restrict] Blocked ${type} event listener.`);
            return;
        }

        if (keyboardEvents.includes(type)) {
            const wrappedListener = function(event) {
                if (isShortcut(event)) {
                    console.log(`[Anti-Restrict] Bypassed shortcut in ${type} event.`);
                    event.stopImmediatePropagation();
                } else {
                    Reflect.apply(listener, this, arguments);
                }
            };

            originalAddEventListener.call(this, type, wrappedListener, options);
            return;
        }

        originalAddEventListener.call(this, type, listener, options);
    };

    // 5. Clean up on* event handlers
    const clearOnEventHandlers = () => {
        const targets = [window, document, document.body];
        const eventHandlers = [
            'oncontextmenu', 'oncopy', 'oncut', 'onpaste',
            'onselectstart', 'ondragstart',
            'onkeydown', 'onkeyup', 'onkeypress'
        ];

        for (const target of targets) {
            if (!target) continue;
            for (const handler of eventHandlers) {
                try {
                    if (target[handler]) {
                        target[handler] = null;
                    }
                    Object.defineProperty(target, handler, {
                        value: null,
                        writable: true,
                        configurable: true
                    });
                } catch (e) {
                    // Ignore errors
                }
            }
        }
    };

    clearOnEventHandlers();
    window.addEventListener('load', clearOnEventHandlers);
    setTimeout(clearOnEventHandlers, 1500);

})();