您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
默认隐藏视频模块。提供独立按钮控制视频模块的显示/隐藏,以及答案的展开/收拢。
// ==UserScript== // @name 粉笔网 - 增强版视频隐藏+答案一键展开 // @license MIT // @namespace http://tampermonkey.net/ // @version 2.7 // Version increased for two independent buttons // @description 默认隐藏视频模块。提供独立按钮控制视频模块的显示/隐藏,以及答案的展开/收拢。 // @author 哈吉米 // @match *.fenbi.com/* // @grant GM_addStyle // @icon https://nodestatic.fbstatic.cn/weblts_spa_online/page/assets/fenbi32.ico // ==/UserScript== (function() { 'use strict'; // --- Video Display Control --- const VIDEO_STYLE_ID = 'fenbi-video-display-style'; let isVideoHidden = true; // Default state: videos are hidden function applyVideoHideStyles() { let styleTag = document.getElementById(VIDEO_STYLE_ID); if (!styleTag) { styleTag = document.createElement('style'); styleTag.id = VIDEO_STYLE_ID; styleTag.type = 'text/css'; document.head.appendChild(styleTag); } styleTag.textContent = ` /* --- Hide "analysis video" section by ID prefix --- */ section[id^="section-video"] { display: none !important; } /* --- Hide video items in the analysis list --- */ .solu-list-item.video-item, /* Hide "expand to watch video analysis" button */ .bg-color-gray-light2.border-gray-light3.font-color-gray-mid.expend-btn, /* Hide other potential video-related promotional elements */ fb-ng-solution-detail-item[videotip], .video-analysis-wrapper, app-solution-video { display: none !important; } `; isVideoHidden = true; } function removeVideoHideStyles() { const styleTag = document.getElementById(VIDEO_STYLE_ID); if (styleTag) { styleTag.remove(); } isVideoHidden = false; } // Apply video hiding styles immediately on load as default applyVideoHideStyles(); // --- DIV Toggle (Expand/Collapse) Control --- // This state variable now indicates if the DIVs are *currently expanded* by our script // So, if true, the next click should *collapse* them ("隐藏答案"). // If false, the next click should *expand* them ("显示答案"). let areDivsExpanded = false; // Initial state: Assume DIVs are collapsed or need expanding let divClickObserver = null; // Mutation Observer instance function toggleDivsClick(expandDivs) { // Renamed parameter to be clearer // Disconnect any active observer to prevent re-triggering during our clicks if (divClickObserver) { divClickObserver.disconnect(); divClickObserver = null; // Reset observer reference } const targetNode = document.body; const config = { childList: true, subtree: true }; const processButtons = (buttons) => { buttons.forEach(button => { const isActive = button.classList.contains('toggle-btn-active'); // 'toggle-btn-active' typically means expanded if (expandDivs) { // If we want to *expand* them (button text: "显示答案") if (!isActive) { // If it's currently NOT active (collapsed), click to expand console.log('Clicking to expand DIV:', button); button.click(); } } else { // If we want to *collapse* them (button text: "隐藏答案") if (isActive) { // If it's currently active (expanded), click to collapse console.log('Clicking to collapse DIV:', button); button.click(); } } }); }; const callback = function(mutationsList, observer) { for (const mutation of mutationsList) { if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { mutation.addedNodes.forEach(node => { if (node.nodeType === 1 && node.matches('div.toggle-btn:has(svg)')) { processButtons([node]); } else if (node.nodeType === 1) { const nestedButtons = node.querySelectorAll('div.toggle-btn:has(svg)'); if (nestedButtons.length > 0) { processButtons(Array.from(nestedButtons)); } } }); } else if (mutation.type === 'attributes' && mutation.attributeName === 'class' && mutation.target.matches('div.toggle-btn:has(svg)')) { processButtons([mutation.target]); } } }; // Initialize and start the observer divClickObserver = new MutationObserver(callback); divClickObserver.observe(targetNode, config); // Process any buttons already present on the page immediately const initialButtons = document.querySelectorAll('div.toggle-btn:has(svg)'); if (initialButtons.length > 0) { console.log('Processing initial toggle DIVs:', initialButtons); processButtons(Array.from(initialButtons)); } } // --- Create and append the trigger buttons --- function createButtons() { // 1. Create DIV Toggle Button (for "答案" / Answer) const divToggleButton = document.createElement('button'); divToggleButton.id = 'fenbi-div-toggle-btn'; // Initial text: Since `areDivsExpanded` is false, the first click will *expand* them. divToggleButton.textContent = '显示答案'; // Button will show answers on click divToggleButton.style.cssText = ` position: fixed; top: 70px; right: 10px; z-index: 9999; padding: 8px 15px; background-color: #007bff; /* Blue - for "show answer" */ color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 14px; opacity: 0.8; transition: opacity 0.3s ease; `; divToggleButton.onmouseover = () => { divToggleButton.style.opacity = '1'; }; divToggleButton.onmouseout = () => { divToggleButton.style.opacity = '0.8'; }; divToggleButton.onclick = () => { if (!areDivsExpanded) { // If divs are currently collapsed (or default), click to EXPAND them toggleDivsClick(true); // Argument `true` means we want to expand them divToggleButton.textContent = '隐藏答案'; // Next click will hide them divToggleButton.style.backgroundColor = '#dc3545'; // Red for "hide answer" areDivsExpanded = true; } else { // If divs are currently expanded, click to COLLAPSE them toggleDivsClick(false); // Argument `false` means we want to collapse them divToggleButton.textContent = '显示答案'; // Next click will show them divToggleButton.style.backgroundColor = '#007bff'; // Blue for "show answer" areDivsExpanded = false; } }; document.body.appendChild(divToggleButton); // 2. Create Video Display Toggle Button const videoToggleButton = document.createElement('button'); videoToggleButton.id = 'fenbi-video-toggle-btn'; videoToggleButton.textContent = '显示视频'; // Initial text, since videos are hidden by default videoToggleButton.style.cssText = ` position: fixed; top: 110px; /* Position below the first button */ right: 10px; z-index: 9999; padding: 8px 15px; background-color: #28a745; /* Green for "show" */ color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 14px; opacity: 0.8; transition: opacity 0.3s ease; `; videoToggleButton.onmouseover = () => { videoToggleButton.style.opacity = '1'; }; videoToggleButton.onmouseout = () => { videoToggleButton.style.opacity = '0.8'; }; videoToggleButton.onclick = () => { if (isVideoHidden) { removeVideoHideStyles(); // Show videos videoToggleButton.textContent = '隐藏视频'; videoToggleButton.style.backgroundColor = '#6c757d'; // Gray for "hide" } else { applyVideoHideStyles(); // Hide videos videoToggleButton.textContent = '显示视频'; videoToggleButton.style.backgroundColor = '#28a745'; // Green for "show" } }; document.body.appendChild(videoToggleButton); } // Ensure buttons are created once the page content is loaded if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', createButtons); } else { createButtons(); } })();