Github News Feed Filter

Add filters for Github homepage news feed items

目前為 2014-03-25 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Github News Feed Filter
  3. // @namespace https://github.com/jerone/UserScripts
  4. // @description Add filters for Github homepage news feed items
  5. // @author jerone
  6. // @homepage https://github.com/jerone/UserScripts/tree/master/Github_News_Feed_Filter
  7. // @homepageURL https://github.com/jerone/UserScripts/tree/master/Github_News_Feed_Filter
  8. // @include https://github.com/
  9. // @include https://github.com/orgs/*/dashboard
  10. // @version 4.4
  11. // @grant none
  12. // ==/UserScript==
  13.  
  14. (function() {
  15.  
  16. var filters = [
  17. { text: "All News Feed", icon: "octicon-radio-tower", classNames: ["*"] },
  18. {
  19. text: "Issues", icon: "octicon-issue-opened", classNames: ["issues_comment", "issues_opened", "issues_closed", "issues_reopened"], subFilters: [
  20. { text: "Comments", icon: "octicon-comment-discussion", classNames: ["issues_comment"] },
  21. { text: "Opened", icon: "octicon-issue-opened", classNames: ["issues_opened"] },
  22. { text: "Closed", icon: "octicon-issue-closed", classNames: ["issues_closed"] },
  23. { text: "Reopened", icon: "octicon-issue-reopened", classNames: ["issues_reopened"] }
  24. ]
  25. },
  26. { text: "Commits", icon: "octicon-git-commit", classNames: ["push", "commit_comment"] },
  27. { text: "Pull Requests", icon: "octicon-git-pull-request", classNames: ["pull_request", "pull_request_comment"] },
  28. { text: "Repo", icon: "octicon-repo", classNames: ["create", "public", "release", "fork"] },
  29. {
  30. text: "User", icon: "octicon-person", classNames: ["watch_started", "member_add", "team_add"], subFilters: [
  31. { text: "Starred", icon: "octicon-star", classNames: ["watch_started"] },
  32. { text: "Member added", icon: "octicon-person-add", classNames: ["member_add", "team_add"] }
  33. ]
  34. },
  35. { text: "Wiki", icon: "octicon-book", classNames: ["gollum"] },
  36. {
  37. text: "Gist", icon: "octicon-gist", classNames: ["gist_created", "gist_updated"], subFilters: [
  38. { text: "Created", icon: "octicon-gist-new", classNames: ["gist_created"] },
  39. { text: "Updated", icon: "octicon-gist", classNames: ["gist_updated"] }
  40. ]
  41. }
  42. // Possible other classes: follow
  43. ];
  44.  
  45. function proxy(fn) {
  46. return function() {
  47. var that = this;
  48. return function(e) {
  49. var args = that.slice(0); // clone;
  50. args.unshift(e); // prepend event;
  51. fn.apply(this, args);
  52. };
  53. }.call([].slice.call(arguments, 1));
  54. }
  55.  
  56. function addFilterMenuItem(filter, parent, container, sidebar) {
  57. var a = document.createElement("a");
  58. a.classList.add("filter-item");
  59. a.setAttribute("href", "/");
  60. a.setAttribute("title", filter.classNames.join(" & "));
  61. if (filter.classNames[0] === "*") {
  62. a.classList.add("selected");
  63. a.style.fontWeight = "bold";
  64. }
  65.  
  66. var s = document.createElement("span");
  67. s.classList.add("octicon", filter.icon);
  68. s.style.marginRight = "10px";
  69. s.style.cssFloat = "left";
  70. s.style.minWidth = "16px";
  71. a.appendChild(s);
  72.  
  73. var c = document.createElement("span");
  74. c.classList.add("count");
  75. c.appendChild(document.createTextNode("0"));
  76. a.appendChild(c);
  77.  
  78. a.appendChild(document.createTextNode(filter.text));
  79.  
  80. a.addEventListener("click", proxy(function(e, className) {
  81. e.preventDefault();
  82.  
  83. Array.forEach(container.querySelectorAll(".alert"), function(alert) {
  84. alert.style.display = className[0] === "*" || className.some(function(cl) { return alert.classList.contains(cl); }) ? "block" : "none";
  85. });
  86.  
  87. Array.forEach(sidebar.querySelectorAll(".filter-list.small"), function(subUl) {
  88. subUl.style.display = "none";
  89. });
  90. var subUl = this.parentNode.querySelector("ul");
  91. if (!subUl && this.parentNode.parentNode.classList.contains("filter-list") && this.parentNode.parentNode.classList.contains("small")) {
  92. subUl = this.parentNode.parentNode;
  93. }
  94. if (subUl) {
  95. subUl.style.display = "block";
  96. }
  97.  
  98. Array.forEach(sidebar.querySelectorAll(".selected"), function(m) { m.classList.remove("selected"); });
  99. this.classList.add("selected");
  100. }, filter.classNames));
  101.  
  102. var li = document.createElement("li");
  103. li.appendChild(a);
  104. li.filterClassNames = filter.classNames;
  105.  
  106. parent.appendChild(li);
  107.  
  108. return li;
  109. }
  110.  
  111. function addFilters() {
  112. var container = document.querySelector(".news");
  113. if (!container) return;
  114.  
  115. var sidebar = document.querySelector(".dashboard-sidebar");
  116.  
  117. var rule = document.createElement("div");
  118. rule.classList.add("rule");
  119. sidebar.insertBefore(rule, sidebar.firstChild);
  120.  
  121. var ul = document.createElement("ul");
  122. ul.classList.add("filter-list");
  123. sidebar.insertBefore(ul, sidebar.firstChild);
  124.  
  125. filters.forEach(function(filter) {
  126. var li = addFilterMenuItem(filter, ul, container, sidebar);
  127.  
  128. if (filter.subFilters) {
  129. var subUl = document.createElement("ul");
  130. subUl.classList.add("filter-list", "small");
  131. subUl.style.marginLeft = "10px";
  132. subUl.style.display = "none";
  133. li.appendChild(subUl);
  134.  
  135. filter.subFilters.forEach(function(subFilter) {
  136. addFilterMenuItem(subFilter, subUl, container, sidebar);
  137. });
  138. }
  139. });
  140.  
  141. // update on clicking "More"-button;
  142. unsafeWindow.$.pageUpdate(function() {
  143. window.setTimeout(function() {
  144. Array.forEach(container.querySelectorAll(".alert"), function(alert) {
  145. if (alert.getElementsByClassName("octicon-git-pull-request").length > 0) {
  146. alert.classList.remove("issues_opened", "issues_closed");
  147. alert.classList.add("pull_request");
  148. } else if (alert.classList.contains("issues_comment") && alert.querySelectorAll(".title a")[1].getAttribute("href").split("/")[5] === "pull") {
  149. alert.classList.remove("issues_comment");
  150. alert.classList.add("pull_request_comment");
  151. } else if (alert.classList.contains("gist")) {
  152. alert.classList.remove("gist");
  153. alert.classList.add("gist_" + alert.querySelector(".title span").textContent);
  154. }
  155. });
  156.  
  157. Array.forEach(ul.querySelectorAll("li"), function(li) {
  158. var c = li.querySelector(".count");
  159. if (li.filterClassNames[0] === "*") {
  160. c.textContent = container.querySelectorAll(".alert").length;
  161. } else {
  162. c.textContent = "0";
  163. Array.forEach(container.querySelectorAll(".alert"), function(alert) {
  164. if (li.filterClassNames.some(function(cl) { return alert.classList.contains(cl); })) {
  165. c.textContent = parseInt(c.textContent, 10) + 1;
  166. }
  167. });
  168. }
  169. });
  170.  
  171. sidebar.querySelector(".selected").dispatchEvent(new Event("click"));
  172. }, 1);
  173. });
  174. }
  175.  
  176. // init;
  177. addFilters();
  178.  
  179. // on pjax;
  180. unsafeWindow.$(document).on("pjax:success", addFilters);
  181.  
  182. })();