UserScripts in Chrome, one Developer’s Perspective

So I have this non-trivial userscript that I’ve had running now for some time and under a variety of browsers and their respective userscript environments.

The most recent environments it’s been regularly used under are Safari 4/GreaseKit 1.3 (patched) and Firefox 3.5/Greasemonkey 0.8.

These environments are quite different. This older version of GreaseKit doesn’t have any kind of environment separation like Greasemonkey does and the script is run at a different time.

Since Chrome seems to do all the things Firefox did for me and since it starts quicker, runs better and doesn’t make me click a million buttons all the time for updates, I’ve switched to it as my primary browser (at least on Windows and Mac. Linux has to wait because my distro is too old).

So of course one of the things I needed to do was update my userscript for Chrome. There were a few surprises.

While Greasemonkey loads the userscript before the page has processed the onload event, GreaseKit and Chrome default to loading the userscript at a point WebKit terms “document-idle” which could be before onload (but after DOM parsing) or after onload. The patch I used with GreaseKit forced it to delay script loading because I didn’t know how to handle this variable timing. Since my script can’t do it’s work until after the onload event, Chrome forced me to address this issue but also gave me a hint as to how to handle it.

if (document.readyState == "complete") {
do_work();
} else {
window.addEventListener("load", do_work, false);
}

I suspect this code would work everywhere (since readyState is a DOM thing).

When Greasemonkey changed the security model the way to access elements of the page’s JavaScript and DOM elements changed. For my script this meant a few calls to alias local variables (var foo = unsafeWindow["foo"];) so I could access/update things. Chrome actually has a stricter environment. You can access the DOM but you can’t access JavaScript from the page at all. It defines unsafeWindow as window but you can only access the DOM through it.

Unfortunately my page needed to access a JS variable embedded into the page via a <script> element that was never stored in a DOM element. It turns out there’s a way to get this but it’s a bit of a hack. You can set location.href to inject some JS code into the page’s context and that JS code can store the JS variable you want into a DOM element that your userscript can then read. I think you could also send the value to a Chrome extension if you had one.

Here’s the kind of code my script uses.

location.href = "javascript:(function(){if (element && variable) element.value = variable;})()";
// We need a delay so the above can work. Hopefully this is enough time...
setTimeout(do_work, 200);

Disgusting right? But it works which is all I care about for now. There were some other things my script had been pulling out of JS variables but they were just references to elements so I put in code to find them in the page for Chrome.

So there you have it. There are differences between the Greasemonkey and Chrome userscript environments but they’re not so large and easyish to work around.

About a1291762

I'm a software developer by trade and a musician by heart. I'm a techno-gadget freak and I dabble in photography. I'm married with two kids, we drive Toyotas and use Macintoshes.
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>