Skip to content

Instantly share code, notes, and snippets.

@olragon
Last active March 22, 2025 05:14
Show Gist options
  • Save olragon/39b6682b5c600a064caa1b956b51a599 to your computer and use it in GitHub Desktop.
Save olragon/39b6682b5c600a064caa1b956b51a599 to your computer and use it in GitHub Desktop.
TamperMonkey Script to force text selectable
// ==UserScript==
// @name Blagu - Text Selectable
// @namespace http://tampermonkey.net/
// @version 1.1
// @description Enables text selection, right-click and copy/paste on website by removing protections
// @author You
// @match *://*.5office.vn/*
// @match *://*.officesaigon.vn/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
// Function to create and inject CSS to force text selection
function injectCSS() {
const style = document.createElement('style');
style.textContent = `
* {
-webkit-user-select: text !important;
-moz-user-select: text !important;
-ms-user-select: text !important;
user-select: text !important;
cursor: auto !important;
}
[unselectable="on"],
[onselectstart="return false;"],
[ondragstart="return false;"],
[onmousedown="return false;"],
[style*="user-select: none"],
[style*="-webkit-user-select: none"],
[style*="-moz-user-select: none"],
[style*="-ms-user-select: none"] {
-webkit-user-select: text !important;
-moz-user-select: text !important;
-ms-user-select: text !important;
user-select: text !important;
}
/* Force highlighting styles for text selection */
::selection {
background-color: #3390ff !important;
color: white !important;
text-shadow: none !important;
opacity: 1 !important;
visibility: visible !important;
}
::-moz-selection {
background-color: #3390ff !important;
color: white !important;
text-shadow: none !important;
opacity: 1 !important;
visibility: visible !important;
}
`;
document.head.appendChild(style);
}
// Call immediately to ensure CSS is applied early
injectCSS();
// Run immediately
disableCopyInterception();
// Also run when DOM is ready (some sites add protection later)
document.addEventListener('DOMContentLoaded', disableCopyInterception);
// Run whenever the page changes (for single-page applications)
const observer = new MutationObserver(function() {
disableCopyInterception();
});
// Start observing once the body is available
window.addEventListener('load', function() {
if (document.body) {
observer.observe(document.body, {
childList: true,
subtree: true
});
}
});
// Function to remove event listeners that prevent selection
function removeProtections() {
// Override specific functions to make text selectable
window.disableSelection = function() { return true; };
window.nocontext = function() { return true; };
window.wccp_pro_iscontenteditable = function() { return true; };
window.wccp_pro_iscontenteditable_flag = true;
window.disable_copy = function() { return true; };
window.isDraggable = true;
window.disable_hot_keys = function() { return true; };
window.call_disable_copy_WithDelay = function() { return true; };
window.disable_copy_ie = function() { return true; };
window.disable_drag_text = function() { return true; };
window.wccp_pro_clear_any_selection = function() { return true; };
window.preventStopSelection = function() { return true; };
// Prevent any selection clearing functions
window.getSelection().removeAllRanges = function() {};
window.getSelection().empty = function() {};
// Remove the masks used to block selection
const masks = document.querySelectorAll('#wccp_pro_mask');
masks.forEach(mask => {
if (mask) mask.remove();
});
// Remove the error message shown when trying to select text
const errorMsgs = document.querySelectorAll('#wpcp-error-message');
errorMsgs.forEach(msg => {
if (msg) msg.remove();
});
// Clean up any context menu prevention
document.oncontextmenu = null;
document.onmousedown = null;
document.onmouseup = null;
document.onselectionchange = null;
document.onselectstart = null;
document.ondragstart = null;
}
// Function to disable copy event interception
function disableCopyInterception() {
// Store original functions
const originalAddEventListener = EventTarget.prototype.addEventListener;
const originalRemoveEventListener = EventTarget.prototype.removeEventListener;
// Override addEventListener to prevent copy event blocking
EventTarget.prototype.addEventListener = function(type, listener, options) {
// Skip intercepting 'copy', 'cut', 'contextmenu' event listeners
if (type === 'copy' || type === 'cut' || type === 'contextmenu') {
console.log('Blocked attempt to intercept:', type);
return;
}
// Call original method for other events
return originalAddEventListener.call(this, type, listener, options);
};
// Override removeEventListener to maintain consistency
EventTarget.prototype.removeEventListener = function(type, listener, options) {
// Skip for copy-related events
if (type === 'copy' || type === 'cut' || type === 'contextmenu') {
return;
}
// Call original method for other events
return originalRemoveEventListener.call(this, type, listener, options);
};
// Remove any existing copy protection
document.oncopy = null;
document.oncut = null;
document.oncontextmenu = null;
// Enable context menu
document.addEventListener('contextmenu', function(e) {
e.stopImmediatePropagation();
}, true);
// Enable copy
document.addEventListener('copy', function(e) {
e.stopImmediatePropagation();
}, true);
// Enable cut
document.addEventListener('cut', function(e) {
e.stopImmediatePropagation();
}, true);
// Disable user-select: none CSS property
const style = document.createElement('style');
style.textContent = `
* {
-webkit-user-select: auto !important;
-moz-user-select: auto !important;
-ms-user-select: auto !important;
user-select: auto !important;
}
`;
document.head.appendChild(style);
console.log('Copy Protection Bypass: Enabled');
}
// Observe and disable any dynamically added protections or scripts
function createObserver() {
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
for (let i = 0; i < mutation.addedNodes.length; i++) {
const node = mutation.addedNodes[i];
// Remove any script blocks that might be reinserting protections
if (node.tagName === 'SCRIPT' &&
(node.innerHTML.includes('wccp_pro') ||
node.innerHTML.includes('disable_copy') ||
node.innerHTML.includes('nocontext'))) {
node.remove();
}
// Remove any added protection masks
if (node.id === 'wccp_pro_mask' || node.id === 'wpcp-error-message') {
node.remove();
}
}
}
});
// Reapply our changes to ensure they stick
removeProtections();
});
// Start observing the document with the configured parameters
observer.observe(document.documentElement, {
childList: true,
subtree: true
});
}
// Clean up any existing inline event handlers that block selection
function cleanupInlineHandlers() {
const elements = document.querySelectorAll('*');
elements.forEach(el => {
if (el.hasAttribute('oncontextmenu')) el.removeAttribute('oncontextmenu');
if (el.hasAttribute('onselectstart')) el.removeAttribute('onselectstart');
if (el.hasAttribute('ondragstart')) el.removeAttribute('ondragstart');
if (el.hasAttribute('onmousedown')) el.removeAttribute('onmousedown');
if (el.hasAttribute('onmouseup')) el.removeAttribute('onmouseup');
if (el.hasAttribute('oncopy')) el.removeAttribute('oncopy');
if (el.hasAttribute('oncut')) el.removeAttribute('oncut');
});
}
// Function to disable all related protections
function disableAllProtections() {
// Add toggle button with close feature
const button = document.createElement('div');
button.id = 'text-selection-toggle';
button.innerHTML = 'T';
button.title = 'Text selection enabled (click to toggle)';
button.style.position = 'fixed';
button.style.bottom = '20px';
button.style.right = '20px';
button.style.zIndex = '9999';
button.style.background = '#4CAF50';
button.style.color = 'white';
button.style.border = 'none';
button.style.borderRadius = '50%';
button.style.width = '48px';
button.style.height = '48px';
button.style.fontSize = '20px';
button.style.cursor = 'pointer';
button.style.display = 'flex';
button.style.alignItems = 'center';
button.style.justifyContent = 'center';
button.style.boxShadow = '0 2px 5px rgba(0,0,0,0.3)';
// Add close button
const closeBtn = document.createElement('div');
closeBtn.className = 'close-btn';
closeBtn.innerHTML = '×';
closeBtn.title = 'Hide button';
closeBtn.style.position = 'absolute';
closeBtn.style.top = '-8px';
closeBtn.style.right = '-8px';
closeBtn.style.backgroundColor = '#333';
closeBtn.style.color = 'white';
closeBtn.style.border = '2px solid white';
closeBtn.style.borderRadius = '50%';
closeBtn.style.width = '20px';
closeBtn.style.height = '20px';
closeBtn.style.fontSize = '12px';
closeBtn.style.display = 'flex';
closeBtn.style.alignItems = 'center';
closeBtn.style.justifyContent = 'center';
closeBtn.style.cursor = 'pointer';
closeBtn.onclick = function(e) {
e.stopPropagation();
button.style.display = 'none';
};
button.appendChild(closeBtn);
let isEnabled = true;
button.addEventListener('click', function() {
isEnabled = !isEnabled;
if (isEnabled) {
button.style.backgroundColor = '#4CAF50';
injectCSS();
removeProtections();
cleanupInlineHandlers();
} else {
button.style.backgroundColor = '#f44336';
}
});
// Wait for the body to be available
if (document.body) {
document.body.appendChild(button);
} else {
window.addEventListener('DOMContentLoaded', function() {
document.body.appendChild(button);
});
}
// Apply all protections
injectCSS();
removeProtections();
cleanupInlineHandlers();
createObserver();
// Intercept and prevent protection functions
window.addEventListener('DOMContentLoaded', function() {
removeProtections();
cleanupInlineHandlers();
});
}
// Execute immediately
disableAllProtections();
// Also run when page is fully loaded
window.addEventListener('load', function() {
disableAllProtections();
});
// Prevent any selection clearing attempts by overriding related functions
const originalGetSelection = window.getSelection;
window.getSelection = function() {
const selection = originalGetSelection.apply(this, arguments);
// Override selection clearing methods
if (selection) {
const originalEmpty = selection.empty;
const originalRemoveAllRanges = selection.removeAllRanges;
selection.empty = function() {
// Do nothing to prevent clearing selection
return selection;
};
selection.removeAllRanges = function() {
// Do nothing to prevent clearing selection
return selection;
};
}
return selection;
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment