Github Reply Comments

Easy reply to Github comments

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

  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. (function () {
  24.  
  25. String.format = function (string) {
  26. var args = Array.prototype.slice.call(arguments, 1, arguments.length);
  27. return string.replace(/{(\d+)}/g, function (match, number) {
  28. return typeof args[number] !== "undefined" ? args[number] : match;
  29. });
  30. };
  31.  
  32. var turndownService = new TurndownService({
  33. headingStyle: 'atx',
  34. codeBlockStyle: 'fenced',
  35. hr: '***'
  36. });
  37. turndownService.use(turndownPluginGfm.gfm);
  38. turndownService.use(turndownPluginGithubCodeSnippet);
  39.  
  40. function getCommentTextarea(replyBtn) {
  41. var newComment = replyBtn;
  42. while (newComment && !newComment.classList.contains("js-quote-selection-container")) {
  43. newComment = newComment.parentNode;
  44. }
  45.  
  46. var inlineComment = newComment.querySelector(".js-inline-comment-form-container");
  47. if (inlineComment) {
  48. inlineComment.classList.add("open");
  49. }
  50.  
  51. var textareas = newComment.querySelectorAll(":scope > :not(.last-review-thread) .comment-form-textarea:not(.github-writer-ckeditor)");
  52. return textareas[textareas.length - 1];
  53. }
  54.  
  55. function getCommentMarkdown(comment) {
  56. var commentText = "";
  57.  
  58. // Use raw comment when available.
  59. var commentForm = comment.querySelector(".comment-form-textarea");
  60. if (commentForm) {
  61. commentText = commentForm.value;
  62. }
  63.  
  64. // Convert comment HTML to markdown.
  65. if (!commentText) {
  66. // Clone it, so we can alter the HTML a bit, without modifing the page.
  67. var commentBody = comment.querySelector(".comment-body").cloneNode(true);
  68.  
  69. // Remove 'Toggle code wrap' buttons from https://gf.qytechs.cn/en/scripts/18789-github-toggle-code-wrap
  70. Array.prototype.forEach.call(commentBody.querySelectorAll(".ghd-wrap-toggle"), function (ghd) {
  71. ghd.remove();
  72. });
  73.  
  74. // GitHub add an extra new line, which is converted by Turndown.
  75. Array.prototype.forEach.call(commentBody.querySelectorAll("pre code"), function (pre) {
  76. pre.innerHTML = pre.innerHTML.replace(/\n$/g, '');
  77. });
  78.  
  79. commentText = turndownService.turndown(commentBody.innerHTML);
  80. }
  81.  
  82. return commentText;
  83. }
  84.  
  85. function addReplyButtons() {
  86. Array.prototype.forEach.call(document.querySelectorAll(".comment, .review-comment"), function (comment) {
  87. var oldReply = comment.querySelector(".GithubReplyComments, .GithubCommentEnhancerReply");
  88. if (oldReply) {
  89. oldReply.parentNode.removeChild(oldReply);
  90. }
  91.  
  92. var header = comment.querySelector(":scope > :not(.minimized-comment) .timeline-comment-header"),
  93. actions = comment.querySelector(":scope > :not(.minimized-comment) .timeline-comment-actions");
  94.  
  95. if (!header) {
  96. header = actions;
  97. }
  98.  
  99. if (!actions) {
  100. if (!header) {
  101. return;
  102. }
  103. actions = document.createElement("div");
  104. actions.classList.add("timeline-comment-actions");
  105. header.insertBefore(actions, header.firstElementChild);
  106. }
  107.  
  108. var reply = document.createElement("button");
  109. reply.setAttribute("type", "button");
  110. reply.setAttribute("title", "Reply to this comment");
  111. reply.setAttribute("aria-label", "Reply to this comment");
  112. reply.classList.add("GithubReplyComments", "btn-link", "timeline-comment-action", "tooltipped", "tooltipped-ne");
  113. reply.addEventListener("click", function (e) {
  114. e.preventDefault();
  115.  
  116. var timestamp = comment.querySelector(".js-timestamp, .timestamp");
  117.  
  118. var commentText = getCommentMarkdown(comment);
  119. commentText = commentText.trim().split("\n").map(function (line) {
  120. return "> " + line;
  121. }).join("\n");
  122.  
  123. var newComment = getCommentTextarea(this);
  124.  
  125. var author = comment.querySelector(".author");
  126. var authorLink = location.origin + (author.getAttribute("href") || "/" + author.textContent);
  127.  
  128. var text = newComment.value.length > 0 ? "\n" : "";
  129. text += String.format('[**@{0}**]({1}) commented on [{2}]({3} "{4} - Replied by Github Reply Comments"):\n{5}\n\n',
  130. author.textContent,
  131. authorLink,
  132. timestamp.firstElementChild.getAttribute("title"),
  133. timestamp.href,
  134. timestamp.firstElementChild.getAttribute("datetime"),
  135. commentText);
  136.  
  137. newComment.value += text;
  138. newComment.setSelectionRange(newComment.value.length, newComment.value.length);
  139. //newComment.closest('.previewable-comment-form').querySelector('.js-write-tab').click();
  140. newComment.focus();
  141.  
  142. // This will enable the "Comment" button, when there was no comment text yet.
  143. newComment.dispatchEvent(new CustomEvent('change', {
  144. bubbles: true,
  145. cancelable: false
  146. }));
  147.  
  148. // This will render GitHub Writer - https://github.com/ckeditor/github-writer
  149. // https://github.com/ckeditor/github-writer/blob/8dbc12cb01b7903d0d6c90202078214a8637de6d/src/app/plugins/quoteselection.js#L116-L127
  150. const githubWriter = newComment.closest([
  151. 'form.js-new-comment-form[data-github-writer-id]',
  152. 'form.js-inline-comment-form[data-github-writer-id]'
  153. ].join());
  154. if (githubWriter) {
  155. window.postMessage({
  156. type: 'GitHub-Writer-Quote-Selection',
  157. id: Number(githubWriter.getAttribute('data-github-writer-id')),
  158. text: text
  159. }, '*');
  160. }
  161. });
  162.  
  163. var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  164. svg.classList.add("octicon", "octicon-mail-reply");
  165. svg.setAttribute("height", "16");
  166. svg.setAttribute("width", "16");
  167. reply.appendChild(svg);
  168. var path = document.createElementNS("http://www.w3.org/2000/svg", "path");
  169. path.setAttribute("d", "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");
  170. svg.appendChild(path);
  171.  
  172. actions.appendChild(reply);
  173. });
  174. }
  175.  
  176. // init;
  177. addReplyButtons();
  178.  
  179. // on pjax;
  180. document.addEventListener('pjax:end', addReplyButtons);
  181.  
  182. })();

QingJ © 2025

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