Re-enabling context actions on websites
A disappointing trend I’ve seen recently has been for sites disabling context actions like copy, paste, select, or right click on their websites. Banks are notoriously bad at this - for some reason, they think it’s a “security feature” to not let you paste in your account number, instead requiring you to manually type it in.
I realized it should be fairly easy to set up some global event listeners in the page and prevent the overridden behavior.
/**
* Stops propagation of an event to other event listeners, while still allowing the event to complete in its native
* context
* @param {string} type - the event type, i.e. 'paste', 'keyup', etc
*/
function stopPropagationOfType(type) {
window.addEventListener(
type,
function (event) {
event.stopPropagation();
},
true
);
}
If you inject this into the page with stopPropagationOfType('paste');
, it will prevent any paste event listeners from running (which probably call e.preventDefault()
.
I created a chrome extension called PasteEnabler that you can use that reenables the following features:
- Ability to paste content
- Ability to copy content
- Ability to cut content
- Ability to right click content
- Ability to autocomplete certain inputs
- Ability to select text
- Ability to drag and drop text to/from inputs
The code is fairly straightforward, and has worked on every site I’ve tried.
/**
* Function invoked on every load of the script
*/
function checkCopyAndPaste() {
// enables paste on all items
stopPropagationOfType("paste");
// enables copying any inputs or text
stopPropagationOfType("copy");
// enables cutting text from an input
stopPropagationOfType("cut");
// enables drag + drop of text into input
stopPropagationOfType("drop");
// Enables autocomplete on all elements that have it
const autocompleteDisabled = document.querySelectorAll("[autocomplete]");
for (const elem of autocompleteDisabled) {
elem.setAttribute("autocomplete", "on");
}
// enables right click context menu
stopPropagationOfType("contextmenu");
// Finds all elements and adds the user-select CSS property as text
// note - this is a *little* hacky, but it's the only way I've found to get it to work, since user-select is not
// inherited
const elements = document.body.getElementsByTagName("*");
if (elements.length) {
for (const elem of elements) {
addStyle(elem, "user-select", "text", true);
}
}
// enables text selection
stopPropagationOfType("selectstart");
// Enables dragging on all elements that have it
const draggableDisabled = document.querySelectorAll("[draggable]");
for (const elem of draggableDisabled) {
elem.setAttribute("draggable", "auto");
}
}
/**
* Adds the given CSS property and value to a DOM element.
* @param {HTMLElement} element - element we are adding the CSS property to
* @param {string} property - CSS property name, accepts hyphenated form (i.e. user-select rather than userSelect)
* @param {string} value - CSS property value
* @param {boolean} important - whether to add !important
*/
function addStyle(element, property, value, important) {
//remove previously defined property
if (element.style.setProperty) {
element.style.setProperty(property, "");
} else {
element.style.setAttribute(property, "");
}
//insert the new style with all the old rules
element.setAttribute(
"style",
element.style.cssText +
property +
":" +
value +
(important ? " !important" : "") +
";"
);
}
The entirety of the package is open source, and can be found on GitHub.
JonLuca at 01:25