Behind The Overlay

One click to close any overlay on any website

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name          Behind The Overlay
// @namespace     Behind The Overlay
// @description   One click to close any overlay on any website
// @author        NicolaeNMV + daijro
// @version       2.0
// @include       *://*
// @icon          https://addons.cdn.mozilla.net/user-media/addon_icons/521/521928-32.png
// @grant         GM_registerMenuCommand
// ==/UserScript==

/**
 * This is a script that will remove overlay popups in the 99% of the cases.
 * It's doing that by detecting DOM elements.
 *
 * Originally from here: https://github.com/NicolaeNMV/BehindTheOverlay
 * Modified by daijro to work as a userscript
 **/

var debug = false;

var utils = (function () {
    function hideElement(element) {
        styleImportant(element, 'display', 'none');
    }

    function styleImportant(element, cssProperty, cssValue) {
        element.style[cssProperty] = '';
        var cssText = element.style.cssText || '';
        if (cssText.length > 0 && cssText.slice(-1) != ';')
            cssText += ';';
        // Some pages are using !important on elements, so we must use it too
        element.style.cssText = cssText + cssProperty + ': ' + cssValue + ' !important;';
    }

    function isVisible(element) {
        return element.offsetWidth > 0 && element.offsetHeight > 0;
    }

    function getZIndex(element) {
        return parseInt(window.getComputedStyle(element).zIndex);
    }

    function isAnElement(node) {
        return node.nodeType == 1; // nodeType 1 mean element
    }

    function nodeListToArray(nodeList) {
        return Array.prototype.slice.call(nodeList);
    }

    function forEachElement(nodeList, functionToApply) {
        nodeListToArray(nodeList).filter(isAnElement).forEach(function (element) {
            functionToApply.call(this, element);
        });
    }

    function collectParrents(element, predicate) {
        var matchedElement = element && predicate(element) ? [element] : [];
        var parent = element.parentNode;

        if (parent && parent != document && parent != document.body) {
            return matchedElement.concat(collectParrents(parent, predicate));
        } else {
            return matchedElement;
        }
    }

    // Calculate the number of DOM elements inside an element
    function elementWeight(element, maxThreshold) {
        var grandTotal = 0;
        var nextElement = element;
        var nextGrandChildNodes = [];

        function calculateBreathFirst(element) {
            var total = 0;
            var nextChildElements = [];

            var childNodes = element.childNodes;
            total = childNodes.length;

            forEachElement(childNodes, function (childNode) {
                var grandChildNodes = nodeListToArray(childNode.childNodes);
                total += grandChildNodes.length;
                nextChildElements = nextChildElements.concat(grandChildNodes.filter(isAnElement));
            });
            return [total, nextChildElements];
        }

        while (nextElement) {
            var tuple_total_nextChildElements = calculateBreathFirst(nextElement);
            var total = tuple_total_nextChildElements[0];

            grandTotal += total;
            nextGrandChildNodes = nextGrandChildNodes.concat(tuple_total_nextChildElements[1]);

            if (grandTotal >= maxThreshold) {
                break;
            } else {
                nextElement = nextGrandChildNodes.pop();
            }
        }

        return grandTotal;
    }

    return {
        hideElement: hideElement,
        isVisible: isVisible,
        getZIndex: getZIndex,
        forEachElement: forEachElement,
        collectParrents: collectParrents,
        elementWeight: elementWeight,
        styleImportant: styleImportant
    }
})();

var overlayRemover = function (debug, utils) {
    function hideElementsAtZIndexNear(nearElement, thresholdZIndex) {
        var parent = nearElement.parentNode;
        // The case when nearElement is a document
        if (parent === null) {
            return;
        }
        var children = parent.childNodes;

        utils.forEachElement(children, function (child) {
            if (utils.getZIndex(child) >= thresholdZIndex) {
                utils.hideElement(child);
            }
        })
    }

    // Check the element in the middle of the screen
    // Search fo elements that have zIndex attribute
    function methodTwoHideElementMiddle() {
        var overlayPopup = document.elementFromPoint(window.innerWidth / 2, window.innerHeight / 2);

        var overlayFound = utils.collectParrents(overlayPopup, function (el) {
            return utils.getZIndex(el) > 0;
        });

        if (debug)
            console.debug('Overlay found: ', overlayFound);

        if (overlayFound.length == 0)
            return false;

        var olderParent = overlayFound.pop();

        if (debug)
            console.debug('Hide parrent: ', olderParent);

        return olderParent;
    }

    function disableBlur() {
        var someContainerMaybe = document.elementFromPoint(window.innerWidth / 2, window.innerHeight / 2);

        var bluredParentsFound = utils.collectParrents(someContainerMaybe, function (el) {
            return window.getComputedStyle(el).filter.includes('blur');
        });

        if (bluredParentsFound.length == 0)
            return false;

        var topParent = bluredParentsFound.pop();

        // Some element can act as a container, that can be blured or masking the whole content
        var isContainerOccupyingAboutSpaceAsBody = topParent.offsetWidth >= (document.body.offsetWidth - 100);

        if (isContainerOccupyingAboutSpaceAsBody) {
            utils.styleImportant(topParent, 'filter', 'blur(0)');

            if (debug) console.log('Blur removed!', topParent);

            return true;
        }

        return false;
    }

    function containersOverflowAuto() {
        var containers = [document.documentElement, document.body];

        containers.forEach(function (element) {
            if (window.getComputedStyle(element).overflowY == 'hidden') {
                utils.styleImportant(element, 'overflow', 'auto');
            }
            if (window.getComputedStyle(element).position == 'fixed') {
                utils.styleImportant(element, 'position', 'static');
            }
        })
    }

    function run() {
        for (var i = 0; i < 10; i++) {
            var candidate = methodTwoHideElementMiddle();
            var first = i == 0;
            if (candidate === false) {
                if (first)
                    alert('No overlay has been found on this website.');
                break;
            } else {
                if (!first) {
                    // Prevent to hide the actual content
                    var weightThreshold = 100;
                    var candidateWeight = utils.elementWeight(candidate, weightThreshold)
                    if (candidateWeight < weightThreshold) {
                        if (debug)
                            console.log('Element is too lightweight, hide it', candidate);
                        utils.hideElement(candidate);
                    } else {
                        if (debug)
                            console.log("Element is too heavy, don't hide it", candidate);
                    }
                } else {
                    utils.hideElement(candidate);
                    containersOverflowAuto();
                    disableBlur();
                }
            }
        }
    }

    return {
        run: run
    };

};

function enableCommandMenu() {
    var commandMenu = true;
    try {
        if (typeof(GM_registerMenuCommand) == undefined) {
            return;
        } else {
            if (commandMenu == true ) {
                GM_registerMenuCommand('Remove overlay', function() {
                    overlayRemoverRun();
                });
            }
        }
    }
    catch(err) {
        console.log(err);
    }
}

overlayRemoverInstance = overlayRemover(debug, utils);

function overlayRemoverRun() {
    overlayRemoverInstance.run();
}

function keyPress(event) {
    if (event.ctrlKey && event.shiftKey && event.keyCode == 88) {
        overlayRemoverRun();
    }
}

enableCommandMenu();
document.addEventListener('keydown', keyPress);