- Published:February 21st, 2008
- Comments:11 Comments
- Category:Extending Firebug Tutorial
Next step in this tutorial is intended to show how a new button can be created within Firebug's toolbar. This part will demonstrate two things (a) how to create a new button that is associated with our "Hello World!" panel and (b) how to append a new button to an existing panel (it'll be the Net panel that is used to monitor network activities). There is also some info about a Model, which is important part of a Firebug extension.
Create button for Hello World! panel
In order to append a new button to our panel, the HelloWorld.xul file has to be modified. This file represents the FB overlay and has been introduced in the previous part.
<script src="chrome://helloworld/content/helloWorld.js" type="application/x-javascript"/>
<commandset id="mainCommandSet">
<command id="cmd_hwMyButton" oncommand="Firebug.HelloWorldModel.onMyButton(FirebugContext)"/>
</commandset>
<toolbar id="fbToolbar" align="center">
<hbox id="fbToolbarInner" insertbefore="fbDetachButton" flex="1" align="center">
<hbox id="fbHelloWorldButtons" insertafter="fbNetButtons">
<toolbarseparator/>
<toolbarbutton id="hwMyButton"
label="Say Hello" class="toolbar-text-button"
tooltiptext="Push to say hello" command="cmd_hwMyButton"/>
</hbox>
</hbox>
</toolbar>
</overlay>
This code inserts new button at appropriate location within the Firebug's UI. Notice that our hwMyButton button uses command cmd_hwMyButton that is consequently associated with following javascript method.
There is a few new things to explain, but let's take a look at the source code first.
var panelName = "HelloWorld";
Firebug.HelloWorldModel = extend(Firebug.Module,
{
showPanel: function(browser, panel) {
var isHwPanel = panel && panel.name == panelName;
var hwButtons = browser.chrome.$("fbHelloWorldButtons");
collapse(hwButtons, !isHwPanel);
},
onMyButton: function(context) {
alert("Hello World!");
}
});
function HelloWorldPanel() {}
HelloWorldPanel.prototype = extend(Firebug.Panel,
{
name: panelName,
title: "Hello World!",
initialize: function() {
Firebug.Panel.initialize.apply(this, arguments);
}
});
Firebug.registerModule(Firebug.HelloWorldModel);
Firebug.registerPanel(HelloWorldPanel);
}});
First of all, there is a new object called HelloWorldModel. This object is derived from internal Model object and represents data model of the extension. Similarly to the Panel, the Model has to be registered within a global Firebug object.
From the MVC perspective the model could be seen as an entity representing a model and a controller at once - it can be used as a data container and handle some user actions at the same time. Important thing is that there is only one instance of the HelloWorldModel object per Firefox main window (browser.xul), which makes possible to share data among web pages within the same browser window.
There is even another object called Context (can be also interpreted as a data model). Every page with enabled Firebug has it's own instance of this object and it's used to store data associated with the page. You'll see that this object is passed as a parameter to many functions.
See the following UML diagram that depicts described relations.
It's not pure UML as in context of JavaScript there are no real classes and "Browser Window" and "Web pages" are just placeholders here (so I hope UML experts will forgive me ;-), but following should be obvious from it:
- The Model object should be used for data shared among pages within the same browser window.
- The Context object should be used for data associated with a web page.
- The Panel object should be used to store presentation data (i.e. HTML)
Just to notice, that Panel has a reference to the Context object, which is set in initialize() method. This is why the predecessor method must be called.
The last important thing in this example is showPanel method.
var isHwPanel = panel && panel.name == panelName;
var hwButtons = browser.chrome.$("fbHelloWorldButtons");
collapse(hwButtons, !isHwPanel);
},
This method is executed by Firebug's framework whenever a panel is displayed. This is the right place where to decide whether our set of buttons (identified as fbHelloWorldButtons) should be displayed or not. The first parameter browser - represents browser window (browser.xul) and the second parameter panel - the panel being activated. According to the panelName we can decide whether to collapse (hide) our button(s).
Notice that the collapse method comes from FBL namespace (about namespaces later).
The button should look like as follows.
Create button for an existing panel
Finally, let's take a look at how to overlay an existing set of buttons. This should be simple task now, see the modified helloWorld.xul overlay.
<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="chrome://helloworld/content/helloWorld.js" type="application/x-javascript"/>
<commandset id="mainCommandSet">
<command id="cmd_hwMyButton" oncommand="Firebug.HelloWorldModel.onMyButton(FirebugContext)"/>
<command id="cmd_hwDisableNetMonitoring"
oncommand="Firebug.HelloWorldModel.onDisableNetMonitoring(FirebugContext)"/>
</commandset>
<toolbar id="fbToolbar" align="center">
<hbox id="fbToolbarInner" insertbefore="fbDetachButton" flex="1" align="center">
<hbox id="fbNetButtons">
<toolbarseparator/>
<toolbarbutton id="hwDisableNetMonitor"
label="Disable Net Monitoring" class="toolbar-text-button" type="checkbox"
tooltiptext="Press To Disable Network Monitoring"
command="cmd_hwDisableNetMonitoring"/>
</hbox>
<hbox id="fbHelloWorldButtons" insertafter="fbNetButtons">
<toolbarseparator/>
<toolbarbutton id="hwMyButton"
label="Say Hello" class="toolbar-text-button"
tooltiptext="Push to say hello" command="cmd_hwMyButton"/>
</hbox>
</hbox>
</toolbar>
</overlay>
There is new overlay for fbNetButtons, which is identifier of an existing set of buttons (for the Net panel). And of course, appropriate javascript handler. So, a method has to be appended to the HelloWorldModel object.
{
// . . .
onDisableNetMonitoring: function(context) {
alert("OK, the click is handled");
}
});
And this is how it should look like.
The extension can be downloaded here.
Update: the example extension uses FirebugContext global variable that has been replaced by Firebug.currentContext in Firebug 1.6+. So, make sure to use the correct one when building an extension for Firebug. See also this thread