您需要先安装一个扩展,例如 篡改猴、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.2 // @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'; function markdownToHtml(md) { if (!md) return ''; let blocks = {}; let blockIndex = 0; // **1. 保护 blockquote 和 blockcode** md = md.replace(/<(blockquote|div class="blockcode")>[\s\S]*?<\/\1>/g, (match) => { let placeholder = `%%BLOCK${blockIndex}%%`; blocks[placeholder] = match; blockIndex++; return placeholder; }); // **2. 还原 Markdown 形式的超链接** md = md.replace(/\[([^\]]+)\]\(<a href="([^"]+)"[^>]*>.*?<\/a>\)/g, '[$1]($2)'); // **3. 处理标题** md = md.replace(/^### (.*$)/gm, '<h3>$1</h3>') .replace(/^## (.*$)/gm, '<h2>$1</h2>') .replace(/^# (.*$)/gm, '<h1>$1</h1>'); // **4. 处理加粗、斜体、行内代码** md = md.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>') .replace(/\*(.*?)\*/g, '<em>$1</em>') .replace(/`(.*?)`/g, '<code>$1</code>'); // **5. 解析 Markdown 列表** md = processLists(md); // **6. 恢复 blockquote、blockcode** Object.keys(blocks).forEach((placeholder) => { md = md.replace(placeholder, blocks[placeholder]); }); // **7. 还原 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(); }); })();