Greasy Fork

Greasy Fork is available in English.

8chan Style Script

Script to style 8chan

当前为 2025-04-18 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name        8chan Style Script
// @namespace   8chanSS
// @match       *://8chan.moe/*
// @match       *://8chan.se/*
// @grant       none
// @version     1.0
// @author      Anon
// @run-at      document-end
// @description Script to style 8chan
// @license     MIT
// ==/UserScript==

// Header Catalog Links
document.getElementById('navBoardsSpan').addEventListener('click', function () {
    var boardLinks = document.querySelectorAll('#navBoardsSpan a');
    var appendString = '\/catalog.html';

    boardLinks.forEach(function (link) {
        link.href += appendString;
    });
});

// Scroll to last read post
// Function to save the scroll position
function saveScrollPosition() {
    const scrollPosition = window.scrollY; // Get the current vertical scroll position
    localStorage.setItem('scrollPosition', scrollPosition); // Store it in localStorage
}

// Function to restore the scroll position
function restoreScrollPosition() {
    const savedPosition = localStorage.getItem('scrollPosition'); // Retrieve the saved position
    if (savedPosition) {
        window.scrollTo(0, parseInt(savedPosition, 10)); // Scroll to the saved position
    }
}

// Event listener to save scroll position before the page unloads
window.addEventListener('beforeunload', saveScrollPosition);

// Restore scroll position when the page loads
window.addEventListener('load', restoreScrollPosition);

// Toggle Announcement & Posting Form
// Create the button
const button = document.createElement('button');
button.style.margin = '10px';
const postingFormDiv = document.getElementById('postingForm');
const announcementDiv = document.getElementById('dynamicAnnouncement');
const panelMessageDiv = document.getElementById('panelMessage');

// Check if divs exist
if (postingFormDiv && announcementDiv && panelMessageDiv) {
    // Insert the button before the announcement div
    postingFormDiv.parentNode.insertBefore(button, postingFormDiv);
    // Retrieve the visibility states from localStorage
    const isPostingFormVisible = localStorage.getItem('postingFormVisible') === 'true';
    const isAnnouncementVisible = localStorage.getItem('announcementVisible') === 'true';
    const isPanelMessageVisible = localStorage.getItem('panelMessageVisible') === 'true';
    // Set the initial state of the divs and button based on stored values
    if (isPostingFormVisible) {
        postingFormDiv.style.display = 'block'; // Show the posting div
    } else {
        postingFormDiv.style.display = 'none'; // Hide the posting div
    }
    if (isAnnouncementVisible) {
        announcementDiv.style.display = 'block'; // Show the announcement div
    } else {
        announcementDiv.style.display = 'none'; // Hide the announcement div
    }
    if (isPanelMessageVisible) {
        panelMessageDiv.style.display = 'block'; // Show the panel message div
    } else {
        panelMessageDiv.style.display = 'none'; // Hide the panel message div
    }
    // Update button text based on the visibility of the announcement div
    button.textContent = (isPostingFormVisible && isAnnouncementVisible && isPanelMessageVisible) ? '-' : '+';
    // Add click event listener to the button
    button.addEventListener('click', () => {
        // Toggle visibility of both divs
        const isCurrentlyVisible = postingFormDiv.style.display !== 'none' && announcementDiv.style.display !== 'none' && panelMessageDiv.style.display !== 'none';

        if (isCurrentlyVisible) {
            postingFormDiv.style.display = 'none'; // Hide the posting div
            announcementDiv.style.display = 'none'; // Hide the announcement div
            panelMessageDiv.style.display = 'none'; // Hide the panel message div
            button.textContent = '+'; // Change button text
            localStorage.setItem('postingFormVisible', 'false'); // Save state
            localStorage.setItem('announcementVisible', 'false'); // Save state
            localStorage.setItem('panelMessageVisible', 'false'); // Save state
        } else {
            postingFormDiv.style.display = 'block'; // Hide the posting div
            announcementDiv.style.display = 'block'; // Show the announcement div
            panelMessageDiv.style.display = 'block'; // Show the panel message div
            button.textContent = '-'; // Change button text
            localStorage.setItem('postingFormVisible', 'true'); // Save state
            localStorage.setItem('announcementVisible', 'true'); // Save state
            localStorage.setItem('panelMessageVisible', 'true'); // Save state
        }
    });
}

