RedirectFromCertainCC98Board

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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();
    }
})();