GreasyFork 论坛 Markdown 小助手

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

当前为 2014-12-07 提交的版本,查看 最新版本

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