您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Eliminate gaps from empty/whitespace paragraphs & leading/trailing <br>. Smart split walls of text into spaced paragraphs. Also get rid of justified text.
// ==UserScript== // @name AO3 Fix double-spaced paragraphs and text walls // @description Eliminate gaps from empty/whitespace paragraphs & leading/trailing <br>. Smart split walls of text into spaced paragraphs. Also get rid of justified text. // @author C89sd // @version 1.6 // @include /^https:\/\/archiveofourown\.org\/(?:collections\/[^\/]+\/)?(:?works|chapters)\/\d+(?:\/chapters\/\d+)?\/?(?:\?.*)?$/ // @namespace https://gf.qytechs.cn/users/1376767 // @noframes // ==/UserScript== 'use strict'; // Testing: // https://archiveofourown.org/works/63851347 empty <p> // https://archiveofourown.org/works/13439460 leading <br> // https://archiveofourown.org/works/5191202?view_full_work=true formatting // https://archiveofourown.org/works/44688217/chapters/112432564 split inner <br> const workskin = document.getElementById('workskin'); if (!workskin) return; // Remove justified text const js = workskin.querySelectorAll('[align="justify"]'); for (const j of js) { j.align = ''; } const IS_EMPTY = /^\s*$/; const STARTS_WITH_EM_DASH = /^[\u2013\u2014-]/; const PRESERVE_BREAK_AFTER = /^(IMG|VIDEO|AUDIO|SOURCE|TRACK|IFRAME|CODE)$/; function getLastRecursiveChild(el) { return el.lastElementChild ? getLastRecursiveChild(el.lastElementChild) : el; } // Remove gaps in paragraphs const ps = workskin.querySelectorAll('p'); for (const p of ps) { // p.innerHTML = "abc;<br>123<br><em>def;</em><em>cde;</em>gdh"; // console.log(p.innerHTML) // Remove gaps from empty paragraphs if (IS_EMPTY.test(p.textContent)) { p.remove(); continue; } // Remove gaps from leading/trailing <br> nodes or empties let n; while ((n = p.firstChild) && (n.tagName === 'BR' || (n.nodeType === 3 && IS_EMPTY.test(n.textContent)))) { // TEXT_NODE (3) n.remove(); } while ((n = p.lastChild) && (n.tagName === 'BR' || (n.nodeType === 3 && IS_EMPTY.test(n.textContent)))) { // TEXT_NODE (3) n.remove(); } // Fast-fail, early rejection if there are no inner <br>, // like this but non recursive: `if (!p.querySelector('br')) continue;` let hasBr = false; for (let n = p.firstChild; n; n = n.nextSibling) { if (n.tagName === 'BR') { hasBr = true; break; } } if (!hasBr) continue; // Assume it's a quote with intended <br> line returns if its parent style is centered. const textAlign = getComputedStyle(p).textAlign; if (textAlign === 'center' || textAlign == 'right' || textAlign == 'end') continue; // Assume it's a quote if the last sentence starts with a dash. if (STARTS_WITH_EM_DASH.test(p.lastChild.textContent)) continue; // Assume it's a quote if the last sentence is a link if (getLastRecursiveChild(p).tagName === 'A') continue; // Split inner <br>: // Create a new <p> behind you and shovel nodes into it as you walk. // Create a new <p> when encountering a <br> to create a gap. { let node = p.firstChild; let newp; let createnewp = true; while (node) { let next = node.nextSibling; let next2 = next?.nextSibling; let shovel = false; let shovel2 = false; // It is plausible that the writer intended this <br> as a line return to this adjacent element. // Keep it by shoveling both at the same time in the new <p>. if (next && node.tagName === 'BR' && PRESERVE_BREAK_AFTER.test(next.tagName)) { shovel = true; shovel2 = true; } else if (next && PRESERVE_BREAK_AFTER.test(node.tagName) && next.tagName === 'BR') { shovel = true; shovel2 = true; } // Hit a <br>, delete it and request a new split to create a gap. else if (node.tagName === 'BR') { p.removeChild(node); createnewp = true; node = next; continue; } // Text-like node (txt,em,i,strong,...), belongs inline while there isn't a <br>. Shovel it in the new <p>. else { shovel = true; } if (createnewp) { createnewp = false; // Create a new <p> before the current node, creates a gap. newp = document.createElement('p'); // // NOTE: Moving nodes into this new <p> adds the standard amount of vertical spacing, // // but we can't be 100% sure that the <br> wasn't on purpose. To mark a difference visually, // // we can set a slightly lower margin that will still be readable. // newp.style.margin = '0.8em auto'; p.insertBefore(newp, node); // Insert behind } if (shovel) { shovel = false; newp.appendChild(node); } if (shovel2) { shovel2 = false; newp.appendChild(next); next = next2; } node = next; } } }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址