Greasemonkey And Dojo Integration


Dojo (http://dojotoolkit.org/) is a wonderful javascript toolkit which just reached version 1.0 at the beginning of November. I have been watching and developing with Dojo for a couple years now and I can’t tell you how excited I am to have passed the version 1 milestone

Greasemonkey (http://www.greasespot.net/) is a handy Firefox extension which allows the injection of javascript (called userscripts) into the webpage currently being viewed. This allows for the customization of the look and feel of a website: improving the user interface or adding additional functionality.

In this example, we are going to use greasemonkey and Dojo to display a dialog widget on an arbitrary website.

To simplify the deployment of a userscript we are going to use the AOL Content Distribution Network to pull in a crossdomain build of the dojo toolkit. This is helpful to us as developers as we don’t have to build or maintain Dojo ourselves and is useful to the user as they get an optimized download from a distributed CDN.

First thing’s first: If you haven’t already, download and install the Greasemonkey extension, and create a new user script.

To access the power of Dojo, we must include the Dojo crossdomain build on the page we are visiting. To do this, we will dynamically create a new script element containing the address of the build and append it to the document head:

var script = document.createElement('script');
script.src="http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js";
document.getElementsByTagName('head')[0].appendChild(script);

Next, since we are going to need a Dijit Dialog object, we will need to also include the Tundra Theme CSS file by appending it to the head object:

var link = document.createElement('link');
link.rel = "stylesheet";
link.type= "text/css";
link.href="http://o.aolcdn.com/dojo/1.0.0/dijit/themes/tundra/tundra.css";
document.getElementsByTagName('head')[0].appendChild(link);

Great! Now we have the Dojo javascript file included on the page as well as the Dijit Tundra theme setup and ready to use. Next, we will actually include the Dojo dependencies we need and display our Dialog!

To ensure that the Dojo Javascript file and the Tundra Stylesheet have been downloaded and parsed we must include the rest of the code in a function that will run when the window fires the “load” event To do this, we will add an event listener to the window object with the function as an argument:

window.addEventListener('load', function(event) {
var dojo =  unsafeWindow["dojo"];
dojo.require("dijit.Dialog");

Also notice that we have created a local variable called Dojo which is a refrence to the unsafeWindow dojo object. Greasemonkey runs all userscripts in a sandbox which provides enhanced security as well as ensures that they do not conflict with any preexisting scripts already on the page. Because, by default, Dojo is instantiated with a visibility relative to the window object it is not visible to our script. By creating a reference to it in a local variable, this allows us to access its functionality.

Also important is the dojo.require statement. This will pull in the dijit.Dialog object which we will be instantiating later on in our script. To ensure that all the dependences have been loaded before we try to create a dialog, we must wait until dojo knows that the external resource has been loaded.

dojo.addOnLoad(function(){
var dijit = unsafeWindow["dijit"];
dojo.addClass(document.getElementsByTagName('body')[0], "tundra");
 
var pane = document.createElement('div');
pane.id = "floatingPane";
pane.innerHTML="Dojo Lives... In GreaseMonkey!";
document.getElementsByTagName('body')[0].appendChild(pane);
 
dialog = new dijit.Dialog({
title: "Dojo Integration Test"
},pane);
dialog.show();
});
}, 'false');

A lot of stuff happens in the above code snippit:
First we grab a local reference to the global dijit object, next we assign a “tundra” class to the body tag, which will allow us to have the correct theme for our Dialog. We create a div node which will eventually become our Dialog, populate it with appropriate attributes and append it to the document’s body tag. Finally we create a new dialog object with a catchy title and the previously created div node as the contents, and display it on screen. Lastly, we close the window.addEventListener object that we created in the previous step.

Downloaded the complete userscript here:
Dojo Integration Userscript This script has been updated and is available here

Special Thanks to Shane Sullivan’s Dojo Debug Script which shows how to access the Dojo object from the Greasemonkey sandbox.

, ,

  1. #1 by Luiz Marcelo Serique on August 14, 2008 - 11:50 am

    Hi,

    i’m testing your code, but firebug show me a error:

    dialog.show is not a function

    thanks.

  2. #2 by Dustin on August 19, 2008 - 8:20 am

    Hi Luiz,
    When I’m doing testing now, I am getting the same error.
    So it seems that my code is not compatible with Firefox 3 or a newer version of greasemonkey (Because that’s all I can think of that has changed).

    When the dialog is created
    dialog = new dijit.Dialog({
    title: “Dojo Integration Test”
    },pane);

    It appears that a Dialog object is not actually created, instead a {title: “Dojo Integration Test”} object is created (You can test this buy going unsafeWindow[‘console’].debug(dialog);

    If you figure out how to get around this please let me know!

  3. #3 by Ramon on October 8, 2008 - 3:22 pm

    Any idea whether this is fundamentally a Dojo, GreaseMonkey or FF issue? Does this work with Dojo 1.2?

  4. #4 by Marcio Wesley Borges on November 17, 2008 - 4:33 pm

    Great article!
    It works for me.
    Thanks!

  5. #5 by wei on February 11, 2009 - 11:10 pm

    I got the same error. but I didn’t use dijit.dialog, I use the dijit.layout.BorderContainer. But the error is the same, it didn’t create a BorderContainer object, it creates a regular objects with only the properites I passed to the constructor.

    how to fix it?

  6. #6 by cn1h on January 10, 2010 - 2:28 pm

    thanks! that’s just what I want.
    By the way, why does @require in Userscript not work?

  7. #7 by Rob on February 6, 2010 - 12:08 pm

    Broken here, “dialog is undefined”, bummer.

(will not be published)