您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a [+]/[-] button to expand/collapse all media in a single post on 8chan.moe/se.
- // ==UserScript==
- // @name 8chan Toggle All Media per Post
- // @namespace sneed
- // @version 1.5
- // @description Adds a [+]/[-] button to expand/collapse all media in a single post on 8chan.moe/se.
- // @author Gemini 2.5
- // @license MIT
- // @match https://8chan.moe/*/res/*.html*
- // @match https://8chan.se/*/res/*.html*
- // @grant none
- // @run-at document-idle
- // ==/UserScript==
- (function() {
- 'use strict';
- const EXPAND_TEXT = '[+]';
- const COLLAPSE_TEXT = '[-]';
- const BUTTON_CLASS = 'toggle-all-media-btn'; // Class for the button
- /**
- * Cleans up extra visible a.hideLink elements in a media cell after collapse.
- * @param {HTMLElement} uploadCell - The figure.uploadCell element.
- */
- function cleanupExtraHideLinks(uploadCell) {
- // We only expect one *functional* hide link per audio/video player when expanded.
- // When collapsed, there should ideally be zero *visible* hide links.
- // This function targets cells that are NOT expanded and might have leftover links.
- if (uploadCell.classList.contains('expandedCell')) {
- return; // Only clean up collapsed cells
- }
- const hideLinks = uploadCell.querySelectorAll('a.hideLink');
- if (hideLinks.length > 1) {
- // console.log(`Cleanup: Found ${hideLinks.length} hide links in a non-expanded cell. Hiding extras.`);
- // Keep the first one potentially, or just hide all visible extras
- // Let's hide all except the first one found, as the first one might be the "correct" one if any interaction happened.
- for (let i = 1; i < hideLinks.length; i++) {
- hideLinks[i].style.display = 'none';
- }
- // Even the first one shouldn't be visible if the cell isn't expanded, based on normal behavior.
- // Let's ensure all hide links are hidden if the cell is not expanded.
- hideLinks.forEach(link => link.style.display = 'none');
- } else if (hideLinks.length === 1) {
- // If there's exactly one hide link, ensure it's hidden if the cell is not expanded
- hideLinks[0].style.display = 'none';
- }
- // If length is 0 or 1 (and handled above), nothing more needed.
- }
- /**
- * Adds a toggle button to expand/collapse all media in a post if it has multiple uploads.
- * @param {HTMLElement} postElement - The post element (.postCell or .opCell).
- */
- function addExpandToggleButton(postElement) {
- const panelUploads = postElement.querySelector('.panelUploads');
- if (!panelUploads || postElement.querySelector(`.${BUTTON_CLASS}`)) {
- return;
- }
- const uploadCells = panelUploads.querySelectorAll('.uploadCell');
- if (uploadCells.length <= 1) {
- return;
- }
- const button = document.createElement('span');
- button.textContent = EXPAND_TEXT;
- button.title = 'Toggle expand/collapse all media in this post';
- button.classList.add(BUTTON_CLASS);
- button.dataset.state = 'collapsed'; // Initial state assumes things start collapsed
- // button.style.display = 'block';
- button.style.marginBottom = '5px';
- button.style.cursor = 'pointer';
- button.style.fontSize = '0.9em';
- button.style.fontWeight = 'bold';
- button.style.color = 'var(--link-color, blue)';
- button.style.userSelect = 'none';
- button.addEventListener('click', (event) => {
- event.preventDefault();
- event.stopPropagation();
- const currentPost = event.target.closest('.postCell, .opCell');
- if (!currentPost) return;
- const currentPanelUploads = currentPost.querySelector('.panelUploads');
- if (!currentPanelUploads) return;
- const mediaItems = currentPanelUploads.querySelectorAll('.uploadCell');
- const currentState = button.dataset.state;
- if (currentState === 'collapsed') {
- // --- Action: Expand currently collapsed items ---
- mediaItems.forEach(cell => {
- // Find items that are NOT expanded
- if (!cell.classList.contains('expandedCell')) {
- const link = cell.querySelector('a.imgLink');
- if (link) {
- // console.log('Expanding:', link.href);
- link.click(); // Click the main link to trigger expansion
- }
- }
- });
- // Update state AFTER action
- button.dataset.state = 'expanded';
- button.textContent = COLLAPSE_TEXT;
- } else { // currentState === 'expanded'
- // --- Action: Collapse currently expanded items ---
- mediaItems.forEach(cell => {
- // Find items that ARE expanded
- if (cell.classList.contains('expandedCell')) {
- // For expanded audio/video, the collapse button is a.hideLink
- const hideLink = cell.querySelector('a.hideLink');
- if (hideLink) {
- // console.log('Collapsing (via hideLink):', cell.querySelector('a.imgLink')?.href);
- hideLink.click(); // Click the hide link
- } else {
- // For expanded images, the collapse action is clicking a.imgLink again
- const mainLink = cell.querySelector('a.imgLink');
- if (mainLink) {
- // console.log('Collapsing (via imgLink):', mainLink.href);
- mainLink.click();
- }
- }
- }
- });
- // Update state AFTER action
- button.dataset.state = 'collapsed';
- button.textContent = EXPAND_TEXT;
- // --- Cleanup: Hide any extra, visible hide links after collapse ---
- // Add a small delay to allow the native script's collapse animation/DOM changes to finish
- // before cleaning up.
- setTimeout(() => {
- mediaItems.forEach(cell => {
- cleanupExtraHideLinks(cell);
- });
- }, 50); // 50ms delay should be sufficient
- }
- });
- const firstUploadCell = panelUploads.querySelector('.uploadCell');
- if (firstUploadCell) {
- panelUploads.insertBefore(button, firstUploadCell);
- } else {
- panelUploads.appendChild(button);
- }
- }
- /**
- * Observes the main post container for newly added posts and adds buttons to them.
- */
- function observeNewPosts() {
- const targetNode = document.querySelector('#divThreads .divPosts');
- if (!targetNode) {
- console.warn('Toggle All Media: Could not find target node for MutationObserver.');
- return;
- }
- const config = { childList: true };
- const callback = function(mutationsList, observer) {
- for(const mutation of mutationsList) {
- if (mutation.type === 'childList') {
- mutation.addedNodes.forEach(node => {
- if (node.nodeType === Node.ELEMENT_NODE) {
- if (node.matches('.postCell, .opCell')) {
- addExpandToggleButton(node);
- } else {
- // Check for posts potentially nested within the added node (e.g. in a wrapper)
- node.querySelectorAll('.postCell, .opCell').forEach(addExpandToggleButton);
- }
- }
- });
- }
- }
- };
- const observer = new MutationObserver(callback);
- observer.observe(targetNode, config);
- }
- // --- Main Execution ---
- document.querySelectorAll('.postCell, .opCell').forEach(addExpandToggleButton);
- requestAnimationFrame(observeNewPosts);
- })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址