RedirectFromCertainCC98Board

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

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

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

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

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

你需要先安裝一款使用者腳本管理器擴展,比如 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();
    }
})();