A Universal Script to Re-Enable the Selection and Copying

Enables select, right-click, copy and drag on pages that disable them.

目前為 2021-06-11 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         A Universal Script to Re-Enable the Selection and Copying
// @version      1.4.0
// @description  Enables select, right-click, copy and drag on pages that disable them.
// @include      /^https?\:\/\//
// @grant        none
// @run-at       document-start
// @namespace https://greasyfork.org/users/371179
// ==/UserScript==
"use strict";
(function(usrScrDS) {

    function isDocumentObj(x) {
        return x && x.nodeType == 9
    }

    function isHTMLElementObj(x) {
        return x && x.nodeType == 1
    }

    function appendCssEnabler(container, cssStyle) {
        if (!isHTMLElementObj(container)) return;
        try {
            var css = document.createElement('style');
            css.type = 'text/css';
            css.innerHTML = cssStyle;
            container.appendChild(css);
        } catch (e) {}
    }

    // console.log('script at', location+"")
    if (document == null) return;
    if (!document.documentElement) return;

    var mKey = 'dqzadwpujtct';
    var nonFalseFunc = '___nff_' + mKey + '___';
    var rvSCC = '___returnValue_' + mKey + '___';


    usrScrDS.utSelectionColorHack = 'msmtwejkzrqa';

    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;}' +
        '[' + usrScrDS.utSelectionColorHack + '] :not(input):not(textarea)::selection{ background-color: Highlight !important; color: HighlightText !important;}' +
        '[' + usrScrDS.utSelectionColorHack + '] :not(input):not(textarea)::-moz-selection{ background-color: Highlight !important; color: HighlightText !important;}';

    //dummy function in case alert replacement is not valid
    usrScrDS.mAlert_DOWN = function() {}
    usrScrDS.mAlert_UP = function() {}

    function universaler(originalFunc, pName) {
        var uid = (+new Date) + "_" + pName
        var resFX = function(ev) {
            var func;
            var p = false;
            try {
                func = this[pName];
                if (typeof func == 'function' && func.uid === uid) {
                    p = true;
                }
            } catch (e) {}
            var res = originalFunc.apply(this, arguments);
            if (p) {
                if (res !== false) {
                    originalFunc[nonFalseFunc] = true;
                    this[pName] = originalFunc;
                    return res;
                }
            } else {
                return res;
            }
        }
        resFX.toString = () => originalFunc.toString()
        resFX.uid = uid
        return resFX;
    }


    usrScrDS.evtListener_disableAll =
        function disableAll(event) {
            var elmNode = event.target
            while (elmNode && elmNode.nodeType > 0) {
                var pName = 'on' + event.type
                var f = elmNode[pName];
                if (f && f[nonFalseFunc] !== true) {
                    var nf = universaler(f, pName);
                    nf[nonFalseFunc] = true;
                    elmNode[pName] = nf;
                }
                elmNode = elmNode.parentNode;
            }
        }


    usrScrDS.isAnySelection =
        function anySelection() {
            var sel = (window.getSelection || function() {})();
            if (!sel) return null;
            if (typeof sel.isCollapsed == 'boolean') return !sel.isCollapsed;
            return sel.toString().length > 0
        }

    usrScrDS.productFakeAlert = function(_alert) {

        var _mAlert = null;

        if (_alert && typeof _alert == 'function') {
            _mAlert = function alert(msg) {
                setTimeout(() => {
                    alert._click.isDisabled() ? console.log("alert msg disabled: ", msg) : _alert.apply(this, arguments)
                }, 9);
            };
            _mAlert.toString = () => "function alert() { [native code] }"
        }

        return _mAlert


    }

    function enableSelectClickCopy() {

        var preventEventList01 = ['copy', 'contextmenu', 'select', 'selectstart', 'dragstart', 'beforecopy'];

        var isAnySelection = usrScrDS.isAnySelection

        Event.prototype.preventDefault = (function(f) {
            var eys = preventEventList01;
            return function preventDefault() {
                if (eys.indexOf(this.type) >= 0) return;
                if (this.type == 'keydown' || this.type == 'keyup') {
                    if (this.ctrlKey && this.keyCode == 67 && !this.altKey && !this.shiftKey && isAnySelection() === true) return;
                }
                return f.apply(this);
            }
        })(Event.prototype.preventDefault);
        Event.prototype.preventDefault.toString = () => "function preventDefault() { [native code] }"

        var exs = preventEventList01;
        Object.defineProperty(Event.prototype, "returnValue", {
            get() {
                return rvSCC in this ? this[rvSCC] : true;
            },
            set(newValue) {
                if (exs.indexOf(this.type) < 0 && newValue === false) this.preventDefault();
                this[rvSCC] = newValue;
            },
            enumerable: true,
            configurable: true
        });

        var ezs = preventEventList01;
        var eventsCount = ezs.length;

        for (var i = 0; i < eventsCount; i++) {
            var event = ezs[i];
            document.addEventListener(event, usrScrDS.evtListener_disableAll, true);
        }


        var _alert = window.alert
        if (_alert && typeof _alert == 'function') {
            var _mAlert = usrScrDS.productFakeAlert(_alert)
            if (_mAlert) {
                var clickLog = {
                    isDisabled: function() {
                        return this.status == 1 && this.last + 50 > +new Date;
                    }
                }
                _mAlert._click = clickLog
                usrScrDS.mAlert_DOWN = function() {
                    clickLog.last = +new Date;
                    clickLog.status = 1;
                }
                usrScrDS.mAlert_UP = function() {
                    clickLog.last = +new Date;
                    clickLog.status = 0;
                }
                window.alert = _mAlert
            }
        }


        usrScrDS.trigger_cssHighlight = () => {
            usrScrDS.trigger_cssHighlight = null
            try {
                //firefox bug: some element, even body, gives wrong bg color -> choose random element on the page.
                var s = [...document.querySelectorAll('a,p,div,span,b,i,strong,li')].filter(elm => elm.childElementCount === 0);
                var elm = (!s.length) ? document.body : s[s.length >> 1];
                var styles = window.getComputedStyle(elm, ':selection');
                var bgColor = styles["backgroundColor"]
                if (/^rgba\(\d+,\s*\d+,\s*\d+,\s*0\)$/.test(bgColor)) document.documentElement.setAttribute(usrScrDS.utSelectionColorHack, "");
            } catch (e) {}

        };


    }

    enableSelectClickCopy()
    appendCssEnabler(document.documentElement, cssStyleOnReady);


    var cid_mouseup = 0;

    var alert_bypass_events_down = ["mousedown", "click", "dblclick", "contextmenu"];
    var alert_bypass_eventFunc_down = function(evt) {
        if (usrScrDS.trigger_cssHighlight) window.requestAnimationFrame(usrScrDS.trigger_cssHighlight);
        if (evt.type != "contextmenu" && evt.which != 3) return;
        if (cid_mouseup > 0) {
            clearTimeout(cid_mouseup)
            cid_mouseup = 0;
        }
        usrScrDS.mAlert_DOWN();
    }
    var alert_bypass_eventFunc_up = function(evt) {
        if (evt.which != 3) return;
        cid_mouseup = setTimeout(function() {
            usrScrDS.mAlert_UP();
        }, 17);
    }

    alert_bypass_events_down.forEach(function(event) {
        document.addEventListener(event, alert_bypass_eventFunc_down, true);
    })

    document.addEventListener("mouseup", alert_bypass_eventFunc_up, true);


})({});