您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
洛谷题目页面改为NOI/NOIP/CSP经典PDF风格,享受沉浸(致郁)式刷题。
当前为
// ==UserScript== // @name 洛谷 - 梦回考场 // @namespace http://tampermonkey.net/ // @version 0.3 // @description 洛谷题目页面改为NOI/NOIP/CSP经典PDF风格,享受沉浸(致郁)式刷题。 // @author Jerrycyx (Luogu UID 545986) // @match https://www.luogu.com.cn/problem/* // @license MPL-2.0 // @run-at document-idle // @grant GM_addStyle // @require https://scriptcat.org/lib/513/2.1.0/ElementGetter.js#sha256=aQF7JFfhQ7Hi+weLrBlOsY24Z2ORjaxgZNoni7pAz5U= // ==/UserScript== //TODO: More SimSun //TODO: Translation (function () { "use strict"; const path = window.location.pathname; const validPrefixes = ["P", "B", "CF", "SP", "AT", "UVA", "T", "U"]; const regex = /^\/problem\/([^/]+)$/; const match = path.match(regex); if (!match) return; if (!validPrefixes.some(prefix => match[1].startsWith(prefix))) return; function processElements(container, selector, processAll, processor) { const elements = container.querySelectorAll(selector); if (elements.length === 0) { console.info(`[Luogu-RER] No elements found with selector: "${selector}"`); return false; } if (processAll) { elements.forEach(el => processor(el)); } else { processor(elements[0]); } return true; } function removeFirst(container, selector) { processElements(container, selector, false, e => { e.remove(); }); } function removeAll(container, selector) { processElements(container, selector, true, e => { e.remove(); }); } window.addEventListener("load", function () { console.log("[Luogu-RER] Loading..."); /* === Defination === */ const mainElement = document.querySelector("#app > .main-container"); mainElement.id = "Main-element"; const oringinalProblemHeader = mainElement.querySelector(".theme-bg > .theme-fg > .columba-content-wrap.header-layout"); const titleContent = oringinalProblemHeader.querySelector("h1.lfe-h1").textContent; const timeLimit = oringinalProblemHeader.querySelector(".stat > .field:nth-child(3) > .stat-text.value").textContent; const memoryLimit = oringinalProblemHeader.querySelector(".stat > .field:nth-child(4) > .stat-text.value").textContent; const problemElement = mainElement.querySelector("main .columba-content-wrap > .sidebar-container > .main > .problem"); problemElement.id = "Problem-element"; GM_addStyle(` #Problem-element { --common-font-family: KaTeX_Main, SimSun; --strong-font-family: KaTeX_Main, SImHei; } .custom-common-text { font-family: var(--common-font-family); font-weight: normal; } .custom-strong-text { font-family: var(--strong-font-family); font-weight: normal; } `); elmGetter.each("#Problem-element p, #Problem-element ul, #Problem-element ol, #Problem-element .attachments", problemElement, e => { e.classList.add("custom-common-text"); }); /* === Removement === */ removeAll(document, "#app > nav"); removeAll(document, "#app > .top-bar"); removeAll(document, "#app > .dropdown"); removeAll(document, "#app > .modal.hide"); removeAll(document, "#app > .page-loading"); removeAll(document, "#app > .nav-scrollbar"); removeAll(mainElement, ".theme-bg"); removeAll(mainElement, "main .columba-content-wrap > .sidebar-container > .side"); removeFirst(problemElement, ".problem-block-actions"); removeAll(problemElement, ".io-sample > .io-sample-block button.lform-size-small"); elmGetter.each("p", problemElement, e => { function isValidChainImage(e) { if (e.tagName === 'IMG') return true; let current = e; while (current) { const childNodes = current.childNodes; if (childNodes.length !== 1 || childNodes[0].nodeType !== 1) { return false; } current = current.firstElementChild; if (current && current.tagName === 'IMG') { return true; } } }; if(isValidChainImage(e)) e.classList.add("single-line-image-p"); }); GM_addStyle(` #Main-element { margin: 46px 0 12px 0; width: auto; } #Main-element > main { background-color: unset; } @media (prefers-color-scheme: light) { body { background-color: #e6e6e6; } } @media (prefers-color-scheme: dark) { body { background-color: #333333; } } #Main-element > main > .columba-content-wrap { padding: 0px; } #Main-element > main > .columba-content-wrap > .sidebar-container { margin: unset; } #Problem-element { color: black; width: 1191px; margin: 0 auto; padding: 77px 141px 156px 141px; border-radius: 0px; box-shadow: 0 1px 10px 0px #1a1a1a1a; } #Problem-element p:not(.single-line-image-p) { text-indent: 2em; } #Problem-element p, #Problem-element ul, #Problem-element ol, #Problem-element .attachments { font-size: 24px; line-height: 1.6; margin: unset; } #Problem-element ul, #Problem-element ol { margin-left: 1em; } #Problem-element :is(ul, ol) :is(ul, ol) { margin-left: unset; } #Problem-element :is(ul, ol) :is(ul, ol) li::marker { content: "– "; } .katex:not(.katex-display .katex) { font-size: 1em; } #Problem-element ::selection{ background-color: #99c1da; //TODO mix-blend-mode: multiply; color: inherit; } .single-line-image-p { text-align: center; } `); /* === Toolbar === */ const customToolbar = document.createElement("div"); customToolbar.classList.add("custom-toolbar"); const customToolbarLeft = document.createElement("div"); customToolbarLeft.classList.add("custom-toolbar-left"); const customToolbarCenter = document.createElement("div"); customToolbarCenter.classList.add("custom-toolbar-center"); const customToolbarRight = document.createElement("div"); customToolbarRight.classList.add("custom-toolbar-right"); customToolbar.append(customToolbarLeft, customToolbarCenter, customToolbarRight); mainElement.insertBefore(customToolbar, mainElement.firstChild); const customToolbarSubmit = document.createElement("a"); customToolbarSubmit.href = "#submit"; customToolbarSubmit.textContent = "提交答案"; customToolbarSubmit.classList.add("custom-toolbar-submit", "custom-toolbar-button"); customToolbarLeft.appendChild(customToolbarSubmit); GM_addStyle(` @media (prefers-color-scheme: light) { .custom-toolbar { --toolbar-bg: #f7f7f7; --toolbar-border: #bebebe; --toolbar-text: #262626; --toolbar-button-hover: #dddddd; --toolbar-button-active: #efefef; --toolbar-separator-color: #b6b6b6; } } @media (prefers-color-scheme: dark) { .custom-toolbar { --toolbar-bg: #3b3b3b; --toolbar-border: #4f4f4f; --toolbar-text: #ffffff; --toolbar-button-hover: #545454; --toolbar-button-active: #424242; --toolbar-separator-color: #737373; } } .custom-toolbar { background-color: var(--toolbar-bg); border-bottom: 1px solid var(--toolbar-border); color: var(--toolbar-text); z-index: 10; position: fixed; top: 0; left: 0; width: 100%; height: 41px; display: flex; justify-content: space-between; align-items: center; box-sizing: border-box; } .custom-toolbar-left, .custom-toolbar-center, .custom-toolbar-right { height: 100%; display: flex; align-items: center; } .custom-toolbar-left { justify-content: flex-start; margin-right: auto; } .custom-toolbar-center { justify-content: center; margin-left: auto; margin-right: auto; } .custom-toolbar-right { justify-content: flex-end; margin-left: auto; } .custom-toolbar-button { cursor: default; border: 2px solid transparent; border-radius: 2px; padding: 0 8px; margin: 4px 0; height: 28px; line-height: 28px; text-align: center; transition: all 0.1s ease-in-out; color: var(--toolbar-text); outline: none; } .custom-toolbar-button:hover { background-color: var(--toolbar-button-hover); color: inherit; filter: unset; } .custom-toolbar-button:active { background-color: var(--toolbar-button-active); color: inherit; } .custom-toolbar-separator { margin: 0 4px; width: 1px; height: 16px; background-color: var(--toolbar-separator-color); } `) /* === Stat === */ const customStat = document.createElement("div"); customStat.classList.add("custom-stat", "custom-common-text"); const customTimeStat = document.createElement("div"); customTimeStat.classList.add("custom-time-stat"); customTimeStat.textContent = "时间限制:" + timeLimit; const customMemoryStat = document.createElement("div"); customMemoryStat.classList.add("custom-memory-stat"); customMemoryStat.textContent = "空间限制:" + memoryLimit; customStat.append(customTimeStat, customMemoryStat); problemElement.insertBefore(customStat, problemElement.firstChild); GM_addStyle(` .custom-stat { font-size: 24px; display: flex; flex-wrap: wrap; justify-content: center; } .custom-time-stat, .custom-memory-stat { margin-left: 1em; margin-right: 1em; } `); /* === Header === */ const customTitleElement = document.createElement("h1"); customTitleElement.classList.add("lfe-h1", "custom-title"); customTitleElement.textContent = titleContent.substring(titleContent.indexOf(" ") + 1); problemElement.insertBefore(customTitleElement, customStat); const customHeaderElement = document.createElement("header"); customHeaderElement.classList.add("custom-header", "custom-common-text"); problemElement.insertBefore(customHeaderElement, customTitleElement); const customHeaderLeftTextElement = document.createElement("div"); customHeaderLeftTextElement.classList.add("custom-header-left-text"); customHeaderLeftTextElement.textContent = "洛谷 Luogu"; customHeaderElement.appendChild(customHeaderLeftTextElement); const customHeaderRightTextElement = document.createElement("div"); customHeaderRightTextElement.classList.add("custom-header-right-text"); customHeaderRightTextElement.textContent = titleContent; customHeaderElement.appendChild(customHeaderRightTextElement); const customHeaderHrElement = document.createElement("hr"); customHeaderHrElement.classList.add("custom-header-hr"); customHeaderElement.appendChild(customHeaderHrElement); GM_addStyle(` .custom-header { font-size: 20px; display: flex; flex-wrap: wrap; margin: 0px 0px 48px 0px; } .custom-header-left-text, .custom-header-right-text { margin: 0px; } .custom-header-left-text { margin-right: auto; } .custom-header-hr { flex-basis: 100%; border: 1px solid #bfbfbf; margin: 0px; } `) /* === Sample Blocks === */ processElements(problemElement, "h2.lfe-h2", true, h2 => { if (h2.textContent.trim() === "输入输出样例") { h2.remove(); } }); processElements(problemElement, ".io-sample > .io-sample-block b", true, b => { const content = b.textContent.trim(); const regex = /^(输入|输出)\s*#(\d+)$/; const match = content.match(regex); if (match) { const type = match[1]; const num = match[2]; const h2 = document.createElement("h2"); h2.classList.add("lfe-h2"); h2.textContent = `样例 ${num} ${type}`; b.parentNode.parentNode.replaceChild(h2, b.parentNode); } }); /* === Titles (h1 ~ h6) === */ elmGetter.each("h1, h2, h3, h4, h5, h6", problemElement, h => { h.classList.add("H123456", "custom-strong-text"); if (!h.classList.contains("custom-title")) { if (h.textContent[0] !== "【") { h.textContent = `【${h.textContent}` }; if (h.textContent[h.textContent.length - 1] !== "】") { h.textContent = `${h.textContent}】` }; } }); GM_addStyle(` .custom-title { text-align: center; } .H123456 { font-weight: normal; } #Problem-element .H123456:not(.custom-title) { text-indent: 1em; } #Problem-element h1 { font-size: 36px; margin: 37px 0px; } #Problem-element h2 { margin-top: 43px; margin-bottom: 18px; font-size: 26px; } #Problem-element h3 { margin-top: 24px; margin-bottom: 7px; font-size: 25px; } #Problem-element h4, #Problem-element h5, #Problem-element h6 { margin-top: 10px; margin-bottom: 7px; font-size: 24px; } `) /* === Dots under <strong> === */ elmGetter.each("strong", problemElement, strong => { strong.classList.add("custom-strong-text"); const fragment = document.createDocumentFragment(); const processNode = (node) => { if (node.nodeType === Node.TEXT_NODE) { const text = node.textContent; const segments = text.split(/([\u4e00-\u9fa5])/); segments.forEach(segment => { if (!segment) return; if (/^[\u4e00-\u9fa5]$/.test(segment)) { const span = document.createElement("span"); span.classList.add("custom-hanzi-dot"); span.textContent = segment; const svgNS = "http://www.w3.org/2000/svg"; const svg = document.createElementNS(svgNS, "svg"); svg.setAttribute("class", "custom-dot"); svg.setAttribute("viewBox", "0 0 10 10"); const circle = document.createElementNS(svgNS, "circle"); circle.setAttribute("cx", "5"); circle.setAttribute("cy", "5"); circle.setAttribute("r", "3"); circle.setAttribute("fill", "black"); svg.appendChild(circle); span.appendChild(svg); fragment.appendChild(span); } else { fragment.appendChild(document.createTextNode(segment)); } }); } else if (node.nodeType === Node.ELEMENT_NODE) { fragment.appendChild(node.cloneNode(true)); } }; strong.childNodes.forEach(node => processNode(node)); strong.innerHTML = ""; strong.appendChild(fragment); }); GM_addStyle(` .custom-hanzi-dot { position: relative; } .custom-hanzi-dot svg.custom-dot { height: 0.15em; position: absolute; left: 0.5em; bottom: -0.1em; transform: translateX(-50%); pointer-events: none; } `) /* === Code Blocks === */ elmGetter.each("pre", problemElement, pre => { const code = pre.querySelector("code") || pre; const text = code.textContent; const lines = text.split("\n"); let lastNonEmptyIndex = -1; for (let i = lines.length - 1; i >= 0; i--) { if (lines[i].trim() !== "") { lastNonEmptyIndex = i; break; } } const nonEmptyLines = lastNonEmptyIndex >= 0 ? lines.slice(0, lastNonEmptyIndex + 1) : []; const lineCount = nonEmptyLines.length; const lineNumbersContainer = document.createElement("div"); lineNumbersContainer.classList.add("custom-pre-line-number"); for (let i = 1; i <= lineCount; i++) { const lineNumber = document.createElement("div"); lineNumber.textContent = i; lineNumbersContainer.appendChild(lineNumber); } const digits = lineCount.toString().length; lineNumbersContainer.style.width = `${digits * 0.5 + 0.5}em`; const wrapper = document.createElement("div"); wrapper.classList.add("custom-pre-wrapper"); pre.parentNode.insertBefore(wrapper, pre); wrapper.appendChild(lineNumbersContainer); wrapper.appendChild(pre); }); removeAll(problemElement, ".code-container > button.copy-button"); GM_addStyle(` #Problem-element > .lfe-marked-wrap { overflow: visible; } #Problem-element > .io-sample { margin: 0px; display: block; } #Problem-element > .io-sample > .io-sample-block { margin: 0px; } #Problem-element pre, #Problem-element code, .custom-pre-line-number { font-family: Consolas; background-color: unset; } #Problem-element pre, #Problem-element code { font-size: 24px; line-height: 1.5; } #Problem-element .custom-pre-line-number { position: absolute; text-align: right; padding: 6px; right: 100%; font-size: 20px; color: #949494; top: 5px; } #Problem-element .custom-pre-line-number > div { position: relative; height: 36px; top: 4px; } #Problem-element code { border: none; } #Problem-element pre { border: solid 1px blue; border-radius: 0; padding: 5px; } #Problem-element .custom-pre-wrapper { position: relative; margin: 27px -5px 62px 17px; } `) /* === Links, Focus and Tables === */ elmGetter.each("a", problemElement, e => { e.classList.add("custom-strong-text"); }); elmGetter.each("table > thead > tr > th, table > tbody > tr > td", problemElement, e => { e.classList.add("custom-common-text"); }); GM_addStyle(` #Problem-element a { color: black; font-style: italic; transition: unset; } #Problem-element a:hover { filter: none; } #Problem-element :focus-visible { outline: 3px dashed black; } #Problem-element table { display: table; margin: 25px auto; width: fit-content; } #Problem-element table > thead > tr { border-bottom: 3px solid black; } #Problem-element table > thead > tr > th, #Problem-element table > tbody > tr > td { font-size: 24px; border: 1px solid black; } #Problem-element table { border-top: 4px solid black; border-bottom: 4px solid black; border-left: 2px solid white; border-right: 2px solid white; } `) console.log("[Luogu-RER] Loaded!"); }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址