Firefox add-ons, or extensions, are small programs that run inside the browser in order to customize some behaviors. In theory, it is possible to develop and maintain a multilingual, multiversion and multiOS Firefox add-on. In practice, there are many obstacles to overcome in order to create and to maintain a working Firefox add-on in one language for one Firefox version and for one OS. A Need Arises
In February 2005, I decided to join Wikipedia: free knowledge for everybody. Yes, everybody, even if you read Farsi like the people in that Middle East country. At first, I was contributing 5, 10 times a day. Then I really got hooked, I peaked to 50, 60 contributions a day. However, there was a problem, a itch to scratch as some would say.
To read and to modify the articles, I used Firefox for many reasons: it has tabs, the rendering engine is good, it has tabs, you can customize it endlessly, it has tabs, you can prevent image loading, it has tabs,… You see the picture. Wikipedia contributors provided a bunch of scripts to ease edition, but none was offering what I wanted; open a page on 20th century politics for instance, read for a while, see “JFK” in plain text (not hyperlinked), select it, and tell Firefox to open the page entitled JFK on a click. Why in the world would I need this feature? I am glad you asked. What is the meaning of JFK ? Is there an article entitled JFK? If it is an acronym, does it have many significations? (Insert your question here). If any question receives a yes, then “JFK” should be wikified (in other words, it should be hyperlinked to the article entitled “JFK”).
Since I was not the first to edit and read Wikipedia pages, there was probably someone who built an add-on having such a feature. After perusing different Web sites (Google, thank you!), the reality sank in: nobody provided such an extension.
Being a software developer for five years, I decided to be the knight who saved the day, my day. That was in October 2005.
First Runs
After browsing different sites, most notably the Mozilla Developer Center, I downloaded and reverse-engineered some add-ons. What I found was simple on the surface, but developer unfriendly underneath.
Dummy.xpi/
content/
dummy.jar/
javascript-0.js
xul-0.xul
...
chrome.manifest
install.rdf
Each add-on is packaged within an XPI file. Sometimes, I found a .jar file inside the .xpi file. After a while, I figured that XPI and JAR file formats are ZIP format in disguise. Still today, I find this file structure unfriendly since I must uncompress the .jar file to view its content and there is no significant gain from compressing a .jar file. However, I will not launch a crusade for that.
There are two files of utmost importance: “chrome.manifest” (the chrome, in Firefox parlance, is a portion of the graphical interface) and “install.rdf” (RDF is a language used to ease add-on update). Whenever I play with those files, I do it with care. Even today, 300 hours later, once the add-on loads properly, I just do not touch them anymore. If any has an error, Firefox either aborts the updating process with no or useless message, or performs the update while missing to do some basic checks. This is developer unfriendly.
In many add-ons, .js files appear beside .xul files. In .js files, I found straight JavaScript mixed with object-oriented JavaScript. Nothing worrisome for me, since I coded in C (a functional programming language from which JavaScript borrowed many ideas), then in C++ (an object-oriented programming language). In .xul files, there was XML sentences, close to the usual HTML sentences. Again, not too worrisome for me, since I played a lot with .html files. There were .css files used to manage the display of the elements in the dialogs . I had already seen that before, and knew what amazing things CSS could do. Finally, there was something called DTD (more on this later).
When I started coding in XUL (a language used to build graphical interface), I hit a wall. Even if XULPlanet was full of examples and descriptions, there was too many things to master. You want to display a button? No problem: <button class="CSS class" label="&DTD variable;" oncommand="JavaScriptFunction();"/a>
As you can see, one XUL sentence covers many languages: XML, CSS, DTD, and JavaScript. Thus, you must resign yourself to be lost for a while when playing with XUL files. Once you have a working recipe for any XUL element, do not change it unless you are ready to walk again the long road of learning.
Being confident in my knowledge and know-how, I coded a short piece, and it worked the first time: it was the simple line alert('Hello World!');
inserted within a bunch of supporting code. Now, I could get into serious business.
After learning and coding for 50 hours, I had what I wanted: a way to click on plain text and tell Firefox to open a page. This is a pretty long scratching! But it was not enough. I wanted to open any Wikipedia page from any writeable and any readable HTML element. Another 20 hours was enough to get the job done, fixing some bugs in the process and adding some dialogs.
I finally had a Firefox 1.5 add-on meeting my expectations: Weekedit.
Publish or Perish
It was time to publish. I uploaded the 0.1 version to the Mozilla repository site. Five days later, I sent the 0.2 version, followed by the 0.3 version six days after. A week passed by, a reviewer rejected versions 0.1 and 0.2 since version 0.3 was the last in. That version was accepted.
I felt I was someone.
As I learned in a previous job, documentation is good for business. I could insert text at the Mozilla site, but it did not offer a way to publish HTML files with pictures and hyperlinks. I wrote a user’s guide and hosted it somewhere else. With time, I expanded the guide to the point it has more than 30 pages today. I believe this is one strength of my add-on.
Even if it was good, the add-on needed some publicity. Thus, I wrote a short text and posted it on the French Wikipedia. Some users responded with enthusiasm, many yawned. I did not understand their lack of reaction. Many contributors complained they wanted to do more in less time. Weekedit would help them, in my opinion. Today, I respect their decision.
In March 2007, the Mozilla Foundation moved all add-ons from mozilla.org to mozilla.com. In the process, Weekedit was pushed in the sandbox, a place where it is available to users willing to try new, and sometimes shaky, things. The Foundation forgot to write me it was sandboxing my add-on, preventing regular users to install it. By luck, someone asked me if I had removed the add-on. After so many hours of work, this was absolutely out of question! I took steps to push my baby out of the dark side and in the public light. It became public two days after.
Even if it has weaknesses, the Mozilla repository is the best place to publish my add-ons. The site is multilingual, it can display some pictures, a development history is available, there is a forum, and users may leave reviews. I must say a word about the reviewers. I believe they test with care to ensure that any add-on on the site is correctly working. And they are respectful. For these two reasons, I commend them.
I18N
In April 2006, while translating articles from the English Wikipedia to the French Wikipedia, I wondered if I could build a bilingual XUL interface. The answer was and is still yes, but I needed to construct DTD files (a Document Type Definition in XML parlance). Again, I hit the road, I mean surf the Web, to learn the grammar of this new language. After many miles, I mean many pages, I was ready to build the interface in English and in French, i.e. internationalization and localization (I18N in short).
This is not straightforward as you might predict. The XUL engine (or is it the DTD engine?) cannot process plain text files containing characters with diacritics (e.g., é, à, ^u). When the browser loads the add-on, it displays an error message and the graphical interface does not load at all (rather harsh, in my opinion). The text must be converted to UTF-8 (a computer format to encode Unicode characters). So I got my hands on a small and free program to do the job. After that, I thought my problems with .dtd files were over. But no, I could not insert some characters from the ASCII 0-127 range, even disguised as HTML entities (like "
for "
). The only solution left was to create JavaScript functions to overcome that limitation.
In the course of my add-on construction, I needed to import sentences from two different DTD files within a XUL file. I read a lot and searched a lot. I finally found an add-on with the right XUL sentence. Hallelujah! However, I believe this should have been easier, but the W3C documentation is usually cryptic.
When all this mess was over, I believed my woes with the language barrier were over, but I was overly optimistic. I needed to display some messages, in English or in French, while the user was interacting with the add-on. They could not be part of any DTD files since JavaScript could not open a DTD file stream. Instead, I needed to create .properties files. The syntax of such files is simple. With all previous knowledge, it was pretty easy to insert the right code within ten minutes. Even if this worked fine, I still believe that JavaScript should be able to directly decode .dtd file content. Maybe it is the case, but I do not have any clue.
While speaking of translation, I translated to French the user’s guide. That was simple: I could tell the browser that the HTML file contained French text. No need to insert UTF-8 characters. Thank god!
Porting
After expanding Weekedit for a while in Firefox 1.5, I decided it was time to port it to Firefox 2.0. I had to first update the “install.rdf” file in order to tell Firefox 2.0 that my add-on worked with it. As I wrote before, playing with that file is never pleasing.
When Firefox 2.0 finally agreed to load the add-on, something failed when the add-on tried to access a global JavaScript object. After searching within forums, Mozillazine and elsewhere, I found an object close to what I was looking for. The search costed me two hours, and the correction took me another two hours: the new object is only valid in Firefox 2.0, I add to retain backward compatibility. This lead me to believe that many developers would not do the port, since it did not add anything to their add-on. I can understand that Firefox needed a code update, but not that it was so poorly documented. We, add-on developers, are amateurs churning out code as a hobby most of the time. In my opinion, an incomplete or outdated documentation is a serious barrier to deliver add-ons working accross a browser family.
In November 2006, two guys decided they needed my add-on for their Linux PC. In order to put pressure on me, they rated it 0 and 3/5. I became mad. I was doing my best to offer a free, documented, and bug-free add-on, and they were biting me. I decided to reply by writing a short message to my “fan base”. And I requested the Mozilla repository to remove the 0 comment. Two months after that incident, even if such behavior was maddening me, I finally started the process of porting the add-on to Linux. Other users were much more respectful, they deserved it.
Since I could port the add-on to different Firefox flavors, I decided to port it to all OSes: Windows, Linux, MacOS, etc. It was working fine in Windows 2000 (W2K), and Windows XP. The port to Linux costed me two (three ?) afternoons. Not so bad considering what I had been through before. My most memorable bug was discovered by a user running an experimental Firefox version against Linux. Weekedit was failing when performing a function call. I was unable to reproduce it in W2K, but everytime in Linux. In a XUL file, a line had onload="Function"
. Because the parenthesis were missing (onload="Function();"
is best), Linux Firefox choked. I still wonder why W2K Firefox never failed.
Naively, I thought if Weekedit worked against two OSes so different, it would work with any OS from now on. A reviewer from the Mozilla repository accepted that version, but wrote me that he could not modify any parameter when using MacOS. I was upset. I had built the add-on with flexibility in mind, and it was not behaving as expected. No MacOS computer around me, I finally settled to only support Windows and Linux.
If you read from time to time about Firefox popularity, you probably saw “Mozilla Firefox”. This is a hint toward Firefox predecessor: Mozilla. While that browser gave lot of inputs to the Firefox developers, it is not officially supported anymore by the Mozilla Foundation. I tried to port Weekedit to its successor, SeaMonkey, but I gave up after one hour. I was not ready to go down that road again.
When the French Wikipedia contributors started to use Weekedit, they discovered a bug. When running Firefox 2.0, the accented characters were not properly rendered. In Firefox 1.5, my usual browser, they displayed as expected. I tried things for one year, then I figured out what was going on. The Gecko engine had changed, and the Unicode strings were rendered in a different way. To kill the bug, I needed to change code in .js and .xul files at the same time. In order to prevent disaster for Weekedit users, I created a new add-on offering the same services in Unicode: Wikudit. From a marketing point of view, that was bad, since I broke a product line, but I believe in responsible software practices. What upsets me the most in all this is that Mozilla Foundation still allows the use of plain characters, while the Firefox interface works with Unicode and it is simple to store and retrieve Unicode strings in the preferences (a persistent storage, like Windows Registry).
Today, Weekedit and Wikudit work with Firefox 1.5, Firefox 2.0, Bon Echo (aka Firefox 2.0 nightly build), and Firefox 3.0 (aka Gran Paradiso) against Windows and Linux, and their interface is in English or in French. These are my many-version, bilingual, and many OSes add-ons.
Miscellany
I use a very sophisticated technique to debug the JavaScript code : alert('...');
. Coupled with Console2, something that I cannot live without anymore, I can get a good view of my add-on bowels. I could use Venkman, a JavaScript debugger, but it only works if the code is inserted within HTML files, not XUL files. My add-on needs to access the preferences for storing persistent data, but this is forbidden from a HTML file since it does not have enough execution privileges (this prevents malware installation). The same goes for .properties files. Thus, Venkman is not for me. I read on Firebug and tried Web Developer, these toolboxes offer something, but I still do not know how they can help. Sometimes, I browse the developer extensions and try things, but usually there is nothing remarkable.
I cannot copy the message of a Firefox popup. I find this quite annoying, especially when debugging. For instance, suppose I load a page and a JavaScript bug is lurking. Pop! a message tells me that a function-with-a-very-long-name failed. I wish I could copy its name, but since popups are modal (any further interaction with the browser is prevented until I click OK or Cancel), I cannot set them aside and copy their content by hand. Like any geek, I decided to provide a custom popup with message that any user can copy. It works decently, but it took me many headaches and many hours to build it. I hope something similar will be introduced in future Firefox versions.
Many times, I wondered what methods (in object-oriented parlance, functions inside objects) a JavaScript object had. Firefox 1.5 and higher come with a DOM Inspector, but it does not work for dialogs outside the main interface (I found a way to partly circumvent that limitation – more on this below). I implemented a function to display the methods of any JavaScript object. I find this function invaluable.
While writing this article, I learned that I can directly open some XUL file, from the chrome directory, in a browser tab. For instance, typing chrome://wikudit/content/options.xul
, in the address bar of my browser, opens up the Wikudit options dialog. I tested it with the DOM Inspector, and it gives me many valuable information and hints. I expect to test the Venkman soon and see what comes out. I still have many roads to explore.
An add-on without any icon is dull. This is the cost for living in the picture age. I decided to insert some plain pictures in mine. I started to explore a new field of knowledge: picture formats, image resizing, color depth, image cropping, noise filtering, etc. While many images were rendered correctly in a standalone viewer, the browser was not outputting the same images. After many hours on the subject, I am still wondering what is the way to create nice icons for Firefox. Please, if you have any good Web site to recommend, I will gladly browse it!
Many add-ons come with an About dialog. This is like a splash screen, but adapted to Firefox add-ons. Mine is available in English and in French, but Firefox cannot directly display the About dialog in French due to a bug. There is a workaround, but it only works if the add-on feeds plain text to Firefox. This thing makes me feel like coding in a tunnel. Just one more function, and I will be out.
For a while, I wanted to change on the fly Wikipedia Web pages: too much stuff. Leveraging Weekedit, I tried hard, but could not find a way to get what I wanted. Maybe I am still too dumb to understand that DOM stuff (in fact, I was searching for an undocumented Firefox event: pageshow
, found in a buggy add-on). One day, I fell over a small add-on showing how this was possible with code retrieved from Greasemonkey. Now, I can change HTML and CSS properties of any loaded Wikipedia page. In fact, of any page within targeted Web domains (e.g., wiktionary.org). This is a tribute to the flexibility of Firefox and to the power of add-ons and.
Many add-ons explicitly display licenses: GPL (two varieties at least), LGPL (two varieties at least), MPL, Artistic license, Creative Commons License (six varieties), etc. Many developers do not care at all. Which license you choose for your add-on does not matter, but choose one. Or somebody else, in a remote country, will for you. Weekedit falls under three licenses at the same time: MPL 1.1/GPL 2.0/LGPL 2.1. Wikudit falls under GPLv3 or later. I believe that GPLv3 has more teeth than GPL 2.0, but I wish to respect Weekedit users: changing the license would be like pushing something down their throat.
Conclusion
In order to create an add-on for Firefox, you should be at least proficient in HTML and JavaScript. You will learn the other languages, CSS, XUL, DTD, and RDF, in due time. Expect to reverse-engineer many extensions. This is normal, since Firefox is a complex program, there are many Firefox flavors, and documentation is lacking, even if there are people trying to close the gap. Since April 2007, the book Programming Firefox is available. For me, it is two years too late. For you, it may be the right time.
Today, my extensions work fine. I am proud of what I achieved, but I believe there should be less obstacles in bringing up an add-on. Now, if you will excuse me, I must get back to Wikudit : I have tests to perform against FreeBSD and ZenWalk. See you on the road!
Resources
If you are still ready to jump in the add-ons pool, then read first Getting started with extension development. It is a good start, but be ready to roam the Web.
I use the following programs to develop my add-ons under Windows 2000.
- UltraEdit (commercial, a nice professional text editor)
- ASCII to UTF8 Converter (free, convert ASCII text to UTF-8 encoding)
- FileZilla (free, FTP client to upload files to Web sites)
- ExplorerXP (free, a tabbed file viewer – the more I use it, the more I like it)
- IrfanView (free, a very nice image viewer)
- XnView (free, another nice image viewer)
- IcoFX (free, icon editor, it has quirks)
About the author:
Olier Raby was previously a natural food store director, an electrical engineer and a software developer. He is now a mathematics teacher interested in customizable educational software, like MediaWiki, the remarkable software behind Wikipedia. He lives in a middle-size city in Canada.
If you would like to see your thoughts or experiences with technology published, please consider writing an article for OSAlert.
If you’re looking into developing Extensions, you should also download Firefox 3a5/Nightly and check out the FUEL API, an API designed to really simplify some of the horrifc JS needed to very basic things in Firefox. You can see the developing specification here:
http://wiki.mozilla.org/FUEL
I personally tried writing a XUL app once, but the documentation was so uterly lacking, outdated and awful I had to give up. If you want to get into Firefox development, do make sure you’ve modified your pension scheme and life insurance to account for the several years you will lose from your life trying to get an extension to work.
And it’s really a shame too.
FF had the potential to become a real player in the RIA/Desktop application development space, if they managed to clean up some of the docs and stabilize the system (so that the docs remained current), as well as writing some solid JS libraries to wrap up a bulk of the communication to the back end. I don’t know why they didn’t simply wrap all of back end calls in JS wrapper that were easy to use and work with.
None of the parts are implicitly horrible (well, RDF has few fans, but…). And the concept is quite sound — solid scripting language on top of a solid core of infrastructure. And they the bits that most folks want for desktop/RIA/ and/or client-server applications.
And what they didn’t have could have been written reasonably efficient for each application.
But putting it all together and find out which end is up is just a nightmare, and the entire platform has struggled because of it.
Now the Web in general has pretty much obsoleted much of what XUL was trying to achieve in more practical measures as far as desktop-esque applications go.
As much as I love the idea of platform-independent web-as-platform applications, all the current methods seem too convoluted. Couldn’t the author have written a Java applet that does the same thing in 1/10th the time?
And the Javascript/HTML/CSS/Webkit/??? web-app mess seems to be what Apple has in mind for IPhone apps too.
Do-able, but needlessly difficult.
When I started the project, I did not considered Java at all : the documentation was not suggesting it.
Even today, I am reluctant to jump into the Java pool : I use three stand-alone applications on my PC, and I do not like the graphics, nor the responsiveness of the graphical interface.
I suggest author to try creating UserJS for Opera browser with almost same functionality and feel the difference – UserJS are way easier!
UserJS came to my mind as well.
Has anyone done an in-depth comparison of capabilities between extensions in Firefox & UserJS in Opera?
That depends on what you’re doing.
I read the first few paragraphs here, and the author could have saved himself much trouble by writing a user script — everything he needed is possible, and most features would be cross-compatible with Opera and Greasemonkey.
Since my time is not infinitely stretchable, I do not expect to use UserJS. Thanks for the suggestion.
That’s interesting; I’ve always wondered if Firefox extensions were really meant to be cross-platform. Extensions like IE Tab just don’t make sense to me.
C is a “procedural” programming language rather than a “functional” programming language, emphasizing imperative programming style.
http://en.wikipedia.org/wiki/Functional_programming
Great article though. Thx.
1. You can actually use a dump() command to output to the JavaScript console. But setting up Firefox appropriately requires a bit of work.
2. I gave up on any documentation. Some of the plugins are well coded and can be used for reference. The alternative is to grep the .js files of firefox.
3. Be extremely careful when you access the XPCOM interface directly. Unlike in the other code, you have to do some cleanup to prevent memory leaks.
4. I think jedit is very useful. Among other things, it allows you to save text files in many codings, including UTF8.
Thanks for the suggestions and the warning.