The Firefox 4 Add-on Bar for Developers

As I mentioned last week, my posts will be a mix of Firefox add-on posts and personal posts. This one is about Firefox add-ons.

One of the new features in Firefox 4 is the add-on bar. Love it or hate it, as an add-on developer, you’re going to have to get used to it. I recently ported one of my add-ons that has a status bar icon over to use the add-on bar, so I thought I would share the experience. This post assumes that you have built a Firefox add-on before and are porting it over to Firefox 4.

The add-on I was porting to Firefox 4 was XFox Live. This add-on has a status bar icon in the lower right that displays your XBox Live friends when it is clicked. Here’s what the XUL for that status bar icon looks like:

<statusbar id="status-bar">
  <statusbarpanel class="statusbarpanel-menu-iconic"
                  id="xfox-statusbarpanel"
                  tooltiptext="XFox Live"
                  context="xfox-contextmenu"
                  onclick="if (event.button == 0) toggleSidebar('xfox-sidebar');">
  </statusbarpanel>
</statusbar>

This is a very simple status bar icon. It is based on the documentation at developer.mozilla.org. It has a statusbarpanel specific class, an id, tooltiptext, a context menu and a handler so that when it is clicked on it displays a sidebar. In the click handler, there is an extra check so the sidebar only shows when mouse button one is clicked.

This code is going to stay the same for anything before Firefox 4, so the first step is to create separate files for Firefox 3.X and Firefox 4. I created two files, xfoxFF3.xul and xfoxFF4.xul. xfoxFF3.xul only contains my statusbar icon. To use different XUL files for Firefox 3 and 4, I put these lines in my chrome.manifest:

overlay   chrome://browser/content/browser.xul   chrome://xfox/content/xfoxFF3.xul appversion<=3.6.*
overlay   chrome://browser/content/browser.xul   chrome://xfox/content/xfoxFF4.xul appversion>3.6.*

The appversion checks in the chrome.manifest allow different XUL files to be used for different versions of Firefox. These are only the overlays for the status bar and for the new toolbar button; I still have another XUL overlay for the rest of the XUL I need.

The next step is to create a toolbar button in the file xfoxFF4.xul. Instructions for creating a toolbar button are on developer.mozilla.org. A simple toolbar button looks like this:

<toolbarpalette id="BrowserToolbarPalette">
  <toolbarbutton class="toolbarbutton-1 chromeclass-toolbar-additional"
                 id="xfox-statusbarpanel" 
                 tooltiptext="XFox Live"
                 label="XFox Live"
                 context="xfox-contextmenu"
                 oncommand="toggleSidebar('xfox-sidebar');">

  </toolbarbutton>
</toolbarpalette>

What’s changed? The classes are different since there are different classes for toolbar buttons. By using the same ID, the amount of code and CSS that needs to be changed is reduced. The tooltiptext is the same. A label is needed now because sometimes toolbar buttons are viewed as text only. The context menu is the same. Finally, the onclick handler becaomes an oncommand because it is a button. oncommand only happens for clicks from button one, so the button check is unnecessary.

This is enough to create a toolbar button. The problem is that when a toolbar button is created in the toolbar palette, the only place it exists is in the Customize Toolbar dialog. There needs to be some Javascript that places the icon in the right place. Here’s the code to do that:

var addonBar = document.getElementById("addon-bar");
if (addonBar) {
  if (!document.getElementById("xfox-statusbarpanel")) {
    var addonBarCloseButton = document.getElementById("addonbar-closebutton")
    addonBar.insertItem("xfox-statusbarpanel", addonBarCloseButton.nextSibling);
    addonBar.collapsed = false;
  }
}

I decided to put my button on the far left side of the add-on bar by default. I did this because if you put it on the right side, part of it is overlaid by the resizing bars on Mac, so it is not usable.

The addon-bar consists of a close button, a spring and a dummy statusbar panel. Because the spring does not have a unique ID (and might not be there), the close button is the best thing to use for positioning the new button. The code above inserts the new button and then makes the add-on bar visible. (The add-on bar is supposed to become visible automatically if something is added to it, but that’s not working right now.)

