A Universal Script to Re-Enable the Selection and Copying

Enables select, right-click, copy and drag on pages that disable them. Enhanced Feature: Alt Key HyperLink Text Selection

As of 2021-06-26. See the latest version.

// ==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.7.9.2
// @icon https://image.flaticon.com/icons/png/128/3848/3848147.png
// @description  Enables select, right-click, copy and drag on pages that disable them. Enhanced Feature: Alt Key HyperLink Text Selection
// @description:zh-TW 解除禁止復制、剪切、選擇文本、右鍵菜單的限制。破解鎖右鍵、文字複製、文字選取。增強功能:Alt鍵超連結文字選取。
// @include      /^https?\:\/\//
// @grant        none
// @run-at       document-start
// @namespace https://greasyfork.org/users/371179
// ==/UserScript==
(function $$() {
    'use strict';
    if (document == null || !document.documentElement) return window.requestAnimationFrame($$); // this is tampermonkey bug?? not sure
    //console.log('script at', location)

    function $nil() {}

    function isSupportAdvancedEventListener() {
        if ('_b1750' in $) return $._b1750
        var prop = 0;
        document.createAttribute('z').addEventListener('nil', $nil, {
            get passive() {
                prop++;
            },
            get once() {
                prop++;
            }
        });
        return ($._b1750 = prop == 2);
    }

    function isSupportPassiveEventListener() {
        if ('_b1650' in $) return $._b1650
        var prop = 0;
        document.createAttribute('z').addEventListener('nil', $nil, {
            get passive() {
                prop++;
            }
        });
        return ($._b1650 = prop == 1);
    }

    var getSelection = window.getSelection || Error()(),
        requestAnimationFrame = window.requestAnimationFrame || Error()(),
        getComputedStyle = window.getComputedStyle || Error()();

    const $ = {
        utSelectionColorHack: 'msmtwejkzrqa',
        utTapHighlight: 'xfcklblvkjsj',
        utLpSelection: 'gykqyzwufxpz',
        utLpSelectionKeyDown:'sdaolbulluuw',
        utHoverBlock: 'meefgeibrtqx', //scc_emptyblock
        utNonEmptyElm: 'ilkpvtsnwmjb',
        utNonEmptyElmPrevElm:'jttkfplemwzo',
        ksFuncReplacerNonFalse: '___dqzadwpujtct___',
        ksEventReturnValue: ' ___ndjfujndrlsx___',
        ksSetData: '___rgqclrdllmhr___',

        eh_capture_passive: () => isSupportPassiveEventListener() ? ($._eh_capture_passive = ($._eh_capture_passive || {
            capture: true,
            passive: true
        })) : true,

        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 = getSelection();
            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) {
                alert.__isDisabled__() ? console.log("alert msg disabled: ", msg) : _alert.apply(this, arguments);
            };
            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[$.ksFuncReplacerNonFalse] = true;
                this[pName] = originalFunc; // restore original
                return res;
            }
            resFX.toString = () => originalFunc.toString();
            return resFX;
        },

        listenerDisableAll: function(evt) {
            var elmNode = evt.target;
            var pName = 'on' + evt.type;
            evt = null;
            Promise.resolve().then(() => {
                while (elmNode && elmNode.nodeType > 0) { //i.e. HTMLDocument or HTMLElement
                    var f = elmNode[pName];
                    if (typeof f == 'function' && f[$.ksFuncReplacerNonFalse] !== true) {
                        var nf = $.createFuncReplacer(f, pName);
                        nf[$.ksFuncReplacerNonFalse] = true;
                        elmNode[pName] = nf;
                    }
                    elmNode = elmNode.parentNode;
                }
            })
        },

        onceCssHighlightSelection: () => {
            if (document.documentElement.hasAttribute($.utLpSelection)) return;
            $.onceCssHighlightSelection = null
            Promise.resolve().then(() => {
                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];
                return elm
            }).then(elm => {
                var selectionStyle = getComputedStyle(elm, ':selection');
                if (/^rgba\(\d+,\s*\d+,\s*\d+,\s*0\)$/.test(selectionStyle.getPropertyValue('background-color'))) document.documentElement.setAttribute($.utSelectionColorHack, "");
                return elm;
            }).then(elm => {
                var elmStyle = getComputedStyle(elm)
                if (/^rgba\(\d+,\s*\d+,\s*\d+,\s*0\)$/.test(elmStyle.getPropertyValue('-webkit-tap-highlight-color'))) document.documentElement.setAttribute($.utTapHighlight, "");
            })
        },

        isCurrentClipboardDataReplaced: function(clipboardData) {
            var items = clipboardData ? clipboardData.items : null;
            if (items && items.length > 0) {
                for (var i = 0, l = items.length; i < l; i++) {
                    if (items[i].type == 'text/plain') return true;
                }
            }
            return false;
        },

        replacementSetData: function(_setData, evt) {
            if (typeof _setData != 'function') return;

            function setData() {
                var res = _setData.apply(this, arguments);
                try {
                    if (evt.clipboardData === this && this.setData === setData && evt.cancelable && evt.defaultPrevented === false) {
                        if ($.isCurrentClipboardDataReplaced(evt.clipboardData)) {
                            evt.preventDefault();
                            if (evt.defaultPrevented === true) {
                                this.setData = _setData;
                                delete this[$.ksSetData];
                            }
                        }
                    }
                } catch (e) {}
                return res;
            }
            setData.toString = () => _setData.toString();
            evt.clipboardData.setData = setData;
            evt.clipboardData[$.ksSetData] = _setData;
        },


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

            function isDeactivePreventDefault(evt) {
                if ($.bypass) return false;
                var j = $.eyEvts.indexOf(evt.type);
                switch (j) {
                    case 6:
                        if ($.enableDragging) return false;
                        if (evt.target.hasAttribute('draggable')) {
                            $.enableDragging = true;
                            return false;
                        }
                        //if(evt.target.hasAttribute('draggable')&&evt.target!=window.getSelection().anchorNode)return false;
                        return true;
                    case 3:
                        if (evt.target instanceof Element && (evt.target.textContent || "").trim().length === 0) return false; //exclude elements like video
                        return true;
                    case -1:
                        return false;
                    case 0:
                    case 1:
                        return (evt.keyCode == 67 && (evt.ctrlKey || evt.metaKey) && !evt.altKey && !evt.shiftKey && $.isAnySelection() === true);
                    case 2:

                        if (!('clipboardData' in evt && 'setData' in DataTransfer.prototype)) return true; // Event oncopy not supporting clipboardData
                        // 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 ($.isCurrentClipboardDataReplaced(evt.clipboardData) == false) { //no replacement data
                            if (!evt.clipboardData[$.ksSetData] && evt.cancelable && evt.defaultPrevented === false) $.replacementSetData(evt.clipboardData.setData, evt);
                            return true;
                        }
                        var trimedSelectionText = getSelection().toString().trim()
                        if (trimedSelectionText) {
                            //there is replacement data and the selection is not empty
                            console.log("copy event - clipboardData replacement is allowed and the selection is not empty", trimedSelectionText)
                            return false;
                        } else {
                            //there is replacement data and the selection is empty
                            return false;
                        }
                        break; // for js formatting only

                    default:
                        return true;
                }
            }

            Event.prototype.preventDefault = (function(f) {
                function preventDefault() {
                    if (!isDeactivePreventDefault(this)) f.call(this);
                }
                preventDefault.toString = () => f.toString();
                return preventDefault;
            })(Event.prototype.preventDefault);

            Object.defineProperty(Event.prototype, "returnValue", {
                get() {
                    return $.ksEventReturnValue in this ? this[$.ksEventReturnValue] : true;
                },
                set(newValue) {
                    if (newValue === false && !isDeactivePreventDefault(this)) this.preventDefault();
                    this[$.ksEventReturnValue] = 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 clickBlockingTo = 0;
                    _mAlert.__isDisabled__ = () => clickBlockingTo > +new Date;
                    $.mAlert_DOWN = () => (clickBlockingTo = +new Date + 50);
                    $.mAlert_UP = () => (clickBlockingTo = +new Date + 20);
                    window.alert = _mAlert
                }
            }

        },

        lpCheckPointer: function(targetElm) {
            if (targetElm && targetElm.nodeType == 1 && targetElm.matches('*:hover')) {
                if (getComputedStyle(targetElm).getPropertyValue('cursor') == 'pointer' && targetElm.textContent) return true;
            }
            return false;
        },

        lpFullCancel: function(evt, toPreventDefault) {
            $.bypass = true;
            !toPreventDefault || evt.preventDefault()
            evt.stopPropagation();
            evt.stopImmediatePropagation();
            $.bypass = false;
        },

        lpKeyPressing: false,

        lpKeyDown: function(evt) {

            if(evt.key=="Alt" && $.lpKeyPressing==false && evt.altKey && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && evt.target){
                $.lpKeyPressing=true;
                const rootNode=$.rootHTML(evt.target);
                if(rootNode && !rootNode.hasAttribute($.utLpSelectionKeyDown)){

                    for(const elm of rootNode.querySelectorAll(`[${$.utNonEmptyElmPrevElm}], [${$.utNonEmptyElm}]`)){
                    elm.removeAttribute($.utNonEmptyElmPrevElm)
                    elm.removeAttribute($.utNonEmptyElm)
                    }

                    const s=[...rootNode.querySelectorAll('*:not(button, textarea, input, script, noscript, style, link, img, br)')].filter((elm)=>elm.childElementCount===0 && (elm.textContent||'').trim().length>0)



                    for(const elm of s){

                        let qElm=elm;
                        let qi=0;

                        while(qElm){
                            qi++;

                        if(qElm.hasAttribute($.utNonEmptyElm))break;
                            qElm.setAttribute($.utNonEmptyElm,qi)

                        let pElm=qElm.previousElementSibling;
                        while(pElm){
                            if(pElm.matches(`[${$.utNonEmptyElm}]`) || pElm.querySelector(`[${$.utNonEmptyElm}]`)){
                            break;
                            }else if(!pElm.matches(`button, textarea, input, script, noscript, style, link, img, br`)&& (pElm.textContent||'').length===0 && pElm.clientWidth * pElm.clientHeight>0){
                            pElm.setAttribute($.utNonEmptyElmPrevElm,'')
                            }
                        pElm=pElm.previousElementSibling;
                        }

                            qElm=qElm.parentNode;
                            if(qElm === rootNode)break;

                        }



                    }

                }

                if(rootNode && !rootNode.hasAttribute($.utLpSelectionKeyDown))rootNode.setAttribute($.utLpSelectionKeyDown, '')

            }

        },
        lpKeyUp: function(evt) {

            if(evt.key=="Alt" && $.lpKeyPressing==true && !evt.altKey && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && evt.target){
                $.lpKeyPressing=false;

                const rootNode=$.rootHTML(evt.target);
                if(rootNode && rootNode.hasAttribute($.utLpSelectionKeyDown))rootNode.removeAttribute($.utLpSelectionKeyDown)


                    for(const elm of rootNode.querySelectorAll(`[${$.utNonEmptyElmPrevElm}], [${$.utNonEmptyElm}]`)){
                    elm.removeAttribute($.utNonEmptyElmPrevElm)
                    elm.removeAttribute($.utNonEmptyElm)
                    }


            }

        },

        lpMouseDown: function(evt) {
            $.lpMouseActive = 0;
            if (evt.altKey && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && evt.button === 0) {
                $.lpMouseActive = 1;
                $.lpFullCancel(evt, false);
                const rootNode=$.rootHTML(evt.target);
                rootNode.setAttribute($.utLpSelection, '');
            }
        },

        lpMouseUp: function(evt) {
            if ($.lpMouseActive == 1) {
                $.lpMouseActive = 2;
                const rootNode=$.rootHTML(evt.target);
                rootNode.removeAttribute($.utLpSelection);
                $.lpFullCancel(evt, false);
                if ($.onceCssHighlightSelection) window.requestAnimationFrame($.onceCssHighlightSelection);
            }
        },

        lpClick: function(evt) {
            if ($.lpMouseActive == 2) {
                $.lpFullCancel(evt, false);
            }
        },

        lpEnable: function() { // this is an optional feature for modern browser
            // the built-in browser feature has already disabled the default event behavior, the coding is just to ensure no "tailor-made behavior" occuring.
            document.addEventListener('keydown', $.lpKeyDown, {
                capture: true,
                passive: true
            })
            document.addEventListener('keyup', $.lpKeyUp, {
                capture: true,
                passive: true
            })
            document.addEventListener('mousedown', $.lpMouseDown, {
                capture: true,
                passive: true
            })
            document.addEventListener('mouseup', $.lpMouseUp, {
                capture: true,
                passive: true
            })
            document.addEventListener('click', $.lpClick, {
                capture: true,
                passive: true
            })
        },

        rootHTML:(node)=>{

            if(!node || !(node.nodeType>0))return null;
            if(!node.ownerDocument) return node;
            let rootNode=node.getRootNode?node.getRootNode():null
            if(!rootNode) {
            let pElm=node;
                while(pElm){

                    if(pElm.parentNode) pElm=pElm.parentNode;
                    else break;

                }
                rootNode=pElm;
            }


            rootNode=rootNode.querySelector('html')||node.ownerDocument.documentElement||null;
            return rootNode

        },

        mainEnableScript: () => {
            var cssStyleOnReady = `
            html, html *,
            html *::before, html *::after,
            html *:hover, html *:link, html *:visited, html *:active,
            html *[style], html *[class]{
                -khtml-user-select: auto !important; -moz-user-select: auto !important; -ms-user-select: auto !important;
                -webkit-touch-callout: default !important; -webkit-user-select: auto !important; user-select: auto !important;
            }
            *:hover>img[src]{pointer-events:auto !important;}

            [${$.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;}

            htm1l[${$.utLpSelectionKeyDown}] *:empty:not(textarea,input,button):not(:last-child), html1[${$.utLpSelectionKeyDown}] *:empty:not(textarea,input,button):not(:last-child){pointer-events:none !important;}
            htm1l[${$.utLpSelectionKeyDown}] *:empty~:not(:empty):not(textarea,input,button), html1[${$.utLpSelectionKeyDown}] *:empty:not(textarea,input,button)~:not(:empty):not(textarea,input,button){z-index:inherit !important;}
           html1[${$.utLpSelectionKeyDown}] *:empty~:not(:empty):not(textarea,input,button) *, html1[${$.utLpSelectionKeyDown}] *:empty:not(textarea,input,button)~:not(:empty):not(textarea,input,button) *{z-index:inherit !important;}

[${$.utLpSelectionKeyDown}] [${$.utNonEmptyElmPrevElm}]{pointer-events:none !important;}
[${$.utLpSelectionKeyDown}] [${$.utNonEmptyElmPrevElm}]~[${$.utNonEmptyElm}], [${$.utLpSelectionKeyDown}] [${$.utNonEmptyElmPrevElm}]~[${$.utNonEmptyElm}] [${$.utNonEmptyElm}]{z-index:inherit !important;}

            html[${$.utLpSelection}] *:hover, html[${$.utLpSelection}] *:hover * { cursor:text !important;}
            html[${$.utLpSelection}] :not(input):not(textarea)::selection {background-color: rgba(255, 156, 179,0.5) !important;}
            html[${$.utLpSelection}] :not(input):not(textarea)::-moz-selection {background-color: rgba(255, 156, 179,0.5) !important;}

            [${$.utHoverBlock}="2"]{pointer-events:none !important;user-select:none !important;}
            img[${$.utHoverBlock}="4"]{display:none !important;}
            [${$.utHoverBlock}="7"]{padding:0 !important;}
            [${$.utHoverBlock}="7"]>img[${$.utHoverBlock}="4"]:first-child{
                display:inline-block !important;
                opacity: 0 !important;
                padding: 0 !important;
                margin: 0 !important;
                position: relative !important;
                z-index:1 !important;
                width: 100% !important;
                height: 100% !important;
                left: 0 !important;
                top: 0 !important;
                outline: 0 !important;
                border: 0 !important;
                box-sizing: border-box !important;
                transform: initial !important;
                float: left !important;
                pointer-events:auto !important; user-select:none !important;cursor:inherit !important;
            }

            `.trim();

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

        },

        mainEvents: (listenerPress, listenerRelease) => {
            document.addEventListener("mousedown", listenerPress, true); // Capture Event; (desktop)
            document.addEventListener("contextmenu", listenerPress, true); // Capture Event; (desktop&mobile)
            document.addEventListener("mouseup", listenerRelease, false); // Bubble Event;
        },

        disableHoverBlock: () => {

            var nMap = new WeakMap()

            function elmParam(elm) {

                var mElm = nMap.get(elm);
                if (!mElm) nMap.set(elm, mElm = {});
                return mElm;
            }

            function overlapArea(rect1, rect2) {

                let l1 = {
                    x: rect1.left,
                    y: rect1.top
                }

                let r1 = {
                    x: rect1.right,
                    y: rect1.bottom
                }
                let l2 = {
                    x: rect2.left,
                    y: rect2.top
                }

                let r2 = {
                    x: rect2.right,
                    y: rect2.bottom
                }

                // Area of 1st Rectangle
                let area1 = Math.abs(l1.x - r1.x) * Math.abs(l1.y - r1.y);

                // Area of 2nd Rectangle
                let area2 = Math.abs(l2.x - r2.x) * Math.abs(l2.y - r2.y);

                // Length of intersecting part i.e
                // start from max(l1.x, l2.x) of
                // x-coordinate and end at min(r1.x,
                // r2.x) x-coordinate by subtracting
                // start from end we get required
                // lengths
                let x_dist = Math.min(r1.x, r2.x) - Math.max(l1.x, l2.x);
                let y_dist = (Math.min(r1.y, r2.y) - Math.max(l1.y, l2.y));
                let areaI = 0;
                if (x_dist > 0 && y_dist > 0) {
                    areaI = x_dist * y_dist;
                }

                return {
                    area1,
                    area2,
                    areaI
                };


            }

            function redirectEvent(event, toElement) {

                toElement.dispatchEvent(new event.constructor(event.type, event));
                if (event.type != 'wheel') event.preventDefault();
                event.stopPropagation();
            }

            const floatingBlockHover = new WeakMap();

            let _nImgs = [];

            function nImgFunc() {

                for (const s of _nImgs) {
                    if (s.lastTime + 800 < +new Date) {
                        s.lastTime = +new Date;
                        return s.elm
                    }
                }

                let nImg = document.createElement('img');
                nImg.onerror = function() {
                    if (this.parentNode != null) this.parentNode.removeChild(this)
                }
                nImg.setAttribute($.utHoverBlock, '4');
                const handle = function(event) {
                    if (this === event.target) {
                        if (event.button != 2) redirectEvent(event, this.parentNode)
                        Promise.resolve().then(() => {
                            for (const s of _nImgs) {
                                if (s.elm === this) {
                                    s.lastTime = +new Date
                                }
                            }
                        })
                    }
                }
                nImg.addEventListener('click', handle, true);
                nImg.addEventListener('mousedown', handle, true);
                nImg.addEventListener('mouseup', handle, true);
                nImg.addEventListener('mousemove', handle, true);
                nImg.addEventListener('mouseover', handle, true);
                nImg.addEventListener('mouseout', handle, true);
                nImg.addEventListener('mouseenter', handle, true);
                nImg.addEventListener('mouseleave', handle, true);
                //nImg.addEventListener('wheel', handle, $.eh_capture_passive());
                _nImgs.push({
                    elm: nImg,
                    lastTime: +new Date
                })

                return nImg;

            }

            const wmHoverUrl = new WeakMap();
            let lastMouseEnterElm = null;
            let lastMouseEnterAt = 0;
            let lastMouseEnterCid = 0;

            function mouseEnter() {
                lastMouseEnterCid = 0;

                if (+new Date - lastMouseEnterAt < 30) {
                    lastMouseEnterCid = setTimeout(mouseEnter, 82)
                    return;
                }

                if($.lpKeyPressing)return;

                const targetElm = lastMouseEnterElm

                Promise.resolve()
                    .then(() => {
                        if (targetElm && targetElm.parentNode) {} else {
                            return;
                        }
                        if (floatingBlockHover.get(targetElm)) {
                            let url = null
                            if (targetElm.getAttribute($.utHoverBlock) == '7' && (url = wmHoverUrl.get(targetElm)) && targetElm.querySelector(`[${$.utHoverBlock}]`) == null) {
                                let _nImg = nImgFunc();
                                if (_nImg.parentNode !== targetElm) {
                                    _nImg.setAttribute('src', url);
                                    targetElm.insertBefore(_nImg, targetElm.firstChild);
                                }
                            }
                            return;
                        }
                        floatingBlockHover.set(targetElm, 1);
                        return 1;
                    }).then((ayRes) => {
                        if (!ayRes) return;

                        if (targetElm.nodeType != 1) return;
                        if ("|SVG|IMG|HTML|BODY|VIDEO|AUDIO|BR|HEAD|NOSCRIPT|SCRIPT|STYLE|TEXTAREA|AREA|INPUT|FORM|BUTTON|".indexOf(`|${targetElm.nodeName}|`) >= 0) return;

                        const targetArea = targetElm.clientWidth * targetElm.clientHeight

                        if (targetArea > 0) {} else {
                            return;
                        }

                        const targetCSS = getComputedStyle(targetElm)
                        const targetBgImage = targetCSS.getPropertyValue('background-image');
                        let exec1 = null

                        if (targetBgImage != 'none' && (exec1 = /^\s*url\s*\("?([^"\)]+\b(\.gif|\.png|\.jpeg|\.jpg|\.webp)\b[^"\)]*)"?\)\s*$/i.exec(targetBgImage))) {
                            if ((targetElm.textContent || "").trim().length > 0) return;
                            const url = exec1[1];
                            return url

                            // console.log(targetBgImage,[...exec1])
                        }



                        if (targetCSS.getPropertyValue('position') == 'absolute' && +targetCSS.getPropertyValue('z-index') > 0) {} else {
                            return;
                        }
                        if ((targetElm.textContent || "").trim().length > 0) return;

                        let possibleResults = [];

                        for (const imgElm of document.querySelectorAll('img[src]')) {
                            const param = elmParam(imgElm)
                            if (!param.area) {
                                const area = imgElm.clientWidth * imgElm.clientHeight
                                if (area > 0) param.area = area;
                            }
                            if (param.area > 0) {
                                if (targetArea > param.area * 0.9) possibleResults.push(imgElm)
                            }
                        }

                        let i = 0;
                        let j = 0;
                        for (const imgElm of possibleResults) {

                            const cmpVal = targetElm.compareDocumentPosition(imgElm)

                            /*


1: The two nodes do not belong to the same document.
2: p1 is positioned after p2.
4: p1 is positioned before p2.
8: p1 is positioned inside p2.
16: p2 is positioned inside p1.
32: The two nodes has no relationship, or they are two attributes on the same element.

            */

                            if (cmpVal & 8 || cmpVal & 16) return;
                            if (cmpVal & 2) j++; // I<p
                            else if (cmpVal & 4) break; // I>p


                            i++;

                        }

                        // before: j-1  after: j

                        let indexBefore = j - 1;
                        let indexAfter = j;
                        if (indexBefore < 0) indexBefore = 0;
                        if (indexAfter > possibleResults.length - 1) indexAfter = possibleResults.length - 1;

                        //    setTimeout(function(){
                        for (let i = indexBefore; i <= indexAfter; i++) {
                            const s = possibleResults[i];
                            const {
                                area1,
                                area2,
                                areaI
                            } = overlapArea(targetElm.getBoundingClientRect(), s.getBoundingClientRect())
                            const criteria = area1 * 0.7
                            if (areaI > 0.9 * area2) {


                                return s.getAttribute('src')


                            }
                        }
                        //   },1000);

                    }).then((sUrl) => {

                        if (typeof sUrl != 'string') return;


                        // console.log(313, evt.target, s)
                        let _nImg = nImgFunc();


                        if (_nImg.parentNode !== targetElm) {
                            _nImg.setAttribute('src', sUrl);
                            targetElm.insertBefore(_nImg, targetElm.firstChild);
                            wmHoverUrl.set(targetElm, sUrl);
                            targetElm.setAttribute($.utHoverBlock, '7');
                        }



                    })

            }

            document.addEventListener('mouseenter', function(evt) {
                lastMouseEnterElm = evt.target
                lastMouseEnterAt = +new Date;
                if (!lastMouseEnterCid) lastMouseEnterCid = setTimeout(mouseEnter, 82)
            }, $.eh_capture_passive())



        }

    }

   // $.holdingElm=null;

    $.mainEnableScript();

    if (isSupportAdvancedEventListener()) $.lpEnable(); // top capture event for alt-click

    $.mainEvents(
        function(evt) {
         //   $.holdingElm=evt.target;
         //   console.log('down',evt.target)
            if ($.onceCssHighlightSelection) window.requestAnimationFrame($.onceCssHighlightSelection);
            if (evt.button == 2 || evt.type == "contextmenu") $.mAlert_DOWN();
        },
        function(evt) {
          //  $.holdingElm=null;
         //   console.log('up',evt.target)
            if (evt.button == 2) $.mAlert_UP();
            if ($.enableDragging) {
                $.enableDragging = false;
            }
        }
    );

    $.disableHoverBlock();

    console.log('userscript running - To Re-Enable Selection & Copying');




})();