Greasy Fork镜像 还支持 简体中文。

Github Comment Enhancer

Enhances Github comments

目前為 2014-05-14 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @id Github_Comment_Enhancer@https://github.com/jerone/UserScripts
  3. // @name Github Comment Enhancer
  4. // @namespace https://github.com/jerone/UserScripts
  5. // @description Enhances Github comments
  6. // @author jerone
  7. // @homepage https://github.com/jerone/UserScripts/tree/master/Github_Comment_Enhancer
  8. // @homepageURL https://github.com/jerone/UserScripts/tree/master/Github_Comment_Enhancer
  9. // @version 1.3
  10. // @grant none
  11. // @run-at document-end
  12. // @include https://github.com/*/*/issues/*
  13. // @include https://github.com/*/*/pull/*
  14. // @include https://github.com/*/*/commit/*
  15. // @include https://github.com/*/*/wiki/*
  16. // ==/UserScript==
  17. /* global unsafeWindow */
  18.  
  19. (function() {
  20.  
  21. // Source: https://github.com/gollum/gollum/blob/9c714e768748db4560bc017cacef4afa0c751a63/lib/gollum/public/gollum/javascript/editor/langs/markdown.js
  22. var MarkDown = {
  23. "function-bold": {
  24. search: /^(\s*)([\s\S]*?)(\s*)$/g,
  25. replace: "$1**$2**$3"
  26. },
  27. "function-italic": {
  28. search: /^(\s*)([\s\S]*?)(\s*)$/g,
  29. replace: "$1_$2_$3"
  30. },
  31. "function-strikethrough": {
  32. search: /^(\s*)([\s\S]*?)(\s*)$/g,
  33. replace: "$1~~$2~~$3"
  34. },
  35.  
  36. "function-h1": {
  37. search: /(.+)([\n]?)/g,
  38. replace: "# $1$2",
  39. forceNewline: true
  40. },
  41. "function-h2": {
  42. search: /(.+)([\n]?)/g,
  43. replace: "## $1$2",
  44. forceNewline: true
  45. },
  46. "function-h3": {
  47. search: /(.+)([\n]?)/g,
  48. replace: "### $1$2",
  49. forceNewline: true
  50. },
  51. "function-h4": {
  52. search: /(.+)([\n]?)/g,
  53. replace: "#### $1$2",
  54. forceNewline: true
  55. },
  56. "function-h5": {
  57. search: /(.+)([\n]?)/g,
  58. replace: "##### $1$2",
  59. forceNewline: true
  60. },
  61. "function-h6": {
  62. search: /(.+)([\n]?)/g,
  63. replace: "###### $1$2",
  64. forceNewline: true
  65. },
  66.  
  67. "function-link": {
  68. exec: function(txt, selText, next) {
  69. var isUrl = selText && /(?:https?:\/\/)|(?:www\.)/.test(selText.trim()),
  70. href = window.prompt("Link href:", isUrl ? selText.trim() : ""),
  71. text = window.prompt("Link text:", isUrl ? "" : selText.trim());
  72. if (href) {
  73. next("[" + (text || href) + "](" + href + ")");
  74. }
  75. }
  76. },
  77. "function-image": {
  78. exec: function(txt, selText, next) {
  79. var isUrl = selText && /(?:https?:\/\/)|(?:www\.)/.test(selText.trim()),
  80. href = window.prompt("Image href:", isUrl ? selText.trim() : ""),
  81. text = window.prompt("Image text:", isUrl ? "" : selText.trim());
  82. if (href) {
  83. next("![" + (text || href) + "](" + href + ")");
  84. }
  85. }
  86. },
  87.  
  88. "function-ul": {
  89. search: /(.+)([\n]?)/g,
  90. replace: "* $1$2",
  91. forceNewline: true
  92. },
  93. "function-ol": {
  94. exec: function(txt, selText, next) {
  95. var repText = "";
  96. if (!selText) {
  97. repText = "1. ";
  98. } else {
  99. var lines = selText.split("\n"),
  100. hasContent = /[\w]+/;
  101. for (var i = 0; i < lines.length; i++) {
  102. if (hasContent.test(lines[i])) {
  103. repText += (i + 1).toString() + ". " + lines[i] + "\n";
  104. }
  105. }
  106. }
  107. next(repText);
  108. }
  109. },
  110. "function-checklist": {
  111. search: /(.+)([\n]?)/g,
  112. replace: "* [ ] $1$2",
  113. forceNewline: true
  114. },
  115.  
  116. "function-code": {
  117. exec: function(txt, selText, next) {
  118. var rt = selText.indexOf("\n") > -1 ? "$1\n```\n$2\n```$3" : "$1`$2`$3";
  119. next(selText.replace(/^(\s*)([\s\S]*?)(\s*)$/g, rt));
  120. }
  121. },
  122. "function-blockquote": {
  123. search: /(.+)([\n]?)/g,
  124. replace: "> $1$2",
  125. forceNewline: true
  126. },
  127. "function-hr": {
  128. append: "\n***\n",
  129. forceNewline: true
  130. },
  131. "function-table": {
  132. append: "\n" +
  133. "| Header | Header | Header |\n" +
  134. "| :--- | :---: | ---: |\n" +
  135. "| Cell | Cell | Cell |\n" +
  136. "| Cell | Cell | Cell |\n",
  137. forceNewline: true
  138. }
  139. };
  140.  
  141. var editorHTML = (function() {
  142. return '<div id="gollum-editor-function-buttons">' +
  143. ' <div class="button-group">' +
  144. ' <a href="#" id="function-bold" class="minibutton function-button" title="Bold" tabindex="-1">' +
  145. ' <b>B</b>' +
  146. ' </a>' +
  147. ' <a href="#" id="function-italic" class="minibutton function-button" title="Italic" tabindex="-1">' +
  148. ' <em>i</em>' +
  149. ' </a>' +
  150. ' <a href="#" id="function-strikethrough" class="minibutton function-button" title="Strikethrough" tabindex="-1">' +
  151. ' <s>S</s>' +
  152. ' </a>' +
  153. ' </div>' +
  154.  
  155. ' <div class="button-group">' +
  156. ' <div class="select-menu js-menu-container js-select-menu js-composer-assignee-picker">' +
  157. ' <span aria-haspopup="true" title="Headers" role="button" class="minibutton select-menu-button icon-only js-menu-target" style="padding:0 18px 0 7px; width:auto; border-bottom-right-radius:3px; border-top-right-radius:3px;">' +
  158. ' <b>h#</b>' +
  159. ' </span>' +
  160. ' <div aria-hidden="false" class="select-menu-modal-holder js-menu-content js-navigation-container js-active-navigation-container" style="top: 26px;">' +
  161. ' <div class="select-menu-modal" style="width:auto;">' +
  162. ' <div class="select-menu-header">' +
  163. ' <span class="select-menu-title">Choose header</span>' +
  164. ' <span class="octicon octicon-remove-close js-menu-close"></span>' +
  165. ' </div>' +
  166. ' <div class="button-group">' +
  167. ' <a href="#" id="function-h1" class="minibutton function-button js-menu-close" title="Header 1" tabindex="-1">' +
  168. ' <b>h1</b>' +
  169. ' </a>' +
  170. ' <a href="#" id="function-h2" class="minibutton function-button js-menu-close" title="Header 2" tabindex="-1">' +
  171. ' <b>h2</b>' +
  172. ' </a>' +
  173. ' <a href="#" id="function-h3" class="minibutton function-button js-menu-close" title="Header 3" tabindex="-1">' +
  174. ' <b>h3</b>' +
  175. ' </a>' +
  176. ' <a href="#" id="function-h4" class="minibutton function-button js-menu-close" title="Header 4" tabindex="-1">' +
  177. ' <b>h4</b>' +
  178. ' </a>' +
  179. ' <a href="#" id="function-h5" class="minibutton function-button js-menu-close" title="Header 5" tabindex="-1">' +
  180. ' <b>h5</b>' +
  181. ' </a>' +
  182. ' <a href="#" id="function-h6" class="minibutton function-button js-menu-close" title="Header 6" tabindex="-1">' +
  183. ' <b>h6</b>' +
  184. ' </a>' +
  185. ' </div>' +
  186. ' </div>' +
  187. ' </div>' +
  188. ' </div>' +
  189. ' </div>' +
  190.  
  191. ' <div class="button-group">' +
  192. ' <a href="#" id="function-link" class="minibutton function-button" title="Link" tabindex="-1">' +
  193. ' <span class="octicon octicon-link"></span>' +
  194. ' </a>' +
  195. ' <a href="#" id="function-image" class="minibutton function-button" title="Image" tabindex="-1">' +
  196. ' <span class="octicon octicon-file-media"></span>' +
  197. ' </a>' +
  198. ' </div>' +
  199. ' <div class="button-group">' +
  200. ' <a href="#" id="function-ul" class="minibutton function-button" title="Unordered List" tabindex="-1">' +
  201. ' <span class="octicon octicon-list-unordered"></span>' +
  202. ' </a>' +
  203. ' <a href="#" id="function-ol" class="minibutton function-button" title="Ordered List" tabindex="-1">' +
  204. ' <span class="octicon octicon-list-ordered"></span>' +
  205. ' </a>' +
  206. ' <a href="#" id="function-checklist" class="minibutton function-button" title="Task List" tabindex="-1">' +
  207. ' <span class="octicon octicon-checklist"></span>' +
  208. ' </a>' +
  209. ' </div>' +
  210.  
  211. ' <div class="button-group">' +
  212. ' <a href="#" id="function-code" class="minibutton function-button" title="Code" tabindex="-1">' +
  213. ' <span class="octicon octicon-code"></span>' +
  214. ' </a>' +
  215. ' <a href="#" id="function-blockquote" class="minibutton function-button" title="Blockquote" tabindex="-1">' +
  216. ' <span class="octicon octicon-quote"></span>' +
  217. ' </a>' +
  218. ' <a href="#" id="function-hr" class="minibutton function-button" title="Horizontal Rule" tabindex="-1">' +
  219. ' <span class="octicon octicon-horizontal-rule"></span>' +
  220. ' </a>' +
  221. ' <a href="#" id="function-table" class="minibutton function-button" title="Table" tabindex="-1">' +
  222. ' <span class="octicon octicon-three-bars"></span>' +
  223. ' </a>' +
  224. ' </div>' +
  225. '</div>';
  226. })();
  227.  
  228. // Source: https://github.com/gollum/gollum/blob/9c714e768748db4560bc017cacef4afa0c751a63/lib/gollum/public/gollum/javascript/editor/gollum.editor.js#L516
  229. function executeAction(definitionObject, commentForm) {
  230. var txt = commentForm.value,
  231. selPos = {
  232. start: commentForm.selectionStart,
  233. end: commentForm.selectionEnd
  234. },
  235. selText = txt.substring(selPos.start, selPos.end),
  236. repText = selText,
  237. reselect = true,
  238. cursor = null;
  239.  
  240. // execute replacement function;
  241. if (definitionObject.exec) {
  242. definitionObject.exec(txt, selText, function(repText) {
  243. replaceFieldSelection(commentForm, repText);
  244. });
  245. return;
  246. }
  247.  
  248. // execute a search;
  249. var searchExp = new RegExp(definitionObject.search || /([^\n]+)/gi);
  250.  
  251. // replace text;
  252. if (definitionObject.replace) {
  253. var rt = definitionObject.replace;
  254. repText = repText.replace(searchExp, rt);
  255. repText = repText.replace(/\$[\d]/g, "");
  256. if (repText === "") {
  257. cursor = rt.indexOf("$1");
  258. repText = rt.replace(/\$[\d]/g, "");
  259. if (cursor === -1) {
  260. cursor = Math.floor(rt.length / 2);
  261. }
  262. }
  263. }
  264.  
  265. // append if necessary;
  266. if (definitionObject.append) {
  267. if (repText === selText) {
  268. reselect = false;
  269. }
  270. repText += definitionObject.append;
  271. }
  272.  
  273. if (repText) {
  274. if (definitionObject.forceNewline === true && (selPos.start > 0 && txt.substr(Math.max(0, selPos.start - 1), 1) !== "\n")) {
  275. repText = "\n" + repText;
  276. }
  277. replaceFieldSelection(commentForm, repText, reselect, cursor);
  278. }
  279. }
  280.  
  281. // Source: https://github.com/gollum/gollum/blob/9c714e768748db4560bc017cacef4afa0c751a63/lib/gollum/public/gollum/javascript/editor/gollum.editor.js#L708
  282. function replaceFieldSelection(commentForm, replaceText, reselect, cursorOffset) {
  283. var txt = commentForm.value,
  284. selPos = {
  285. start: commentForm.selectionStart,
  286. end: commentForm.selectionEnd
  287. };
  288.  
  289. var selectNew = true;
  290. if (reselect === false) {
  291. selectNew = false;
  292. }
  293.  
  294. var scrollTop = null;
  295. if (commentForm.scrollTop) {
  296. scrollTop = commentForm.scrollTop;
  297. }
  298.  
  299. commentForm.value = txt.substring(0, selPos.start) + replaceText + txt.substring(selPos.end);
  300. commentForm.focus();
  301.  
  302. if (selectNew) {
  303. if (cursorOffset) {
  304. commentForm.setSelectionRange(selPos.start + cursorOffset, selPos.start + cursorOffset);
  305. } else {
  306. commentForm.setSelectionRange(selPos.start, selPos.start + replaceText.length);
  307. }
  308. }
  309.  
  310. if (scrollTop) {
  311. commentForm.scrollTop = scrollTop;
  312. }
  313. }
  314.  
  315. function isWiki() {
  316. return /\/wiki\//.test(location.href);
  317. }
  318.  
  319. var functionButtonClick = function(e) {
  320. e.preventDefault();
  321. executeAction(MarkDown[this.id], this.commentForm);
  322. return false;
  323. };
  324.  
  325. function addToolbar() {
  326. if (isWiki()) {
  327. // Override existing language with improved & missing functions and remove existing click events;
  328. unsafeWindow.$.GollumEditor.defineLanguage("markdown", MarkDown);
  329. unsafeWindow.$(".function-button:not(#function-help)").unbind("click");
  330.  
  331. // Remove existing click events when changing languages;
  332. document.getElementById("wiki_format").addEventListener("change", function() {
  333. unsafeWindow.$(".function-button:not(#function-help)").unbind("click");
  334.  
  335. Array.forEach(document.querySelectorAll(".comment-form-textarea .function-button"), function(button) {
  336. button.removeEventListener("click", functionButtonClick);
  337. });
  338. });
  339. }
  340.  
  341. Array.forEach(document.querySelectorAll(".comment-form-textarea"), function(commentForm) {
  342. if (commentForm.classList.contains("GithubCommentEnhancer")) { return; }
  343. commentForm.classList.add("GithubCommentEnhancer");
  344.  
  345. var gollumEditor;
  346. if (isWiki()) {
  347. gollumEditor = document.getElementById("gollum-editor-function-bar");
  348. var temp = document.createElement("div");
  349. temp.innerHTML = editorHTML;
  350. temp.firstChild.appendChild(document.getElementById("function-help")); // restore the help button;
  351. gollumEditor.replaceChild(temp.firstChild, document.getElementById("gollum-editor-function-buttons"));
  352. } else {
  353. gollumEditor = document.createElement("div");
  354. gollumEditor.innerHTML = editorHTML;
  355. gollumEditor.id = "gollum-editor-function-bar";
  356. gollumEditor.style.border = "0 none";
  357. gollumEditor.classList.add("active");
  358. commentForm.parentNode.insertBefore(gollumEditor, commentForm.parentNode.firstChild);
  359. }
  360.  
  361. Array.forEach(gollumEditor.querySelectorAll(".function-button"), function(button) {
  362. button.commentForm = commentForm; // remove event listener doesn't accept `bind`;
  363. button.addEventListener("click", functionButtonClick);
  364. });
  365. });
  366. }
  367.  
  368. // init;
  369. addToolbar();
  370.  
  371. // on pjax;
  372. unsafeWindow.$(document).on("pjax:success", addToolbar);
  373.  
  374. // on page update;
  375. unsafeWindow.$.pageUpdate(function() {
  376. window.setTimeout(function() {
  377. addToolbar();
  378. }, 1);
  379. });
  380.  
  381. })();

QingJ © 2025

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