Background Network Requests Indicator

Shows an indicator at bottom right/left when there is one or more background network requests in progress.

目前为 2020-04-10 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Background Network Requests Indicator
  3. // @namespace BackgroundNetworkRequestsIndicator
  4. // @version 1.0.6
  5. // @license AGPL v3
  6. // @author jcunews
  7. // @description Shows an indicator at bottom right/left when there is one or more background network requests in progress.
  8. // @website https://greasyfork.org/en/users/85671-jcunews
  9. // @include *://*/*
  10. // @grant none
  11. // @run-at document-start
  12. // ==/UserScript==
  13.  
  14. /*
  15. The number on the indicator shows the number of background network requests in progress.
  16.  
  17. When it shows, by default it will be placed at bottom-right. When the mouse cursor is
  18. moved to the right half area of the page, the indicator will move itself to the bottom-left.
  19.  
  20. If the SHIFT key is held down, the indicator will stay. And when the mouse cursor is on it,
  21. a list of pending network request URLs will be shown.
  22. */
  23.  
  24. ((eleContainer, eleStyle, eleList, eleIndicator, xhrId, xhrCount, xhrAbort, xhrOpen, xhrSend, shiftPressed) => {
  25.  
  26. if (!(document instanceof HTMLDocument)) return;
  27.  
  28. (eleContainer = document.createElement("DIV")).id = "bnriContainer";
  29. eleContainer.innerHTML = `<style>
  30. #bnriContainer, #bnriList, #bnriList>.url, #bnriIndicator {
  31. display:block!important; opacity:1!important; visibility:visible!important;
  32. position:static!important; float:none!important; margin:0!important;
  33. box-sizing:content-box!important; border:none!important; padding:0!important;
  34. width:auto!important; min-width:0!important; max-width:none!important;
  35. height:auto!important; min-height:0!important; max-height:none!important;
  36. background:transparent!important; font:10pt/normal sans-serif!important;
  37. }
  38. #bnriContainer {
  39. position:fixed!important; z-index:9999999999!important; left:auto!important;
  40. top:auto!important; right:0!important; bottom:0!important;
  41. }
  42. #bnriContainer.left, #bnriContainer.left #bnriList {
  43. left:0!important; right:auto!important;
  44. }
  45. #bnriList {
  46. display:none!important; position:fixed!important; left:auto!important; top:auto!important;
  47. right:0!important; bottom:1.7em!important; border:1px solid #555!important;
  48. background-color:#ddd!important;
  49. }
  50. #bnriContainer:hover>#bnriList {
  51. display:block!important;
  52. }
  53. #bnriList>.url {
  54. max-width:90vw!important; max-height:50vw!important;
  55. overflow-x:hidden!important; overflow-y:auto!important;
  56. padding:0 .2em!important; line-height:1.5em!important;
  57. white-space: nowrap!important; text-overflow:ellipsis!important;
  58. }
  59. #bnriList>.url:nth-child(2n) {
  60. background-color:#ccc!important;
  61. }
  62. #bnriIndicator {
  63. border:1mm solid #bb0!important; border-radius:2em!important;
  64. padding:0 1mm!important; background-color:#ff0!important; text-align:center!important;
  65. cursor:default!important;
  66. }
  67. </style>
  68. <div id="bnriList"></div>
  69. <div id="bnriIndicator"></div>
  70. `;
  71. eleList = eleContainer.querySelector("#bnriList");
  72. eleIndicator = eleContainer.querySelector("#bnriIndicator");
  73.  
  74. xhrId = xhrCount = 0;
  75.  
  76. function checkCursor(ev) {
  77. if (!shiftPressed) {
  78. if (ev.clientX >= Math.floor(innerWidth / 2)) {
  79. eleContainer.className = "left";
  80. } else eleContainer.className = "";
  81. }
  82. }
  83.  
  84. function doneRequest(xhr) {
  85. if (--xhrCount < 0) xhrCount = 0;
  86. delete xhr.id_bnri;
  87. if (xhr.ele_bnri) xhr.ele_bnri.remove();
  88. if (xhrCount) {
  89. eleIndicator.textContent = xhrCount;
  90. } else if (eleContainer.parentNode) {
  91. removeEventListener("mousemove", checkCursor);
  92. document.body.removeChild(eleContainer);
  93. }
  94. }
  95.  
  96. function checkState() {
  97. if ((this.readyState >= XMLHttpRequest.HEADERS_RECEIVED) && !eleContainer.parentNode && document.body) {
  98. document.body.appendChild(eleContainer);
  99. addEventListener("mousemove", checkCursor);
  100. }
  101. if ((this.readyState !== XMLHttpRequest.DONE) || !this.id_bnri) return;
  102. if (--xhrCount < 0) xhrCount = 0;
  103. doneRequest(this);
  104. }
  105.  
  106. function showList() {
  107. }
  108.  
  109. xhrAbort = XMLHttpRequest.prototype.abort;
  110. XMLHttpRequest.prototype.abort = function() {
  111. doneRequest(this);
  112. return xhrAbort.apply(this, arguments);
  113. };
  114.  
  115. xhrOpen = XMLHttpRequest.prototype.open;
  116. XMLHttpRequest.prototype.open = function() {
  117. if (!this.url_bnri) this.addEventListener("readystatechange", checkState);
  118. this.url_bnri = arguments[1];
  119. return xhrOpen.apply(this, arguments);
  120. };
  121.  
  122. xhrSend = XMLHttpRequest.prototype.send;
  123. XMLHttpRequest.prototype.send = function() {
  124. if (!this.id_bnri) {
  125. this.id_bnri = ++xhrId;
  126. (this.ele_bnri = eleList.appendChild(document.createElement("DIV"))).className = "url";
  127. this.ele_bnri.textContent = this.url_bnri;
  128. }
  129. eleIndicator.textContent = ++xhrCount;
  130. if (!eleContainer.parentNode && document.body) {
  131. document.body.appendChild(eleContainer);
  132. addEventListener("mousemove", checkCursor);
  133. }
  134. return xhrSend.apply(this, arguments);
  135. };
  136.  
  137. addEventListener("keydown", e => {
  138. if (e.key === "Shift") shiftPressed = true;
  139. });
  140.  
  141. addEventListener("keyup", e => {
  142. if (e.key === "Shift") shiftPressed = false;
  143. });
  144.  
  145. })();