Github Reply Comments

Easy reply to Github comments

当前为 2024-02-03 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Github Reply Comments
  3. // @namespace https://github.com/jerone/UserScripts
  4. // @description Easy reply to Github comments
  5. // @author jerone
  6. // @copyright 2016+, jerone (https://github.com/jerone)
  7. // @license CC-BY-NC-SA-4.0; https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode
  8. // @license GPL-3.0-or-later; http://www.gnu.org/licenses/gpl-3.0.txt
  9. // @homepage https://github.com/jerone/UserScripts/tree/master/Github_Reply_Comments
  10. // @homepageURL https://github.com/jerone/UserScripts/tree/master/Github_Reply_Comments
  11. // @supportURL https://github.com/jerone/UserScripts/issues
  12. // @contributionURL https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VCYMHWQ7ZMBKW
  13. // @version 1.0.5
  14. // @icon https://github.githubassets.com/pinned-octocat.svg
  15. // @grant none
  16. // @include https://github.com/*
  17. // @include https://gist.github.com/*
  18. // @require https://unpkg.com/turndown@5.0.3/dist/turndown.js
  19. // @require https://unpkg.com/turndown-plugin-gfm@1.0.2/dist/turndown-plugin-gfm.js
  20. // @require https://unpkg.com/turndown-plugin-github-code-snippet@1.0.2/turndown-plugin-github-code-snippet.js
  21. // ==/UserScript==
  22.  
  23. // cSpell:ignore textareas, previewable, tooltipped
  24. /* eslint security/detect-object-injection: "off" */
  25.  
  26. (function () {
  27. String.format = function (string) {
  28. var args = Array.prototype.slice.call(arguments, 1, arguments.length);
  29. return string.replace(/{(\d+)}/g, function (match, number) {
  30. return typeof args[number] !== "undefined" ? args[number] : match;
  31. });
  32. };
  33.  
  34. var turndownService = new TurndownService({
  35. headingStyle: "atx",
  36. codeBlockStyle: "fenced",
  37. hr: "***",
  38. });
  39. turndownService.use(turndownPluginGfm.gfm);
  40. turndownService.use(turndownPluginGithubCodeSnippet);
  41.  
  42. function getCommentTextarea(replyBtn) {
  43. var newComment = replyBtn;
  44. while (
  45. newComment &&
  46. !newComment.classList.contains("js-quote-selection-container")
  47. ) {
  48. newComment = newComment.parentNode;
  49. }
  50.  
  51. var inlineComment = newComment.querySelector(
  52. ".js-inline-comment-form-container",
  53. );
  54. if (inlineComment) {
  55. inlineComment.classList.add("open");
  56. }
  57.  
  58. var textareas = newComment.querySelectorAll(
  59. ":scope > :not(.last-review-thread) .comment-form-textarea:not(.github-writer-ckeditor)",
  60. );
  61. return textareas[textareas.length - 1];
  62. }
  63.  
  64. function getCommentMarkdown(comment) {
  65. var commentText = "";
  66.  
  67. // Use raw comment when available.
  68. var commentForm = comment.querySelector(".comment-form-textarea");
  69. if (commentForm) {
  70. commentText = commentForm.value;
  71. }
  72.  
  73. // Convert comment HTML to markdown.
  74. if (!commentText) {
  75. // Clone it, so we can alter the HTML a bit, without modifying the page.
  76. var commentBody = comment
  77. .querySelector(".comment-body")
  78. .cloneNode(true);
  79.  
  80. // Remove 'Toggle code wrap' buttons from https://gf.qytechs.cn/en/scripts/18789-github-toggle-code-wrap
  81. Array.prototype.forEach.call(
  82. commentBody.querySelectorAll(".ghd-wrap-toggle"),
  83. function (ghd) {
  84. ghd.remove();
  85. },
  86. );
  87.  
  88. // GitHub add an extra new line, which is converted by Turndown.
  89. Array.prototype.forEach.call(
  90. commentBody.querySelectorAll("pre code"),
  91. function (pre) {
  92. pre.innerHTML = pre.innerHTML.replace(/\n$/g, "");
  93. },
  94. );
  95.  
  96. commentText = turndownService.turndown(commentBody.innerHTML);
  97. }
  98.  
  99. return commentText;
  100. }
  101.  
  102. function addReplyButtons() {
  103. Array.prototype.forEach.call(
  104. document.querySelectorAll(".comment, .review-comment"),
  105. function (comment) {
  106. var oldReply = comment.querySelector(
  107. ".GithubReplyComments, .GithubCommentEnhancerReply",
  108. );
  109. if (oldReply) {
  110. oldReply.parentNode.removeChild(oldReply);
  111. }
  112.  
  113. var header = comment.querySelector(
  114. ":scope > :not(.minimized-comment) .timeline-comment-header",
  115. ),
  116. actions = comment.querySelector(
  117. ":scope > :not(.minimized-comment) .timeline-comment-actions",
  118. );
  119.  
  120. if (!header) {
  121. header = actions;
  122. }
  123.  
  124. if (!actions) {
  125. if (!header) {
  126. return;
  127. }
  128. actions = document.createElement("div");
  129. actions.classList.add("timeline-comment-actions");
  130. header.insertBefore(actions, header.firstElementChild);
  131. }
  132.  
  133. var reply = document.createElement("button");
  134. reply.setAttribute("type", "button");
  135. reply.setAttribute("title", "Reply to this comment");
  136. reply.setAttribute("aria-label", "Reply to this comment");
  137. reply.classList.add(
  138. "GithubReplyComments",
  139. "btn-link",
  140. "timeline-comment-action",
  141. "tooltipped",
  142. "tooltipped-ne",
  143. );
  144. reply.addEventListener("click", function (e) {
  145. e.preventDefault();
  146.  
  147. var timestamp = comment.querySelector(
  148. ".js-timestamp, .timestamp",
  149. );
  150.  
  151. var commentText = getCommentMarkdown(comment);
  152. commentText = commentText
  153. .trim()
  154. .split("\n")
  155. .map(function (line) {
  156. return "> " + line;
  157. })
  158. .join("\n");
  159.  
  160. var newComment = getCommentTextarea(this);
  161.  
  162. var author = comment.querySelector(".author");
  163. var authorLink =
  164. location.origin +
  165. (author.getAttribute("href") ||
  166. "/" + author.textContent);
  167.  
  168. var text = newComment.value.length > 0 ? "\n" : "";
  169. text += String.format(
  170. '[**@{0}**]({1}) commented on [{2}]({3} "{4} - Replied by Github Reply Comments"):\n{5}\n\n',
  171. author.textContent,
  172. authorLink,
  173. timestamp.firstElementChild.getAttribute("title"),
  174. timestamp.href,
  175. timestamp.firstElementChild.getAttribute("datetime"),
  176. commentText,
  177. );
  178.  
  179. newComment.value += text;
  180. newComment.setSelectionRange(
  181. newComment.value.length,
  182. newComment.value.length,
  183. );
  184. //newComment.closest('.previewable-comment-form').querySelector('.js-write-tab').click();
  185. newComment.focus();
  186.  
  187. // This will enable the "Comment" button, when there was no comment text yet.
  188. newComment.dispatchEvent(
  189. new CustomEvent("change", {
  190. bubbles: true,
  191. cancelable: false,
  192. }),
  193. );
  194.  
  195. // This will render GitHub Writer - https://github.com/ckeditor/github-writer
  196. // https://github.com/ckeditor/github-writer/blob/8dbc12cb01b7903d0d6c90202078214a8637de6d/src/app/plugins/quoteselection.js#L116-L127
  197. const githubWriter = newComment.closest(
  198. [
  199. "form.js-new-comment-form[data-github-writer-id]",
  200. "form.js-inline-comment-form[data-github-writer-id]",
  201. ].join(),
  202. );
  203. if (githubWriter) {
  204. window.postMessage(
  205. {
  206. type: "GitHub-Writer-Quote-Selection",
  207. id: Number(
  208. githubWriter.getAttribute(
  209. "data-github-writer-id",
  210. ),
  211. ),
  212. text: text,
  213. },
  214. "*",
  215. );
  216. }
  217. });
  218.  
  219. var svg = document.createElementNS(
  220. "http://www.w3.org/2000/svg",
  221. "svg",
  222. );
  223. svg.classList.add("octicon", "octicon-mail-reply");
  224. svg.setAttribute("height", "16");
  225. svg.setAttribute("width", "16");
  226. reply.appendChild(svg);
  227. var path = document.createElementNS(
  228. "http://www.w3.org/2000/svg",
  229. "path",
  230. );
  231. path.setAttribute(
  232. "d",
  233. "M6 2.5l-6 4.5 6 4.5v-3c1.73 0 5.14 0.95 6 4.38 0-4.55-3.06-7.05-6-7.38v-3z",
  234. );
  235. svg.appendChild(path);
  236.  
  237. actions.appendChild(reply);
  238. },
  239. );
  240. }
  241.  
  242. // init;
  243. addReplyButtons();
  244.  
  245. // on pjax;
  246. document.addEventListener("pjax:end", addReplyButtons);
  247. })();

QingJ © 2025

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