GreasyFork 论坛 Markdown 小助手

在论坛默认使用 Markdown 格式,添加格式帮助链接及 Markdown 工具栏

目前为 2014-12-08 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name GreasyFork forum MARKDOWN for comments
  3. // @name:en GreasyFork forum MARKDOWN for comments
  4. // @name:ru GreasyFork форум - MARKDOWN в комментариях
  5. // @name:zh-CN GreasyFork 论坛 Markdown 小助手
  6. // @name:zh-TW GreasyFork 论坛 Markdown 小助手
  7. // @author wOxxOm
  8. // @contributor JixunMoe
  9. // @license MIT License
  10. // @description Select MARKDOWN format by default, add help links, add toolbar formatting buttons for markdown
  11. // @description:ru Включает формат MARKDOWN по умолчанию, добавляет справочные ссылки по форматам, добавляет панель кнопок форматирования markdown
  12. // @description:zh-CN 在论坛默认使用 Markdown 格式,添加格式帮助链接及 Markdown 工具栏
  13. // @description:zh-TW 在论坛默认使用 Markdown 格式,添加格式帮助链接及 Markdown 工具栏
  14. // @icon https://raw.githubusercontent.com/dcurtis/markdown-mark/master/png/66x40-solid.png
  15. // @namespace wOxxOm.scripts
  16. // @version 1.2.1
  17. // @include https://gf.qytechs.cn/*forum/discussion/*
  18. // @include https://gf.qytechs.cn/*forum/post/discussion*
  19. // @run-at document-start
  20. // @grant none
  21. // ==/UserScript==
  22.  
  23. var ob = new MutationObserver(function(mutations){
  24. for (var i=0, ml=mutations.length, m; (i<ml) && (m=mutations[i]); i++)
  25. for (var j=0, nodes=m.addedNodes, nl=nodes.length, n; (j<nl) && (n=nodes[j]); j++)
  26. if (n.nodeType == 1) {
  27. if (n.localName == 'label') {
  28. if (n.for != 'Form_Format2')
  29. continue;
  30. }
  31. else if (!(n = n.querySelector('label[for="Form_Format2"]')))
  32. continue;
  33.  
  34. for (var p=n; (p = p.parentNode) && (p.localName != 'form'); ) {}
  35. if (p && (p.action.indexOf('/editcomment/') < 0))
  36. n.click();
  37.  
  38. addFeatures(n);
  39. return;
  40. }
  41. });
  42. ob.observe(document, {subtree:true, childList:true});
  43.  
  44. function addFeatures(n) {
  45. // add formatting help tooltips
  46. n.previousElementSibling.insertAdjacentHTML('beforeend',
  47. ' (<a href="/help/allowed-markup" target="_blank" title="'+
  48. '* (name, title), a (href), abbr, b, blockquote (cite), br, center, cite, code, dd, del, dfn, div, dl, dt, em, '+
  49. 'h1, h2, h3, h4, h5, h6, hr, i, ins, img (alt, height, src (https), width), kbd, li, mark, ol, p, pre, q (cite), '+
  50. 'rp, rt, ruby, s, samp, small, span, strike, strong, tt, table, tbody, tfoot, thead, td, th, tr, sub, sup, '+
  51. 'time (datetime, pubdate), u, ul, var">?</a>)');
  52. n.insertAdjacentHTML('beforeend',
  53. ' (<a href="http://www.darkcoding.net/software/markdown-quick-reference/" target="_blank">?</a>)');
  54.  
  55. // add buttons
  56. n.parentNode.textAreaNode = n.parentNode.querySelector('textarea');
  57. btnMake(n, '<b>'+__('B')+'</b>', __('Bold'), '**');
  58. btnMake(n, '<i>'+__('I')+'</i>', __('Italic'), '*');
  59. btnMake(n, '<u>'+__('U')+'</u>', __('Underline'), '<u>','</u>');
  60. btnMake(n, '<s>'+__('S')+'</s>', __('Strikethrough'), '<s>','</s>');
  61. btnMake(n, '&lt;br&gt;', __('Force line break'), '<br>','', true);
  62. btnMake(n, '---', __('Horizontal line'), '\n\n---\n\n', '', true);
  63. btnMake(n, __('URL'), __('Add URL to selected text'),
  64. function(e) {
  65. try {edWrapInTag('[', ']('+prompt(__('URL')+':')+')', edInit(e.target))}
  66. catch(e) {};
  67. });
  68. btnMake(n, __('Image (https)'), __('Convert selected https://url to inline image'), '!['+__('image')+'](', ')');
  69. btnMake(n, __('Table'), __('Insert table template'), __('\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n'), '', true);
  70. btnMake(n, __('Code'), __('Apply CODE markdown to selected text'),
  71. function(e){
  72. var ed = edInit(e.target);
  73. if (ed.sel.indexOf('\n') < 0)
  74. edWrapInTag('`', '`', ed);
  75. else
  76. edWrapInTag(((ed.sel1==0) || (ed.text.charAt(ed.sel1-1) == '\n') ? '' : '\n') + '```' + (ed.sel.charAt(0) == '\n' ? '' : '\n'),
  77. (ed.sel.substr(-1) == '\n' ? '' : '\n') + '```' + (ed.text.substr(ed.sel2,1) == '\n' ? '' : '\n'),
  78. ed);
  79. });
  80. }
  81.  
  82. function btnMake(afterNode, label, title, tag1_or_cb, tag2, noWrap) {
  83. var a = document.createElement('a');
  84. a.className = 'Button';
  85. a.style.setProperty('float','right');
  86. a.innerHTML = label;
  87. a.title = title;
  88. a.addEventListener('click',
  89. typeof(tag1_or_cb) == 'function'
  90. ? tag1_or_cb
  91. : noWrap ? function(e){edInsertText(tag1_or_cb, edInit(e.target))}
  92. : function(e){edWrapInTag(tag1_or_cb, tag2, edInit(e.target))});
  93. a.textAreaNode = afterNode.parentNode.textAreaNode;
  94. afterNode.parentNode.insertBefore(a, afterNode.nextElementSibling);
  95. }
  96.  
  97. function edInit(btn) {
  98. var ed = {node: btn.textAreaNode || btn.parentNode.textAreaNode}
  99. ed.sel1 = ed.node.selectionStart;
  100. ed.sel2 = ed.node.selectionEnd,
  101. ed.text = ed.node.value;
  102. ed.sel = ed.text.substring(ed.sel1, ed.sel2);
  103. return ed;
  104. }
  105.  
  106. function edWrapInTag(tag1, tag2, ed) {
  107. ed.node.value = ed.text.substr(0, ed.sel1) + tag1 + ed.sel + (tag2?tag2:tag1) + ed.text.substr(ed.sel2);
  108. ed.node.setSelectionRange(ed.sel1 + tag1.length, ed.sel1 + tag1.length + ed.sel.length);
  109. ed.node.focus();
  110. }
  111.  
  112. function edInsertText(text, ed) {
  113. ed.node.value = ed.text.substr(0, ed.sel2) + text + ed.text.substr(ed.sel2);
  114. ed.node.setSelectionRange(ed.sel2 + text.length, ed.sel2 + text.length);
  115. ed.node.focus();
  116. }
  117.  
  118. var __ = (function (l, langs) {
  119. var lang = langs[l] || langs[l.replace(/-.+/, '')];
  120. return lang ? function (text) { return lang[text] || text; }
  121. : function (text) { return text; } // No matching language, fallback to english
  122. })(location.pathname.match(/^\/(.+?)\//)[1], {
  123. // Can be full name, or just the beginning part.
  124. 'zh-CN': {
  125. 'Bold': '粗体',
  126. 'Italic': '斜体',
  127. 'Underline': '下划线',
  128. 'Strikethrough': '删除线',
  129. 'Force line break': '强制换行',
  130. 'Horizontal line': '水平分割线',
  131. 'URL': '链接',
  132. 'Add URL to selected text': '为所选文字添加链接',
  133. 'Image (https)': '图片 (https)',
  134. 'Convert selected https://url to inline image': '将所选地址转换为行内图片',
  135. 'image': '图片描述', // Default image alt value
  136. 'Table': '表格',
  137. 'Insert table template': '插入表格模板',
  138. 'Code': '代码',
  139. 'Apply CODE markdown to selected text': '将选中代码围起来',
  140.  
  141. '\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n':
  142. '\n| 表头 1 | 表头 2 |\n|-------|-------|\n| 表格 1 | 表格 2 |\n| 表格 3 | 表格 4 |\n'
  143. },
  144. 'ru': {
  145. 'B': 'Ж',
  146. 'I': 'К',
  147. 'U': 'Ч',
  148. 'S': 'П',
  149. 'Bold': 'Жирный',
  150. 'Italic': 'Курсив',
  151. 'Underline': 'Подчеркнутый',
  152. 'Strikethrough': 'Перечеркнутый',
  153. 'Force line break': 'Новая строка',
  154. 'Horizontal line': 'Горизонтальная линия',
  155. 'URL': 'ссылка',
  156. 'Add URL to selected text': 'Добавить ссылку к выделенному тексту',
  157. 'Image (https)': 'Картинка (https)',
  158. 'Convert selected https://url to inline image': 'Преобразовать выделенный https:// адрес в картинку',
  159. 'image': 'картинка', // Default image alt value
  160. 'Table': 'Таблица',
  161. 'Insert table template': 'Вставить шаблон таблицы',
  162. 'Code': 'Код',
  163. 'Apply CODE markdown to selected text': 'Пометить выделенный фрагмент как программный код',
  164.  
  165. '\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n':
  166. '\n| заголовок1 | заголовок2 |\n|-------|-------|\n| ячейка1 | ячейка2 |\n| ячейка3 | ячейка4 |\n'
  167. }
  168. });

QingJ © 2025

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