tohle jsem mírně vylepšil, opět raději používejte whitelistem jenom na stránkách, kde nejde kopírovat text (jako třeba odemčené premiové články na idnes.cz)
// ==UserScript==
// @namespace         
https://www.github.com/Cat7373/// @name              Remove web limits
// @description       Pass to kill most of the site, you can lift the restrictions prohibited to copy, cut, select the text, right-click menu.
// @homepageURL       
https://cat7373.github.io/remove-web-limits/// @supportURL        
https://github.com/Cat7373/remove-web-limits/issues/// @author            Cat73 + Claude.ai
// @version           1.4
// @license           LGPLv3
// @compatible        chrome Chrome_46.0.2490.86 + TamperMonkey + Script_1.3 tested
// @compatible        firefox Firefox_42.0 + GreaseMonkey + Script_1.2.1 tested
// @compatible        opera Opera_33.0.1990.115 + TamperMonkey + Script_1.1.3 tested
// @compatible        safari Not tested
// @match             *://*/*
// @grant             none
// @run-at            document-start
// ==/UserScript==
(function() {
  'use strict';
  // ========== USER CONFIGURATION ==========
  // Set to 0 to disable DOM clearing loop completely
  // Set to positive number (milliseconds) to enable periodic clearing
  // Example: 60000 = 1 minute, 30000 = 30 seconds, 0 = disabled
  const DOM_CLEAR_INTERVAL = 0; // Default: disabled for performance
  // Delay before first DOM clear after page load (milliseconds)
  const INITIAL_CLEAR_DELAY = 2500;
  // Enable/disable aggressive mode (processes all elements vs only interactive ones)
  const AGGRESSIVE_MODE = false;
  // Enable console debugging messages
  const DEBUG_MODE = false;
  // ========================================
  // Domain rules list
  var rules = {
    black_rule: {
      name: "black",
      hook_eventNames: "",
      unhook_eventNames: ""
    },
    default_rule: {
      name: "default",
      hook_eventNames: "contextmenu|select|selectstart|copy|cut|dragstart",
      unhook_eventNames: "mousedown|mouseup|keydown|keyup",
      dom0: true,
      hook_addEventListener: true,
      hook_preventDefault: true,
      hook_set_returnValue: true,
      add_css: true
    },
    // Lighter rule for sites that need some functionality
    light_rule: {
      name: "light",
      hook_eventNames: "copy|cut|selectstart",
      unhook_eventNames: "",
      dom0: false,
      hook_addEventListener: true,
      hook_preventDefault: false,
      hook_set_returnValue: false,
      add_css: true
    }
  };
  // Domain lists
  var lists = {
    // Blacklist - sites to completely skip
    black_list: [
      /.*\.youtube\.com.*/,
      /.*\.wikipedia\.org.*/,
      /mail\.qq\.com.*/,
      /translate\.google\..*/,
      /docs\.google\.com.*/,
      /drive\.google\.com.*/,
      /.*\.github\.com.*/,
      /.*\.gmail\.com.*/,
      /.*\.outlook\.com.*/,
      /.*\.office\.com.*/
    ],
    // Light touch list - sites that need minimal intervention
    light_list: [
      /.*\.medium\.com.*/,
      /.*\.quora\.com.*/,
      /.*\.stackoverflow\.com.*/,
      /.*\.reddit\.com.*/
    ]
  };
  // Event lists to process
  var hook_eventNames, unhook_eventNames, eventNames;
  // Storage name for namespacing
  var storageName = getRandStr('qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM', parseInt(Math.random() * 12 + 8));
  // Store hooked functions
  var EventTarget_addEventListener = EventTarget.prototype.addEventListener;
  var document_addEventListener = document.addEventListener;
  var Event_preventDefault = Event.prototype.preventDefault;
  // Hook addEventListener process
  function addEventListener(type, func, useCapture) {
    try {
      var _addEventListener = this === document ? document_addEventListener : EventTarget_addEventListener;
      if(hook_eventNames.indexOf(type) >= 0) {
        _addEventListener.apply(this, [type, returnTrue, useCapture]);
      } else if(this && unhook_eventNames.indexOf(type) >= 0) {
        var funcsName = storageName + type + (useCapture ? 't' : 'f');
        if(this[funcsName] === undefined) {
          this[funcsName] = [];
          _addEventListener.apply(this, [type, useCapture ? unhook_t : unhook_f, useCapture]);
        }
        this[funcsName].push(func);
      } else {
        _addEventListener.apply(this, arguments);
      }
    } catch(e) {
      if(DEBUG_MODE) console.error('addEventListener hook error:', e);
      // Fallback to original function
      EventTarget_addEventListener.apply(this, arguments);
    }
  }
  // Clear DOM0 event handlers
  function clearLoop() {
    try {
      var elements = getElements();
      for(var i in elements) {
        // Skip if element is null or undefined
        if(!elements[i]) continue;
        for(var j in eventNames) {
          var name = 'on' + eventNames[j];
          // Check if property exists and is modifiable
          try {
            if(elements[i][name] !== null && elements[i][name] !== onxxx) {
              if(unhook_eventNames.indexOf(eventNames[j]) >= 0) {
                elements[i][storageName + name] = elements[i][name];
                elements[i][name] = onxxx;
              } else {
                elements[i][name] = null;
              }
            }
          } catch(e) {
            // Some properties might be read-only, skip them
            if(DEBUG_MODE) console.warn('Cannot modify property:', name, 'on element:', elements[i]);
          }
        }
      }
    } catch(e) {
      if(DEBUG_MODE) console.error('clearLoop error:', e);
    }
  }
  // Return true function
  function returnTrue(e) {
    return true;
  }
  function unhook_t(e) {
    return unhook(e, this, storageName + e.type + 't');
  }
  function unhook_f(e) {
    return unhook(e, this, storageName + e.type + 'f');
  }
  function unhook(e, self, funcsName) {
    try {
      var list = self[funcsName];
      if(list && Array.isArray(list)) {
        for(var i in list) {
          if(typeof list[i] === 'function') {
            list[i](e);
          }
        }
      }
    } catch(ex) {
      if(DEBUG_MODE) console.error('unhook error:', ex);
    }
    e.returnValue = true;
    return true;
  }
  function onxxx(e) {
    try {
      var name = storageName + 'on' + e.type;
      if(this[name] && typeof this[name] === 'function') {
        this[name](e);
      }
    } catch(ex) {
      if(DEBUG_MODE) console.error('onxxx error:', ex);
    }
    e.returnValue = true;
    return true;
  }
  // Get random string for namespacing
  function getRandStr(chs, len) {
    var str = '';
    while(len--) {
      str += chs[parseInt(Math.random() * chs.length)];
    }
    return str;
  }
  // Get elements to process - improved version
  function getElements() {
    try {
      if(AGGRESSIVE_MODE) {
        // Original aggressive mode - gets ALL elements
        var elements = Array.prototype.slice.call(document.getElementsByTagName('*'));
        elements.push(document);
        return elements;
      } else {
        // Optimized mode - only get potentially problematic elements
        var elements = [];
        // Add document
        elements.push(document);
        // Add body if it exists
        if(document.body) {
          elements.push(document.body);
        }
        // Add common interactive elements
        var selectors = ['a', 'button', 'input', 'textarea', 'select', 'img', 'video', 'audio', 'canvas', 'svg'];
        selectors.forEach(function(selector) {
          try {
            var found = document.querySelectorAll(selector);
            elements = elements.concat(Array.prototype.slice.call(found));
          } catch(e) {
            // Selector might fail on some pages
          }
        });
        // Add elements with text content that might be restricted
        var textElements = document.querySelectorAll('p, div, span, article, section, main, h1, h2, h3, h4, h5, h6, pre, code');
        // Only add first 100 to avoid performance issues
        var textArray = Array.prototype.slice.call(textElements, 0, 100);
        elements = elements.concat(textArray);
        return elements;
      }
    } catch(e) {
      if(DEBUG_MODE) console.error('getElements error:', e);
      // Return at least document to avoid complete failure
      return [document];
    }
  }
  // Add CSS styles
  function addStyle(css) {
    try {
      // Check if head exists, wait if not
      if(!document.head) {
        setTimeout(function() { addStyle(css); }, 100);
        return;
      }
      var style = document.createElement('style');
      style.innerHTML = css;
      document.head.appendChild(style);
    } catch(e) {
      if(DEBUG_MODE) console.error('addStyle error:', e);
    }
  }
  // Get rule for target domain
  function getRule(url) {
    function testUrl(list, url) {
      for(var i in list) {
        if(list[i].test(url)) {
          return true;
        }
      }
      return false;
    }
    // Check blacklist first
    if(testUrl(lists.black_list, url)) {
      return rules.black_rule;
    }
    // Check light list
    if(testUrl(lists.light_list, url)) {
      return rules.light_rule;
    }
    return rules.default_rule;
  }
  // Initialize script
  function init() {
    try {
      // Get rule for current domain
      var url = window.location.host + window.location.pathname;
      var rule = getRule(url);
      // Exit early if blacklisted
      if(rule.name === 'black') {
        if(DEBUG_MODE) console.log('Site blacklisted, script disabled');
        return;
      }
      // Set event lists
      hook_eventNames = rule.hook_eventNames.split("|").filter(function(x) { return x; });
      unhook_eventNames = rule.unhook_eventNames.split("|").filter(function(x) { return x; });
      eventNames = hook_eventNames.concat(unhook_eventNames);
      // Set up DOM0 event clearing
      if(rule.dom0) {
        // Only set interval if user configured it
        if(DOM_CLEAR_INTERVAL > 0) {
          setInterval(clearLoop, DOM_CLEAR_INTERVAL);
          if(DEBUG_MODE) console.log('DOM clear interval set to:', DOM_CLEAR_INTERVAL, 'ms');
        }
        // Initial clear after delay
        setTimeout(clearLoop, INITIAL_CLEAR_DELAY);
        // Clear on page load
        window.addEventListener('load', clearLoop, true);
        // Initial immediate clear
        clearLoop();
      }
      // Hook addEventListener
      if(rule.hook_addEventListener) {
        EventTarget.prototype.addEventListener = addEventListener;
        document.addEventListener = addEventListener;
      }
      // Hook preventDefault
      if(rule.hook_preventDefault) {
        Event.prototype.preventDefault = function() {
          if(eventNames.indexOf(this.type) < 0) {
            Event_preventDefault.apply(this, arguments);
          }
        };
      }
      // Hook set returnValue
      if(rule.hook_set_returnValue) {
        try {
          Event.prototype.__defineSetter__('returnValue', function() {
            if(this.returnValue !== true && eventNames.indexOf(this.type) >= 0) {
              this.returnValue = true;
            }
          });
        } catch(e) {
          // __defineSetter__ might not be available in all browsers
          if(DEBUG_MODE) console.warn('Cannot set returnValue setter:', e);
        }
      }
      if(DEBUG_MODE) {
        console.log('Remove Web Limits - Initialized');
        console.log('URL:', url);
        console.log('Storage Name:', storageName);
        console.log('Rule:', rule.name);
        console.log('DOM Clear Interval:', DOM_CLEAR_INTERVAL || 'disabled');
      }
      // Add CSS
      if(rule.add_css) {
        addStyle('html, * {-webkit-user-select:text!important; -moz-user-select:text!important; user-select:text!important; -ms-user-select:text!important; -khtml-user-select:text!important;}');
      }
    } catch(e) {
      console.error('Remove Web Limits - Initialization failed:', e);
    }
  }
  // Start the script
  init();
})();