The user interface portion of a Firefox extension is created using XUL (pronounced "zool"), a markup language used in creating user interfaces. XUL can be thought of as a flavor of XML, simply because XUL is nothing more than XML that makes use of predefined elements (also called widgets). The beauty of XUL comes through the use of what it calls dynamic overlays. A dynamic overlay allows a developer to modify the behavior of a window’s user interface, without having to change the original interface’s code. Not having to change the code base allows us to focus on our extension, rather than having to worry about reinventing the wheel.
Create a file in the content directory of our extension’s file structure, and name it tuttoolbar.xul. After you create this file, the directory structure should look like the following:
TutToolbar/ |-- install.rdf |-- chrome.manifest +-- chrome/ +-- content/ +-- tuttoolbar.xul
Now that we’ve created the file, we can begin discussing the contents line by line. As we go along, I will provide sample XUL files at each step, showing the entire file’s contents. This should make it easier to see what’s going on. By the end of this chapter, our XUL file will be quite robust.
Because XUL is simply an XML flavor, the first line of the file needs to be the XML declaration:
Now that we have declared this an XML file, we can begin to create the overlay itself. We do so by creating an
overlay element. This element will be the root element of the entire document. In other words, everything else we place in this file must be a child of this element (between the opening and closing tags). Here’s how our
overlay element will look:
<overlay id="TutTB-Overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> </overlay>
This element has two attributes:
xmlns. As those familiar with HTML will already know, the value of the
id attribute must be unique. And what may be more surprising is that it must be unique across the entire browser system. There are a number of strategies that you can employ to make sure that your ID’s are unique. In the example above, you will note that I used the
TutTB- prefix in the
id attribute’s value. Choosing a prefix that corresponds to your extension’s name will help improve the odds that your ID’s will be unique. Also note that the actual value need not include the word "overlay"; I simply do that to help me keep track of what element is what.
The second attribute in this element,
xmlns, specifies the XML namespace that will be used in the overlay. Since this is a XUL document, we must point to the XUL namespace definition. The value shown is the value you should always use.
The Toolbox and Toolbar
All toolbars in Firefox should live within a toolbox. We specify a toolbox using the aptly named
toolbox element like so (remember that this element gets placed inside the
overlay element we created moments ago):
<toolbox id="navigator-toolbox"> </toolbox>
Note that the
id attribute here has a predefined value:
navigator-toolbox. This special value represents the primary toolbox element in the Firefox window, which houses the navigation toolbar, menu bar, URL bar, and other similar controls. By specifying this particular toolbox, we ensure that our toolbar will show up alongside all of the others. I recommend that you always place your toolbars within this particular toolbox. Not only will you be consistent with the standard toolbars, but your custom toolbar gets added to the View » Toolbars menu, allowing you to quickly hide or show it (a very handy feature you get for free).
Let us now turn our attention to the
toolbar element, which we will place inside the
toolbox we just specified. Here’s how our element looks:
<toolbar id="TutTB-Toolbar" toolbarname="Tutorial Toolbar" accesskey="T" class="chromeclass-toolbar" context="toolbar-context-menu" hidden="false" persist="hidden"> </toolbar>
Let’s take a look at the new attributes in this element (we’ll skip the ones we’ve already seen):
toolbarname– This attribute specifies the name of our toolbar (that is, the text that a user will see in the View » Toolbars menu).
accesskey– Specifies the letter in the toolbar name (that we just specified) which will be underlined for use as a keyboard access key. For this tutorial toolbar, we will use the capital letter T. Note that although this is an optional attribute, it is highly recommended that you make use of it (so that users who only make use of the keyboard will be able to toggle your toolbar’s visibility).
class– Specifies the particular style class to apply to the toolbar. The predefined value shown (
chromeclass-toolbar) is the class used for the standard Firefox toolbar look and feel. Again, this is an optional, but recommended, attribute.
context– Specifies the context menu that we want to display when the user right-clicks our toolbar. You can provide the ID of your own menu here, or you can provide the value for the standard View » Toolbars menu, which is shown in the example above (
hidden– Specifies whether or not the toolbar should be hidden. By default, we want our toolbar to be visible to the user, so we set the value to false.
persist– This attribute is a space separated list of attributes that should persist across browser sessions. In the example shown above, I have provided a value of "hidden", telling Firefox that it should remember the hidden state of our toolbar between sessions. Note that if your toolbar element does not have an
idattribute set, the persist attribute will not work! So make sure you have specified an
idfor your toolbar element.
You can find a complete reference on all of the toolbar element’s attributes at the Mozilla Developer Network.
Let us now take a look at the XUL overlay we have created so far: [View XUL Overlay Revision 1]
Toolbar buttons have three flavors in Firefox: normal, menu, and button-menu. These flavors are all created using the same
toolbarbutton element. Let’s examine each one individually. Keep in mind that these elements get placed within the
toolbar element that we just created.
Here is the XUL markup used to create your standard, run-of-the-mill toolbar button:
<toolbarbutton id="TutTB-Web-Button" tooltiptext="Search the Web" class="TutTB-HasIcon" label="Web Search" oncommand="objTutorialToolbar.Search(event, 'web')" />
As we have been doing, let’s take a look at this element’s new attributes:
tooltiptext– Specifies what the tooltip will say when the user hovers their mouse pointer over the button.
label– Specifies the text to be displayed on the toolbar button itself.
oncommand– Specifies what code you want to execute when the
oncommandevent is fired (i.e. the toolbar button is clicked/activated). In this example, we call the
Search()function associated with our
objTutorialToolbarobject. We will discuss this function in greater detail in chapter 6 of this tutorial.
You can find a complete reference on the toolbarbutton element’s attributes at the Mozilla Developer Network.
The second button flavor, the menu button, displays a drop-down menu when it is clicked. Although the markup for this button is similar to the normal button’s markup, we must add an embedded
menupopup element to represent the menu that we want to show. For the sake of brevity, the following example only contains two menu items.
<toolbarbutton id="TutTB-MainMenu" type="menu" class="TutTB-HasIcon" tooltiptext="Tutorial Toolbar Main Menu"> <menupopup> <menuitem label="Google Home Page" accesskey="G" oncommand="objTutorialToolbar.LoadURL('http://www.google.com/')" /> <menuseparator /> <menuitem label="Born Geek Website" accesskey="B" oncommand="objTutorialToolbar.LoadURL('https://www.borngeek.com/')" /> </menupopup> </toolbarbutton>
toolbarbutton element has had two significant changes made to it. First is the new
type attribute which, in our example, has been given a value of "menu" (specifying that this is a menu button, not a normal button). Second, you will notice that there is no
oncommand attribute, as there was with the normal button. Because a menu button’s sole purpose in life is to display a popup menu, there is no need for it to execute any code (showing the menu will be handled automatically by Firefox).
Also note the new
menuseparator elements. The
menupopup element is a container into which all menu items go, and is responsible for creating and displaying the actual menu. In the example, this element has no attributes. Likewise, the
menuseparator element is very simple: it places a horizontal separator in the drop-down menu to help visually separate different menu regions.
The attributes seen in the
menuitem element should all look familiar to you. You can find a complete reference on the menuitem element’s attributes at the Mozilla Developer Network.
The third and final button flavor, the "button-menu" button, is the most complex of the three. It essentially combines the ideas from the previous two flavors, providing both a clickable button region as well as a drop-down menu. Here’s the markup we’ll use to create one:
<toolbarbutton id="TutTB-Combined-Button" label="Search" class="TutTB-HasIcon" type="menu-button" tooltiptext="Combined Search" searchType="web" oncommand="objTutorialToolbar.CombinedSearch(event)"> <menupopup oncommand="objTutorialToolbar.CombinedSearch(event); event.stopPropagation();"> <menuitem id="TutTB-Combined-Web" label="Web Search" class="menuitem-iconic TutTB-HasIcon" searchType="web" /> <menuitem id="TutTB-Combined-Image" label="Image Search" class="menuitem-iconic TutTB-HasIcon" searchType="image" /> </menupopup> </toolbarbutton>
Note that the
toolbarbutton element has an
oncommand attribute, just like normal buttons do, and it includes all of the nested
menuitem elements that we saw with the menu button. There are a few extra things worth noting about the markup for this button type:
typeattribute in the
toolbarbuttonelement has been given a value of
- A custom attribute
searchTypehas been added to the
toolbarbuttonelement, as well as each
menuitemelement (we will return to this in chapter 6)
menupopupelement in this case has an associated
oncommandattribute (again, something we’ll return to later)
Now that we have discussed the various button flavors, let’s take a look at our new XUL overlay file: [View XUL Overlay Revision 2]. In this sample, I have ordered the buttons differently than we discussed them in the text above: the menu button appears first, the button-menu button second, and the normal button third. Otherwise, everything is exactly as it is shown above.
Drop-Down Edit Box
The next item we will add to our toolbar is a drop-down edit box. This type of control can be created using the
menulist element, whose markup looks like this:
<toolbaritem id="TutTB-SearchTerms-TBItem" persist="width"> <menulist id="TutTB-SearchTerms" editable="true" flex="1" minwidth="100" width="250" onkeypress="objTutorialToolbar.KeyHandler(event);"> <menupopup id="TutTB-SearchTermsMenu" onpopupshowing="objTutorialToolbar.Populate()" /> </menulist> </toolbaritem>
Note that we have surrounded the
menulist element with a
toolbaritem element. Any item you place within a
toolbar that is not a
toolbarbutton, should be wrapped in a
toolbaritem element. Also note that we have specified an
id for the
toolbaritem element, and we have asked it to remember its width (through the use of the
persist attribute). More on why we do this in a moment.
menulist element is what actually creates the drop-down edit box. There are a few new attributes shown within the markup for this element:
editable– When set to true, the user can type inside the edit box.
flex– Indicates that this element is flexible. The value is an integer specifying the relative "flexibility" of the element in relation to other toolbar elements. A element with a flex value of 2 will therefore try to become twice as wide as an element with a flex value of 1. A value of 0 indicates that the element can not flex (it is fixed width).
minwidth– Specifies the minimum allowable width of this element, in pixels.
width– Specifies the initial width of this element, in pixels.
onkeypress– Specifies the code to be executed when the user presses a key within the element (i.e. typing in the edit box).
You can find a complete reference on the menulist element’s attributes at the Mozilla Developer Network.
menulist element is a
menupopup element. As with the menu button we looked at earlier, the
menupopup is the container that will hold all of our
menuitem elements. The
onpopupshowing event is fired right before the drop-down box is shown to the user. The code snippet shown is a function that we will write to dynamically populate the menu with items, something we will discuss later in the tutorial. You can add static menu items if you like; the process is exactly the same as for the menu button earlier.
Let’s take another look at our XUL overlay at this point: [View XUL Overlay Revision 3]. Our extension is really starting to take shape!
persist attribute we added to the
toolbaritem element that surrounds the
menulist? We specified that attribute so that the width of our search box could be saved between browser sessions. In order for the user to be able to change the width, however, we need to provide them with a resizing gripper. The XUL element responsible for this is the
splitter element, and the markup for ours looks like this:
<splitter id="TutTB-ResizeSplitter" state="open" collapse="none" resizebefore="closest" resizeafter="farthest" tooltiptext="Resize the Search Box"> <vbox id="TutTB-ResizeBar" /> </splitter>
Here is a list of the
splitter element’s new attributes:
state– Indicates whether or not the splitter has collapsed (hidden) content. A value of "open" indicates that the content either before or after the splitter (in our case both), is visible.
collapse– Determines which side of the splitter is collapsed. We have specified a value of "none" since we don’t want either side of the splitter to be hidden.
resizebefore– Indicates which element to the left of the splitter should be resized when the splitter is repositioned. A value of "closest" indicates that we want our edit box (the closest element to the left of the splitter) to be resized when the splitter moves.
resizeafter– Indicates which element to the right of the splitter should be resized when the splitter is repositioned. In this sample, we use the value of "farthest" since we want the "free space" on the far right of the toolbar to be resized.
vbox element inside of the
splitter has been placed there for styling purposes. We’ll come back to this when we discuss how to skin our toolbar in chapter 5.
You can find a complete reference on the splitter element’s attributes at the Mozilla Developer Network.
splitter element should always appear either before, after, or between containers (in the case of a toolbar, it should lie between two
toolbaritem elements). Our example toolbar only has one such element so far, wrapping the
menulist. We need to place another one around our two search buttons (the "button-menu" button and the normal button). Here’s the markup we will use:
<toolbaritem flex="0"> </toolbaritem>
Let’s take a look at our XUL overlay with these new
[View XUL Overlay Revision 4].
In order to prevent a slightly annoying cosmetic problem with the resizing gripper, we need to place yet another
toolbaritem element, exactly as we just did with the search buttons, around our first toolbar element (the menu button). Again, make sure that the
flex attribute has a value of 0. This will prevent our menu button from being pushed off the left side of the toolbar when the gripper is dragged all the way to the left.
While we are adding this element, let’s go ahead and add two more. First, let’s place a
toolbarseparator element between the last two buttons (this is just for cosmetic purposes). Second, let’s place a
toolbarspring element right after the closing tag for the final
toolbaritem element. This spring will allow us to drag the resizer all the way to the right, so that we can see the full resizing effect in action. The markup for each of these two elements is incredibly simple:
<toolbarseparator /> <toolbarspring />
Let’s take a look at our completed XUL overlay: [View XUL Overlay Revision 5].