// ==UserScript==
// @name A Universal Script to Re-Enable the Selection and Copying
// @version 1.5.1
// @description Enables select, right-click, copy and drag on pages that disable them.
// @description:zh-TW 解除禁止復制、剪切、選擇文本、右鍵菜單的限制。
// @include /^https?\:\/\//
// @grant none
// @run-at document-start
// @namespace https://gf.qytechs.cn/users/371179
// ==/UserScript==
'use strict';
(function($) {
// console.log('script at', location+"")
if (document == null || !document.documentElement) return;
var mKey = 'dqzadwpujtct';
var _ksNonFalseFunc = '___nff_' + mKey + '___',
_ksReturnValue = '___returnValue_' + mKey + '___';
$ = {
utSelectionColorHack: 'msmtwejkzrqa',
mAlert_DOWN: function() {}, //dummy function in case alert replacement is not valid
mAlert_UP: function() {}, //dummy function in case alert replacement is not valid
isAnySelection: function() {
var sel = (window.getSelection || function() {})();
return !sel ? null : (typeof sel.isCollapsed == 'boolean') ? !sel.isCollapsed : (sel.toString().length > 0);
},
createCSSElement: function(cssStyle, container) {
var css = document.createElement('style'); //slope: DOM throughout
css.type = 'text/css';
css.innerHTML = cssStyle;
if (container) container.appendChild(css);
return css;
},
createFakeAlert: function(_alert) {
if (typeof _alert != 'function') return null;
function alert(msg) {
setTimeout(() => (alert.__isDisabled__() ? console.log("alert msg disabled: ", msg) : _alert.apply(this, arguments)), 9);
};
alert.toString = () => "function alert() { [native code] }";
return alert;
},
createFuncReplacer: function(originalFunc, pName, resFX) {
resFX = function(ev) {
var res = originalFunc.apply(this, arguments);
if (!this || this[pName] != resFX) return res; // if this is null or undefined, or this.onXXX is not this function
if (res === false) return; // return undefined when "return false;"
originalFunc[_ksNonFalseFunc] = true;
this[pName] = originalFunc; // restore original
return res;
}
resFX.toString = () => originalFunc.toString();
return resFX;
},
listenerDisableAll: function(evt) {
var elmNode = evt.target;
while (elmNode && elmNode.nodeType > 0) { //i.e. HTMLDocument or HTMLElement
var pName = 'on' + evt.type
var f = elmNode[pName];
if (typeof f == 'function' && f[_ksNonFalseFunc] !== true) {
var nf = $.createFuncReplacer(f, pName);
nf[_ksNonFalseFunc] = true;
elmNode[pName] = nf;
}
elmNode = elmNode.parentNode;
}
},
onceCssHighlightSelection: () => {
$.onceCssHighlightSelection = null
var s = [...document.querySelectorAll('a,p,div,span,b,i,strong,li')].filter(elm => elm.childElementCount === 0); // randomly pick an element containing text only to avoid css style bug
var elm = !s.length ? document.body : s[s.length >> 1];
var bgColor = window.getComputedStyle(elm, ':selection').backgroundColor;
if (/^rgba\(\d+,\s*\d+,\s*\d+,\s*0\)$/.test(bgColor)) document.documentElement.setAttribute($.utSelectionColorHack, "");
},
enableSelectClickCopy: function() {
$.eyEvts = ['keydown', 'keyup', 'copy', 'contextmenu', 'select', 'selectstart', 'dragstart', 'beforecopy']; //slope: throughout
function isDeactivePreventDefault(evt) {
var j = $.eyEvts.indexOf(evt.type);
return (j >= 2) || ((j == 0 || j == 1) && evt.ctrlKey && evt.keyCode == 67 && !evt.altKey && !evt.shiftKey && $.isAnySelection() === true); //j<0 return false
}
Event.prototype.preventDefault = (function(f) {
return function preventDefault() {
if (!isDeactivePreventDefault(this)) f.apply(this);
}
})(Event.prototype.preventDefault);
Event.prototype.preventDefault.toString = () => "function preventDefault() { [native code] }"
Object.defineProperty(Event.prototype, "returnValue", {
get() {
return _ksReturnValue in this ? this[_ksReturnValue] : true;
},
set(newValue) {
if (!isDeactivePreventDefault(this) && newValue === false) this.preventDefault();
this[_ksReturnValue] = newValue;
},
enumerable: true,
configurable: true
});
for (var i = 2, eventsCount = $.eyEvts.length; i < eventsCount; i++) {
document.addEventListener($.eyEvts[i], $.listenerDisableAll, {
capture: true, // Capture Event
passive: false // expected occurrence COMPLETELY before Target Capture and Target Bubble
}, true);
}
var _alert = window.alert; //slope: temporary
if (typeof _alert == 'function') {
var _mAlert = $.createFakeAlert(_alert);
if (_mAlert) {
var lastClickAt = 0;
_mAlert.__isDisabled__ = () => lastClickAt + 50 > +new Date;
$.mAlert_DOWN = () => (lastClickAt = +new Date);
$.mAlert_UP = () => (lastClickAt = 0);
window.alert = _mAlert
}
}
},
mainEnableScript: () => {
var cssStyleOnReady = '*, body *, div, span, body *::before, body *::after, *:hover, *:link, *:visited, *:active , *[style], *[class]{' +
'-webkit-touch-callout: default !important; -webkit-user-select: auto !important; ' +
'-khtml-user-select: auto !important; -moz-user-select: auto !important; ' +
'-ms-user-select: auto !important; user-select: auto !important;}' +
'html body *:hover>img[src]{pointer-events:auto;}' +
'[' + $.utSelectionColorHack + '] :not(input):not(textarea)::selection{ background-color: Highlight !important; color: HighlightText !important;}' +
'[' + $.utSelectionColorHack + '] :not(input):not(textarea)::-moz-selection{ background-color: Highlight !important; color: HighlightText !important;}';
$.enableSelectClickCopy()
$.createCSSElement(cssStyleOnReady, document.documentElement);
},
mainEvents: (listenerPress, listenerRelease) => {
(["mousedown", "click", "dblclick", "contextmenu"]).forEach(function(event) {
document.addEventListener(event, listenerPress, {
capture: true, // Capture Event
passive: false // ensure the occurrence of 1st capture event COMPLETELY before executing other listeners
}, true);
});
document.addEventListener("mouseup", listenerRelease, {
capture: false, // Bubble Event
passive: true // order for releasing is insignificant
});
}
}
$.mainEnableScript();
$.mainEvents(function(evt) {
if ($.onceCssHighlightSelection) window.requestAnimationFrame($.onceCssHighlightSelection);
if (evt.type != "contextmenu" && evt.which != 3) return;
if ($.cid_mouseup > 0) $.cid_mouseup = clearTimeout($.cid_mouseup);
$.mAlert_DOWN();
},
function(evt) {
if (evt.which != 3) return;
$.cid_mouseup = setTimeout($.mAlert_UP, 17);
});
})();