Last week I made a very simple Firefox extension (that could certainly have been done more easily/straightforwardly in html/javascript) that implements a chess clock. The code still needs a bit of refactoring but the exorcize proved a good introduction to XUL and developing for Firefox.
This tool also pointed me towards some developer guides. The one that proved most useful was a screen-cast called
Extensions Bootcamp: Zero to “Hello World” in 45 Minutes. The screen-cast went over a lot basics I already new at this point but it did point out a few things that proved invaluable.
It explained that building a separate development Firefox profile was a good idea to avoid conflicts with existing extensions. To do this:
$ mkdir -pv ~/profiles/dev
$ /Applications/Firefox.app/Contents/MacOS/firefox -profile ~/profiles/dev -no-remote &
The -profile flag specifies that Firefox should open with the specified profile (creating it if it's an empty folder) and the -no-remote flag creates a new instance of Firefox so that you can continue to browse the web in you own copy of Firefox while you debug the new extension. In this case the idea was that this would allow you to continue watching the screen-cast.
I created an alias for the latter command.
The other key thing this screen-cast pointed out was that re packaging the extension every time I made a change to the code would be extremely time consuming. Instead, it suggested:
$ echo "{PATH TO EXTENSION}" > ~/profiles/dev/extensions/{UNIQUE ID}
{PATH TO EXTENSION} is the directory where my extension files are. In my case the directory created by unpacking the
chessclockblank.zip file created by the generator. {UNIQUE ID} is the unique identifier I specified to the generator tool, Firefox uses this to differentiate all extensions from one another.
During the developing process, after each change to the code, all I had to do was quit the development instance of Firefox and call my alias again and the extension was already installed.
I used a number of tutorials and reference sites including
https://developer.mozilla.org/en/XUL_School and
https://developer.mozilla.org/en/XUL_Tutorial, to actually build the XUL extension. One of the nice features of the XUL I employed to add my extension to the tools menu was the overlay system. Most of this was setup for me by the generator tool but the chrome.manifest file specified that my file, ff-overlay.xul extends the file chrome://browser/content/browser.xul (This is not a normal path, it's Mozilla format that finds a file in a way that is defined by these .manifest files) which defines the entire Firefox interface. The XUL
tags in my file contain elements that are added to parts of the interface, in this case the menu-bar. I then specified that my new menu item uses JavaScript to open a new window which contains the content described by my clock.xul file. This in turn uses JavaScript to run a simple chess clock application.
I initially ran into some snags packaging the extension as a .xpi file. A lot of the documentation talked about creating a .zip file and then renaming it to .xpi. This resulted in the error "This add-on could not be installed because it appears to be corrupt." This was when I tried using the Finder's built in zip feature to create a zip archive of the extension directory. I'm not entirely certain why, but I was able to make the extension work with the following:
$ zip -r chessclock.xpi chrome chrome.manifest defaults install.rdf
I'm guessing that making it a zip of the files in the directory instead of a zip of the directory was the key difference.
I've attached the working .xpi file as well as a zip of the final extension directory.