So my goal was to hijack all XMLHttpRequest
responses and do something with them in my script's scope. But since I @grant
something I had to use couldn't do it easy way. (I don't know why, but I couldn't change unsafeWindow
unsafeWindow.XMLHttpRequest.prototype.open
. There was no error, but XMLHttpRequest
didn't work at all.) So I ended up with this piece of code:
// ==UserScript==
// @name a
// @include *
// @version 1
// @grant GM_xmlhttpRequest
// ==/UserScript==
realProcess = function(xhr) {
// do something
}
function hijackAjax(process) {
if(typeof process != "function") {
process = function(e){ console.log(e); };
}
window.addEventListener("hijack_ajax", function(event) {
process(event.detail);
}, false);
function injection() {
var open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
this.addEventListener("load", function() {
window.dispatchEvent(new CustomEvent("hijack_ajax", {detail: this}));
}, false);
open.apply(this, arguments);
};
}
window.setTimeout("(" + injection.toString() + ")()", 0);
}
hijackAjax(realProcess);
My question is: can it be done better/faster/more elegant?
EDIT: Updated code according to hints.
The solution depends on how you want to do interact. You could inject all the logic into the site's scope, however, there is a barrier between userscript's scope and site's scope if you want to interact. It is not trivial to exchange data between both scopes. unsafeWindow
is evil, avoid usage. Inject the logic as string to be evaluatet inside a setTimeout(String)
, so that it is executed in site's scope. If you need to interact with the userscript in privileged scope, setup a messaging system with window.dispatchEvent(new CustomEvent('eventname', {'detail': scalarData}));
. You won't be able to transfer complex datatype declared in a scope with other privileges.