GitHub Mentioned Links

A userscript adds all mentioned links in the side bar

目前为 2020-03-29 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name GitHub Mentioned Links
  3. // @version 0.1.0
  4. // @description A userscript adds all mentioned links in the side bar
  5. // @license MIT
  6. // @author Rob Garrison
  7. // @namespace https://github.com/Mottie
  8. // @include https://github.com/*
  9. // @run-at document-idle
  10. // @grant GM_getValue
  11. // @grant GM_setValue
  12. // @require https://greasyfork.org/scripts/28721-mutations/code/mutations.js?version=666427
  13. // @require https://greasyfork.org/scripts/398877-utils-js/code/utilsjs.js?version=785415
  14. // @icon https://github.githubassets.com/pinned-octocat.svg
  15. // ==/UserScript==
  16. (() => {
  17. "use strict";
  18. /* global $ $$ on */
  19.  
  20. // GitHub loves to change class names
  21. const selectors = {
  22. // Insert entry after milestone in the sidebar
  23. sidebar: ".discussion-sidebar-item.sidebar-progress-bar",
  24. // Load more comments button (2 buttons; either works)
  25. loadMore: "form[action*='more_items'] button",
  26. // Issue/PR timeline element with anchor id
  27. timelineGroup: ".timeline-comment-group",
  28. // All links within a timeline comment
  29. links: ".comment-body a:not(.user-mention)"
  30. };
  31.  
  32. const internalLinkIcon = `
  33. <svg aria-hidden="true" class="octicon octicon-internal-link" viewBox="0 0 12 16" height="12">
  34. <path d="M11 10h1v3c0 .6-.4 1-1 1H1c-.6 0-1-.4-1-1V3c0-.5.4-1 1-1h3v1H1v10h10v-3z"/>
  35. <path d="M11 9L8.8 6.7 12 3.5 10.5 2 7.3 5.2 5 3v6z"/>
  36. </svg>`
  37.  
  38. // Sidebar item
  39. const item = document.createElement("details");
  40. item.id = "ghml-wrapper";
  41. item.className = "discussion-sidebar-item sidebar-mentioned-links";
  42. item.open = GM_getValue("mentionedOpened", false);
  43. item.onclick = event => {
  44. // Set as opposite makes it work?! DOM update delay, maybe?
  45. GM_setValue("mentionedOpened", !event.target.parentElement.open);
  46. };
  47.  
  48. // Load more button
  49. const loadMoreButton = document.createElement("button");
  50. loadMoreButton.className = "btn btn-block btn-sm width-auto ml-2 py-0 px-1 text-normal";
  51. loadMoreButton.style.fontSize = "10px";
  52. loadMoreButton.title = "Each click loads up to 60 items";
  53.  
  54. function getLinks() {
  55. const list = new Set();
  56. const links = [];
  57. $$(selectors.timelineGroup).forEach(body => {
  58. $$(selectors.links, body).forEach(link => {
  59. if (!list.has(link.href) && !$("img", link)) {
  60. list.add(link.href);
  61. links.push(
  62. `<li class="css-truncate css-truncate-overflow">
  63. <a href="#${body.id}" class="link-gray" title="Internal link">
  64. ${internalLinkIcon}
  65. </a>
  66. ${link.outerHTML}
  67. </li>`
  68. );
  69. }
  70. });
  71. });
  72. list.clear();
  73. buildLinks(links);
  74. }
  75.  
  76. function addLoadMoreButton() {
  77. const formButton = $(selectors.loadMore);
  78. if (formButton) {
  79. const more = loadMoreButton.cloneNode(true);
  80. more.textContent = formButton.textContent;
  81. more.onclick = event => {
  82. const target = event.target;
  83. target.textContent = "Loading…";
  84. formButton.click();
  85. };
  86. $("#ghml-wrapper summary").append(more);
  87. }
  88. }
  89.  
  90. function buildLinks(links) {
  91. const entry = $("#ghml-wrapper") || item.cloneNode(true);
  92. entry.innerHTML = `
  93. <summary class="discussion-sidebar-heading text-bold d-flex flex-items-center">
  94. Mentioned Links
  95. </summary>
  96. <ul class="list-style-none">
  97. ${links.length ? links.join("") : "No links found"}
  98. </ul>`;
  99. $(selectors.sidebar).after(entry);
  100. addLoadMoreButton();
  101. }
  102.  
  103. function init() {
  104. if ($("#discussion_bucket") && $(selectors.sidebar)) {
  105. getLinks();
  106. }
  107. }
  108.  
  109. on(document, "ghmo:container ghmo:comments", init);
  110. init();
  111.  
  112. })();