GitHub Show Repo Issues

A userscript that adds a repo issues count to the repository tab & organization page (https://github.com/:user)

当前为 2016-05-26 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name GitHub Show Repo Issues
  3. // @version 2.3.2
  4. // @description A userscript that adds a repo issues count to the repository tab & organization page (https://github.com/:user)
  5. // @license https://creativecommons.org/licenses/by-sa/4.0/
  6. // @namespace http://github.com/Mottie
  7. // @include https://github.com/*
  8. // @grant GM_addStyle
  9. // @grant GM_xmlhttpRequest
  10. // @connect api.github.com
  11. // @run-at document-idle
  12. // @author Rob Garrison
  13. // ==/UserScript==
  14. /* global GM_addStyle, GM_xmlhttpRequest */
  15. (function() {
  16. "use strict";
  17. var busy = false,
  18.  
  19. addIssues = function() {
  20.  
  21. // look for repo tab or user/organization page
  22. if (document.querySelectorAll(".tabnav-tab.selected, .repo-list").length &&
  23. // no stargazer/fork items on https://github.com/stars
  24. document.querySelectorAll("a.repo-list-stat-item").length &&
  25. // and not already applied
  26. !document.querySelectorAll(".repo-list-stat-item.issues").length) {
  27.  
  28. // set busy flag to ignore mutation observer firing while adding new content
  29. busy = true;
  30.  
  31. // Does not include forks & only includes the first 10 repos, or first 20 on the
  32. // organization page - these are the repos showing the participation graphs
  33. var user, len, url,
  34. items = document.querySelectorAll(".repo-list-item"),
  35.  
  36. // bug icon
  37. icon = "<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 53 53'><path d='m39.2 0c2 0 3.7 1.5 3.7 3.4 0 1.9-1.7 3.4-3.7 3.4l-0.9-0.1-3.4 4c2.3 1.6 4.4 3.8 6 6.4-4 1.2-8.9 1.9-14.2 1.9-5.3 0-10.1-0.7-14.2-1.9 1.5-2.6 3.5-4.7 5.7-6.3l-3.5-4.1c-0.2 0-0.4 0.1-0.6 0.1-2 0-3.7-1.5-3.7-3.4 0-1.9 1.7-3.4 3.7-3.4 2 0 3.7 1.5 3.7 3.4 0 0.7-0.2 1.3-0.6 1.8l3.5 4.2c1.8-0.8 3.8-1.3 5.9-1.3 2 0 3.9 0.4 5.6 1.2l3.7-4.3c-0.3-0.5-0.4-1-0.4-1.6 0-1.9 1.6-3.4 3.7-3.4zm11.8 28.5c1.2 0 2.2 0.9 2.2 2 0 1.1-1 2-2.2 2l-6.7 0c-0.1 1.5-0.3 2.9-0.6 4.3l7.8 3.4c1.1 0.5 1.6 1.7 1.1 2.7-0.5 1-1.8 1.5-2.9 1l-7.2-3.1c-2.7 6.7-8 11.4-14.3 12.1l0-31.2c5.2-0.1 10-1 13.9-2.3l0.3 0.7 7.5-2.7c1.1-0.4 2.4 0.1 2.9 1.2 0.4 1.1-0.1 2.2-1.3 2.6l-7.9 2.8c0.3 1.4 0.6 2.9 0.7 4.5l6.7 0 0 0zm-48.7 0 6.7 0c0.1-1.5 0.3-3.1 0.7-4.5l-7.9-2.8c-1.1-0.4-1.7-1.6-1.3-2.6 0.4-1 1.7-1.6 2.9-1.2l7.5 2.7 0.3-0.7c3.9 1.3 8.7 2.1 13.9 2.3l0 31.2c-6.2-0.7-11.5-5.4-14.3-12.1l-7.2 3.1c-1.1 0.5-2.4 0-2.9-1-0.5-1 0-2.2 1.1-2.7l7.8-3.4c-0.3-1.4-0.5-2.8-0.6-4.3l-6.7 0c-1.2 0-2.2-0.9-2.2-2 0-1.1 1-2 2.2-2z' /></svg>",
  38.  
  39. // issue count = get all repos from user => api v3 - https://api.github.com/users/:user/repos,
  40. // then look for "open_issues_count" in the named repos
  41. // previsouly used https://api.github.com/repos/:user/:repo/issues?state=open (first 30 issues only)
  42. api = "https://api.github.com/users";
  43.  
  44. items = Array.prototype.filter.call(items, function(item) {
  45. var cl = item.classList;
  46. return cl.contains("public") && !cl.contains("fork");
  47. });
  48. len = items.length;
  49.  
  50. // expecting fork link to look like this:
  51. // <a class="repo-list-stat-item tooltipped tooltipped-s" href="/:user/:repo/network" aria-label="Forks">
  52. // <span class="octicon octicon-git-branch"></span> 1
  53. // </a>
  54. url = len ? items[ 0 ].querySelector("a.repo-list-stat-item[aria-label='Forks']").getAttribute("href") : "";
  55. user = (url || "").match(/^\/[^/]+/);
  56.  
  57. if (user && user.length) {
  58.  
  59. // add bug image background
  60. GM_addStyle([
  61. ".repo-list-stats a.issues svg { position: relative; top: 2px; fill: #888; }",
  62. ".repo-list-stats a.issues:hover svg { fill: #4078C0; }"
  63. ].join(""));
  64.  
  65. GM_xmlhttpRequest({
  66. method : "GET",
  67. url : api + user[ 0 ] + "/repos",
  68. onload : function(response) {
  69. var itemIndex, repoIndex, repoLen, repo, link,
  70. data = JSON.parse(response.responseText || "null");
  71.  
  72. if (data) {
  73. repoLen = data.length;
  74. for (itemIndex = 0; itemIndex < len; itemIndex++) {
  75. link = items[ itemIndex ].querySelector("a.repo-list-stat-item[aria-label='Forks']");
  76. repo = (link.getAttribute("href") || "").replace("/network", "").slice(1);
  77.  
  78. for (repoIndex = 0; repoIndex < repoLen; repoIndex++) {
  79. if (repo === data[ repoIndex ].full_name) {
  80. link.insertAdjacentHTML("afterend",
  81. "<a class='repo-list-stat-item tooltipped tooltipped-s issues' href='" + repo +
  82. "/issues' aria-label='Issues'>" + icon + " " + data[ repoIndex ].open_issues_count + "</a>"
  83. );
  84. }
  85. }
  86.  
  87. }
  88. }
  89. busy = false;
  90. }
  91. });
  92.  
  93. } else {
  94. busy = false;
  95. }
  96. } else {
  97. busy = false;
  98. }
  99. },
  100.  
  101. containers = "#js-repo-pjax-container, #js-pjax-container, .js-contribution-activity",
  102. targets = document.querySelectorAll(containers);
  103.  
  104. Array.prototype.forEach.call(targets, function(target) {
  105. new MutationObserver(function(mutations) {
  106. mutations.forEach(function(mutation) {
  107. // preform checks before addIssues to minimize function calls
  108. if (!(busy || document.querySelectorAll(".repo-list-stat-item.issues").length) &&
  109. document.querySelectorAll(".tabnav-tab.selected, .repo-list").length &&
  110. mutation.target === target) {
  111. addIssues();
  112. }
  113. });
  114. }).observe(target, {
  115. childList: true,
  116. subtree: true
  117. });
  118. });
  119.  
  120. addIssues();
  121.  
  122. })();