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();
})();