rBlock

移除一些网站用于数据统计的链接跳转及部分其他功能,加快网站访问速度。

目前為 2016-11-30 提交的版本,檢視 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name            rBlock
// @author          nonoroazoro
// @description     移除一些网站用于数据统计的链接跳转及部分其他功能,加快网站访问速度。
// @description:en  Remove redirects and some features of web sites.
// @homepageURL     https://github.com/nonoroazoro/rBlock
// @namespace       https://greasyfork.org/zh-CN/scripts/20568-rblock
// @grant           none
// @version         1.2.9
// @run-at          document-end
// @include         /^https?:\/\/(.+\.)?github\./
// @include         /^https?:\/\/(.+\.)?google\./
// @include         /^https?:\/\/(.+\.)?zhihu\./
// ==/UserScript==

const rBlock = {

    _blockers: [],

    start: function ()
    {
        this.init();
        this._blockers.forEach(blocker => blocker.start());
    },

    init: function ()
    {
        this._blockers = [];
        const _host = window.location.host;

        // 1. google
        if (/^(.+\.)?google\./.test(_host))
        {
            this._blockers.push({
                start: function ()
                {
                    // 1. for static pages.
                    // when google instant predictions is disabled,
                    // this blocker will only be called once.
                    this._block();

                    // 2. for dynamic pages.
                    // when google instant predictions is enabled,
                    // this blocker will be call whenever the current page is updated.
                    _startMutationObserver(
                        {
                            "id":
                            [
                                "search", // all/videos/news/shopping/books/apps
                            ],
                            "class":
                            [
                                "irc_rit", // images
                                "pspo-popout pspo-lpop", // shopping
                            ]
                        },
                        this._block
                    );
                },

                // block redirects of google
                _block: function ()
                {
                    const base = document.querySelector("div#search");
                    if (base)
                    {
                        // 1. general
                        revealURL(
                            base.querySelectorAll(`a[href*="url="]`),
                            /.*url=(http[^&]+)/i
                        );

                        // 2. all/videos/news/apps
                        let elems = base.querySelectorAll(`a[onmousedown^="return rwt("]`);
                        _removeAttributes(elems, "onmousedown");

                        // 3. cached links
                        elems = document.querySelectorAll(`a[href^="http://webcache.googleusercontent."], a[href^="https://webcache.googleusercontent."]`);
                        const targets = document.querySelectorAll(`a.rblock-cached-link`);
                        if (elems.length !== targets.length * 2)
                        {
                            // prevent duplication
                            let menuLink;
                            let cacheLink;
                            elems.forEach((elem) =>
                            {
                                elem.style.display = "inline";
                                menuLink = elem.closest("div.action-menu.ab_ctl");

                                cacheLink = document.createElement("a");
                                cacheLink.setAttribute("href", elem.getAttribute("href").replace(/^http\:/, "https:"));
                                cacheLink.setAttribute("class", "rblock-cached-link");
                                cacheLink.target = "_blank";
                                cacheLink.innerText = " Cached ";

                                menuLink.parentNode.insertBefore(cacheLink, menuLink);
                            });
                        }
                    }
                }
            });
        }

        // 2. zhihu

        if (/^(.+\.)?zhihu\./.test(_host))
        {
            this._blockers.push({
                start: function ()
                {
                    this._block();

                    _startMutationObserver(
                        {
                            "id":
                            [
                                "js-home-feed-list", // 首页最新动态
                                "zh-question-answer-wrap", // 具体内容
                            ],
                            "class":
                            [
                                "zm-item-rich-text expandable js-collapse-body", // 首页、话题显示全部
                                "zh-general-list clearfix", // 话题
                                "entry", // 专栏
                            ],
                            "data-type":
                            [
                                "daily", // 发现
                            ]
                        },
                        this._block
                    );
                },

                _block: function ()
                {
                    // 1. general
                    revealURL(
                        document.querySelectorAll(`a[href*="?target="]`),
                        /.*target=(http[^&]+)/i
                    );

                    // 2. open in new tab
                    document.querySelectorAll(`a.internal`).forEach((elem) => _openInNewTab(elem));
                }
            });
        }

        // 3. github
        if (/^(.+\.)?github\./.test(_host))
        {
            this._blockers.push({
                start: function ()
                {
                    this._block();
                },

                _block: function ()
                {
                    // 1. disable keyboard shortcuts: "s" and "w"
                    document.addEventListener("keydown", (e) =>
                    {
                        if (e.key === "s" || e.key === "S" || e.key === "w" || e.key === "W")
                        {
                            e.stopPropagation();
                        }
                    }, true);
                }
            });
        }
    }
};

function _startMutationObserver(p_filter, p_handler)
{
    if (typeof p_handler === "function")
    {
        const filter = p_filter || {};
        const observer = new window.MutationObserver((p_mutations) =>
        {
            let needUpdate = false;
            for (let mutation of p_mutations)
            {
                for (let key in p_filter)
                {
                    if (p_filter[key].indexOf(mutation.target.getAttribute(key)) != -1)
                    {
                        needUpdate = true;
                        break;
                    }
                }

                if (needUpdate)
                {
                    break;
                }
            }

            if (needUpdate)
            {
                p_handler();
            }
        });
        observer.observe(document.body,
            {
                childList: true,
                subtree: true
            }
        );
    }
}

function _removeAttributes(p_elements, p_attributes)
{
    if (p_elements && typeof p_attributes === "string")
    {
        const attributes = p_attributes.split(/\W+/) || [];
        p_elements.forEach((elem) =>
        {
            attributes.forEach((attr) =>
            {
                elem.removeAttribute(attr);
            });
        });
    }
}

function _removeListeners(p_element, p_events)
{
    if (p_element && typeof p_events === "string")
    {
        const events = p_events.split(/\W+/) || [];
        events.forEach((event) =>
        {
            p_element.removeEventListener(event, _preventDefaultAction, true);
            p_element.addEventListener(event, _preventDefaultAction, true);
        });
    }
}

function _preventDefaultAction(e)
{
    e.stopPropagation();
}

function revealURL(p_elems, p_regex)
{
    if (p_elems && p_regex)
    {
        let groups;
        p_elems.forEach((elem) =>
        {
            // reveal url & open in new tab
            groups = decodeURIComponent(elem.getAttribute("href")).match(p_regex);
            if (groups && groups[1])
            {
                elem.setAttribute("href", groups[1]);
                _openInNewTab(elem);
            }
        });
    }
}

function _openInNewTab(p_elem)
{
    if (p_elem)
    {
        p_elem.target = "_blank";
    }
}

rBlock.start();