在需要的地方启用 MarkDown 语法,添加格式帮助链接及 Markdown 工具栏
// ==UserScript== // @name Markdown-A-Textarea // @namespace wdssmq // @version 1.0.3 // @author 沉冰浮水 // @description 在需要的地方启用 MarkDown 语法,添加格式帮助链接及 Markdown 工具栏 // @link https://greasyfork.org/zh-CN/scripts/29203 // @null ---------------------------- // @contributionURL https://github.com/wdssmq#%E4%BA%8C%E7%BB%B4%E7%A0%81 // @contributionAmount 5.93 // @null ---------------------------- // @link https://github.com/wdssmq/userscript // @link https://afdian.net/@wdssmq // @link https://greasyfork.org/zh-CN/users/6865-wdssmq // @null ---------------------------- // @contributor JixunMoe // @contributor wOxxOm // @license MIT License // @include https://* // @include http://* // @grant GM_addStyle // ==/UserScript== /* eslint no-useless-escape: 0 */ /* global GM_addStyle */ /* jshint multistr:true */ function $n(e) { return document.querySelector(e); } function $na(e) { return document.querySelectorAll(e); } function xml2md(xml) { var md = xml; if (xml.indexOf("isXML") > -1) { // 移除isXML md = md.replace(/\n?<!--isXML-->/g, ""); // 行内 // 链接 md = md.replace(/<a href="([^"]+)" title="([^"]+)"\s*([^>]*)>(.+)<\/a>/g,"[$4]($1 \"$2\"){$3}"); // 图片 md = md.replace(/<img src="([^"]+)" alt="([^"]+)"[^>]*>/g,""); // 段落 md = md.replace(/<p>/g, ""); md = md.replace(/<\/p>/g, "\n\n"); // h1-h6 md = md.replace(/<h6>(.+?)<\/h6>/g, "###### $1\n\n"); md = md.replace(/<h5>(.+?)<\/h5>/g, "##### $1\n\n"); md = md.replace(/<h4>(.+?)<\/h4>/g, "#### $1\n\n"); md = md.replace(/<h3>(.+?)<\/h3>/g, "### $1\n\n"); md = md.replace(/<h2>(.+?)<\/h2>/g, "## $1\n\n"); md = md.replace(/<h1>(.+?)<\/h1>/g, "# $1\n\n"); // 格式化换行 md = md.replace(/\n\n+/g, "\n\n"); md = md.replace(/\n+$/g, ""); // 修正 md = md.replace(/\){}/g, ")"); } return md; } function md2xml(md) { var xml = md; if (md.indexOf("isXML") == -1) { // 格式化换行 xml = xml.replace(/\n\n+/g, "\n\n"); xml = xml.replace(/\n+$/g, ""); // h1-h6 xml = xml.replace(/(^|\n)######\s*([^\n]+)/g, "$1<h6>$2</h6>"); xml = xml.replace(/(^|\n)#####\s*([^\n]+)/g, "$1<h5>$2</h5>"); xml = xml.replace(/(^|\n)####\s*([^\n]+)/g, "$1<h4>$2</h4>"); xml = xml.replace(/(^|\n)###\s*([^\n]+)/g, "$1<h3>$2</h3>"); xml = xml.replace(/(^|\n)##\s*([^\n]+)/g, "$1<h2>$2</h2>"); xml = xml.replace(/(^|\n)#\s*([^\n]+)/g, "$1<h1>$2</h1>"); // 段落 xml = xml.replace(/^(?!(<h|<p|<div))/g, "<p>"); xml = xml.replace(/\n+(<h|<p|<div)/g, "</p>\n$1"); xml = xml.replace(/\n\n/g, "</p>\n<p>"); xml = xml.replace(/(p>|h\d>|div>)<\/p>/g, "$1"); xml = xml.replace(/<p>$/g, ""); xml = xml.replace(/<p>(?!<\/p>)(.+)$/g, "<p>$1</p>"); // 行内标记 xml = xml.replace(/([^\*]*)\*\*(.*)\*\*/g, "$1<b>$2</b>"); xml = xml.replace(/([^\*]*)\*(.*)\*/g, "$1<i>$2</i>"); // 图片 xml = xml.replace(/!\[([^\]]+)\]\(([^\s\)]+)[^\)]*\)/g, "<img src=\"$2\" alt=\"$1\" title=\"$1\">"); console.log(xml); // 链接 xml = xml.replace(/\[(.+)\]\(([^\s\)]+)\s*"?([^"]+)*"?\)(?:{([^}]+)})?/g, "<a href=\"$2\" title=\"$3\" $4>$1</a>"); xml = xml.replace(/title=""/g,"title=\"点击链接查看\""); // xml = xml.replace(/\[(.+)\]\(([^\s\)]+)\)/g, '<a href="$2">$1</a>'); // 修正 xml = xml.replace(/\s>/g,">"); xml = xml.replace(/2xml/g,""); // 添加 isXML xml += "\n<!--isXML-->"; } return xml; } window.addEventListener("load", function (e) { var domTxa = $n("textarea.md-needed"); if (!domTxa){ return; } console.log(1); domTxa.addEventListener("keyup", function () { if(domTxa.value.indexOf("2xml") > -1){ domTxa.value = md2xml(domTxa.value); } }); $n("input[type=submit]").addEventListener("mouseenter", function () { domTxa.value = md2xml(domTxa.value); }); $n("input[type=submit]").addEventListener("mouseout", function () { domTxa.value = xml2md(domTxa.value); }); $n(".md-toolbar").innerHTML = "<i style=\"clear:both;display: table;\"></i>"; // 添加工具栏 addFeatures(domTxa); GM_addStyle("\ .md-button {\ display: inline-block;\ cursor: pointer;\ margin: 0 1px;\ font-size: 12px;\ line-height: 1;\ font-weight: bold;\ padding: 4px 6px;\ background: #eee;\ border: 1px solid #999;\ border-radius: 2px;\ white-space: nowrap;\ text-shadow: 0px 1px 0px #FFF;\ box-shadow: 0px 1px 0px #FFF inset, 0px -1px 2px #BBB inset;\ color: #333;}\ .md-toolbar {\ clear: both;\ padding: 0;\ margin: 1px 1px 3px;\ }"); }); function addFeatures(n) { if (!n){ return; } // add buttons // btnMake(n, '<b>Test</b>', "test", function (e) { // n.value = md2xml(n.value) // }); btnMake(n, "<b>" + __("B") + "</b>", __("Bold"), "**"); btnMake(n, "<i>" + __("I") + "</i>", __("Italic"), "*"); btnMake(n, "<u>" + __("U") + "</u>", __("Underline"), "<u>", "</u>"); btnMake(n, "<s>" + __("S") + "</s>", __("Strikethrough"), "<s>", "</s>"); btnMake(n, "<br>", __("Force line break"), "<br>", "", true); btnMake(n, "---", __("Horizontal line"), "\n\n---\n\n", "", true); btnMake(n, __("URL"), __("Add URL to selected text"), function (e) { try { edWrapInTag("[", "](" + prompt(__("URL") + ":") + ")", edInit(e.target)); } catch (ex) { console.log(ex); } }); btnMake(n, __("Image (https)"), __("Convert selected https://url to inline image"), ""); btnMake(n, __("Table"), __("Insert table template"), __("\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n"), "", true); btnMake(n, __("Code"), __("Apply CODE markdown to selected text"), function (e) { var ed = edInit(e.target); if (ed.sel.indexOf("\n") < 0){ edWrapInTag("`", "`", ed); } else{ edWrapInTag(((ed.sel1 === 0) || (ed.text.charAt(ed.sel1 - 1) == "\n") ? "" : "\n") + "```" + (ed.sel.charAt(0) == "\n" ? "" : "\n"), (ed.sel.substr(-1) == "\n" ? "" : "\n") + "```" + (ed.text.substr(ed.sel2, 1) == "\n" ? "" : "\n"), ed);} }); } function btnMake(elTxa, label, title, tag1_or_cb, tag2, noWrap) { var a = document.createElement("a"); a.className = "md-button"; a.innerHTML = label; a.title = title; a.style.setProperty("float", "right"); a.addEventListener("click", typeof(tag1_or_cb) == "function" ? tag1_or_cb : noWrap ? function (e) { edInsertText(tag1_or_cb, edInit(e.target)); } : function (e) { edWrapInTag(tag1_or_cb, tag2, edInit(e.target)); }); var elToolbar = elTxa.parentNode.querySelector(".md-toolbar"); // console.log(elToolbar); a.textAreaNode = elTxa; elToolbar.insertBefore(a, elToolbar.firstElementChild); } function edInit(btn) { var ed = { node: btn.textAreaNode, }; ed.sel1 = ed.node.selectionStart; ed.sel2 = ed.node.selectionEnd; ed.text = ed.node.value; ed.sel = ed.text.substring(ed.sel1, ed.sel2); return ed; } function edWrapInTag(tag1, tag2, ed) { ed.node.value = ed.text.substr(0, ed.sel1) + tag1 + ed.sel + (tag2 ? tag2 : tag1) + ed.text.substr(ed.sel2); ed.node.setSelectionRange(ed.sel1 + tag1.length, ed.sel1 + tag1.length + ed.sel.length); ed.node.focus(); } function edInsertText(text, ed) { ed.node.value = ed.text.substr(0, ed.sel2) + text + ed.text.substr(ed.sel2); ed.node.setSelectionRange(ed.sel2 + text.length, ed.sel2 + text.length); ed.node.focus(); } var __ = (function (l, langs) { var lang = langs[l] || langs[l.replace(/-.+/, "")]; return lang ? function (text) { return lang[text] || text; } : function (text) { return text; }; // No matching language, fallback to english })("zh-CN", { // Can be full name, or just the beginning part. "zh-CN": { "Bold": "粗体", "Italic": "斜体", "Underline": "下划线", "Strikethrough": "删除线", "Force line break": "强制换行", "Horizontal line": "水平分割线", "URL": "链接", "Add URL to selected text": "为所选文字添加链接", "Image (https)": "图片 (https)", "Convert selected https://url to inline image": "将所选地址转换为行内图片", "image": "图片描述", // Default image alt value "Table": "表格", "Insert table template": "插入表格模板", "Code": "代码", "Apply CODE markdown to selected text": "将选中代码围起来", "\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n": "\n| 表头 1 | 表头 2 |\n|-------|-------|\n| 表格 1 | 表格 2 |\n| 表格 3 | 表格 4 |\n", }, "ru": { "B": "Ж", "I": "К", "U": "Ч", "S": "П", "Bold": "Жирный", "Italic": "Курсив", "Underline": "Подчеркнутый", "Strikethrough": "Перечеркнутый", "Force line break": "Новая строка", "Horizontal line": "Горизонтальная линия", "URL": "ссылка", "Add URL to selected text": "Добавить ссылку к выделенному тексту", "Image (https)": "Картинка (https)", "Convert selected https://url to inline image": "Преобразовать выделенный https:// адрес в картинку", "image": "картинка", // Default image alt value "Table": "Таблица", "Insert table template": "Вставить шаблон таблицы", "Code": "Код", "Apply CODE markdown to selected text": "Пометить выделенный фрагмент как программный код", "\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n": "\n| заголовок1 | заголовок2 |\n|-------|-------|\n| ячейка1 | ячейка2 |\n| ячейка3 | ячейка4 |\n", }, "fr": { "B": "G", "I": "I", "U": "S", "S": "B", "Bold": "Gras", "Italic": "Italique", "Underline": "Souligné", "Strikethrough": "Barré", "Force line break": "Forcer le saut de ligne", "Horizontal line": "Ligne horizontale", "URL": "URL", "Add URL to selected text": "Ajouter URL au texte sélectionné", "Image (https)": "Image (https)", "Convert selected https://url to inline image": "Convertir https://url sélectionnés en images", "image": "image", // Default image alt value "Table": "Tableau", "Insert table template": "Insérer un modèle de table", "Code": "Code", "Apply CODE markdown to selected text": "Appliquer CODE markdown au texte sélectionné", "\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n": "\n| En-tête 1 | En-tête 2 |\n|-------|-------|\n| cellule 1 | cellule 2 |\n| cellule 3 | cellule 4 |\n", }, });