Markdown-A-Textarea

在需要的地方启用 MarkDown 语法,添加格式帮助链接及 Markdown 工具栏

  1. // ==UserScript==
  2. // @name Markdown-A-Textarea
  3. // @namespace wdssmq
  4. // @version 1.0.3
  5. // @author 沉冰浮水
  6. // @description 在需要的地方启用 MarkDown 语法,添加格式帮助链接及 Markdown 工具栏
  7. // @link https://gf.qytechs.cn/zh-CN/scripts/29203
  8. // @null ----------------------------
  9. // @contributionURL https://github.com/wdssmq#%E4%BA%8C%E7%BB%B4%E7%A0%81
  10. // @contributionAmount 5.93
  11. // @null ----------------------------
  12. // @link https://github.com/wdssmq/userscript
  13. // @link https://afdian.net/@wdssmq
  14. // @link https://gf.qytechs.cn/zh-CN/users/6865-wdssmq
  15. // @null ----------------------------
  16. // @contributor JixunMoe
  17. // @contributor wOxxOm
  18. // @license MIT License
  19. // @include https://*
  20. // @include http://*
  21. // @grant GM_addStyle
  22. // ==/UserScript==
  23.  
  24. /* eslint no-useless-escape: 0 */
  25. /* global GM_addStyle */
  26. /* jshint multistr:true */
  27. function $n(e) {
  28. return document.querySelector(e);
  29. }
  30. function $na(e) {
  31. return document.querySelectorAll(e);
  32. }
  33.  
  34. function xml2md(xml) {
  35. var md = xml;
  36. if (xml.indexOf("isXML") > -1) {
  37. // 移除isXML
  38. md = md.replace(/\n?<!--isXML-->/g, "");
  39. // 行内
  40.  
  41. // 链接
  42. md = md.replace(/<a href="([^"]+)" title="([^"]+)"\s*([^>]*)>(.+)<\/a>/g,"[$4]($1 \"$2\"){$3}");
  43. // 图片
  44. md = md.replace(/<img src="([^"]+)" alt="([^"]+)"[^>]*>/g,"![$2]($1)");
  45. // 段落
  46. md = md.replace(/<p>/g, "");
  47. md = md.replace(/<\/p>/g, "\n\n");
  48. // h1-h6
  49. md = md.replace(/<h6>(.+?)<\/h6>/g, "###### $1\n\n");
  50. md = md.replace(/<h5>(.+?)<\/h5>/g, "##### $1\n\n");
  51. md = md.replace(/<h4>(.+?)<\/h4>/g, "#### $1\n\n");
  52. md = md.replace(/<h3>(.+?)<\/h3>/g, "### $1\n\n");
  53. md = md.replace(/<h2>(.+?)<\/h2>/g, "## $1\n\n");
  54. md = md.replace(/<h1>(.+?)<\/h1>/g, "# $1\n\n");
  55. // 格式化换行
  56. md = md.replace(/\n\n+/g, "\n\n");
  57. md = md.replace(/\n+$/g, "");
  58. // 修正
  59. md = md.replace(/\){}/g, ")");
  60. }
  61. return md;
  62. }
  63.  
  64. function md2xml(md) {
  65. var xml = md;
  66. if (md.indexOf("isXML") == -1) {
  67. // 格式化换行
  68. xml = xml.replace(/\n\n+/g, "\n\n");
  69. xml = xml.replace(/\n+$/g, "");
  70. // h1-h6
  71. xml = xml.replace(/(^|\n)######\s*([^\n]+)/g, "$1<h6>$2</h6>");
  72. xml = xml.replace(/(^|\n)#####\s*([^\n]+)/g, "$1<h5>$2</h5>");
  73. xml = xml.replace(/(^|\n)####\s*([^\n]+)/g, "$1<h4>$2</h4>");
  74. xml = xml.replace(/(^|\n)###\s*([^\n]+)/g, "$1<h3>$2</h3>");
  75. xml = xml.replace(/(^|\n)##\s*([^\n]+)/g, "$1<h2>$2</h2>");
  76. xml = xml.replace(/(^|\n)#\s*([^\n]+)/g, "$1<h1>$2</h1>");
  77. // 段落
  78. xml = xml.replace(/^(?!(<h|<p|<div))/g, "<p>");
  79. xml = xml.replace(/\n+(<h|<p|<div)/g, "</p>\n$1");
  80. xml = xml.replace(/\n\n/g, "</p>\n<p>");
  81. xml = xml.replace(/(p>|h\d>|div>)<\/p>/g, "$1");
  82. xml = xml.replace(/<p>$/g, "");
  83. xml = xml.replace(/<p>(?!<\/p>)(.+)$/g, "<p>$1</p>");
  84. // 行内标记
  85. xml = xml.replace(/([^\*]*)\*\*(.*)\*\*/g, "$1<b>$2</b>");
  86. xml = xml.replace(/([^\*]*)\*(.*)\*/g, "$1<i>$2</i>");
  87. // 图片
  88. xml = xml.replace(/!\[([^\]]+)\]\(([^\s\)]+)[^\)]*\)/g, "<img src=\"$2\" alt=\"$1\" title=\"$1\">");
  89. console.log(xml);
  90. // 链接
  91. xml = xml.replace(/\[(.+)\]\(([^\s\)]+)\s*"?([^"]+)*"?\)(?:{([^}]+)})?/g, "<a href=\"$2\" title=\"$3\" $4>$1</a>");
  92. xml = xml.replace(/title=""/g,"title=\"点击链接查看\"");
  93. // xml = xml.replace(/\[(.+)\]\(([^\s\)]+)\)/g, '<a href="$2">$1</a>');
  94.  
  95. // 修正
  96. xml = xml.replace(/\s>/g,">");
  97. xml = xml.replace(/2xml/g,"");
  98. // 添加 isXML
  99. xml += "\n<!--isXML-->";
  100. }
  101. return xml;
  102. }
  103.  
  104. window.addEventListener("load", function (e) {
  105. var domTxa = $n("textarea.md-needed");
  106.  
  107. if (!domTxa){
  108. return;
  109. }
  110. console.log(1);
  111. domTxa.addEventListener("keyup", function () {
  112. if(domTxa.value.indexOf("2xml") > -1){
  113. domTxa.value = md2xml(domTxa.value);
  114. }
  115. });
  116. $n("input[type=submit]").addEventListener("mouseenter", function () {
  117. domTxa.value = md2xml(domTxa.value);
  118. });
  119. $n("input[type=submit]").addEventListener("mouseout", function () {
  120. domTxa.value = xml2md(domTxa.value);
  121. });
  122. $n(".md-toolbar").innerHTML = "<i style=\"clear:both;display: table;\"></i>";
  123.  
  124. // 添加工具栏
  125. addFeatures(domTxa);
  126.  
  127. GM_addStyle("\
  128. .md-button {\
  129. display: inline-block;\
  130. cursor: pointer;\
  131. margin: 0 1px;\
  132. font-size: 12px;\
  133. line-height: 1;\
  134. font-weight: bold;\
  135. padding: 4px 6px;\
  136. background: #eee;\
  137. border: 1px solid #999;\
  138. border-radius: 2px;\
  139. white-space: nowrap;\
  140. text-shadow: 0px 1px 0px #FFF;\
  141. box-shadow: 0px 1px 0px #FFF inset, 0px -1px 2px #BBB inset;\
  142. color: #333;}\
  143. .md-toolbar {\
  144. clear: both;\
  145. padding: 0;\
  146. margin: 1px 1px 3px;\
  147. }");
  148. });
  149.  
  150. function addFeatures(n) {
  151. if (!n){
  152. return;
  153. }
  154. // add buttons
  155. // btnMake(n, '<b>Test</b>', "test", function (e) {
  156. // n.value = md2xml(n.value)
  157. // });
  158. btnMake(n, "<b>" + __("B") + "</b>", __("Bold"), "**");
  159. btnMake(n, "<i>" + __("I") + "</i>", __("Italic"), "*");
  160. btnMake(n, "<u>" + __("U") + "</u>", __("Underline"), "<u>", "</u>");
  161. btnMake(n, "<s>" + __("S") + "</s>", __("Strikethrough"), "<s>", "</s>");
  162. btnMake(n, "&lt;br&gt;", __("Force line break"), "<br>", "", true);
  163. btnMake(n, "---", __("Horizontal line"), "\n\n---\n\n", "", true);
  164. btnMake(n, __("URL"), __("Add URL to selected text"),
  165. function (e) {
  166. try {
  167. edWrapInTag("[", "](" + prompt(__("URL") + ":") + ")", edInit(e.target));
  168. } catch (ex) {
  169. console.log(ex);
  170. }
  171. });
  172. btnMake(n, __("Image (https)"), __("Convert selected https://url to inline image"), "![" + __("image") + "](", ")");
  173. btnMake(n, __("Table"), __("Insert table template"), __("\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n"), "", true);
  174. btnMake(n, __("Code"), __("Apply CODE markdown to selected text"),
  175. function (e) {
  176. var ed = edInit(e.target);
  177. if (ed.sel.indexOf("\n") < 0){
  178. edWrapInTag("`", "`", ed);
  179. }
  180. else{
  181. edWrapInTag(((ed.sel1 === 0) || (ed.text.charAt(ed.sel1 - 1) == "\n") ? "" : "\n") + "```" + (ed.sel.charAt(0) == "\n" ? "" : "\n"),
  182. (ed.sel.substr(-1) == "\n" ? "" : "\n") + "```" + (ed.text.substr(ed.sel2, 1) == "\n" ? "" : "\n"),
  183. ed);}
  184. });
  185. }
  186.  
  187. function btnMake(elTxa, label, title, tag1_or_cb, tag2, noWrap) {
  188. var a = document.createElement("a");
  189. a.className = "md-button";
  190. a.innerHTML = label;
  191. a.title = title;
  192. a.style.setProperty("float", "right");
  193. a.addEventListener("click",
  194. typeof(tag1_or_cb) == "function" ? tag1_or_cb
  195. : noWrap ? function (e) {
  196. edInsertText(tag1_or_cb, edInit(e.target));
  197. }
  198. : function (e) {
  199. edWrapInTag(tag1_or_cb, tag2, edInit(e.target));
  200. });
  201. var elToolbar = elTxa.parentNode.querySelector(".md-toolbar");
  202. // console.log(elToolbar);
  203. a.textAreaNode = elTxa;
  204. elToolbar.insertBefore(a, elToolbar.firstElementChild);
  205. }
  206.  
  207. function edInit(btn) {
  208. var ed = {
  209. node: btn.textAreaNode,
  210. };
  211. ed.sel1 = ed.node.selectionStart;
  212. ed.sel2 = ed.node.selectionEnd;
  213. ed.text = ed.node.value;
  214. ed.sel = ed.text.substring(ed.sel1, ed.sel2);
  215. return ed;
  216. }
  217.  
  218. function edWrapInTag(tag1, tag2, ed) {
  219. ed.node.value = ed.text.substr(0, ed.sel1) + tag1 + ed.sel + (tag2 ? tag2 : tag1) + ed.text.substr(ed.sel2);
  220. ed.node.setSelectionRange(ed.sel1 + tag1.length, ed.sel1 + tag1.length + ed.sel.length);
  221. ed.node.focus();
  222. }
  223.  
  224. function edInsertText(text, ed) {
  225. ed.node.value = ed.text.substr(0, ed.sel2) + text + ed.text.substr(ed.sel2);
  226. ed.node.setSelectionRange(ed.sel2 + text.length, ed.sel2 + text.length);
  227. ed.node.focus();
  228. }
  229.  
  230. var __ = (function (l, langs) {
  231. var lang = langs[l] || langs[l.replace(/-.+/, "")];
  232. return lang ? function (text) {
  233. return lang[text] || text;
  234. }
  235. : function (text) {
  236. return text;
  237. }; // No matching language, fallback to english
  238. })("zh-CN", {
  239. // Can be full name, or just the beginning part.
  240. "zh-CN": {
  241. "Bold": "粗体",
  242. "Italic": "斜体",
  243. "Underline": "下划线",
  244. "Strikethrough": "删除线",
  245. "Force line break": "强制换行",
  246. "Horizontal line": "水平分割线",
  247. "URL": "链接",
  248. "Add URL to selected text": "为所选文字添加链接",
  249. "Image (https)": "图片 (https)",
  250. "Convert selected https://url to inline image": "将所选地址转换为行内图片",
  251. "image": "图片描述", // Default image alt value
  252. "Table": "表格",
  253. "Insert table template": "插入表格模板",
  254. "Code": "代码",
  255. "Apply CODE markdown to selected text": "将选中代码围起来",
  256.  
  257. "\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n":
  258. "\n| 表头 1 | 表头 2 |\n|-------|-------|\n| 表格 1 | 表格 2 |\n| 表格 3 | 表格 4 |\n",
  259. },
  260. "ru": {
  261. "B": "Ж",
  262. "I": "К",
  263. "U": "Ч",
  264. "S": "П",
  265. "Bold": "Жирный",
  266. "Italic": "Курсив",
  267. "Underline": "Подчеркнутый",
  268. "Strikethrough": "Перечеркнутый",
  269. "Force line break": "Новая строка",
  270. "Horizontal line": "Горизонтальная линия",
  271. "URL": "ссылка",
  272. "Add URL to selected text": "Добавить ссылку к выделенному тексту",
  273. "Image (https)": "Картинка (https)",
  274. "Convert selected https://url to inline image": "Преобразовать выделенный https:// адрес в картинку",
  275. "image": "картинка", // Default image alt value
  276. "Table": "Таблица",
  277. "Insert table template": "Вставить шаблон таблицы",
  278. "Code": "Код",
  279. "Apply CODE markdown to selected text": "Пометить выделенный фрагмент как программный код",
  280.  
  281. "\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n":
  282. "\n| заголовок1 | заголовок2 |\n|-------|-------|\n| ячейка1 | ячейка2 |\n| ячейка3 | ячейка4 |\n",
  283. },
  284. "fr": {
  285. "B": "G",
  286. "I": "I",
  287. "U": "S",
  288. "S": "B",
  289. "Bold": "Gras",
  290. "Italic": "Italique",
  291. "Underline": "Souligné",
  292. "Strikethrough": "Barré",
  293. "Force line break": "Forcer le saut de ligne",
  294. "Horizontal line": "Ligne horizontale",
  295. "URL": "URL",
  296. "Add URL to selected text": "Ajouter URL au texte sélectionné",
  297. "Image (https)": "Image (https)",
  298. "Convert selected https://url to inline image": "Convertir https://url sélectionnés en images",
  299. "image": "image", // Default image alt value
  300. "Table": "Tableau",
  301. "Insert table template": "Insérer un modèle de table",
  302. "Code": "Code",
  303. "Apply CODE markdown to selected text": "Appliquer CODE markdown au texte sélectionné",
  304.  
  305. "\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n":
  306. "\n| En-tête 1 | En-tête 2 |\n|-------|-------|\n| cellule 1 | cellule 2 |\n| cellule 3 | cellule 4 |\n",
  307. },
  308. });

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址