Article

Home » Client-side Coding » HTML & XHTML Tutorials » Beat Any Website into Shape with Greasemonkey
SitePoint Feature Article

About the Author

James Edwards

author_jamesE James (aka brothercake) is a front-end developer based in the UK, specializing in advanced JavaScript programming and accessible web site development. He is an outspoken advocate of standards-based development, and contributing author to SitePoint's The Art & Science of JavaScript.

View all articles by James Edwards...

Beat Any Website into Shape with Greasemonkey

By James Edwards

September 7th, 2005

Reader Rating: 7

Page: 1 2 Next

Greasemonkey is a Firefox extension by Aaron Boodman, which allows you to run personal DHTML scripts (known as "user scripts") on any Website. User scripts are essentially bookmarklets that run automatically, but because they do, they're a whole lot more useful.

Ever used a site that doesn't work in Firefox, even though it could with just a few minor tweaks? Ever frustrated by a site you really like apart from one annoying thing it does, or felt the desire to customise sites you visit often? Just as user CSS allows you to change the way Websites appear, so user JS allows you change the way Websites behave.

This article looks at user scripting in general, and Greasemonkey in particular, to explore some possible applications, and discuss any issues that arise.
We'll go from simple to increasingly complex examples, and I'll be assuming you're already familiar with JavaScript and the DOM; but all except one are working user scripts, so you can install and use them whatever your JavaScript skills. You will of course need Firefox and the Greasemonkey extension; if you don't already have them, you can download them from the following links:

You might also want to download the code archive for this article -- it contains all the scripts we'll use here.

Before we start, I want to take a brief overview of how to install and write user scripts for Greasemonkey; if you're already familiar with the extension, you may want to skip straight to the section headed Putting it to use.

Installing User Scripts

Greasemonkey user scripts are .js files with the name convention "scriptname.user.js". You can install the scripts in a couple of ways:

  • Right-click on a link and select Install User Script... from the context menu.
  • View the script in Firefox and select Install User Script... from the Tools menu.

Greasemonkey doesn't have an interface that allows you to edit the source of user scripts directly, so if it has any optional settings or you want to change it at all, you will need to download and edit the script locally, before installing it in the normal way.

Writing User Scripts

Greasemonkey user scripts run on the document once the DOM is ready, but before the onload event. They have no special rules, but it's considered best-practice to wrap them in anonymous functions, so they don't interfere with other scripting:

(function()
{
 ... scripting ...

})();

Apart from that, I have one suggestion to make for writing user scripts: wherever possible, use only well-supported DOM scripting techniques.

Specifically, I try to avoid technologies like XPath, which are not very widely supported and, likewise, non-standard properties like document.body and innerHTML, which may not exist in XHTML mode (on pages served as application/xhtml+xml or equivalent).

