Nodeloc 去右侧栏

移除右侧推荐栏并让主体内容扩展到三列布局

// ==UserScript==
// @name         Nodeloc 去右侧栏
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  移除右侧推荐栏并让主体内容扩展到三列布局
// @match        *://www.nodeloc.com/*
// @match        *://www.nodeloc.cc/*
// @run-at       document-start
// @grant        GM_addStyle
// @noframes
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    // 右侧广告/侧栏的选择器
    var RIGHT_RAIL_SEL = [
        '.sidebar-ads-wrapper',
        '#right-sidebar',
        '.right-sidebar',
        '[data-region="right-sidebar"]',
        '.discourse-right-sidebar'
    ].join(',');

    // 主体内容容器
    var MAIN_CONTENT_SEL = [
        '#main-outlet',
        '#main-outlet-wrapper > #main-outlet',
        '#main-outlet-wrapper > .contents',
        '#main-outlet-wrapper > .wrap',
        '#main-outlet-wrapper > .container',
        '#main-outlet-wrapper > main'
    ].join(',');

    // 网格容器
    var GRID_WRAP_SEL = '#main-outlet-wrapper';

    function scopeSelectors(base, csv) {
        var parts = csv.split(',');
        for (var i = 0; i < parts.length; i++) {
            var item = parts[i].trim();
            if (item.indexOf(base) === 0) {
                parts[i] = item;
            } else {
                parts[i] = base + ' ' + item;
            }
        }
        return parts.join(', ');
    }

    var MAIN_CONTENT_SCOPED = scopeSelectors(GRID_WRAP_SEL, MAIN_CONTENT_SEL);

    var css = [
        RIGHT_RAIL_SEL + ' { display: none !important; }',
        MAIN_CONTENT_SCOPED + ' { grid-column: 2 / 4 !important; }',
        GRID_WRAP_SEL + ' > * { grid-column: auto; }',
        GRID_WRAP_SEL + ' { grid-auto-columns: 0 !important; grid-auto-flow: row !important; }'
    ].join('\n');

    if (typeof GM_addStyle === 'function') {
        GM_addStyle(css);
    } else {
        var s = document.createElement('style');
        s.textContent = css;
        (document.head || document.documentElement).appendChild(s);
    }

    function collectRightRails(root) {
        var list = [];
        if (!root) return list;
        if (root.matches && root.matches(RIGHT_RAIL_SEL)) {
            list.push(root);
        }
        if (root.querySelectorAll) {
            var found = root.querySelectorAll(RIGHT_RAIL_SEL);
            for (var i = 0; i < found.length; i++) {
                list.push(found[i]);
            }
        }
        return list;
    }

    function removeRightRail(root) {
        var targets = collectRightRails(root || document);
        for (var i = 0; i < targets.length; i++) {
            targets[i].style.display = 'none';
        }
    }

    function expandMain(root) {
        var scope = root || document;
        var main = scope.querySelector(MAIN_CONTENT_SEL);
        if (main) {
            main.style.gridColumn = '2 / 4';
            main.style.minWidth = '0';
        }
    }

    function fixOnce(root) {
        removeRightRail(root);
        expandMain(root);
    }

    fixOnce(document);

    var mo = new MutationObserver(function (mutations) {
        var touched = false;
        for (var k = 0; k < mutations.length; k++) {
            var m = mutations[k];
            if (m.type !== 'childList' || m.addedNodes.length === 0) continue;
            for (var j = 0; j < m.addedNodes.length; j++) {
                var node = m.addedNodes[j];
                if (node.nodeType !== 1) continue;
                if (node.matches && node.matches(RIGHT_RAIL_SEL)) {
                    removeRightRail(node);
                    touched = true;
                    continue;
                }
                if (node.matches && node.matches(MAIN_CONTENT_SEL)) {
                    expandMain(node);
                    touched = true;
                }
                if (node.querySelectorAll) {
                    var subList = node.querySelectorAll(RIGHT_RAIL_SEL);
                    if (subList.length) {
                        removeRightRail(node);
                        touched = true;
                    }
                }
            }
        }
        if (touched) {
            expandMain(document);
        }
    });

    var observing = false;

    function getTarget() {
        return document.querySelector(GRID_WRAP_SEL) || document.body || document.documentElement;
    }

    function startObserve() {
        if (observing) return;
        var target = getTarget();
        if (!target) return;
        try {
            mo.observe(target, { childList: true, subtree: true });
            observing = true;
        } catch (e) {
            observing = false;
            setTimeout(startObserve, 50);
        }
    }

    function stopObserve() {
        if (!observing) return;
        mo.disconnect();
        observing = false;
    }

    document.addEventListener('visibilitychange', function () {
        if (document.hidden) {
            stopObserve();
        } else {
            startObserve();
        }
    });

    startObserve();
})();