您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
re-render markdown with marked.js and highlight codeblocks with highlight.js
// ==UserScript== // @name Old Reddit Better Codeblocks // @namespace http://tampermonkey.net/ // @version 0.4.2 // @license MIT // @description re-render markdown with marked.js and highlight codeblocks with highlight.js // @author cultab // @match http*://*.reddit.com/* // @exclude http*://new.reddit.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=reddit.com // @grant GM_addStyle // @grant GM_getResourceText // @require https://cdn.jsdelivr.net/npm/@violentmonkey/dom@2 // @require https://cdn.jsdelivr.net/npm/[email protected]/lib/marked.umd.min.js // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/purify.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js // @resource hljs https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/styles/github-dark.min.css // ==/UserScript== /* global VM hljs DOMPurify marked */ const DEBUG = false; function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function until(conditionFunction) { const poll = resolve => { if (conditionFunction()) { resolve(); } else { setTimeout(_ => poll(resolve), 400); } } return new Promise(poll); } function parse(md) { log(md) md = md.replace(/(https?:\/\/.*\.(jpeg|jpg|png|gif|webp).*(\?[A-z])?)/g, "$1:\n\n"); log(md) md = md.replace('/ /g', ' '); md = DOMPurify.sanitize(marked.parse(md)); md = md.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); return md; } function log(...vars) { if (DEBUG) { console.log(...vars); } } const skipme_marker = "orbc_skip"; const source_marker = "orbc_source"; const stoyle = GM_getResourceText("hljs"); GM_addStyle(stoyle); const content = document.body.querySelector("div.content"); log(content); let base = 0; const genRanHex = size => [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join(''); const disconnect = VM.observe(content, () => { const id = genRanHex(6); // all posts/comments const entries = document.getElementsByClassName("entry"); // barrier for callback completion let barrier = entries.length; log(id, " Start with #", barrier); let changed = false; for (const entry of entries) { // const eid = genRanHex(4); // if it contains an expando we need to check some stuff :) let expando_btn = entry.querySelector(".expando-button") if (expando_btn) { if (expando_btn.classList.contains("collapsed") || !expando_btn.classList.contains("selftext")) { entry.classList.remove(skipme_marker); barrier--; continue; } else { } } // if we proccesed this entry, skip it if (entry.classList.contains(skipme_marker)) { barrier--; continue; } // find view source button and if exists click it twice let btn = entry.querySelector(".viewSource"); if (!btn) { barrier--; continue; } btn.children[0].click(); // yes twice btn.children[0].click(); // when source is loaded, use it to replace post content with marked.js markdown const fn = () => { /* intended shared reference to barrier and changed*/ let source = entry.querySelector("textarea").innerHTML; if (!source) { log(id, "no source yet"); return false; } entry.classList.add(source_marker); entry.classList.add(skipme_marker); let post = entry.querySelector(".usertext-body"); if (post) { changed = true; post.children[0].innerHTML = parse(source); } else { log("null post for id: ", id); } barrier--; return true } // if view source has loaded run if (entry.classList.contains(source_marker)) { fn(); } else { // else wait for it to load VM.observe(entry, fn); } } (async () => { // wait until all posts have been re-parsed await until(() => { log(id, "barrier", barrier); return barrier == 0; }); log(id, " Exit, changed: ", changed); if (!changed) { return false; } // create a div with class hlhs let hl = document.createElement("div"); hl.classList.add('hljs'); hl.setAttribute("id", "hljshack"); document.querySelector("body").append(hl); // use it to get the style of hljs classes let ready_and_styled = document.getElementById("hljshack"); let wanted_styles = window.getComputedStyle(ready_and_styled); // force hljs styles on code and pre blocks let code_blocks = document.querySelectorAll("code"); for (let blk of code_blocks) { // highlight block blk.innerHTML = hljs.highlightAuto(blk.innerText).value; blk.style.backgroundColor = wanted_styles.backgroundColor; blk.style.color = wanted_styles.color; } let pre_elems = document.querySelectorAll("pre"); for (let pre of pre_elems) { pre.style.backgroundColor = wanted_styles.backgroundColor; pre.style.borderColor = wanted_styles.color; } })(); return false; }); content.append(document.createElement("span"));