Subscribe to RSS Feed

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.

<?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"/>

    <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.

Firebug.HelloWorldModel.onMyButton(FirebugContext)

There is a few new things to explain, but let's take a look at the source code first.

FBL.ns(function() { with (FBL) {
var panelName = "HelloWorld";
Firebug.HelloWorldModel = extend(Firebug.Module,
{
    showPanel: function(browser, panel) {
        var isHwPanel = panel &amp;&amp; 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.

Panel, Model and Context 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.

    showPanel: function(browser, panel) {
        var isHwPanel = panel &amp;&amp; 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.

A new button for Hello World! panel

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.

<?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"/>

    <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.

Firebug.HelloWorldModel = extend(Firebug.Module,
{
    // . . .

    onDisableNetMonitoring: function(context) {
        alert("OK, the click is handled");
    }
});

And this is how it should look like.

A new button for Net panel

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


Rss Commenti

11 Comments

  1. Nice set of tutorials - I look forward to more.

    One thing I have struggled with with Firebug Plugins is in extending the existing panels for my own use rather than the default Firebug.Panel.

    Is it possible to extend the Firebug Console panel itself and then override the UI and add methods?

    I found it pretty easy to send/call the Console panel from a plugin panel but would like the response (inc. the links to DOM objects, and log messages etc) viewable in my plug-in Panel as it seems silly to re-implement it.

    Any info on this much appreciated.

    Regards

    Liam

    #1 Liam Clancy (metafeather)
  2. I hope it won't be interpreted:
    " var isHwPanel = panel && panel.name == panelName;"

    should read:
    " var isHwPanel = panel && panel.name == panelName;"

    #2 Asrail
  3. =(

    " var isHwPanel = panel &amp;&amp; panel.name == panelName;"

    should read:
    " var isHwPanel = panel && panel.name == panelName;"

    PS: this site should have a preview option.

    #3 Asrail
  4. Liam: It's definitely possible to extend the console panel, just the appropriate ancestor class has to be used (Firebug.ConsolePanel in this case).
    But, you can also listen for all logs (see Firebug.Console.addListener & removeListener). Perhaps this could be the right way for you.

    #4 Honza
  5. Asrail: thanks, I have fixed this. From some reason, WordPress is escaping the code. I am doing something wrong here 🙁

    #5 Honza
  6. > this site should have a preview option.
    yep, that would be nice! Do you know about some plugin for WordPress that would do it?

    #6 Honza
  7. one small thing: I assume panelName is defined somewhere like

    var panelName = 'HelloWorld';

    but it's not visible in the code snippets from the article.

    Great writeups, btw, very much appreciated!

    #7 Stoyan
  8. You right, fixed, thanks!

    #8 admin
  9. That && thing tripped me up as well. If you can't fix it, can you put a note into the article to help people in the future?

    #9 Aron
  10. Ooops, fixed again. I really have to install the Code Markup WordPress plugin.

    #10 admin
  11. I am not succeeding to insert the panel. Don't know what i am doing wrong.
    Does it have anything to do with " var isHwPanel = panel && panel.name == panelName;"
    My code seems to be perfect, just followed the instructions.Please help me!

    #11 mappad

Sorry, the comment form is closed at this time.