Published : February 5th, 2008

: Comments : 29 Comments

: Category: Extending Firebug Tutorial

It's been a while since I have started contributing to Firebug. Everybody use this amazing Firefox extension and I am having great time with exploring the underlying architecture. Well, it was hard time at the beginning 😉 I had to dive into unknown waters and understand what's under the hood. I remember it quite exactly, I have spent many hours with debugging a debugger trying to understand how it works.

I was searching the web intensively and if anybody would like to enjoy the same journey, I would recommend to check out Christoph Dorn's awesome article on Extending Firebug. There is also a cool page about Firebug Internals written by John J. Barton. And last but not least source of information is certainly Firebug Group page, yep you can always ask there...

However, what I was really looking for was a step by step tutorial that starts with the familiar "Hello World!" application. I didn't find it. So, I decided to write down something by myself. Perhaps it will be useful for those programmers, who are interested in contributing to Firebug, extending Firebug or developing an entirely new extension for Firefox. So, here it is: Firebug tutorial for extension developers.

Hello World!

The first thing to do is to setup a structure of the extension. This step is easy if you are already familiar with Firefox extension development.

In this case, the directory structure should look like this:

helloworld@janodvarko.cz/ chrome/ content/ helloworld/ helloWorld.xul helloWorld.js chrome.manifest install.rdf

The most important files are obviously helloWorld.xul and helloWorld.js. These two files contains the actual Hello World! implementation. The other two files are used by Firefox to properly install the extension.

See the chrome.manifest first.

xpcnativewrappers= no content helloworld chrome/content/helloworld/no overlay chrome://firebug/content/firebugOverlay.xul chrome://helloworld/content/helloWorld.xul

Notice that xpcnativewrappers=no turns off security tests. After revisiting this code, I would recommend to remove the option or at least be aware of it.

The file specifies that there is a content under chrome/content/helloworld/ directory and that our helloWorld.xul represents an overlay for firebugOverlay.xul. If you are interested, see an article about chrome registration here.

The install.rdf contains standard information about the extension. No comment is needed for this, see detailed info about install manifests here if you want.

<?xml version = "1.0" ?> <RDF xmlns = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"

xmlns:em = "http://www.mozilla.org/2004/em-rdf#" > <Description about="urn:mozilla:install-manifest">

<em:id>helloworld@janodvarko.cz</em:id>

<em:version>0.0.1</em:version> <!-- Firefox -->

<em:targetApplication>

<Description>

<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>

<em:minVersion>1.5</em:minVersion>

<em:maxVersion>3.0.0.*</em:maxVersion>

</Description>

</em:targetApplication> <!-- Extension -->

<em:name>Hello World!</em:name>

<em:description>Firebug Hello World! Extension</em:description>

<em:creator>Jan Odvarko</em:creator>

<em:homepageURL>http://www.janodvarko.cz</em:homepageURL>

</Description>

</RDF>

The helloWorld.xul is currently almost empty (be patient there'll be more things later), only the helloWorld.js is included.

<?xml version = "1.0" ?> <overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<script src="chrome://helloworld/content/helloWorld.js" type="application/x-javascript"/>

</overlay>

This is how the JS script looks like:

ns ( function ( ) { with ( FBL ) { FBL.FBL function HelloWorldPanel() {}

HelloWorldPanel.prototype = extend(Firebug.Panel,

{

name: "HelloWorld",

title: "Hello World!", initialize: function() {

Firebug.Panel.initialize.apply(this, arguments);

},

}); Firebug.registerPanel(HelloWorldPanel); }});

The main and only purpose of helloWorld.js so far, is to create and register a new Firebug Panel (tab). Notice that a Panel plays the same role as a View in MVC (Model View Controller) design pattern. In other words, the Panel is intended to present data to the user.

So, there is a new object called HelloWorldPanel, which is extended from internal Firebug.Panel object. The extension mechanism is realized through extend function, which creates a new object and copies all properties from the first parameter (predecessor object - Firebug.Panel) and then all properties from the second parameter (our new panel - HelloWorldPanel) into it. The object is then returned from the function. You could see this as an imitation of class inheritance.

Our Panel has two properties and a method. Theirs meaning is quite obvious, a name is used to identify the panel (should be unique so, we can access it through getPanel method later) and a title (which is display name of the tab). The later should be localized, but don't worry about it now, we'll deal with these nitpickings later. There is even an initialize method. This is called automatically by the framework when the Panel is activated (displayed) at the first time. It's empty now, but it'll be useful for Panel initialization. Don't forget to call predecessor method, there is some initialization to be made.

Firebug. registerPanel ( HelloWorldPanel ) ;

Finally, the new panel object is registered and so, Firebug can ensure it's properly displayed.

Careful reader might have noticed that entire code is surrounded by a following code:

ns ( function ( ) { with ( FBL ) { FBL.FBL // Panel definition }});

This is how namespaces are realized in Firebug framework. It's smart and useful. This makes possible to avoid global variables and so, dangerous collisions. Something, which everybody should take care of. However let's just use it as it is for now, we'll fall in to this later.

Ok, that's it for now. See the following screen-shot that shows how the new panel should look like within Firebug's UI.

The extension can be downloaded here.

Next time we'll take a look at how to create a new button for our panel and associate a logic with it...