A Universal Script to Re-Enable the Selection and Copying

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

2021-06-13 या दिनांकाला. सर्वात नवीन आवृत्ती पाहा.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

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

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

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

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==UserScript==
// @name         A Universal Script to Re-Enable the Selection and Copying
// @name:zh-TW   A Universal Script to Re-Enable the Selection and Copying
// @version      1.6.0a2
// @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://greatest.deepsurf.us/users/371179
// ==/UserScript==
'use strict';
(function $$($) {

    console.log('script at', location + " #1")
    if (document == null || !document.documentElement) return window.requestAnimationFrame($$); // this is tampermonkey bug?? not sure

    console.log('script at', location + " #2")

    function isPassiveEventListenerSupporting() {
        if ('_bPassive' in $) return $._bPassive
        var supportsPassive = false;
        document.createAttribute('z').addEventListener('', null, {
            get passive() {
                supportsPassive = true;
            }
        });
        return ($._bPassive = supportsPassive);
    }

    var mKey = 'dqzadwpujtct';
    var _ksNonFalseFunc = '___nff_' + mKey + '___',
        _ksReturnValue = '___returnValue_' + mKey + '___';

    $ = {
        utSelectionColorHack: 'msmtwejkzrqa',
        utTapHighlight: 'xfcklblvkjsj',

        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 selectionStyle = window.getComputedStyle(elm, ':selection');
            if (/^rgba\(\d+,\s*\d+,\s*\d+,\s*0\)$/.test(selectionStyle.backgroundColor)) document.documentElement.setAttribute($.utSelectionColorHack, "");

            var elmStyle = window.getComputedStyle(elm)
            if (/^rgba\(\d+,\s*\d+,\s*\d+,\s*0\)$/.test(elmStyle.webkitTapHighlightColor)) document.documentElement.setAttribute($.utTapHighlight, "");

        },


        enableSelectClickCopy: function() {

            $.eyEvts = ['keydown', 'keyup', 'copy', 'contextmenu', 'select', 'selectstart', 'dragstart', 'beforecopy']; //slope: throughout


            function getClipText(evt) {

                var text;
                var clip = (evt.originalEvent || evt).clipboardData;
                if (clip) {
                    text = clip.getData('text/plain') || clip.getData('text/html');
                } else {
                    text = window.clipboardData.getData("text") || null;
                }
                return text;

            }

            function isDeactivePreventDefault(evt) {
                if ($.bypass) return false;
                var j = $.eyEvts.indexOf(evt.type);
                switch (j) {
                    case -1:
                        return false;
                    case 0:
                    case 1:
                        return (evt.keyCode == 67 && (evt.ctrlKey || evt.metaKey) && !evt.altKey && !evt.shiftKey && $.isAnySelection() === true);
                    case 2:
                        var dataTypeString = ((evt.clipboardData || {}).types || [])[0];
                        // see the richtext hack in https://www.cleancss.com/css-beautify/
                        // see https://developer.mozilla.org/zh-CN/docs/Web/API/Element/copy_event
                        // see https://w3c.github.io/clipboard-apis/#widl-ClipboardEvent-clipboardData

                        if (!dataTypeString) {
                            //no replacement data
                            return true;
                        } else if (window.getSelection().toString().trim()) {

                            //there is replacement data and the selection is not empty
                            console.log("copy event - clipboardData replacement is allowed and the selection is not empty", window.getSelection().toString().trim())
                            return false;
                        } else {
                            //there is replacement data and the selection is empty
                            return false;
                        }

                        default:
                            return true;
                }
            }

            Event.prototype.preventDefault = (function(f) {
                return function preventDefault() {
                    console.log(this.type, '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, true); // Capture Event; passive:false; expected occurrence COMPLETELY before Target Capture and Target Bubble
            }

            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 vv = 'gykqyzwufxpz';
            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;}
` + (1 ? `
            a:link, a:visited, a:active, a:link *, a:visited *, a:active *{
            -webkit-user-select: text !important;
            -khtml-user-select: text !important; -moz-user-select: text !important;
            -ms-user-select: text !important; user-select: text !important;
             }` : '') +
                /*
                                `
                            a[${vv}]:link,  a[${vv}]:visited, a[${vv}]:active,  a[${vv}]:link *, a[${vv}]:visited *, a[${vv}]:active *{
                            cursor:text !important; }` +*/

                `html[${vv}] *:hover { cursor:text !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;}
            [${$.utTapHighlight}] *{ -webkit-tap-highlight-color: rgba(0, 0, 0, 0.18) !important;}
            `.trim();

            $.enableSelectClickCopy()
            $.createCSSElement(cssStyleOnReady, document.documentElement);

        },

        mainEvents: (listenerPress, listenerRelease) => {
            (["mousedown", "click", "dblclick", "contextmenu"]).forEach(function(event) {
                document.addEventListener(event, listenerPress, true); // Capture Event; passive:false; ensure the occurrence of 1st capture event COMPLETELY before executing other listeners
            });
            document.addEventListener("mouseup", listenerRelease, false); // Bubble Event; passive: true/false; 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);
        });

    console.log('userscript running - To Re-Enable Selection & Copying');
    /*
        function anchorElm(targetElm) {

            var p = targetElm;
            while (p && p.nodeType > 0) {
                if (p.tagName == 'A') {
                    return p
                }
                p = p.parentNode
            }
            return null;

        }

        var disableLinkingAt = 0;
        var mouseDownHold = 0;
        var timeoutEndOfLinking = 0;

        var sequential = 0,
            fDragStart = 1<<3,
            fDelaySelectable = 1 << 4,
            fPressAnchor = 1 << 8,
            fSelectionChange=1<<5
        var initVariables = () => {
            timeoutEndOfLinking = 0;
            mouseDownHold = mouseDownHold ? clearTimeout(mouseDownHold) : 0;

            disableLinkingAt = 0;

            if ((sequential & fDelaySelectable) ? 1 : 0) {
                // remove selectable
                window.requestAnimationFrame(removeLinkSelectionAttr)

            }


            sequential = 0;

        }



        var removeLinkSelectionAttr = () => [...document.querySelectorAll(`[${'gykqyzwufxpz'}]`)].forEach(elm => elm.removeAttribute('gykqyzwufxpz'));

        var endOfLinkSelection = (evt) => {

            switch (true) {

                case !!(sequential & fDelaySelectable): // target might not be the same one as mousedown

                    disableLinkingAt = +new Date;


                   /\* fall through *\/

                case disableLinkingAt + 50 > +new Date:
                    $.bypass = true;
                    evt.preventDefault()
                    evt.stopPropagation();
                    evt.stopImmediatePropagation();
                    $.bypass = false;

            }


        }

        document.addEventListener('mousedown', function(evt) { // both draggable and non-draggable



            console.log('MOUSEDOWN', evt.target)




            initVariables()

            var targetElement = evt.target

            if(mouseDownHold>0)mouseDownHold=clearTimeout(mouseDownHold)
            mouseDownHold=setTimeout(function() {
            mouseDownHold=0


                var mAnchor = anchorElm(targetElement)
                if (mAnchor) {
                    sequential |= fPressAnchor;
                        if ($.isAnySelection() || mAnchor.hasAttribute('gykqyzwufxpz')) return; // pressing the selected text
                        mAnchor.setAttribute('gykqyzwufxpz', 1);
                        sequential |= fDelaySelectable;
                }


            },300);

        }, isPassiveEventListenerSupporting() ? {
            passive: true,
            capture: true
        } : true)

        document.addEventListener('dragstart', function(evt) { //draggable link only, always after mousedown
            sequential |= fDragStart;
            console.log('dragstart', evt.target)
            if (mouseDownHold > 0) mouseDownHold = clearTimeout(mouseDownHold);
            if (!!(sequential & fDelaySelectable)) {
                $.bypass = true;
                evt.preventDefault()
                evt.stopPropagation();
                evt.stopImmediatePropagation();
                $.bypass = false;
            }
        }, true);





        document.addEventListener('mouseup', function(evt) {

            console.log('onmouseup', evt.target)

            if (mouseDownHold > 0) mouseDownHold = clearTimeout(mouseDownHold);
            if(!!(sequential&fSelectionChange) && !(sequential & fDelaySelectable) && $.isAnySelection() ){
                   $.bypass = true;
                evt.preventDefault()
                evt.stopPropagation();
                evt.stopImmediatePropagation();
                $.bypass = false;

                disableLinkingAt = +new Date

                return

            }

            if (!!(sequential & fPressAnchor) && $.isAnySelection()) {


                if (!(sequential & fDelaySelectable)) disableLinkingAt = +new Date; // in case this is a selectable link

                endOfLinkSelection(evt)
            }


            if (!!(sequential & fPressAnchor) && !!(sequential & fDelaySelectable)) {

                timeoutEndOfLinking = clearTimeout(timeoutEndOfLinking)
                timeoutEndOfLinking = setTimeout(initVariables, 50)



            }

        }, true);


        document.addEventListener('click', function(evt) { // after mouseup - preventDefault to avoid linking


            console.log('onclick', evt.target)

            if (disableLinkingAt + 50 > +new Date) {
                $.bypass = true;
                evt.preventDefault()
                evt.stopPropagation();
                evt.stopImmediatePropagation();
                $.bypass = false;
            }

        }, true);


        document.addEventListener('dragend', function(evt) { //mouseup might be not triggered for draggable link

            console.log('dragend', evt.target)

            if (mouseDownHold > 0) mouseDownHold = clearTimeout(mouseDownHold);
            if (!!(sequential & fPressAnchor)) {

                endOfLinkSelection(evt)


                timeoutEndOfLinking = clearTimeout(timeoutEndOfLinking)
                timeoutEndOfLinking = setTimeout(initVariables, 50)



            }

        }, true)

        document.addEventListener('selectionchange', function(evt) { //mouseup might be not triggered for draggable link

            sequential|=fSelectionChange;

        },true)
    */
    /*
        var lastMouseDownAt=0, selectionActive=0, selectionChange=false

        document.addEventListener('mousedown', function(evt) {

            selectionActive=0;
            lastMouseDownAt=1;
            selectionChange=false;
            if(evt.target&&evt.target.nodeType>0){
                if(lastMouseDownAt==1)
            lastMouseDownAt=+new Date+370;
            }

        },false)


        document.addEventListener('mouseup', function(evt) {

            console.log('up', selectionActive)
        lastMouseDownAt=0
            if(selectionChange){
            selectionChange=false;
            document.documentElement.removeAttribute('gykqyzwufxpz')
            }
            if(selectionActive==1||selectionActive==2){

                $.bypass=true;
                    evt.preventDefault()
                    evt.stopPropagation();
                    evt.stopImmediatePropagation();
                $.bypass=false;
                selectionActive=2;
            }
        },true)


        document.addEventListener('click', function(evt) {
            if(selectionActive==2){

                $.bypass=true;
                    evt.preventDefault()
                    evt.stopPropagation();
                    evt.stopImmediatePropagation();
                $.bypass=false;
            }
        },true)


        document.addEventListener('dragstart', function(evt) {

            if(lastMouseDownAt>1000 && lastMouseDownAt< +new Date && !$.isAnySelection()){
            console.log(1212)
                $.bypass=true;
                    evt.preventDefault()
                    evt.stopPropagation();
                    evt.stopImmediatePropagation();
                $.bypass=false;
                //selectionActive=1;
            }else{
            document.documentElement.removeAttribute('gykqyzwufxpz')
            }

        })


        document.addEventListener('selectionchange', function(evt) {
        selectionChange=true;
            lastMouseDownAt=+new Date +180
            document.documentElement.setAttribute('gykqyzwufxpz','')
            if(selectionActive==0 && $.isAnySelection()) selectionActive=1;


        })
        */


})();