You may wonder why I check the visibility of my button before I place the button. If the user has moved my button anywhere else in the UI, I don’t put it back on the add-on bar. But if they have removed it completely, I put it back on the add-on bar. You may choose to do this differently.

There’s one more thing to take care of. If you were to open the customize toolbar dialog and drag the new button into it, the icon would be distorted or not display at all. This is because when you have a toolbar button, the CSS for your button needs to be applied to both the main browser window and to the customize toolbar dialog. This line in chrome.manifest will do that:

style chrome://global/content/customizeToolbar.xul chrome://xfox/skin/xfox.css

It’s a good idea to create a small CSS file that just contains the toolbar button customizations so all of your add-ons styles aren’t applied to the Customize Toolbar dialog. Here’s the CSS file that I used:

#xfox-statusbarpanel {
   list-style-image: url("chrome://xfox/skin/xfox-small.png");
}

The icon is a 16×16 icon. I used the same icon for both the statusbar and the toolbar button. Because the state of toolbar buttons icons is in flux right now, creating new icons didn’t make a lot of sense.

And that’s how to update an add-on for the new Firefox 4 addon-bar.

If you’d like to see this code in action, you can check out my XFox Live add-on.

Please note: I reserve the right to delete comments that are offensive or off-topic.

Leave a Reply

Your email address will not be published. Required fields are marked *