// Keyboard Shortcuts
// QR (CTRL+Q)
function toggleDiv(event) {
    // Check if Ctrl + Q is pressed
    if (event.ctrlKey && (event.key === 'q' || event.key === 'Q')) {
        const hiddenDiv = document.getElementById('quick-reply');
        // Toggle QR
        if (hiddenDiv.style.display === 'none' || hiddenDiv.style.display === '') {
            hiddenDiv.style.display = 'block'; // Show the div
        }
        else {
            hiddenDiv.style.display = 'none'; // Hide the div
        }
    }
}
// Add an event listener for keydown events
document.addEventListener('keydown', toggleDiv);


// Custom CSS injection
function addCustomCSS(css) {
    if (!css) return;
    const style = document.createElement('style');
    style.type = 'text/css';
    style.appendChild(document.createTextNode(css));
    document.head.appendChild(style);
}
// Get the current URL path
const currentPath = window.location.pathname.toLowerCase();
const currentHost = window.location.hostname.toLowerCase();

// Apply CSS based on URL pattern
// Thread page CSS
if (/\/res\/[^/]+\.html$/.test(currentPath)) {
    const css = `
/* Quick Reply */
#quick-reply {
    display: block;
    padding: 0 !important;
    top: auto !important;
    bottom: 0;
    left: auto !important;
    position: fixed;
    right: 0 !important;
}
#qrbody {
    resize: vertical;
    max-height: 50vh;
}
.floatingMenu {
    padding: 0 !important;
}
#qrFilesBody {
    max-width: 300px;
}
/* Banner */
#bannerImage {
    width: 305px;
    right: 0;
    position: fixed;
    top: 26px;
}
.innerUtility.top {
    margin-top: 2em;
    background-color: transparent !important;
    color: var(--link-color) !important;
}
.innerUtility.top a {
    color: var(--link-color) !important;
}
/* Hover Posts */
img[style*="position: fixed"] {
    position: fixed !important;
    max-width: 80vw;
    max-height: 80vh !important;
    z-index: 200;
}
.quoteTooltip {
    z-index: 110;
}
/* (You) Replies */
.innerPost:has(.youName) {
    border-left: solid #68b723 5px;
}
.innerPost:has(.quoteLink.you) {
    border-left: solid #dd003e 5px;
}
/* Filename */
.originalNameLink {
  display: inline;
  overflow-wrap: anywhere;
  white-space: normal;
}
`;
    addCustomCSS(css);
}

if (/^8chan\.(se|moe)$/.test(currentHost)) {
    // General CSS for all pages
    const css = `
/* Margins */
#mainPanel {
    margin-left: 10px;
    margin-right: 305px;
    margin-top: 0;
    margin-bottom: 0;
}
.innerPost {
    margin-left: 40px;
    display: block;
}
/* Cleanup */
#footer,
#actionsForm,
#navTopBoardsSpan,
.coloredIcon.linkOverboard,
.coloredIcon.linkSfwOver,
.coloredIcon.multiboardButton,
#navLinkSpan>span:nth-child(9),
#navLinkSpan>span:nth-child(11),
#navLinkSpan>span:nth-child(13) {
    display: none;
}
/* Header */
#dynamicHeaderThread,
.navHeader {
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}
/* Thread Watcher */
#watchedMenu .floatingContainer {
    min-width: 330px;
}
.quoteTooltip .innerPost {
    overflow: hidden;
}
`;
    addCustomCSS(css);
}

// Catalog page CSS
if (/\/catalog\.html$/.test(currentPath)) {
    const css = `
#dynamicAnnouncement {
    display: none;
}
#postingForm {
  margin: 2em auto;
}
`;
    addCustomCSS(css);
}