Article

Home » Client-side Coding » JavaScript & Ajax Tutorials » 10 Things They Never Tell You In Firefox Extension School
SitePoint Feature Article

About the Author

James Edwards

author_jamesE James (aka brothercake) is a front-end developer based in the UK, specializing in advanced JavaScript programming and accessible web site development. He is an outspoken advocate of standards-based development, and contributing author to SitePoint's The Art & Science of JavaScript.

View all articles by James Edwards...

10 Things They Never Tell You In Firefox Extension School

By James Edwards

September 22nd, 2009

Reader Rating: 9.5

Page: 1 2 Next

This is a follow-up article to my recent ebook, Build Your Own Firefox Extension—an extra selection of useful tips, tricks, and hacks that I’ve collected from my experience with building extensions for Firefox, including CodeBurner, the SitePoint Reference extension. Basic knowledge of how to build a Firefox extension is assumed, so you might like to grab your free copy of the ebook first, if you’ve yet to do so already.

Most of what’s here is not explicitly documented at the Mozilla Developer Center (MDC), either because it’s still on their “to do” list, or because I made it up myself. Some of it is well documented, but it’s so useful that I thought it was worth directing your attention to it anyway.

The tips are listed in order of complexity, beginning with the shortest and simplest, and moving onto the longer and more complex ideas.

Please note: in many places throughout this article, I’ll be creating little methods to package-up self-contained techniques, and in all cases I’ll create them as top-level functions (using the function keyword). In practice though, you should create them as methods of your main extension object.

1. Add Icons with list-style-image

Many XUL elements are without support for the CSS background-image property, but many of them do support list-style-image. This includes <menuitem>, <button>, and <textbox>. You could use these for adding your application’s icon to its main menu item, or affixing a little magnifying glass icon to a textbox used for searching:

textbox[type="search"]
{
 list-style-image:url(chrome://myextension/content/images/magglass.png);
}

2. Make <tab> Elements Keyboard-accessible in Mac OS X

<tab> elements are natively inaccessible to the keyboard in Firefox for Mac OS X. To make them accessible you need to manually insert them into the tab order, by adding a tabindex attribute with the value 0. This value is effectively “auto”, and places the element at its source-order position in the overall tab order:

<tab label="About" tabindex="0"/>

Once that’s done you can use the arrow keys to switch between tabs, just the same as in Windows and Linux.

A keyboard-focused tab in Mac OS X

3. Reference the Original Mouse-target of a Context Menu Event

When you click on an item in an XUL context menu, the event target reference is to the <menuitem> you clicked on. But what if you wanted a reference to the original target element; that is, the element you right-clicked on to spawn the menu in the first place?
This is incredibly simple, as Firefox provides a property that contains this very reference. It’s called popupNode and is a property of the document. The easiest way to use it is to pass it through the menu item’s command event:

<popup id="contentAreaContextMenu">
 <menuitem label="This bloke won't haggle"  
           oncommand="offerMeFourteen(document.popupNode)"
 />
</popup>

4. Preventing an Element from Inheriting flex

If you add the flex attribute to most XUL elements, they’ll expand to fill the available space. But flex is inherited, so its children will also expand, which in some cases is highly undesirable. For example, if the child element is an <image> you would want it to have precise dimensions; but there is no way to explicitly negate inherited flex.

But it only inherits one level deep, so you can negate it by adding an intermediate wrapper element, without a declared flex attribute:

<hbox flex="1">

 <hbox>
   <image  
      src="chrome://myextension/content/images/logo.png"  
      width="135"  
      height="130"
    />
 </hbox>

</hbox>

5. Spawn a Dialog from the Chrome load Event

If you use window.openDialog to spawn a dialog with the modal and centerscreen features from the chrome load event, the dialog will be mostly invisible in Mac OS X, hidden in the top-left corner of the screen. This is because the dialog is positioned before the window’s size is established, so the centerscreen property fails to work as expected. The same problem occurs with the alert function, which can be an issue if you’re using it as a quick and dirty debugging tool.

One solution is to wrap the openDialog or alert function in a quick setTimeout. This ensures that the main window is sized before the dialog fires, so it will be positioned correctly:

setTimeout(function(){ alert(foo.bar); },1);

6. Add Custom Dialog Icons for Windows and Linux

To add a custom icon to a dialog, first create a folder named icons inside your extension’s chrome directory. Then, inside the icons folder, create another folder called default. Within the default folder, save an icon with the same name as the <dialog> element’s ID.

So, for example, if the dialog had the ID myextension-preferences you would create an icon called myextension-preferences.ico (for Windows, or .png for Linux). The MDC documentation says to use XPM images for Linux, but they lack support for alpha-channel transparency. PNG files do provide support, and they work just as well.

In Windows the icon will also show up in the taskbar:

A custom dialog icon in Windows XP

This differs to Mac OS X, because its dialogs are displayed without icons.

7. Get a Reference to the Most Recently Opened Window

You can use Firefox’s window mediator interface to get a reference to the most recently opened browser window. This might be useful if you wanted to open a web link from an external dialog, and is more reliable than window.opener.

Here’s a short and sweet little method that returns the window reference, or null if no browser windows are open:

function getRecentWindow()  
{
 var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator);
 var win = wm.getMostRecentWindow("navigator:browser");

 return win;
}

If you liked this article, share the love:
Print-Friendly Version Suggest an Article