您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Convert potential Markdown syntax into HTML in 4d4y forum posts without removing existing HTML elements. Toggle original text with Ctrl+M, with a mode switch notification.
当前为
- // ==UserScript==
- // @name 4d4y Markdown Enhancer
- // @namespace http://tampermonkey.net/
- // @version 2.5
- // @description Convert potential Markdown syntax into HTML in 4d4y forum posts without removing existing HTML elements. Toggle original text with Ctrl+M, with a mode switch notification.
- // @match https://www.4d4y.com/forum/*
- // @author 屋大维 + ChatGPT
- // @license MIT
- // @grant none
- // @run-at document-end
- // ==/UserScript==
- (function () {
- "use strict";
- window.copyCode = function (button) {
- let codeElement = button.parentElement.querySelector("pre code");
- if (!codeElement) return;
- let text = codeElement.innerText;
- navigator.clipboard.writeText(text).then(() => {
- button.innerText = "已复制!";
- setTimeout(() => (button.innerText = "复制"), 1500);
- });
- };
- function markdownToHtml(md) {
- if (!md) return "";
- let blocks = {};
- let blockIndex = 0;
- // **1. 处理带语言标签的代码块**
- md = md.replace(/```(\w+)\s*<br>\s*([\s\S]*?)```/g, (match, lang, code) => {
- let placeholder = `%%CODE${blockIndex}%%`;
- let cleanCode = code.replace(/<br\s*\/?>/g, "").trim();
- let langLabel = `<div style="
- background-color: #3a3f4b;
- color: #ffffff;
- font-size: 12px;
- font-weight: bold;
- padding: 6px 12px;
- border-top-left-radius: 6px;
- font-family: sans-serif;
- display: inline-block;
- min-width: 100px;
- text-align: left;
- ">${lang}</div>`;
- let copyButton = `<button onclick="copyCode(this)" style="
- position: absolute;
- top: 6px;
- right: 10px;
- background-color: transparent;
- border: none;
- color: #ffffff;
- font-size: 12px;
- cursor: pointer;
- font-family: sans-serif;
- opacity: 0;
- transition: opacity 0.2s ease-in-out;
- ">复制</button>`;
- blocks[placeholder] = `
- <div style="
- position: relative;
- display: inline-block;
- width: 100%;
- background-color: #3a3f4b;
- border-radius: 6px;
- margin-bottom: 10px;
- overflow: hidden;
- " onmouseover="this.querySelector('button').style.opacity = 1"
- onmouseout="this.querySelector('button').style.opacity = 0">
- ${langLabel}
- ${copyButton}
- <pre style="
- background-color: #2d2d2d;
- color: #f8f8f2;
- padding: 12px;
- border-bottom-left-radius: 6px;
- border-bottom-right-radius: 6px;
- overflow-x: auto;
- font-family: 'Consolas', 'Courier New', monospace;
- font-size: 14px;
- line-height: 1.5;
- margin: 0;
- "><code>${cleanCode.replace(/</g, "<").replace(/>/g, ">")}</code></pre>
- </div>`;
- blockIndex++;
- return placeholder;
- });
- // **2. 处理普通代码块**
- md = md.replace(/```([\s\S]*?)```/g, (match, code) => {
- let placeholder = `%%CODE${blockIndex}%%`;
- let cleanCode = code.replace(/<br\s*\/?>/g, "").trim();
- let copyButton = `<button onclick="copyCode(this)" style="
- position: absolute;
- top: 6px;
- right: 10px;
- background-color: transparent;
- border: none;
- color: #ffffff;
- font-size: 12px;
- cursor: pointer;
- font-family: sans-serif;
- opacity: 0;
- transition: opacity 0.2s ease-in-out;
- ">复制</button>`;
- blocks[placeholder] = `<div style="
- position: relative;
- display: inline-block;
- width: 100%;
- background-color: #3a3f4b;
- border-radius: 6px;
- margin-bottom: 10px;
- overflow: hidden;
- " onmouseover="this.querySelector('button').style.opacity = 1"
- onmouseout="this.querySelector('button').style.opacity = 0">
- ${copyButton}
- <pre style="
- background-color: #2d2d2d;
- color: #f8f8f2;
- padding: 12px;
- border-radius: 6px;
- overflow-x: auto;
- font-family: 'Consolas', 'Courier New', monospace;
- font-size: 14px;
- line-height: 1.5;
- margin: 0;
- "><code>${cleanCode.replace(/</g, "<").replace(/>/g, ">")}</code></pre>
- </div>`;
- blockIndex++;
- return placeholder;
- });
- // **3. 还原 Markdown 形式的超链接**
- md = md.replace(
- /\[([^\]]+)\]\(<a href="([^"]+)"[^>]*>.*?<\/a>\)/g,
- "[$1]($2)",
- );
- // **4. 处理标题**
- md = md
- .replace(/^### (.*$)/gm, "<h3>$1</h3>")
- .replace(/^## (.*$)/gm, "<h2>$1</h2>")
- .replace(/^# (.*$)/gm, "<h1>$1</h1>");
- // **5. 处理加粗、斜体**
- md = md
- .replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
- .replace(/\*(.*?)\*/g, "<em>$1</em>");
- // **6. 解析 Markdown 列表**
- md = processLists(md);
- // **7. 处理行内代码**
- md = md.replace(
- /`([^`]+)`/g,
- `<code style="
- background-color: #f5f5f5;
- color: #d63384;
- padding: 2px 5px;
- border-radius: 4px;
- font-family: 'Courier New', monospace;
- font-size: 90%;
- ">$1</code>`,
- );
- // **8. 恢复代码块**
- Object.keys(blocks).forEach((placeholder) => {
- md = md.replace(placeholder, blocks[placeholder]);
- });
- // **9. 还原 Markdown 超链接为标准 HTML `<a>`**
- // 还原 Markdown 超链接,支持各种协议(http, https, chrome-extension, file, mailto 等)
- md = md.replace(
- /\[([^\[\]]+)\]\(\s*(([a-zA-Z][a-zA-Z\d+\-.]*):\/\/[^\s)]+)\s*\)/g,
- '<a href="$2">$1</a>',
- );
- return md;
- }
- function processLists(md) {
- if (!md) return "";
- let lines = md.split("\n");
- let output = [];
- let prevWasNewList = true;
- lines.forEach((line) => {
- let isNewLine = line.trim() === "<br>";
- if (isNewLine) {
- prevWasNewList = true;
- output.push(line);
- return;
- }
- let cleanedLine = line.replace(/<br>$/, "");
- let spaces = (cleanedLine.match(/^(?: )+/) || [""])[0].length / 6;
- let reducedLine = cleanedLine.replace(/^(?: )+/, "").trim();
- // 检查有序列表 (必须是整数 + 点 + 空格)
- let matchOrdered = reducedLine.match(/^(\d+)\.\s+(.+)$/);
- // 检查无序列表 (- 或 * 后跟空格)
- let matchUnordered = reducedLine.match(/^([-*])\s+(.+)$/);
- if (matchOrdered) {
- let number = matchOrdered[1];
- let content = matchOrdered[2];
- let marginLeft = spaces * 20; // 每级缩进 20px
- let listItem = `<div style="margin-left: ${marginLeft}px;"><span style="font-weight:bold;">${number}.</span> ${content}</div>`;
- output.push(listItem);
- prevWasNewList = false;
- } else if (matchUnordered) {
- let bullet = matchUnordered[1] === "-" ? "•" : "◦"; // 使用不同符号区分 - 和 *
- let content = matchUnordered[2];
- let marginLeft = spaces * 20;
- let listItem = `<div style="margin-left: ${marginLeft}px;"><span style="font-weight:bold;">${bullet}</span> ${content}</div>`;
- output.push(listItem);
- prevWasNewList = false;
- } else {
- output.push(line);
- prevWasNewList = false;
- }
- });
- return output.join("\n");
- }
- function processForumPosts() {
- document.querySelectorAll("td.t_msgfont").forEach((td) => {
- if (!td.dataset.processed) {
- let originalDiv = document.createElement("div");
- let markdownDiv = document.createElement("div");
- originalDiv.innerHTML = td.innerHTML;
- markdownDiv.innerHTML = markdownToHtml(td.innerHTML);
- markdownDiv.style.display = "block";
- originalDiv.style.display = "none";
- td.innerHTML = "";
- td.appendChild(markdownDiv);
- td.appendChild(originalDiv);
- td.dataset.processed = "true";
- td.dataset.toggled = "true"; // **默认 Markdown 模式**
- }
- });
- }
- function toggleMarkdown(showNotification = true) {
- document.querySelectorAll("td.t_msgfont").forEach((td) => {
- if (td.dataset.processed) {
- let markdownDiv = td.children[0];
- let originalDiv = td.children[1];
- if (td.dataset.toggled === "true") {
- markdownDiv.style.display = "none";
- originalDiv.style.display = "block";
- td.dataset.toggled = "false";
- if (showNotification) showToggleNotification("原始文本模式已启用");
- } else {
- markdownDiv.style.display = "block";
- originalDiv.style.display = "none";
- td.dataset.toggled = "true";
- if (showNotification) showToggleNotification("Markdown 模式已启用");
- }
- }
- });
- }
- function showToggleNotification(message) {
- let notification = document.createElement("div");
- notification.textContent = message;
- notification.style.position = "fixed";
- notification.style.top = "10px";
- notification.style.left = "50%";
- notification.style.transform = "translateX(-50%)";
- notification.style.padding = "10px 20px";
- notification.style.backgroundColor = "black";
- notification.style.color = "white";
- notification.style.fontSize = "16px";
- notification.style.borderRadius = "5px";
- notification.style.zIndex = "1000";
- notification.style.opacity = "1";
- notification.style.transition = "opacity 1s ease-in-out";
- document.body.appendChild(notification);
- setTimeout(() => {
- notification.style.opacity = "0";
- setTimeout(() => document.body.removeChild(notification), 1000);
- }, 2000);
- }
- function setupKeyboardShortcut() {
- document.addEventListener("keydown", function (event) {
- if (event.ctrlKey && event.key === "m") {
- toggleMarkdown(true); // **按 Ctrl+M 时,一定要弹出通知**
- event.preventDefault();
- }
- });
- }
- window.addEventListener("load", () => {
- processForumPosts(); // **默认 Markdown 模式**
- setupKeyboardShortcut();
- });
- })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址