These guidelines may seem pointless since we're only writing for Firefox, but we'll improve the chances of wider compatibility this way (Firefox is not the only browser in which user scripting is available; but we'll talk more about that later).

Meta-data Comments

Greasemonkey has a simple comments syntax, which is used to define the sites that a script should or shouldn't run on, the script's name, it's description and namespace (a URI namespace as with XML, in which the name of the script must be unique). Here's a summary:

// ==UserScript==
// @name            Script name
// @namespace       http://www.sitepoint.com/userscripts/
// @description     Brief description of script
// @include         http://google.com/*
// @exclude         http://msn.com/*
// ==/UserScript==

The syntax is pretty self-explanatory, but the Greasemonkey authoring guide goes into more detail.

Putting it to Use

The development of Greasemonkey was heavily inspired by Adrian Holovaty's site-specific extension for All Music Guide, which is designed to fix what many people consider are serious problems with the new site design. The developer's aim was to make it as easy to write a site-specific extension as it is to write DHTML. And so he has.

Simon Willison's Fixing MSDN with Greasemonkey was among the first to make popular use of Greasemonkey, presenting a script that reveals information that would otherwise only be visible to IE, while Mihai Parparita's Adding Persistent Searches to Gmail is by far the most sophisticated example I've seen to date.

But we're going to dive in with a few simple site enhancements, to introduce the possibilities, as well as the practicalities of user scripting. I made a blank template for Greasemonkey scripts that you may find useful; it also includes some handy methods.

Customising Sites you Visit Often

Auto-complete Forms

Our first example auto-completes a single form element on a specific page. In this case, the page is the SitePoint Forum homepage, and the value is my username:

View or install the script auto-complete.user.js from the code archive.

Even though the forum remembers me with a cookie, I might not have it, since I clear all my cookies quite often. There are plenty of other times where this could come in handy: a cookie might have expired, or a site might have more basic functionality that doesn't remember people.

Let's extend the principle by adding another site: the Yahoo! mail login page. First we would add the @include path to the top of the comments section:

// @include         http://mail.yahoo.com/

We then add the appropriate scripting; in this case, the login field doesn't have an id, so we'll have to find it through document.forms:

//look for the yahoo mail login form
var yahoo = typeof document.forms['login_form'] != 'undefined'
 ? document.forms['login_form']['login'] : null;
if(yahoo != null)
{
 //write your username to the field
 yahoo.value = 'brothercake';
}

You can add further sites as you like, defining for each an @include domain, and a chunk of code to find and complete its form field (changing the username to yours, obviously!).

Change the Layout

A user script can do much more than write a single element: it could rewrite the entire DOM of any page, making it look and behave exactly the way you want. In this next example, I'm going to modify the default Slashdot front page. I'll remove the ad frame from the top and replace it with a duplicate of the site-search form, which is otherwise displayed only at the bottom:

View or install the script slashdot-restructure.user.js from the code archive.

As with the auto-complete example, or, for that matter, any user script that modifies a specific page, I only know which elements to change because I looked at the source code. But I don't control it, and somewhere down the line it will probably change.

That's an obvious point, but nonetheless, it's important: anything we write that makes assumptions about the DOM will stop working one day, and we can't do anything about that.

However, we can at least prepare for it by making sure we test for the existence of something before we modify it. That's good practice anyway, but it becomes doubly-important here. In fact, it's the purpose of the tests against null in the Slashdot example script; things like this:

//the first center element contains an ad frame
var adframe = document.getElementsByTagName('center')[0];

//remove it
if(adframe != null) { adframe.parentNode.removeChild(adframe); }

Now, if the script does fail, at least it won't throw any errors.

Customise Search Results

I've often though it would be cool if search results could come back as a tree menu, with +/- icons to allow users to show and hide the summaries. Thankfully, Google results have a predictable (if soupy) structure that's easy to iterate over, so it's a fairly simple task to extract the relevant information and reformat it into a dynamic list:

View or install the script google-tree.user.js from the code archive.

The only serious complication we'll face in parsing the HTML is that the format varies when the result includes a translate link (it has an additional containing <table>). But, provided we allow for that, we can reliably identify the summary of each result, for which we then add show/hide behaviours that are triggered from a dynamically-created icon.

The behaviours come from an onclick handler on the icon, which works with both mouse and keyboard navigation. The use of javascript:void(null) in the link href simply provides an href value; otherwise the link wouldn't be keyboard navigable (because Mozilla can't set focus on a link that has no href). It's essentially the same trick as using href="#", but this method is cleaner: it doesn't do anything else, so you don't have to control its return value the same way.

Improving Web Usability

All the examples we've looked at so far are designed for specific Websites. But user scripts can be made to run on every Website, and this is perhaps where the idea becomes remarkable: you can write user scripts to change how the whole Web behaves. Effectively, you can customise your browser just by writing some simple JS.

The practical considerations are slightly different here, because, generally speaking, we won't be looking for specific structures: we'll be making something new, or modifying widely-used attributes. As such, the scripts in this example are generally more forwards-compatible than previous examples.

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Sponsored Links