Greasy Fork

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 提交的版本。查看 最新版本

// ==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);


})({});