Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Markdown Editor Enhancer for Mastodon glitch-soc v5.05 (DeepSeek ChatGPT)
- // @version 5.05
- // @namespace http://tampermonkey.net/
- // @description Improved Markdown preview with proper ESC clearing
- // @author Johan
- // @match *://cr8r.gg/*
- // @match *://tilde.zone/*
- // @match *://infosec.exchange/*
- // @match *://toot.cat/*
- // @grant none
- // ==/UserScript==
- (function() {
- 'use strict';
- // 1. Inline-разметка
- function inlineMarkdown(text) {
- return text
- // Ссылки [текст](URL) — улучшенный регексп
- .replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, '<a href="$2" target="_blank" rel="noopener nofollow noreferrer" class="status-link unhandled-link">$1</a>')
- .replace(/#([а-яa-z0-9_]+)/gi, '<span class="mention hashtag status-link">#$1</span>')
- .replace(/@([a-zA-Z0-9_]+)@([a-zA-Z0-9\.\-]+)/g, '<a href="https://$2/@$1" class="u-url mention status-link" rel="nofollow noopener" target="_blank" title="@$1@$2">@<span>$1@$2</span></a>'
- )
- .replace(/\[(.*?)\]\((.*?)\)/g, '<a href="$2" target="_blank">$1</a>')
- .replace(/`(.*?)`/g, '<code>$1</code>')
- .replace(/~~(.*?)~~/g, '<del>$1</del>')
- .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
- .replace(/__(.*?)__/g, '<strong>$1</strong>')
- .replace(/\*(.*?)\*/g, '<em>$1</em>')
- .replace(/_(.*?)_/g, '<em>$1</em>')
- }
- // 2. Парсинг Markdown
- function parseMarkdown(raw) {
- const lines = raw.split('\n');
- let result = '';
- let inQuote = false;
- let inCodeBlock = false;
- let codeContent = [];
- let currentParagraph = [];
- let inList = false;
- let listType = '';
- function flushParagraph() {
- if (currentParagraph.length === 0) return;
- let content = currentParagraph.join('\n').trim();
- if (!content) {
- currentParagraph = [];
- return;
- }
- if (inQuote) {
- content = content.replace(/^>\s?/gm, '');
- result += `<blockquote><p>${inlineMarkdown(content)}</p></blockquote>`;
- } else if (listType) {
- const listItems = content.split('\n');
- result += `<${listType === 'unordered' ? 'ul' : 'ol'}>`;
- listItems.forEach(item => {
- const text = item.replace(/^(?:-|\d+\.)\s+/, '').trim();
- if (text) result += `<li>${inlineMarkdown(text)}</li>`;
- });
- result += `</${listType === 'unordered' ? 'ul' : 'ol'}>`;
- } else {
- result += `<p>${inlineMarkdown(content)}</p>`;
- }
- currentParagraph = [];
- }
- function flushCodeBlock() {
- if (codeContent.length === 0) return;
- result += `<pre><code>${codeContent.join('\n')
- .replace(/&/g, '&')
- .replace(/</g, '<')
- .replace(/>/g, '>')
- }</code></pre>`;
- codeContent = [];
- }
- for (const line of lines) {
- const trimmedLine = line.trim();
- if (trimmedLine.startsWith('```')) {
- if (inCodeBlock) {
- flushCodeBlock();
- inCodeBlock = false;
- } else {
- flushParagraph();
- inCodeBlock = true;
- }
- continue;
- }
- if (inCodeBlock) {
- codeContent.push(line);
- continue;
- }
- if (trimmedLine.startsWith('# ')) {
- flushParagraph();
- result += `<h1>${trimmedLine.substring(2)}</h1>`;
- continue;
- }
- const isQuoteLine = line.startsWith('>');
- if (isQuoteLine && !inQuote) {
- flushParagraph();
- inQuote = true;
- } else if (!isQuoteLine && inQuote) {
- flushParagraph();
- inQuote = false;
- }
- const isListLine = /^(-|\d+\.)\s+/.test(trimmedLine);
- if (isListLine && !inList) {
- flushParagraph();
- inList = true;
- listType = trimmedLine.startsWith('-') ? 'unordered' : 'ordered';
- } else if (!isListLine && inList) {
- flushParagraph();
- inList = false;
- listType = '';
- }
- if (trimmedLine === '') {
- flushParagraph();
- continue;
- }
- currentParagraph.push(line);
- }
- flushParagraph();
- flushCodeBlock();
- return result;
- }
- // 3. Создание превью
- function applyPreview(textarea) {
- const preview = textarea.nextElementSibling || document.createElement('div');
- if (!preview.classList.contains('md-preview')) {
- preview.className = 'md-preview status__content__text status__content__text--visible translate';
- preview.style.cssText = `
- border-top: 1px solid #ccc;
- padding: 10px;
- margin-top: 5px;
- white-space: normal;
- // раскомментируйте, если хотите со скроллбаром max-height: 300px;
- overflow-y: auto;
- `;
- textarea.parentNode.insertBefore(preview, textarea.nextSibling);
- textarea.addEventListener('keydown', (e) => {
- if (e.key === 'Escape') {
- if (textarea.value === '') {
- preview.innerHTML = '';
- } else {
- textarea.value = '';
- preview.innerHTML = '';
- }
- e.preventDefault();
- }
- });
- }
- preview.innerHTML = parseMarkdown(textarea.value);
- }
- // 4. Глобальный обработчик Escape
- function setupEscapeHandler() {
- document.addEventListener('keydown', (e) => {
- if (e.key === 'Escape') {
- const activeTextarea = document.activeElement;
- if (activeTextarea && activeTextarea.matches('textarea.autosuggest-textarea__textarea')) {
- const preview = activeTextarea.nextElementSibling;
- if (preview?.classList.contains('md-preview')) {
- if (activeTextarea.value === '') {
- preview.innerHTML = '';
- }
- activeTextarea.focus();
- }
- }
- }
- });
- }
- // 5. Инициализация
- function init() {
- const textarea = document.querySelector('textarea.autosuggest-textarea__textarea');
- if (textarea) {
- textarea.addEventListener('input', () => applyPreview(textarea));
- applyPreview(textarea);
- }
- setupEscapeHandler();
- }
- /*
- // Собственные стили, пока не работает
- const style = document.createElement('style');
- style.textContent = `
- .md-preview {
- font-family: inherit;
- color: inherit;
- }
- .md-preview blockquote {
- border-left: 3px solid #4a90e2 !mportant;
- padding-left: 1em !mportant;
- margin: 0.8em 0 !mportant;
- color: #333 !mportant;
- }
- .md-preview p {
- margin: 0.5em 0 !mportant;
- line-height: 1. !mportant;
- }
- .md-preview code {
- background: #f0f0f0 !mportant;
- padding: 0.2em 0.4em !mportant;
- border-radius: 3px !mportant;
- font-family: monospace !mportant;
- }
- .md-preview pre {
- background: #f5f5f5 !mportant;
- padding: 1em !mportant;
- overflow: auto !mportant;
- border-radius: 3px !mportant;
- }
- .md-preview h1 {
- font-size: 1.2em !mportant;
- margin: 1em 0 0.5em 0 !mportant;
- font-weight: bold !mportant;
- }
- .md-preview ul, .md-preview ol {
- margin: 0.5em 0 !mportant;
- padding-left: 2em !mportant;
- }
- `;
- document.head.appendChild(style);
- */
- // Запуск
- if (document.readyState === 'complete') {
- init();
- } else {
- window.addEventListener('load', init);
- }
- })();
Advertisement
Add Comment
Please, Sign In to add comment