GitHub Issues 默认过滤器

替换 GitHub issues 的默认过滤器

  1. // ==UserScript==
  2. // @name GitHub Default Issues Filter
  3. // @name:zh-CN GitHub Issues 默认过滤器
  4. // @description Replaces GitHub issue's default filter
  5. // @description:zh-CN 替换 GitHub issues 的默认过滤器
  6. // @version 0.1
  7. // @author guansss
  8. // @namespace https://github.com/guansss
  9. // @source https://github.com/guansss/userscripts
  10. // @supportURL https://github.com/guansss/userscripts/issues
  11. // @match *://github.com/*
  12. // @run-at document-start
  13. // @grant GM_info
  14. // @license MIT
  15. // @noframes
  16. // ==/UserScript==
  17.  
  18. function _script_main() {
  19. 'use strict';
  20.  
  21. const ready = new Promise((resolve) => {
  22. if (document.readyState === 'loading') {
  23. document.addEventListener('DOMContentLoaded', () => resolve);
  24. } else {
  25. resolve();
  26. }
  27. });
  28.  
  29. function hookMethod(object, method, callback) {
  30. const original = object[method];
  31.  
  32. object[method] = function () {
  33. callback.apply(this, arguments);
  34. return original.apply(this, arguments);
  35. };
  36. }
  37.  
  38. let log;
  39.  
  40. setLogger(console.log);
  41.  
  42. function setLogger(logger) {
  43. log = logger.bind(console, `[${GM_info.script.name}]`);
  44. }
  45.  
  46. /**
  47. * Periodically calls given function until it returns true.
  48. */
  49. function repeat(fn, interval = 200) {
  50. if (fn()) {
  51. return 0;
  52. }
  53.  
  54. const id = setInterval(() => {
  55. try {
  56. fn() && clearInterval(id);
  57. } catch (e) {
  58. log(e);
  59. clearInterval(id);
  60. }
  61. }, interval);
  62.  
  63. return id;
  64. }
  65.  
  66. /**
  67. * Periodically calls given function until the return value is truthy.
  68. * @returns A CancelablePromise that resolves with the function's return value when truthy.
  69. */
  70. function until(fn, interval = 0) {
  71. let cancelled = false;
  72.  
  73. const promise = new Promise((resolve, reject) =>
  74. repeat(() => {
  75. if (cancelled) {
  76. return true;
  77. }
  78.  
  79. try {
  80. const result = fn();
  81.  
  82. if (result) {
  83. resolve(result);
  84.  
  85. // break the repeat() loop
  86. return true;
  87. }
  88. } catch (e) {
  89. reject(e);
  90. return true;
  91. }
  92. }, interval)
  93. );
  94.  
  95. promise.cancel = () => (cancelled = true);
  96.  
  97. return promise;
  98. }
  99.  
  100. const urlRegex = /.*issues\/?$/;
  101. const defaultFilters = 'is:issue is:open ';
  102. const targetFilters = 'is:issue';
  103.  
  104. let currentTask;
  105.  
  106. function cancelCurrentTask() {
  107. currentTask && currentTask.cancel();
  108. }
  109.  
  110. function check(url) {
  111. if (urlRegex.test(url)) {
  112. cancelCurrentTask();
  113.  
  114. currentTask = until(() => {
  115. const input = document.getElementById('js-issues-search');
  116.  
  117. if (input && input.parentElement && input.parentElement.tagName === 'FORM') {
  118. // when navigating from pull requests to issues, the input is persisted until navigation completes,
  119. // so we should ensure the input value is as expected
  120. if (input.value === defaultFilters) {
  121. input.value = targetFilters;
  122. input.parentElement.dispatchEvent(new SubmitEvent('submit', { bubbles: true }));
  123.  
  124. return true;
  125. }
  126.  
  127. // cancel current task whenever the input is changed by user, usually this won't happen
  128. // since the interval is very short, but just in case the user is Shining Finger
  129. input.addEventListener('input', cancelCurrentTask, { once: true });
  130. }
  131. }, 100);
  132. }
  133. }
  134.  
  135. const handleStateChange = (data, unused, url) => {
  136. if (url instanceof URL) {
  137. url = url.href;
  138. }
  139.  
  140. if (url) {
  141. check(url);
  142. }
  143. };
  144.  
  145. hookMethod(history, 'pushState', handleStateChange);
  146. hookMethod(history, 'replaceState', handleStateChange);
  147.  
  148. ready.then(() => check(location.href));
  149. }
  150.  
  151. _script_main();

QingJ © 2025

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