Squak Mountain Consulting, Inc.
![]() |
Replacing Javascript using Greasemonkey
|
Please visit these links to our sponsor: Amazon.com |
|
I knew it could be done, I just didn't know how: how to replace the code of a javascript function in a webpage.
I *could* do something fancy (and difficult) by hooking into the IP stack and changing the web page as it flys by. That is sort of a heavyweight solution for this problem, to say the least. Or, I could use an add-on tool for firefox, but which one?
I looked at a lot of tools, and found 2 that do the job. One is a debugger. I set a breakpoint on the javascript to force the return value of the javascript function. This is crude, difficult, labor-intensive, but at least it worked. I forgot the name of the debugger, unfortunately.
The other is greasemonkey. At first, this looked to be very difficult. But, like a lot of things, once you know how, it's easy. It turned out to take quite a number of hours to find a technique that would work. I started out by trying to modify 1 character of the script in the DOM. But, I couldn't get the script text to change when I did that. I started digging, and it seems to have to do with security and the context that Greasemonkey is executing in. I'll figure this out eventually. But, for now, I have to get this thing working!
Could I override the entire Javascript function with one of my own? It turned out I could. The official Greasemonkey documentation didn't mention anything like this. I was confused; isn't this a basic thing someone would want to do with a tool like greasemonkey?
I did a lot of searching on the web for "greasemonkey replace javascript" and similar phrases. I had to dig through a lot of false positive hits until I found a useful answer. A very nice person in Barcelona had run into a similar problem, and had written some documentation on it! That documentation can be found here: http://luckyshot.es/blog/greasemonkey-user-scripts-quick-guide at "Inserting Script and CSS Style tags"
It was even written in English, woo hoo! Now, I wasn't sure if this would work, since what is does is add a new Javascript function at the end of all the other scripts. I would then have two scripts with the same name. Wouldn't the two scripts conflict somehow, or at least be rejected by the browser?
A little experimentation showed that this technique has the effect of replacing the original script. The later script overrides the earlier script. Is this by design in Firefox, or did i find a bug? I don't know yet and, for the moment (Firefox 3.0.5), it works.
It turns out it is a feature. JavaScript in non-strict mode will use the last function definition it finds. According to Mozilla a feature called Strict Mode may reject duplicate function definitions as a syntax error. But, the JavaScript specification does not state that clearly.
For non-strict mode, here's how it goes:
First of all, I'm using a function I put on this page for this example, and I put it right near the start of my page, where it's easy for you to find. Here's the function
<script> function getcurrenttime(){ now=new Date; var currenttime = now.getTime(); } </script>We are going to replace it with
<script> function getcurrenttime(){ now=new Date; var currenttime = now.getTime(); alert("The time is now: " + now ); } </script>OK, now let's have you run this example on your browser. You can later take the example and use it as the start of your greasemonkey script. Just install greasemonkey, browse to the page you're reading right now, right-click on the monkey head icon
// ==UserScript== // @name get current time alert // @include http* // @grant none // ==/UserScript== var scriptCode = new Array(); // this is where we are going to build our new script // here's the build of the new script, one line at a time scriptCode.push('function getcurrenttime(){' ); scriptCode.push(' now=new Date;' ); scriptCode.push(' var currenttime = now.getTime();'); scriptCode.push(' alert("The time is: " + now );' ); scriptCode.push('}' ); // now, we put the script in a new script element in the DOM var script = document.createElement('script'); // create the script element script.innerHTML = scriptCode.join('\n'); // add the script code to it scriptCode.length = 0; // recover the memory we used to build the script // this is sort of hard to read, because it's doing 2 things: // 1. finds the first <head> tag on the page // 2. adds the new script just before the </head> tag document.getElementsByTagName('head')[0].appendChild(script); |
Advertisements - Please visit my sponsors and help support development! |