RedirectFromCertainCC98Board

使用模态框实现的版面拦截器

// ==UserScript==
// @name         RedirectFromCertainCC98Board
// @namespace    http://tampermonkey.net/
// @version      2025-02-25
// @description  使用模态框实现的版面拦截器
// @author       Monci
// @match        *://www.cc98.org/*
// @match       *://www-cc98-org-s.webvpn.zju.edu.cn:8001/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

// 关于创建窗口的方案和脚本头部的参数借鉴了yacu - Yet another CC98 userscript(https://update.greasyfork.org/scripts/438399/yacu%20-%20Yet%20another%20CC98%20userscript.user.js)
// 安装后启用,在cc98论坛内部所有页面右侧顶端生成一个透明蓝色按钮,点击按钮弹出对话框指定需要拦截的版面。打开相应版面的帖子时,将自动重定向到cc98论坛的主页(使用webvpn访问情况下也生效)


(function () {
    'use strict';

    const FIXED_BOARD_LIST = ["感性空间",
                              "心灵之约",
                              "郁闷小屋",
                             ];
    let boardConditions = JSON.parse(GM_getValue('boardConditions', '[]'));
    let isModalOpen = false; // 用于跟踪模态框是否已经打开

    // 添加全局样式(仅修改按钮部分)
    GM_addStyle(`
        .blocker-modal {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0,0,0,0.2);
            z-index: 10000;
            min-width: 300px;
        }
        .modal-mask {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0,0,0,0.5);
            z-index: 9999;
        }
        .modal-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
        }
        .modal-close {
            cursor: pointer;
            font-size: 24px;
        }
        .board-list {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
        }
        .board-item {
            flex: 1 0 30%; /* 每个版面占用30%的宽度,确保每行最多显示3个 */
            margin: 8px 0;
            display: flex;
            align-items: center;
        }
        /* 处理不足三个版面时,最后一个项居中显示 */
        .board-item:nth-child(3n+1) {
            margin-left: 0;
        }
        .board-item:nth-child(3n) {
            margin-right: 0;
        }
        .save-button {
            margin-top: 15px;
            padding: 8px 20px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        /* 新增按钮样式 */
        .floating-btn {
            background: #007bff !important;
            color: white !important;
            border: none !important;
            border-radius: 4px !important;
            padding: 8px 16px !important;
            opacity: 0.2 !important;
            transition: opacity 0.3s ease !important;
            cursor: pointer !important;
            box-shadow: 0 2px 4px rgba(0,0,0,0.2) !important;
        }
        .floating-btn:hover {
            opacity: 1 !important;
        }
            .board-list {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        gap: 10px;
        margin-bottom: 15px;
        }
        .board-item {
            display: flex;
            align-items: center;
            white-space: nowrap;
            gap: 8px;
            margin: 0 !important;
        }
    `);

    // 创建控制按钮(修改后)
    function createControlButton() {
        const btn = document.createElement('button');
        btn.className = 'floating-btn'; // 应用新样式类
        btn.textContent = '拦截设置';

        // 位置设置保持不变
        btn.style.position = 'fixed';
        btn.style.top = '10px';
        btn.style.right = '10px';
        btn.style.zIndex = '10000';

        btn.addEventListener('click', showModal);
        document.body.appendChild(btn);
    }

    // 显示模态框
    function showModal() {
        // 如果模态框已经打开,直接返回
        if (isModalOpen) return;

        isModalOpen = true; // 标记模态框为已打开

        const mask = document.createElement('div');
        mask.className = 'modal-mask';

        const modal = document.createElement('div');
        modal.className = 'blocker-modal';

        // 弹窗内容
        modal.innerHTML = `
            <div class="modal-header">
                <h3>选择要拦截的版面</h3>
                <div class="modal-close">×</div>
            </div>
            <div class="board-list">
                ${FIXED_BOARD_LIST.map(name => `
                    <label class="board-item">
                        <input type="checkbox" ${boardConditions.includes(name) ? 'checked' : ''}>
                        ${name}
                    </label>
                `).join('')}
            </div>
            <button class="save-button">保存设置</button>
        `;

        // 关闭事件
        const closeBtn = modal.querySelector('.modal-close');
        closeBtn.addEventListener('click', () => {
            mask.remove();
            isModalOpen = false; // 标记模态框已关闭
        });
        mask.addEventListener('click', (e) => {
            if (e.target === mask) {
                mask.remove();
                isModalOpen = false; // 标记模态框已关闭
            }
        });

        // 保存事件
        const saveBtn = modal.querySelector('.save-button');
        saveBtn.addEventListener('click', () => {
            const checked = Array.from(modal.querySelectorAll('input:checked'))
                .map(input => input.parentNode.textContent.trim());

            boardConditions = checked;
            GM_setValue('boardConditions', JSON.stringify(checked));
            mask.remove();
            isModalOpen = false; // 标记模态框已关闭
            checkRedirect(); // 立即应用新规则
        });

        mask.appendChild(modal);
        document.body.appendChild(mask);
    }

    // 确认是否是通过webvpn访问
    function getRedirectURL() {
        // 判断当前是否在VPN域名下
        const isVPN = window.location.hostname.includes('webvpn.zju.edu.cn');
        return isVPN
           ? 'http://www-cc98-org-s.webvpn.zju.edu.cn:8001/'
           : 'https://www.cc98.org/';
   }

    // 检查是否需要重定向
    function checkRedirect() {
        const currentBoard = document.querySelector("#root > div > div.center > div:nth-child(1) > div > div.row > a:nth-child(5)"); // 根据实际页面结构调整选择器
        if (currentBoard && boardConditions.includes(currentBoard.textContent.trim())) {
            // window.location.href = 'https://www.cc98.org/';
            window.location.href = getRedirectURL();
        }
    }

    // 初始化
    function init() {
        createControlButton();
        checkRedirect();
        // 添加DOM变化监听(根据实际需要)
        new MutationObserver(checkRedirect).observe(document.body, {
            childList: true,
            subtree: true
        });
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();