您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
16/04/2025, 18:06:52
当前为
- // ==UserScript==
- // @name Fullchan X
- // @namespace Violentmonkey Scripts
- // @match https://8chan.moe/*/res/*.html*
- // @grant none
- // @version 1.0
- // @author vfyxe
- // @description 16/04/2025, 18:06:52
- // ==/UserScript==
- if (!document.querySelector('.divPosts')) return;
- class fullChanX extends HTMLElement {
- constructor() {
- super();
- this.enableNestedQuotes = true;
- }
- init() {
- this.threadParent = document.querySelector('#divThreads');
- this.thread = this.threadParent.querySelector('.divPosts');
- this.posts = [...this.thread.querySelectorAll('.postCell')];
- this.postOrder = 'default';
- this.postOrderSelect = this.querySelector('#thread-sort');
- this.yousContainer = this.querySelector('#my-yous');
- this.updateYous();
- this.observers();
- }
- observers () {
- this.postOrderSelect.addEventListener('change', (event) => {
- this.postOrder = event.target.value;
- this.assignPostOrder();
- });
- const observerCallback = (mutationsList, observer) => {
- for (const mutation of mutationsList) {
- if (mutation.type === 'childList') {
- this.posts = [...this.thread.querySelectorAll('.postCell')];
- if (this.postOrder !== 'default') this.assignPostOrder();
- this.updateYous();
- }
- }
- };
- const threadObserver = new MutationObserver(observerCallback);
- threadObserver.observe(this.thread, { childList: true, subtree: false });
- if (this.enableNestedQuotes) {
- this.thread.addEventListener('click', event => {
- const nestQuote = event.target.closest('.quoteLink');
- if (nestQuote) {
- event.preventDefault();
- this.nestQuote(nestQuote);
- }
- });
- }
- }
- assignPostOrder () {
- const postOrderReplies = (post) => {
- const replyCount = post.querySelectorAll('.panelBacklinks a').length;
- post.style.order = 100 - replyCount;
- }
- const postOrderCatbox = (post) => {
- const postContent = post.querySelector('.divMessage').textContent;
- const matches = postContent.match(/catbox\.moe/g);
- const catboxCount = matches ? matches.length : 0;
- post.style.order = 100 - catboxCount;
- }
- if (this.postOrder === 'default') {
- this.thread.style.display = 'block';
- return;
- }
- this.thread.style.display = 'flex';
- if (this.postOrder === 'replies') {
- this.posts.forEach(post => postOrderReplies(post));
- } else if (this.postOrder === 'catbox') {
- this.posts.forEach(post => postOrderCatbox(post));
- }
- }
- updateYous () {
- const yous = this.posts.filter(post => post.querySelector('.quoteLink.you'));
- const yousLinks = yous.map(you => {
- const youLink = document.createElement('a');
- youLink.textContent = '>>' + you.id;
- youLink.href = '#' + you.id;
- return youLink;
- })
- this.yousContainer.innerHTML = '';
- yousLinks.forEach(you => this.yousContainer.appendChild(you));
- }
- nestQuote(quoteLink) {
- const parentPostMessage = quoteLink.closest('.divMessage');
- const quoteId = quoteLink.href.split('#')[1];
- const quotePost = document.getElementById(quoteId);
- if (!quotePost) return;
- const quotePostContent = quotePost.querySelector('.innerOP') || quotePost.querySelector('.innerPost');
- if (!quotePostContent) return;
- const existing = parentPostMessage.querySelector(`.nestedPost[data-quote-id="${quoteId}"]`);
- if (existing) {
- existing.remove();
- return;
- }
- const wrapper = document.createElement('div');
- wrapper.classList.add('nestedPost');
- wrapper.setAttribute('data-quote-id', quoteId);
- const clone = quotePostContent.cloneNode(true);
- clone.style.whiteSpace = "unset";
- wrapper.appendChild(clone);
- parentPostMessage.appendChild(wrapper);
- }
- };
- window.customElements.define('fullchan-x', fullChanX);
- // Create fullchan-x elemnt
- const fcx = document.createElement('fullchan-x');
- fcx.innerHTML = `
- <div class="fcx__controls">
- <select id="thread-sort">
- <option value="default">Default</option>
- <option value="replies">Replies</option>
- <option value="catbox">Catbox</option>
- </select>
- <div class="fcx__my-yous">
- <p class="my-yous__label">My (You)s</p>
- <div class="my-yous__yous" id="my-yous"></div>
- </div>
- </div>
- `;
- document.body.appendChild(fcx);
- fcx.init();
- // Styles
- const style = document.createElement('style');
- style.innerHTML = `
- fullchan-x {
- display: block;
- position: fixed;
- top: 2.5rem;
- right: 2rem;
- padding: 10px;
- background: var(--contrast-color);
- border: 1px solid var(--navbar-text-color);
- color: var(--link-color);
- font-size: 14px;
- opacity: 0.5;
- }
- fullchan-x:hover {
- opacity: 1;
- }
- .divPosts {
- flex-direction: column;
- }
- .fcx__controls {
- display: flex;
- flex-direction: column;
- gap: 2px;
- }
- #thread-sort {
- padding: 0.4rem 0.6rem;
- background: white !important;
- border: none !important;
- border-radius: 0.2rem;
- transition: all ease 150ms;
- cursor: pointer;
- }
- .my-yous__yous {
- display: none;
- flex-direction: column;
- }
- .my-yous__label {
- padding: 0.4rem 0.6rem;
- background: white !important;
- border: none !important;
- border-radius: 0.2rem;
- transition: all ease 150ms;
- cursor: pointer;
- }
- .fcx__my-yous:hover .my-yous__yous {
- display: flex;
- }
- .innerPost:has(.quoteLink.you) {
- border-left: solid red 6px;
- }
- // --- Nested quotes ----
- // I don't know why it needs this, weird CSS inheritance on cloned element
- .nestedPost {}
- .divMessage .nestedPost {
- display: block;
- white-space: normal!important;
- overflow-wrap: anywhere;
- margin-top: 0.5em;
- border: 1px solid var(--navbar-text-color);
- }
- `;
- document.head.appendChild(style);
- // Asuka and Eris (fantasy Asuka) are best girls