|
|
A page loads an external script, which I have blocked, and then code on the page itself calls a function that would be defined in the blocked external script. This of course results in an error because the function is not defined. I would like to replace the missing function with one which I will write. It seems I can't accomplish this through the obvious means. How would I then? If the page I'm visiting on site.tld says something like this: <script type="text/javascript" src="http://example.tld/annoying.js" /> <script type="text/javascript"> annoying(); </script> And annoying.js defines the function Here's what I tried, which didn't work:
// ==UserScript==
// @name substitute that function
// @namespace tag:fooblarg,2008-05-02:subst-func
// @description Replaces an annoying function
// @include http://site.tld/*
// @include http://*.site.tld/*
// ==/UserScript==
window.annoying = function(){
// do this instead ... ;
return true;
}
|
|
|
unsafeWindow.annoying=function(){return true;} |
|
|
Yeah, I thought about that after I posted. Isn't that unsafe, though? Something to do with providing the page with a means to escalate to chrome privileges? The function in question is called on a multitude of pages which are not controlled by any one author, but by many authors of unknown trustworthiness, competence, carefulness, etc. I tried the location hack also, but it seems to take effect too late to be of use:
location.href="javascript:void((function(){window.annoying=function(){return true;};})());";
It does (re)define the function successfully, but after the (undefined) function has already been called. Is there any safe way to inject JavaScript into the page, and have it execute in the page's context (i.e., with the page's privileges, not chrome's), before any of the page's JavaScript executes? [In other words, I want the script I write to run as if the page author(s) wrote it, and to do so before any scripts they actually did write.] |
|
|
maybe use xpath and innerHTML to replace the function called by the page with your own code. or if the script tag is hard to get with xpath you could use Regexp and replace. |
|
|
So, you're saying rewrite the page. Sure, I can try that, but are there any guarantees that the rewrite would take effect before the part of the page to be rewritten was to be executed, or would I be risking some sort of race condition or whatnot? |
|
|
GM is executed after the page has been generated, if the function in called during the page generation you haven't any chance to avoid it. window.location.assign(void(window.annoying=function(){return true;})); |
|
|
The way I came up with is fucking crazy and really hacky, but its the only way you can be sure. Plus it forces you to load the same page twice.
// ==UserScript==
// @name substitute that function
// @namespace tag:fooblarg,2008-05-02:subst-func
// @description Replaces an annoying function
// @include http://site.tld/*
// @include http://*.site.tld/*
// ==/UserScript==
function XHR(url) {
GM_xmlhttpRequest({
method: 'GET',
url: url,
headers: {
'User-agent': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11',
'Accept': 'application/atom+xml,application/xml,text/xml',
},
onload: function(responseDetails) {
body = responseDetails.responseText.split(/<body[^>]*>((?:.|\n)*)<\/body>/i)[1];
document.body.innerHTML = body;
});
}
function get_url() {
if (self.location == top.location) { //Make Sure this doesn't preform in an iFrame
url = window.location.href;
if (window.location.hash != null) {
url = url.split('#')[0];
}
var url = url + "#refresh";
return url;
} else {
return false;
}
}
url = get_url();
if (url != false) {
window.location.assign(void(window.annoying=function(){return true;}));
XHR(url);
}
|
|
|
Why do you add an hash with refresh to the url? What's wrong if you do something like this:
|
|
|
If I remember right if you xmlhttprequest the same page you are on you get a cached version of the page. This is probably unimportant for this script but since I took this code out of one of my scripts I naturally forgot to omit that line. Your code will probably work aswell. |
|
|
Also if the gm_xmlhttpRequest receive the cached version, it isn't a problem, the cached version should be the virgin html without the modifications done from the javascript function. |
|
|
@Aquilax xmlhttpRequests returns plain text, which means that javascript functions are never evaluated. It doesn't really matter whether or not the page is cached. That only mattered in a script of mine which automatically reloaded parts of a page. |
|
|
Mikado had a pretty nice solution in this thread. |
|
|
So, it sounds like the real solution to this sort of issue would be if the GM developers would provide a means to for user scripts to stipulate the whether they should be executed before any of the page's script are (defaulting to the current behaviour, for compatibility, if the user script's preferred timing is unspecified, of course). But, that's a topic for GM's development discussion boards, not this one. It would also be good if there were an easier way to inject JavaScript into the page's context, but that too is a topic for said other boards. @[sizzlemctwizzle, Aquilax]
@dob
|
|
|
This is the first thing I wanted to know when I downloaded greasemonkey. Found the answer on the wiki (after reading unsafeWindow shouldn't be used) http://wiki.greasespot.net/Code_snippets#Embed_...
function annoying()
{
alert('very annoying!');
}
embedFunction(annoying);
|
|
|
|
|
|
@high6
@shizzlemctwizzle
And just so it's been said, it serves me no real advantage if I have to make the function call myself, after the failed call has already occurred. I do need to define the function before the page calls it, and it does have to be the page that makes the call. |