North-Plus Block

为北+提供关键词屏蔽功能

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         North-Plus Block
// @namespace    https://github.com/sssssssl/NP-Scripts
// @version      0.2.1
// @description  为北+提供关键词屏蔽功能
// @author       sl
// @match        https://*.summer-plus.net/thread.php?fid-*
// @match        https://*.summer-plus.net/thread.php?fid-*
// @match        https://*.level-plus.net/thread.php?fid-*
// @match        https://*.white-plus.net/thread.php?fid-*
// @match        https://*.south-plus.net/thread.php?fid-*
// @match        https://*.imoutolove.me/thread.php?fid-*
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==

(function() {
    'use strict';


    const STORE_BLOCK_MODE_KEY = 'blockEnabled';
    const STORE_BLOCK_WORDS_KEY = 'blockWords';

    const ID_BTN_BLOCK_SWITCH = 'np-block-switch';
    const ID_BTN_SHOW_LIST = 'np-block-btn-show-list';
    const ID_NP_BLOCK_LIST_CONTAINER = 'np-block-list-container';
    const ID_NP_BLOCK_LIST = 'np-block-list';

    const ID_BTN_ADD_WORD = 'np-block-list-add-btn';
    const ID_INPUT_WORD = 'np-block-list-add-input';
    const CLS_BTN_DEL_WORD = 'btn-delete-block-word';

    const CLS_MODE_DISABLED = 'np-block-disabled';
    const CLS_MODE_ENABLED = 'np-block-enabled';
    const CLS_LIST_UNFOLD = 'np-list-unfold';
    const CLS_LIST_FOLD = 'np-list-fold';
    const CLS_LIST_ITEM = 'block-list-item';

    const CLS_FADEIN = 'np-fadein';
    const CLS_FADEOUT = 'np-fadeout';
    const TIME_FADE = 1;

    const CLS_THREAD = '.tr3.t_one';
    const CLS_THREAD_TITLE = 'h3 a';

    const NP_BLOCK_HTML = `
        <div id="np-block" class="${CLS_FADEIN} np-fixed-height">
            <div id="np-block-header">
                <span>屏蔽模式</span>
                <span id="${ID_BTN_BLOCK_SWITCH}" class="${CLS_MODE_DISABLED} np-clickable">关</span>
            </div>
            <div id="${ID_BTN_SHOW_LIST}" class="${CLS_MODE_DISABLED} np-clickable">屏蔽列表</div>
            <div id="${ID_NP_BLOCK_LIST_CONTAINER}" class="${CLS_LIST_FOLD}">
                <div id="${ID_NP_BLOCK_LIST}"> 
                </div>
                <div id="np-block-list-add" class="block-list-item">
                    <input id="np-block-list-add-input" class="np-fixed-height" type="text">
                    <span id="np-block-list-add-btn" class="np-clickable">加</span>
                </div>
            </div>
        </div>
    `;

    const NP_BLOCK_STYLE = `
        <style>
        #np-block {
            position: fixed;
            width: 140px;
            top: 10px;
            right: 10px;
            background-color: rgb(234, 237, 237);
        }

        .${CLS_FADEIN} {
            -ms-animation: fadein ${TIME_FADE}s;
            -webkit-animation: fadein ${TIME_FADE}s;
            animation fadein ${TIME_FADE}s;
        }

        @keyframes fadein {
            from { opacity: 0; }
            to   { opacity: 1; }
        }

        @-webkit-keyframes fadein {
            from { opacity: 0; }
            to   { opacity: 1; }
        }

        @-ms-keyframes fadein {
            from { opacity: 0; }
            to   { opacity: 1; }
        }

        .${CLS_FADEOUT} {
            -ms-animation: fadeout ${TIME_FADE}s;
            -webkit-animation: fadeout ${TIME_FADE}s;
            animation fadeout ${TIME_FADE}s;     
        }

        @keyframes fadeout {
            from { opacity: 1; }
            to   { opacity: 0; }
        }

        @-webkit-keyframes fadeout {
            from { opacity: 1; }
            to   { opacity: 0; }
        }

        @-ms-keyframes fadeout {
            from { opacity: 1; }
            to   { opacity: 0; }
        }

        #np-block > * {
            width: 90%;
            margin-left: auto;
            margin-right: auto;
            text-align: center;
            margin-top: 5px;
        }

        .np-fixed-height {
            line-height: 22px;
            vertical-align: middle;
        }
        
        #${ID_BTN_BLOCK_SWITCH} {
            padding-left: 10px;
            padding-right: 10px;
            float: right;
            transition: all 0.5s;
        }
        
        #${ID_BTN_SHOW_LIST} {
            transition: all 0.5s;
        }
        
        .${CLS_MODE_DISABLED} {
            background-color: black;
            color: white;
        }
        
        .${CLS_MODE_ENABLED} {
            background-color: white;
            color: black;
        }
        
        #${ID_NP_BLOCK_LIST_CONTAINER} {
            overflow: hidden;
            transition: all 0.5s;
        }
        
        .${CLS_LIST_FOLD} {
            max-height: 0px;
        }
        
        .${CLS_LIST_UNFOLD} {
            max-height: 250px;
            margin-bottom: 5px;
        }
        
        #${ID_NP_BLOCK_LIST} {
            max-height: 200px;
            overflow-y: scroll;
        }
        
        #${ID_NP_BLOCK_LIST}::-webkit-scrollbar {
            display: none;
        }
        
        .${CLS_LIST_ITEM} {
            text-align: center;
            background-color: rgb(33, 47, 61);
            color: white;
            width: 90%;
            margin-left: auto;
            margin-right: auto;
            margin-top: 5px;
        }
        
        .${CLS_BTN_DEL_WORD} {
            float: right;
            background-color: red;
            padding-right: 10px;
            padding-left: 10px;
            transition: all 0.5s;
        }
        
        .${CLS_BTN_DEL_WORD}:hover {
            background-color: rgb(192, 57, 43);
        }
        
        #np-block-list-add {
            background-color: inherit;
        }
        
        #np-block-list-add-input {
            appearance: none;
            font-size: 1em;
            width: 60%;
            border: none;
            margin: auto auto;
            box-sizing: border-box;
        }
        
        #np-block-list-add-input:focus {
            outline: 0;
        }
        
        #np-block-list-add-btn {
            float: right;
            background-color: green;
            padding-right: 10px;
            padding-left: 10px;
            transition: all 0.5s;
        }
        
        #np-block-list-add-btn:hover {
            background-color: rgb(28, 40, 51);
        }

        .np-clickable {
            cursor: default;
        }

        .np-clickable:hover {
            cursor: pointer;
        }
        </style>
    `;

    // 2. CODE ENTRYPOINT.

    let blockModeEnabled = GM_getValue(STORE_BLOCK_MODE_KEY, false);
    let blockWords = GM_getValue(STORE_BLOCK_WORDS_KEY);
    if(!blockWords) {
        blockWords = [];
    }
    let hiddenThreads = [];

    // add panel & register callbacks.
    document.head.insertAdjacentHTML('beforeend', NP_BLOCK_STYLE);
    document.body.insertAdjacentHTML('beforeend', NP_BLOCK_HTML);

    let btnBlockSwitch = document.getElementById(ID_BTN_BLOCK_SWITCH)
    let btnShowlist = document.getElementById(ID_BTN_SHOW_LIST);
    let btnAddWord = document.getElementById(ID_BTN_ADD_WORD);
    let inputWord = document.getElementById(ID_INPUT_WORD);
    let npBlockListContainer = document.getElementById(ID_NP_BLOCK_LIST_CONTAINER);
    let npBlockList = document.getElementById(ID_NP_BLOCK_LIST);

    btnShowlist.onclick = () => {
        btnShowlist.classList.toggle(CLS_MODE_DISABLED);
        btnShowlist.classList.toggle(CLS_MODE_ENABLED);
        npBlockListContainer.classList.toggle(CLS_LIST_FOLD);
        npBlockListContainer.classList.toggle(CLS_LIST_UNFOLD);
    };

    btnBlockSwitch.onclick = () => {
        btnBlockSwitch.classList.toggle(CLS_MODE_DISABLED);
        btnBlockSwitch.classList.toggle(CLS_MODE_ENABLED);
        blockModeEnabled = !blockModeEnabled;
        btnBlockSwitch.textContent = blockModeEnabled ? '开' : '关';
        GM_setValue(STORE_BLOCK_MODE_KEY, blockModeEnabled);
        if(blockModeEnabled) {
            parseThreadTitle(blockWords);
        }
        else {
            let i = hiddenThreads.length;
            while (i > 0) {
                let elem = hiddenThreads.pop();
                elem.style.display = 'table-row';
                elem.classList.remove(CLS_FADEOUT);
                elem.classList.add(CLS_FADEIN);
                i -= 1;
            }
        }
    };

    btnAddWord.onclick = () => {
        let word = inputWord.value;
        if(word.length == 0) {
            return;
        }
        inputWord.value = '';
        blockWords.push(word);
        GM_setValue(STORE_BLOCK_WORDS_KEY, blockWords);
        renderBlockWord(word);
        if(blockModeEnabled) {
            parseThreadTitle([word]);
        }
    }

    btnBlockSwitch.textContent = blockModeEnabled ? '开' : '关';
    if(blockModeEnabled && btnBlockSwitch.classList.contains(CLS_MODE_DISABLED)) {
        btnBlockSwitch.classList.toggle(CLS_MODE_DISABLED);
        btnBlockSwitch.classList.toggle(CLS_MODE_ENABLED);
    }

    blockWords.forEach(renderBlockWord);

    if(blockModeEnabled) {
        parseThreadTitle(blockWords);
    }

    function parseThreadTitle(wordList) {
        let titleList = [];
        let threads = document.querySelectorAll(CLS_THREAD);
        threads.forEach((elem) => {
            let title = elem.querySelector(CLS_THREAD_TITLE).textContent;
            wordList.forEach(word => {
                if(title.includes(word)) {
                    hiddenThreads.push(elem);
                    elem.classList.remove(CLS_FADEIN);
                    elem.classList.add(CLS_FADEOUT);
                    setTimeout(() => {
                        elem.style.display = 'none';
                    }, TIME_FADE*1000);
                }
            });
        });
    }

    function addDeleteWordCallback(btn) {
        btn.onclick = () => {
            let word = btn.previousElementSibling.textContent;
            let idx = blockWords.indexOf(word);
            if(idx >= 0) {
                blockWords.splice(idx, 1);
                GM_setValue(STORE_BLOCK_WORDS_KEY, blockWords);
                btn.parentElement.remove();
            }
            else {
                console.log(`${word}, ${idx}`);
            }
        };
    }

    function renderBlockWord(word) {
        let wordHTML = `
            <div class="${CLS_LIST_ITEM}">
                <span class="block-word">${word}</span>
                <span class="${CLS_BTN_DEL_WORD} np-clickable">删</span>
            </div>
        `;
        npBlockList.insertAdjacentHTML('afterbegin', wordHTML);
        let newDelBtn = npBlockList.querySelector(`.${CLS_BTN_DEL_WORD}`);
        addDeleteWordCallback(newDelBtn);
    }

})();