19 thoughts on “The Firefox 4 Add-on Bar for Developers

  1. Forgive my ignorance but… what is the difference between the add-on bar and the status bar? I’m running a nightly and other than a re-skin, I can’t see the difference. My addons developed for Fx3 XUL display just fine in Fx4’s addon-bar – they need no adjustment.

    • The reason your add-ons work is because the Firefox team put a shim into the add-on bar for now so that existing add-ons that use the status bar will still work without any changes.

      At some point that shim will be removed and add-ons will be required to have custom code to add their add-ons to the add-on bar.

  2. Good post; got a question though. Would this code:

    if (addonBar) {
    if (!document.getElementById(“xfox-statusbarpanel”)) {
    var addonBarCloseButton = document.getElementById(“addonbar-closebutton”)
    addonBar.insertItem(“xfox-statusbarpanel”, addonBarCloseButton.nextSibling);
    addonBar.collapsed = false;
    }
    }

    make the xfox panel appear every time? Or does it respect the user’s customization?

    • It respects the user’s customization unless they’ve removed it completely and then it puts it back. If they move it around to other toolbars, it doesn’t get put back on the add-on bar.

      If you didn’t want to do that, you would need to put this code in some sort of “first run” code in your addon so it only executes the first time you are installed (or when you are upgraded).

      I wanted to make sure my addon was always available.

  3. Hey thanks. This is some very cool info.
    I just learned that I should drop the status bar id so that I don’t have to worry about it in the future. I didn’t know that it was temporary.

    The add-on that I have is Firefox 4 only, so no worries.

  4. Putting the URL of the icon in a css file is new to FF4. In the past, I used the src attribute to define the location of the icon. This method allowed me to change the icon in response to user behavior (clicking on the button) or application behavior (using the icon to indicate status).

    How can I achieve the same thing using the add on bar?

    • What I do is specify multiple images with different attributes. Like this:

      xfox-statusbarpanel[icon='special'] {
         list-style-image: url("chrome://xfox/skin/xfox-small-special.png");
      }
      

      Then I just set my attribute on the button.

      document.getElementById("xfox-statusbarpanel").setAttribute("icon","special");
      

      Then I can do all the image stuff in CSS.

  5. I find it really disturbing that the add-on bar is not visible per default. Does anybody know if that is going to be FF’s policy for version 4 or is that just a setting during the beta runs? Or will they enable the if-something-is-added-it-becomes-visible feature?

    This policy is a serious handicap for extension developers. And it might well backfire at the user. Cause if we must pull out hacks like the one you provide here (thanks for the valuable input :), we provoke usability issues. For example if a user disabled the add-on bar on purpose, the above hack will bring it back to him. That can’t be a good. I advice and plead for a sane but extension-friendly environment, that does not require hacks.

  6. I had an addon with a status bar icon that changed when my addon was activated or deactivated.

    I did this with the code bellow:

    CSS:

    #status-menu[status=”on”] {
    list-style-image: url(“chrome://chrome/on.png”);
    }

    #status-menu[status=”off”] {
    list-style-image: url(“chrome://chrome/off.png”);
    }

    and this JavaScript code in an observer:

    if (prefManager.getBoolPref(‘extensions.myext.myvar’) == false) {

    document.getElementById(“status_bar_icon”).setAttribute(“status”, “off”);
    }

    else {
    document.getElementById(“status_bar_icon”).setAttribute(“status”, “on”);
    }

    I run the same Javascript when the addon loads at firefox startup and it shows the right icon, but it doesn’t work in the observer as it used to with the status bar icon.

    What’s wrong???

  7. Yeah, yeah… Sorry for this! This is not the actual code. I wrote it when I made the post to demonstrate the method I’m using.

    The actual code has not such problems. It works for the status bar icon, but not for toolbarbutton which is placed at the add-on bar. They have both the same IDs (toolbarbutton and statusbar icon), but they are placed in different overlays. One for Firefox 4 and one for older versions. The same JavaScript file and the same function is supposed to change both, but it works only for the status bar, not the add-on bar…

    Any ideas?

    • Have you verified that the document.getElementById returns the toolbar button? The button might not be there yet since it’s added dynamically.

  8. I use Console 2. When a variable is null it reports it…

    I also tried this code:

    var addonBar = document.getElementById(“addon-bar”);

    if (addonBar) {

    if (prefManager.getBoolPref(‘extensions.myext.myvar’) == false )

    {
    addonBar.getElementById(“status-menu”).setAttribute(“status”, “off”);
    }

    else {
    addonBar.getElementById(“status-menu”).setAttribute(“status”, “on”);
    }
    }

    but it didn’t work too. I can’t think of something else now…

  9. I put the test the Add-on Bar on FF4 ran. I see that first time is working Add-on Bar. About 15 pages on the website. Then Close a FF4. Re-open the FF4 disappear the Add-on bar. I tried it is not working. I did uninstall and re-install add-on or FF4 or Both are failed. I wasn’t pleased with it. Your design is NOT working with FF4. Because Many computer who have difference a application software were installed in their country. I believe your FF4 Development is working with you or staff. But Global Country has not working with your FF4. We should PUT BACK A STATUS BAR on the FF4 immediate. DO NOT ignore the public were told you in thousand of times. Include Forum user still FIGHT !

  10. Many add-ons are now in pre- and post- FX4 versions because developers couldn’t figure the two overlays trick. Anyway, I think there’s an easier way to add support for FX4 without ‘breaking’ anything else, f.e. sweat

    Say you have your developed a typical old-fashioned add-on that puts a statusbarpanel element in the status bar. On FX4, now it gets stuck in the add-on bar, which is off by default, and you don’t want to force users to turn it on, because you’re so well-meaning

    All you need to do somewhere along your initial stuff is:

    var addonBar = document.getElementById(‘addon-bar’);
    if (!addonBar) return; // No FX4 -> Done, phew!
    var myBar = document.getElementById(‘whatever’);
    var wrapper = document.createElement(toolbaritem);
    wrapper.id = ‘whatever_on_skates’;
    wrapper.appendChild(myBar);
    addonBar.appendChild(wrapper);

    and voilà. Your little status bar still ends up in the add-on bar with FX4, but it’s not stuck there anymore, so users can move it around freely.

    Are there any drawbacks to this?

    I’m thinking it should be equally easy to initially move your bar to the palette (I’m assuming addonBar present ToolBarPalette present) if it turns out you’re running on FX4. But apparently ToolBarPalette is hidden away…

  11. One difference between the status bar and add-on bar is text. When I add a text label to the status bar, I can count on it being displayed. When I add a text label to the add-on bar, it is only displayed if the user has selected the option Icons And Text in the View Menu > Customize… > Show pull down menu.

    This is a problem for me (and has been complained about by the uses of my add-on. Their gripe is that they don’t want to have the Show menu set to Icons and Text because it clutters up their UI with text below the all the buttons in the standard FF5 interface. Under FF4, my add-on has a control to turn off and on the text, but I can’t see a way of turning on the text under FF5 without using Icons And Text option.

    Am I missing something?