userscripts/Abort Network Requests on E...

71 lines
2.1 KiB
JavaScript

// ==UserScript==
// @name Abort Network Requests on Escape
// @namespace blankie-scripts
// @match http*://*/*
// @grant none
// @version 1.0.0
// @author blankie
// @description Aborts network requests invoked from XMLHttpRequest and fetch() when Escape is pressed
// @run-at document-start
// @inject-into page
// ==/UserScript==
"use strict";
let activeXHRs = new Set();
let abortControllers = new Set();
unsafeWindow.XMLHttpRequest = new Proxy(unsafeWindow.XMLHttpRequest, {
construct: function(target, args) {
let xhr = new target(...args);
xhr.addEventListener("loadstart", function() {
activeXHRs.add(this);
}, {passive: true});
xhr.addEventListener("loadend", function() {
activeXHRs.delete(this);
}, {passive: true});
return xhr;
}
});
let originalFetch = unsafeWindow.fetch;
unsafeWindow.fetch = function(resource, options = undefined) {
let abortController = new AbortController();
options = options || {};
let originalSignal = options.signal;
if (originalSignal) {
originalSignal.addEventListener("abort", function() {
abortController.abort(originalSignal.reason);
}, {passive: true});
}
options.signal = abortController.signal;
abortControllers.add(abortController);
return originalFetch.call(this, resource, options).finally(function() {
abortControllers.delete(abortController);
});
}
function abortAllRequests() {
for (let activeXHR of activeXHRs) {
activeXHR.abort();
}
activeXHRs.clear();
let error = new DOMException("Network request cancelled by Abort Network Requests on Escape", "NetworkError");
for (let abortController of abortControllers) {
abortController.abort(error);
}
abortControllers.clear();
}
window.addEventListener("keydown", function(event) {
if (event.key !== "Escape" || event.target !== document.body || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
return;
}
abortAllRequests();
}, {passive: true});