Sie sind auf Seite 1von 37

Table of Contents

Chapter 1: Getting Started


Before We Start Tools You Will Need File Structure Layout

Chapter 2: Creating the Framework


Installer Manifest Chrome Manifest

Chapter 3: Structuring the Toolbar


The Toolbox and Toolbar Toolbar Buttons Drop Down Edit Box Resizing Gripper

Chapter 4: Dynamic Development


A Word of Warning How to Develop Dynamically The Development Process

Chapter 5: Skinning the Toolbar


Updating the File Structure Updating the Chrome Manifest Creating the Image Files Applying the Images with CSS Using the Style Sheet

Chapter 6: Scripting the Toolbar


Tying XUL to JavaScript Adding Functionality to the Buttons Adding Functionality to the Search Box Dynamically Populating a Menu Dynamically Adding Toolbar Buttons Disabling and Enabling Buttons Dynamically Showing and Hiding Buttons Reading and Storing User Preferences

Chapter 7: Packaging the Toolbar

Updating the Chrome Manifest

Creating the JAR File Creating the XPI File Test Installing Your Extension Speeding Up the Packaging Process Ant Support

Chapter 8: Testing Our Extension


What to Do if Firefox Breaks Useful Browser Settings Logging to the JavaScript Console Logging to the Standard Console The DOM Inspector

Chapter 1: Getting Started


Before We Start
There are a number of highly useful items that you need to be aware of before we begin making our first Firefox toolbar extension.

Tutorial Downloads
Throughout the course of this tutorial, we will be creating a skeleton version of Googlebar Lite. To aid in the learning process, a working version of this toolbar is available for you to download. There are two files available:

Example Toolbar XPI: This is the installable version of the toolbar we will create. Example Toolbar Source Code: This zip file contains all of the source files used to create the above toolbar.

Note that the XPI file also contains the source code (as we will learn a little later), so you technically only need to download that one file. The second file is provided for the sake of convenience.

Useful References
I highly recommend that you bookmark the following sites. They were incredibly helpful to me as I learned about extension development, and I am sure that you will find them helpful as well.

XUL Hub at the Mozilla Developers Center MozillaZine Extension Development Forum Search the Firefox Source Code roachfiend.com Extension Tutorial

Learning the Prerequisites


As I previously mentioned, extension development in Firefox requires that you know a little about XML, JavaScript, and CSS. Each of these topics are fairly easy to pick up on your own. I have provided here a few tutorials covering each of these topics.

Learn XML Learn JavaScript Learn CSS

Tools You Will Need


Several software tools are required to create a Firefox extension, and all of them are freely available. Every file that we work with (except for images) will be a plain text file. As such, you will need a good text editor. I recommend against using a word processor like Microsoft Word. There are a number of excellent programmer text editors available for free on the web, which will help you out tremendously with features like automatic indentation, syntax highlighting, and more. Several popular editors include Crimson Editor, TextPad, and JCreator. The second tool you need is a zip-file utility. I personally use WinZip, although there are plenty of others available (7-Zip, WinRAR, etc.). We will make use of our zip tool when packaging our extension. If you plan on doing a lot of extension development, I recommend you find a zip-file tool that has a command line interface. Using the command line will allow you to easily automate the packaging process, which will save you a tremendous amount of time.

File Structure Layout


Firefox extensions require a specific internal structure, so we need to make sure that we get this step right. Otherwise, things will not work the way they should. First, let us create a top-level folder with the name of our extension. For this tutorial, we will use the name TutToolbar (lets avoid using spaces in the name). Inside of this newly created folder, we need to create a second folder. This one should be named chrome (using all lowercase letters). Since we are having so much fun creating folders, lets create a third one, this time inside of the chrome folder we just created. Name this one content (again, using all lowercase letters). Here is how our directory structure looks at this point in time:
+- TutToolbar/ +- chrome/ +- content/ ------------------------------------------------------------------------------

Chapter 2: Creating the Framework


An extensions framework is used to tell Firefox about the extension: how its files are structured, who created it, its GUID, etc. Beginning with Firefox 1.5, this area of extension development changed greatly. The old mechanisms used by Firefox 1.0.x were clunky at best; the new means of creating the framework is much simpler.

Installer Manifest
The installer manifest is how we provide details on our extension to Firefox. There are some important items that are placed in this file, so we need to make sure we get this right. Create a new file in your top level folder, and give it the name install.rdf. Here is how the directory structure should look once youve created the file:
+- TutToolbar/ +- install.rdf +- chrome/ +- content/

Before we begin working with our installer manifest, let us take a look at a sample. All of the data which we will need to edit has been highlighted, while all the data we must not edit is displayed in plain text. After we look at the files contents, I will explain each piece in detail (and we can begin creating our own).
<?xml version="1.0"?> <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> <Description about="urn:mozilla:install-manifest"> <!-- Required Items --> <em:id>yourextension@yoursite.com</em:id> <em:name>Your Extension's Name</em:name> <em:version>1.0</em:version> <em:targetApplication> <Description> <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <em:minVersion>1.5</em:minVersion> <em:maxVersion>3.0.*</em:maxVersion> </Description> </em:targetApplication> <!-- Optional Items --> <em:creator>Your Name</em:creator> <em:description>A description of the extension</em:description> <em:homepageURL>http://www.yoursite.com/</em:homepageURL> </Description> </RDF>

The first line above indicates that this is nothing more than an XML file. The second line, which begins with the opening <RDF> tag, is the root element of the document. Its responsibility is to identify this as an RDF (Resource Description Framework) file. The next tag (<Description>)

likewise identifies this is an installer manifest. Now that all of the boilerplate is out of the way, lets look at the first part of what we need to edit (all of which is required):
<em:id>yourextension@yoursite.com</em:id> <em:name>Your Extension's Name</em:name> <em:version>1.0</em:version>

The first thing we need to worry about is the extension ID. Prior to Firefox 1.5, an extensions ID had to be specified using a globally unique identifier (GUID). Although GUIDs are still supported, the new format is much easier to use. Simply use the name of your extension (all one word), an @ symbol, and the URL to the top level domain of your website. For the toolbar we are building in this tutorial, lets use the value tuttoolbar@borngeek.com. Next up is the extensions name (as it will appear in the Extension Manager). For our example, lets use the name Toolbar Tutorial. Make sure that you do not include the version number as a part of this name, because the version number has its own tag. That tag happens to be the next one we need to edit. Since this is our first attempt at a toolbar extension, lets use the value of 1.0. Keep in mind that, in the real world, you need to update this value each time you release an updated version of your extension. Scripters should have no problem writing a small program to automate the version updating process. I utilize such a script (written in Perl) for all of my extensions. In chapter 7 of this tutorial, I will show you how I do it. The next block of code in this file, which is also required, is one of the most important pieces of the installer manifest. Lets take a look at it now:
<em:targetApplication> <Description> <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <em:minVersion>1.5</em:minVersion> <em:maxVersion>3.0.*</em:maxVersion> </Description> </em:targetApplication>

This block is responsible for saying what application our extension is intended for. In our case, we are developing an extension for Firefox. As such, the value within the <em:id> element specifies the Firefox GUID. You should not change this value! Doing so will prevent your extension from installing correctly. The only two sections in this block that we need to touch are the <em:minVersion> and <em:maxVersion> elements. These two elements specify what versions of Firefox our extension should be compatible with (the minVersion being the lowest supported version, and the maxVersion being the highest supported version). For our example, we will be using the value 1.5 for the minVersion and 3.0.* for the maxVersion. Because we are making use of extension development improvements available only in Firefox 1.5, we cannot set the the minVersion value to less than 1.5; otherwise we would have to throw out all of the improvements that we now have available to us. Note that the version values you use for these two elements must follow a standard convention. For example, a value of "1.5 Release Candidate 1" will not suffice. The current Firefox versioning scheme is fairly strict, and is detailed in the Toolkit Version Format article at the Mozilla Developer Center. I recommend you read the article, to get a feel for what version strings are (and are not) allowed. Also, be sure to take a look at the valid application versions document at the Mozilla add-

ons website. This document lists all of the "officially approved" version strings. The rest of our installer manifest is simply meta-data that describes our extension:
<!-- Optional Items --> <em:creator>Your Name</em:creator> <em:description>A description of the extension</em:description> <em:homepageURL>http://www.yoursite.com/</em:homepageURL>

As the comment suggests, all of these elements are optional. I have chosen three elements to use for this tutorial. The first element, <em:creator>, allows the extension author to specify his name (so that others will know who created the extension). Next, the <em:description> element allows us to provide a short description of our extension. This description will appear in the Extension Manager, underneath our extensions name. Finally, the <em:homepageURL> element allows us to specify where people can find our extension on the web. Note that these arent the only meta-data elements available to us; a number of other optional ones also exist. For example, there is an element to let us use our own icon in the Extension Manager. Another element allows us to specify the location of a custom options or about dialog. For an entire list of the available elements (they are also known as properties), take a look at the Installer Manifests article at the Mozilla Developer Center. And one final note: all of these elements are not order dependent. In other words, you can place them in any order you like in this file; they simply have to be direct descendants of the first <Description> element that we created. Now that we know about the installer manifest, lets take a look at our finalized version, which we will be using in this tutorial. Feel free to copy the code below and place it in the install.rdf file that we created moments ago.
<?xml version="1.0"?> <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> <Description about="urn:mozilla:install-manifest"> <!-- Required Items --> <em:id>tuttoolbar@borngeek.com</em:id> <em:name>Tutorial Toolbar</em:name> <em:version>1.0</em:version> <em:targetApplication> <Description> <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <em:minVersion>1.5</em:minVersion> <em:maxVersion>3.0.*</em:maxVersion> </Description> </em:targetApplication> <!-- Optional Items --> <em:creator>Jonah Bishop</em:creator> <em:description>An example toolbar extension.</em:description> <em:homepageURL>http://www.borngeek.com/firefox/</em:homepageURL> </Description> </RDF>

Chrome Manifest
The chrome manifest is new to Firefox 1.5. Previously, all of the data contained in this file appeared in two places: some of it in the installer manifest, and other portions in a contents.rdf file. The new format is much simpler. Create another file, again in the top level folder, and name it chrome.manifest. Here is how our directory structure should now look:
+- TutToolbar/ +- install.rdf +- chrome.manifest +- chrome/ +- content/

A chrome manifest is how we tell Firefox what packages and overlays our extension provides. Let us again take a look at a sample file before we begin creating our own:
content myextension chrome/content/ overlay chrome://browser/content/browser.xul chrome://myextension/content/overlay.xul locale myextension en-US chrome/locale/en-US/ skin myextension classic/1.0 chrome/skin/

Compared to the old contents.rdf file (which was usually on the order of 20 lines long), this is incredibly simple! The first line registers a content package using the package name you specify (the above sample uses myextension), as well as the location to the content folder. Note that the package name must use lowercase letters; a mixed case package name is not allowed (nor is all uppercase). This first line allows chrome s like chrome://myextension/content/ to point to the appropriate place in our extensions hierarchy. Note that the content folders location is relative to the root folder of our extension. For our tutorial, we will use a package name of tuttoolbar. The rest of the data shown will stay the same. The second line registers an overlay for chrome://browser/content/browser.xul. This allows you to add to or modify the user interface in the main Firefox window. In the sample above, the file used as the overlay is specified by chrome://myextension/content/overlay.xul. In other words, the file overlay.xul located in our extensions content folder is how we will be adding our new user interface controls (our toolbar). The overlay value we will be using for this tutorial is chrome://tuttoolbar/content/tuttoolbar.xul. The next line demonstrates how a locale can be created. We will not be creating a locale in this tutorial (although its a very simple process). The final line sets up a skin, the mechanism we will use to make our toolbar look pretty. For now, lets ignore it (we will come back to this in chapter 5). That was easy, wasnt it? Below is the final chrome manifest we will use for our tutorial (well, its the semi-final version; well come back and add skinning information later). Again, feel free to copy the code below and paste it into the chrome manifest file we created moments ago:
content tuttoolbar chrome/content/ overlay chrome://browser/content/browser.xul chrome://tuttoolbar/content/tuttoolbar.xul

Now that the framework is in place, lets have some fun creating our toolbar! ----------------------------------------------------------------------------------------------------------------------

Chapter 3: Structuring the Toolbar


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 windows user interface, without having to change the original interfaces code. Not having to change the code base allows us to focus on our extension, rather than having to worry about reinventing the wheel. In this chapter of the tutorial, we will take a look at the necessary XUL markup required to create a toolbar. Keep in mind that XUL is simply how we structure our toolbar. To make our toolbar actually do something, we need to make use of JavaScript, which is the subject of the chapter 6. But were getting ahead of ourselves. Lets start creating our example toolbar. Create a file in the content directory of our extensions 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 weve 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 files contents. This should make it easier to see whats 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:
<?xml version="1.0"?>

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). Heres 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: id and 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 IDs are unique. In the example above, you will note that I used the TutTBprefix in the id attributes value. Choosing a prefix that corresponds to your extensions name will

help improve the odds that your IDs 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. Heres 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>

Lets take a look at the new attributes in this element:

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 toolbars 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 (toolbarcontext-menu). 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 id attribute set, the persist attribute will not work! So make sure you have specified an id for your toolbar element.

You can find a complete reference on all of the toolbar elements attributes at the Mozilla Developer Center. Let us now take a look at the XUL overlay we have created so far: [View XUL Overlay Revision 1]

Toolbar Buttons
Toolbar buttons have three flavors in Firefox: normal, menu, and button-menu. These flavors are all created using the same toolbarbutton element. Lets examine each one individually. Keep in mind that these elements get placed within the toolbar element that we just created.

Normal Buttons
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" label="Web Search" oncommand="TutTB_Search(event, 'web')" />

As we have been doing, lets take a look at this elements 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 oncommand event is fired (i.e. the toolbar button is clicked/activated). In this example, we call the TutTB_Search() function. We will discuss this function in greater detail in chapter 6 of this tutorial.

You can find a complete reference on the toolbarbutton elements attributes at the Mozilla Developers Center.

Menu Buttons
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 buttons 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" tooltiptext="Tutorial Toolbar Main Menu"> <menupopup> <menuitem label="Google Home Page" accesskey="G" tooltiptext="Navigate to Google" oncommand="TutTB_LoadURL('http://www.google.com/')" />

<menuseparator /> <menuitem label="Born Geek Website" accesskey="B" tooltiptext="Navigate to Born Geek" oncommand="TutTB_LoadURL('http://www.borngeek.com/')" /> </menupopup> </toolbarbutton>

The 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 buttons 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 menupopup, menuitem, and 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 simply places a horizontal separator in the drop-down menu (to help visually separate different menu regions). The menuitem element is somewhat more complex. Here are the new attributes we specified in the above example:

label - Specifies the text to be displayed for the menu item. tooltiptext - This attribute is exactly the same as we saw with the toolbarbutton element earlier, but there is one caveat. Due to an unfortunate bug in Firefox (bug #147670), this attribute is rather necessary. If you decide to omit this attribute from the menuitem element, be warned that an empty tooltip box will appear when the user hovers their mouse over the menu item. Because menus do not traditionally have tooltips, this is an unpleasant feature.

You can find a complete reference on the menuitem elements attributes at the Mozilla Developers Center.

Button-Menu Buttons
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. The backward and forward navigation buttons are examples of this type of button. Heres the markup required to create one:
<toolbarbutton id="TutTB-Combined-Button" label="Search" type="menu-button" tooltiptext="Combined Search" oncommand="TutTB_Search(event, 'web')"> <menupopup> <menuitem id="TutTB-Combined-Web" label="Web Search" class="menuitem-iconic" tooltiptext="Search the Web" oncommand="TutTB_Search(event, 'web'); event.stopPropagation();" /> <menuitem id="TutTB-Combined-Image" label="Image Search" class="menuitem-iconic" tooltiptext="Search Images"

/>

oncommand="TutTB_Search(event, 'image'); event.stopPropagation();"

</menupopup> </toolbarbutton>

There are two notable changes between the markup for this button type and the previous two: the type attribute in the toolbarbutton element has been given a value of menu-button, and theres an extra line of code in the oncommand attribute. I will explain what that extra code is responsible for in chapter 6. Note that the toolbarbutton element has an oncommand attribute, just like normal buttons do, and it includes all of the nested menupopup and menuitem elements that we saw with the menu button. Now that we have discussed the various button flavors, lets again take a look at our 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 is created using the menulist element, and the markup looks like this:
<toolbaritem id="TutTB-SearchTerms-TBItem" persist="width"> <menulist id="TutTB-SearchTerms" editable="true" flex="1" minwidth="100" width="250" onkeypress="TutTB_KeyHandler(event);"> <menupopup id="TutTB-SearchTermsMenu" onpopupshowing="TutTB_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. The 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 elements attributes at the Mozilla Developers

Center. Within the 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. Lets take another look at our XUL overlay at this point: [View XUL Overlay Revision 3]. Our extension is really starting to take shape!

Chapter 3: Structuring the Toolbar


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 windows user interface, without having to change the original interfaces code. Not having to change the code base allows us to focus on our extension, rather than having to worry about reinventing the wheel. In this chapter of the tutorial, we will take a look at the necessary XUL markup required to create a toolbar. Keep in mind that XUL is simply how we structure our toolbar. To make our toolbar actually do something, we need to make use of JavaScript, which is the subject of the chapter 6. But were getting ahead of ourselves. Lets start creating our example toolbar. Create a file in the content directory of our extensions 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 weve 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 files contents. This should make it easier to see whats 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:
<?xml version="1.0"?>

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). Heres 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: id and 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 IDs are unique. In the example above, you will note that I used the TutTBprefix in the id attributes value. Choosing a prefix that corresponds to your extensions name will help improve the odds that your IDs 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. Heres 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>

Lets take a look at the new attributes in this element:

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 toolbars 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 (toolbarcontext-menu). 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 id attribute set, the persist attribute will not work! So make sure you have specified an id for your toolbar element.

You can find a complete reference on all of the toolbar elements attributes at the Mozilla Developer Center. Let us now take a look at the XUL overlay we have created so far: [View XUL Overlay Revision 1]

Toolbar Buttons
Toolbar buttons have three flavors in Firefox: normal, menu, and button-menu. These flavors are all created using the same toolbarbutton element. Lets examine each one individually. Keep in mind that these elements get placed within the toolbar element that we just created.

Normal Buttons
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" label="Web Search" oncommand="TutTB_Search(event, 'web')" />

As we have been doing, lets take a look at this elements 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 oncommand event is fired (i.e. the toolbar button is clicked/activated). In this example, we call the TutTB_Search() function. We will discuss this function in greater detail in chapter 6 of this tutorial.

You can find a complete reference on the toolbarbutton elements attributes at the Mozilla Developers Center.

Menu Buttons
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 buttons 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" tooltiptext="Tutorial Toolbar Main Menu"> <menupopup> <menuitem label="Google Home Page" accesskey="G" tooltiptext="Navigate to Google" oncommand="TutTB_LoadURL('http://www.google.com/')" /> <menuseparator /> <menuitem label="Born Geek Website" accesskey="B" tooltiptext="Navigate to Born Geek" oncommand="TutTB_LoadURL('http://www.borngeek.com/')" /> </menupopup> </toolbarbutton>

The 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 buttons 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 menupopup, menuitem, and 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 simply places a horizontal separator in the drop-down menu (to help visually separate different menu regions). The menuitem element is somewhat more complex. Here are the new attributes we specified in the above example:

label - Specifies the text to be displayed for the menu item. tooltiptext - This attribute is exactly the same as we saw with the toolbarbutton element earlier, but there is one caveat. Due to an unfortunate bug in Firefox (bug #147670), this attribute is rather necessary. If you decide to omit this attribute from the menuitem element, be warned that an empty tooltip box will appear when the user hovers their mouse over the menu item. Because menus do not traditionally have tooltips, this is an unpleasant feature.

You can find a complete reference on the menuitem elements attributes at the Mozilla Developers Center.

Button-Menu Buttons
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. The backward and forward navigation buttons are examples of this type of button. Heres the markup required to create one:

<toolbarbutton id="TutTB-Combined-Button" label="Search" type="menu-button" tooltiptext="Combined Search" oncommand="TutTB_Search(event, 'web')"> <menupopup> <menuitem id="TutTB-Combined-Web" label="Web Search" class="menuitem-iconic" tooltiptext="Search the Web" oncommand="TutTB_Search(event, 'web'); event.stopPropagation();" /> <menuitem id="TutTB-Combined-Image" label="Image Search" class="menuitem-iconic" tooltiptext="Search Images" oncommand="TutTB_Search(event, 'image'); event.stopPropagation();" /> </menupopup> </toolbarbutton>

There are two notable changes between the markup for this button type and the previous two: the type attribute in the toolbarbutton element has been given a value of menu-button, and theres an extra line of code in the oncommand attribute. I will explain what that extra code is responsible for in chapter 6. Note that the toolbarbutton element has an oncommand attribute, just like normal buttons do, and it includes all of the nested menupopup and menuitem elements that we saw with the menu button. Now that we have discussed the various button flavors, lets again take a look at our 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 is created using the menulist element, and the markup looks like this:
<toolbaritem id="TutTB-SearchTerms-TBItem" persist="width"> <menulist id="TutTB-SearchTerms" editable="true" flex="1" minwidth="100" width="250" onkeypress="TutTB_KeyHandler(event);"> <menupopup id="TutTB-SearchTermsMenu" onpopupshowing="TutTB_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. The 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 elements attributes at the Mozilla Developers Center. Within the 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. Lets take another look at our XUL overlay at this point: [View XUL Overlay Revision 3]. Our extension is really starting to take shape!

Resizing Gripper
Remember the 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 elements 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 dont 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.

The vbox element inside of the splitter has been placed there for styling purposes. Well come

back to this when we discuss how to skin our toolbar in chapter 5. You can find a complete reference on the splitter elements attributes at the Mozilla Developers Center. A 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). Heres the markup we will use:
<toolbaritem flex="0"> </toolbaritem>

Lets take a look at our XUL overlay with these new splitter and toolbaritem elements: [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, lets go ahead and add two more. First, lets place a toolbarseparator element between the last two buttons (this is just for cosmetic purposes). Second, lets 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 />

Lets take a look at our completed XUL overlay: [View XUL Overlay Revision 5].

Chapter 4: Dynamic Development


Firefox 1.5 introduced the single most useful feature for developers: dynamic extension development. This new capability allows you to work on your extension and see the results in real time! You no longer have to repackage your extension every time you want to test changes to either your XUL overlays or JavaScript code. Not only does this reduce your development time, but it makes debugging even easier than before. How does this feature work? Well, we can thank the chrome manifest that we created in chapter 2 for this capability. You see, up until now, I havent told you everything there is to know about the chrome manifest. The version we created back at the beginning of this tutorial was created specifically for dynamic development. In other words, we wont be packaging our extension with that version of the chrome manifest (there are some changes we need to make to it before we can

package things up). There are a few steps we have to take to "enable" dynamic development for our extension, but first Id like to present you with some sound advice.

A Word of Warning
Extension development can be a somewhat dangerous thing, especially when working with XUL overlay files. I highly recommend that you avoid developing your extensions in the same profile that you normally use for web surfing. In other words, you should create a brand new profile in which you do all of your development and testing. This will prevent you from losing key browser data: stored passwords, cookies, bookmarks, and any other stuff you would hate to lose. To learn more about how profiles work in Firefox, consult either the tutorial I offer on the subject, or the official profile documentation. Creating and using a new profile is an easy task, and it will save you a great deal of headache down the road.

How to Develop Dynamically


The majority of our work has already been completed in the chrome manifest (even though you may not have realized what we were doing at the time). Now all that we need is a file to point Firefox to our extensions location on our hard drive. We will do so through the use of a "pointer" file. First, create a text file anywhere on your computer and give it the same name as the GUID we used in the install manifest. For this tutorial, the value we chose was tuttoolbar@borngeek.com; so our text file should use that exact same name. Unfortunately for Windows users, the ".com" file extension usually indicates an executable. In our case, it will just be a simple text file. If you would like to keep the ".com" portion out of the filename for now you may do so; just remember to update the GUID value in the install manifest to match your altered name (and remember to change it back when you package your extension). Inside of this file we will place exactly one line of text: the absolute path to the folder where your extension is stored (that is, the folder that contains your install.rdf and chrome.manifest files). In my case, this tutorial extension is stored in the following location on my computer:
C:\Born Geek\TutToolbar

You should clearly use the path to the extension on your computer, unless the path happens to exactly match the one above (and I doubt that it does). After typing the absolute path to your extension, save the file. We now must move this file to our development profiles folder. The profile documentation I mentioned earlier discusses exactly how to locate your profile folder. Once you find where the profile is located, place the pointer file we just created in the extensions folder within the profile folder. Here is how my sample profile file structure looks (trimmed down for brevitys sake):
+- tl5wlpz3.Nightly/ +- bookmarkbackups/ +- chrome/ +- extensions/ +- tuttoolbar@borngeek.com +- (... other files and folders ...)

As you can see from the name of my profiles top folder, I use a "Nightly" profile to try out nightly Firefox builds as well as to do my extension development. Once the pointer file you have created has been placed in the proper location, start Firefox, making sure that you use your development profile (again the profile documentation mentioned earlier will show you how to do this). If you have done everything right up until this point, you should see your toolbar, in all of its un-skinned glory!

The Development Cycle


So now that we have enabled dynamic extension development, how do we use it? The process is actually very simple: 1. Edit your extension files. 2. Reopen the window(s) that the modified files apply to, or use the Reload Chrome feature of the Extension Developers Extension. There are two special cases you should be aware of:

If you change the chrome.manifest file, you will have to restart Firefox (this file only gets parsed on startup). If you change the install.rdf file, you will have to alter the modified time of the folder that your "pointer file" points to. In Linux you can simply use the touch command to do this. In Windows, its somewhat more difficult (unless you have the Cygwin tools installed, in which case you can simply use the touch command). One simple way to handle this case is to create a new folder within the extensions top level folder, then delete that new folder.

As you can already see, this will be an incredibly handy tool as we develop and debug our extension. It sure beats having to repackage everything for each development cycle, which was the standard process before release 1.5. Now lets make this ugly toolbar weve created look a little better!

Chapter 5: Skinning the Toolbar


A "skin" is a collection of styling rules (specified with CSS) and images that get used to change the appearance of chrome (in our case, the toolbar we are building). Keep in mind that although skinning is entirely optional, it can greatly improve the quality of your extension. After all, a users first impression of your toolbar will be its appearance, not its functionality. However, if you are comfortable using only text labels for your toolbar buttons (or your extension doesnt make use of a chrome overlay at all), you can skip this step.

Updating the File Structure


The first step in creating a skin for our toolbar is to create the folder that will hold all of our skin files. Create a folder named skin inside of the chrome folder. The resulting file structure should look like the following:
+- TutToolbar/

+- install.rdf +- chrome.manifest +- chrome/ +- content/ +- tuttoolbar.xul +- skin/

Now that we have a place to store our skins files, we need to register this location with our chrome.

Updating the Chrome Manifest


Remember the chrome manifest file we created in chapter 2? We need to add a line of code to that file which will register our skin. Lets take a look at the line of code that is necessary (it has been highlighted below):
content tuttoolbar chrome/content/ overlay chrome://browser/content/browser.xul chrome://tuttoolbar/content/tuttoolbar.xul skin tuttoolbar classic/1.0 chrome/skin/

This additional line of code is quite simple, and has only four parts. The first part, which is simply the word "skin", states that what follows is the skins registration information. Next up is the package name which, in this tutorial, is tuttoolbar. The third part indicates the name of an installed skin which we will be extending. The value shown (classic/1.0) is the value you should always use for Firefox extensions. Finally comes the most important part: the relative path name to the folder that contains our skins files. This path is always relative to the chrome directory. It is very important that you note the trailing slash (/) in the given path above. That slash is required, so make sure you include it.

Creating the Image Files


To keep things simple for this tutorial, we will be using one image for each toolbar button. Note that this is neither the most efficient nor elegant way of skinning a toolbar, but it makes things incredibly easier to understand. For those that are curious, image sheets are the best way to skin an extension, but they are outside the scope of this tutorial. We need a total of five images for our toolbar as it is currently designed: one for our "main menu" (the menu button), one for the combined search button, one for our web search button, one for the resizing gripper, and one for the image search menu item in the combined search menu. The following list shows each of the five images I have chosen to use for our extension. Note that these images are in a transparent PNG format, so if you are using Internet Explorer 6 or earlier to view this tutorial, the images will not be displayed properly.

Main Menu Icon (main.png): Combined Search Icon (combined.png): Web Search Icon (web.png): Images Search Icon (images.png): Resizing Gripper Icon (gripper.png):

Lets save these images to our skin folder that we created moments ago. Our resulting file structure

will look like this:


+- TutToolbar/ +- install.rdf +- chrome.manifest +- chrome/ +- content/ +- tuttoolbar.xul +- skin/ +- combined.png +- gripper.png +- images.png +- main.png +- web.png

Applying the Images With CSS


Now that we have some images to use, and our skin directory has been registered, we can begin applying the images to our toolbar buttons. We will do so through the use of a Cascading Style Sheet (CSS). As I mentioned at the beginning of this tutorial, W3Schools has an excellent CSS tutorial if you are unfamiliar with how style sheets work. Lets create our CSS file, naming it tuttoolbar.css and placing it inside of the skin folder, along with our images. Here is the resulting file structure:
+- TutToolbar/ +- install.rdf +- chrome.manifest +- chrome/ +- content/ +- tuttoolbar.xul +- skin/ +- combined.png +- gripper.png +- images.png +- main.png +- web.png +- tuttoolbar.css

Lets take a look at the contents of our style sheet before we go into any detail:
#TutTB-MainMenu { list-style-image: url("chrome://tuttoolbar/skin/main.png"); } #TutTB-Combined-Button { list-style-image: url("chrome://tuttoolbar/skin/combined.png"); } #TutTB-Combined-Button > .toolbarbutton-menubutton-button { -moz-box-orient: horizontal; } #TutTB-Web-Button, #TutTB-Combined-Web { list-style-image: url("chrome://tuttoolbar/skin/web.png"); } #TutTB-Combined-Image { list-style-image: url("chrome://tuttoolbar/skin/images.png");

} #TutTB-ResizeBar { background-image: url("chrome://tuttoolbar/skin/gripper.png"); min-height: 22px; min-width: 3px; } #TutTB-ResizeSplitter { background: transparent; border: none !important; }

The first rule shown specifies the image to be used for the "main menu" button. Back in chapter 3, we gave that button an ID value of TutTB-MainMenu, and we use that ID here to set up the rule. The preceding hash mark (#) is called the ID selector, and is how one specifies rules in CSS for elements with a particular ID value. For toolbar buttons, we make use of the list-styleimage CSS property to specify the image to be displayed. You will note that the path we use is a chrome path; that is, the path to the image within your extensions file structure. The general format for these paths is as follows:
chrome://<packagename>/skin/<image_file_name>

For our example, the package name is tuttoolbar and the image we want to use for the main menu is named main.png. As you can see, we use similar rules for all of the toolbar buttons, as well as our menu items in our combined search buttons menu. Theres one caveat to handling menu item icons, however. If you recall, we made use of a special class value for the menu items in our combined search menu. That special class was menuitem-iconic, and it is a built-in class provided by Firefox. In a sense it "enables" icon support for each menu item that uses it. You undoubtedly also noticed the special rule for the combined search button:
#TutTB-Combined-Button > .toolbarbutton-menubutton-button { -moz-box-orient: horizontal; }

The special CSS property used here (-moz-box-orient) specifies how the label for our button should appear: aligned vertically or horizontally. By default, toolbar button labels are aligned vertically, meaning that the label shows up underneath the icon. We dont want that in this case, so we use the horizontal value to force the label to show up after the icon. There are two rules in our style sheet that deal with the resizing gripper. Remember that vbox element that we placed inside of our splitter element? We use the ID of that vbox to display a background image for our gripper. This time we use the background-image property. We also must provide a minimum height and width (using the min-height and min-width properties), so that our gripper shows up. By default, the vbox and hbox elements size to the smallest value possible for their content. Since our vbox is empty, it sizes to a default of 0, which prevents us from seeing the background image. We also provide a rule for the splitter element itself. We tell the background to become transparent (so that we can see the vbox image), and we tell it to not use a border (by default, all splitter elements have a border). Now that our CSS file is complete, we need to tell our overlay how to use

it.

Using the Style Sheet


Only one line of code needs to be added to our XUL overlay to enable the style sheet we just created. It must be placed underneath the XML directive at the top of the file, but before the actual overlay element. Below I show the first few lines of our XUL overlay file, highlighting the line we need to add:
<?xml version="1.0"?> <?xml-stylesheet href="chrome://tuttoolbar/skin/tuttoolbar.css" type="text/css"?> <overlay id="TutTB-Overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> (... rest of XUL overlay file ...)

Like we saw with the images in the style sheet, a chrome path gets used to specify the location to the style sheet. The type attribute simply tells the parser that the file being referenced is a CSS file. And thats all there is to it! Lets take a look at the entire XUL overlay file as it appears with this additional line: [View XUL Overlay Revision 6]. And dont forget to test it out! Open the Firefox instance that includes your dynamic extension installation (which we discussed in the previous chapter), and see what the extension looks like. Next up, well be bringing the toolbar to life.

Chapter 6: Scripting the Toolbar


Firefox extensions are usually driven by JavaScript, a programming language that is fairly easy to learn. As you will soon find out, the code that our toolbar extension will use is very straightforward. We will make fairly heavy use of the Firefox chromes DOM, which allows us to access the individual elements of our toolbar. Before we write any code, there is one very important point you should be aware of. Just as the id attributes for our XUL elements needed to be unique across the entire browser system, so too must our JavaScript variables and functions be unique. All JavaScript included in a browser overlay is global, hence this unique name constraint. We will again employ the same technique here that we used for our XUL elements: all variable and function names will be prefixed with a short identifier created from our extensions name. The prefix we will use for this tutorial is TutTB_. So, our search function will be named TutTB_Search(). Lets now create our JavaScript file. Place it inside of the content folder, and name it tuttoolbar.js. Our resulting file structure now looks like this:
+- TutToolbar/ +- install.rdf

+- chrome.manifest +- chrome/ +- content/ +- tuttoolbar.xul +- tuttoolbar.js +- skin/ +- combined.png +- gripper.png +- images.png +- main.png +- web.png +- tuttoolbar.css

Before we place any code within this file, lets first tell our XUL markup how to use our JavaScript.

Tying XUL to JavaScript


Our XUL markup (stored in the tuttoolbar.xul file) needs to be told where to find the corresponding JavaScript. We can tell it where to look by making use of the script element:
<script type="application/x-javascript" src="chrome://tuttoolbar/content/tuttoolbar.js" />

This element should be placed inside the overlay element in our XUL markup. The type attribute indicates that we are pointing to a JavaScript file, and src attribute simply specifies the chrome path to our JavaScript file (that we just created). Lets take a look at what our XUL overlay looks like after we insert this element: [View XUL Overlay Revision 7].

Adding Functionality to the Buttons


Remember the oncommand attribute we supplied for each toolbar button back in our XUL markup? That attribute is how we specify what code to execute when the command event gets fired (i.e. the user activates the toolbar button). We could have used the onclick event instead, but it doesnt respond to the keyboard; oncommand responds to both the keyboard and the mouse. Lets take a look back at the value we supplied for this attribute for our web search button:
oncommand="TutTB_Search(event, 'web')"

This value shows a call to the TutTB_Search() function, passing in two values: the event that generated this function call, and our own custom value that indicates what type of search to do (in this case, a web search). We wont be making use of the event parameter at the moment; weve simply included it here for future use. Because the code is rather lengthy, I have decided not to show it within the text of this article. Instead, I will present the code to you in sample code files, which you can examine at your leisure. The code is well commented, so I wont go into a great deal of explanation on what each line does. Lets take a look at the first sample file now (copy the contents of this file and paste them into the JavaScript file you created moments ago): [View JavaScript Revision 1]. Start up Firefox (with your development profile), enter a search term into our toolbars search box, and click one of the web search buttons. The code should execute and the Google search results page should appear! This dynamic development stuff is pretty handy!

A Special Note About Button-Menu Buttons


Before we move on to the next topic, one very important note must be made concerning "buttonmenu" style buttons. Recall that this type of button provides both a clickable button as well as a popup menu (the forward and backward navigation buttons are prime examples). Also recall that the toolbarbutton sub-element of this button style, as well as each individual menuitem element, contains an oncommand attribute. When the toolbar button portion is activated, the code specified in the toolbarbutton elements oncommand attribute gets executed, just as you would expect. But what happens when the user activates one of the menuitem elements? Not only does the menuitem elements oncommand event fire, the toolbarbutton elements event also fires! So two events fire at once, even though you only wanted one of them to be triggered. Because the toolbarbuttons event fires last, its code is what gets executed. In other words, the menuitems event never gets a chance. So how can we fix this problem? Well, truth be told, we already have. Lets look back at the markup for one of our menuitem elements (the interesting piece is highlighted):
<menuitem id="TutTB-Combined-Image" label="Image Search" class="menuitem-iconic" tooltiptext="Search Images" oncommand="TutTB_Search(event, 'image'); event.stopPropagation();" />

By making use of the DOM function stopPropagation(), we are able to prevent the oncommand event from propagating up the DOM tree. This effect is why the toolbarbuttons code was always getting executed. To make a long story short, always keep the following rule in mind: when creating a "button-menu" type toolbar button, always add event.stopPropagation() to the oncommand attribute of each menuitem element.

Adding Functionality to the Search Box


Now that we have the search buttons working, we need to add some capability to the search box itself. The user should be able to enter a search term and press the [Enter] key to execute a search. How can we do that? Well, lets look back at our XUL markup to see what function we anticipated on using:
<toolbaritem id="TutTB-SearchTerms-TBItem" persist="width"> <menulist id="TutTB-SearchTerms" editable="true" flex="1" minwidth="100" width="250" onkeypress="TutTB_KeyHandler(event);"> <menupopup id="TutTB-SearchTermsMenu" onpopupshowing="TutTB_Populate()" /> </menulist> </toolbaritem>

This time, instead of using the oncommand event, we rely on the onkeypress event. This event gets fired each time the user presses a key inside of the search box. In this example, we are making a call to the TutTB_KeyHandler() function, which is surprisingly simple:
function TutTB_KeyHandler(event) { if(event.keyCode == event.DOM_VK_RETURN) TutTB_Search(event, 'web'); }

This function simply checks to see if the key that was pressed is the [Enter] key. If it is, it calls the TutTB_Search() function that we just looked at. If the [Enter] key wasnt pressed, the function simply does nothing. Lets add this function to our JavaScript file (Ive placed it at the bottom of the file): [View JavaScript Revision 2]. Again, start Firefox with your development profile, type some search terms into the toolbars search box, and press the [Enter] key on your keyboard. A web search should take place, just like clicking the button before. Our extension has really come to life!

Dynamically Populating a Menu


Being able to dynamically populate a menu with menu items is surprisingly useful. Thankfully, this feature is quite easy to implement. For our tutorial toolbar, we will dynamically add some items to the search box drop-down menu. Lets again look back at the XUL markup we used to create our search box:
<toolbaritem id="TutTB-SearchTerms-TBItem" persist="width"> <menulist id="TutTB-SearchTerms" editable="true" flex="1" minwidth="100" width="250" onkeypress="TutTB_KeyHandler(event);"> <menupopup id="TutTB-SearchTermsMenu" onpopupshowing="TutTB_Populate()" /> </menulist> </toolbaritem>

Note the highlighted onpopupshowing attribute in the menupopup element. We have specified that a function named TutTB_Populate() should be executed each time the popup menu is about to be displayed. This function will be responsible for creating our dynamic menu items. Lets take a look at that functions code (again, the code is well commented to explain exactly whats going on): [View TutTB_Populate() Code]. This example function does not show how to instruct each menuitem element to execute some code when it is selected. To tell each menuitem what code it should execute, we simply make an additional call to the setAttribute() function, passing in the event to be handled and the code to be executed. Here is an example of handling the oncommand event:
tempItem.setAttribute("oncommand", "TutTB_SomeFunction()");

Lets add the TutTB_Populate() function to the end of our JavaScript file and take a look at the results: [View JavaScript Revision 3]. Thats all there is to dynamic menu population!

Dynamically Adding Toolbar Buttons


(This section is being provided for informational purposes only; it does not appear in the example toolbars source code). Adding dynamic toolbar buttons to a toolbar is just as easy as dynamically populating a menu, and its done in a very similar fashion. We first need a container to hold our dynamic buttons. The toolbaritem element is the perfect fit for this, and the markup would look like the following:

<toolbaritem id="TutTB-DynButtonContainer" />

Now that this container is available to us, we can use it to add our dynamic toolbarbutton elements. Lets examine a sample function that we could use to add dynamic buttons:
function TutTB_AddDynamicButtons() { // Get the toolbaritem "container" that we added to our XUL markup var container = document.getElementById("TutTB-DynButtonContainer"); // Remove all of the existing buttons for(i=container.childNodes.length; i > 0; i--) { container.removeChild(container.childNodes[0]); } // Add 5 dynamic buttons for(var i=0; i<5; i++) { var tempButton = null; tempButton = document.createElement("toolbarbutton"); tempButton.setAttribute("label", "Button " + i); tempButton.setAttribute("tooltiptext", "Button " + i); tempButton.setAttribute("oncommand", "TutTB_SomeFunction()"); container.appendChild(tempButton); } }

This function looks very similar to the one we used to populate our dynamic menu. We remove all of the existing dynamic buttons from the container (the way shown here is different that we used in the dynamic menu code), then we create the new buttons to add to the container, appending them as we go. Optional Programming Exercise: Try to use this general idea to add "search word buttons" to our example toolbar. As the user types search words into the search word box, dynamically add buttons to the end of the toolbar, one button for each word the user types. Here are a few hints to get you started: 1. Youll need to add a toolbaritem "container" to the end of our toolbars XUL markup (right before the toolbarspring element is a good choice). Make sure to give it a unique ID. 2. Make use of the oninput event in the menulist (search box) element. This event gets fired as the user types text into the search box (which is just what we want). 3. The JavaScript function you call will need to do the following: (a) Obtain the search words from the search box, (b) remove all previously created dynamic buttons, (c) split up the search words based on whitespace, and (d) create a button for each individual word. This is (almost) exactly how I handle this feature in Googlebar Lite.

Disabling and Enabling Buttons


(This section is being provided for informational purposes only; it does not appear in the example toolbars source code). You may occasionally want to dynamically disable or enable a toolbar button. For example, the highlighter button in Googlebar Lite is disabled when no search words are present in the search box,

and enabled when there are search words. The following example shows how to create a menu item that toggles the disabled status of a normal toolbar button. Again, this isnt the most practical example in the world, but it demonstrates how the effect is achieved. Here is the markup for our menu item:
<menuitem label="Toggle Web Search Button" tooltiptext="Toggle Web Search Button" oncommand="TutTB_ToggleWebSearchButton()" />

And here is the code for TutTB_ToggleWebSearchButton() function:


function TutTB_ToggleWebSearchButton() { var button = document.getElementById("TutTB-Web-Button"); var value = button.disabled; if(value == true) button.disabled = false; else button.disabled = true; }

We first get the toolbar button we are interested in by using its ID value and the getElementById() function. Once we have the button, we can get its current state (enabled or disabled) using the disabled property of the button object. If the value is true, we set it to false, and vice-versa. Firefox takes care of disabling the button for us, so that it is no longer clickable (note that the buttons image may not appeared grayed out: we must rely on skinning for that).

Dynamically Showing and Hiding Buttons


(This section is being provided for informational purposes only; it does not appear in the example toolbars source code). Googlebar Lite allows the user to choose the buttons they wish to see on their toolbar. This means that the toolbar must be able to dynamically show or hide the available buttons. Here is a snippet of JavaScript code that will accomplish exactly what we want:
var TB_Web = document.getElementById("TutTB-Web-Button"); TB_Web.setAttribute("hidden", !TutTB_ShowWebButton);

We first get the toolbar button element itself using the getElementById() function. Then we make a call to the setAttribute() function to change the value of the hidden attribute. Youll note that I set the value of the hidden attribute to the opposite value of a variable I have called TutTB_ShowWebButton. This variable is simply a boolean flag, telling us whether or not the user wants to see the "web search" button. The actual value stored in this variable comes from reading the users preference for the "Show Web Search Button" option. Read on to see how we can do that.

Reading and Storing User Preferences


(This section is being provided for informational purposes only; it does not appear in the example toolbars source code).

In order to read a stored preference, we need to get access to the Firefox preferences service interface. We do so by creating a variable like the following (note that this code has been formatted to fit this sites layout):
const TutTB_PrefService = Components.classes["@mozilla.org/preferences-service;1"]. getService(Components.interfaces.nsIPrefService);

Once we have access to the preferences interface, we can obtain our extensions preferences branch (i.e. the location in the preferences "registry" where our extensions settings are kept):
const TutTB_Branch = TutTB_PrefService.getBranch("tuttoolbar.");

Let us assume that all of our example toolbars preferences begin with the text tuttoolbar. (note the trailing period). As a result, we must pass this string into getBranch() (a built-in Firefox function). This function gives us access to our extensions preferences, so we can finally obtain the value for an individual option. Here is how we can obtain the value for the "Show Web Search Button" option we mentioned a moment ago:
if(TutTB_Branch.prefHasUserValue("show.button.web")) TutTB_ShowWebButton = TutTB_Branch.getBoolPref("show.button.web"); else { TutTB_Branch.setBoolPref("show.button.web", false); TutTB_ShowWebButton = false; }

We first test to see if the preference exists in the preferences tree. If it does, we use the getBoolPref() function to read its value (storing it in the variable TutTB_ShowWebButton). If the preference does not exist, we set the default value (both in the preferences tree and in our global variable). So storing a preference is just as easy as reading one. You simply supply the name of the preference to set, and then the value to use:
TutTB_Branch.setBoolPref("show.button.web", TutTB_ShowWebButton);

Reading and writing preferences is a handy way to store your toolbars settings. Most extensions utilize this feature, so there are certainly plenty of working examples out there for you to examine. In addition, an excellent expanded tutorial on preferences is available at the Mozilla Developers Center.

Chapter 7: Packaging the Toolbar


Up to this point in the tutorial, we have been relying on the dynamic development system to handle installation responsibility for our extension. The end-user doesnt want to go to all of this trouble to install your extension, so we must package everything up into one installable file. We will actually be creating two files: an XPI (cross platform installer) and a JAR. Dont let these file extension names fool you; both files are simply zip files in disguise.

This is where our zip tool comes in handy. For the purposes of this tutorial, I will make use of the standard UNIX zip tool, available for Windows in the Cygwin tool set.

Updating the Chrome Manifest


The first step in the packaging process involves updating the chrome manifest. Note that if you want to continue doing dynamic development, youll need to keep two chrome manifests around: one to package the extension with, and one for dynamic development purposes. Dealing with two files can be tricky, so we will only work with our existing chrome manifest for this tutorial. Note that after we modify our manifest, we wont be able to do dynamic development any more (unless we revert the modifications). Lets first take a look back at the contents of our chrome manifest:
content tuttoolbar chrome/content/ overlay chrome://browser/content/browser.xul chrome://tuttoolbar/content/tuttoolbar.xul skin tuttoolbar classic/1.0 chrome/skin/

All of the file-system paths in this file need to be updated (there are 2 total). Lets take a look at the updated version of the first line (the changes have been highlighted):
content tuttoolbar jar:chrome/tuttoolbar.jar!/content/

Youll note that weve added two items. The first is the jar: directive placed at the beginning of the path. This indicates to Firefox that it needs to look inside of a JAR file to find the content of this extension. The second item we added is the tuttoolbar.jar!/ bit of text, right between the chrome/ and content/ folder names. This bit of text tells the installer which JAR file it needs to look in. The filename of the JAR we have specified uses the exact same name as our package name (a requirement of the installer). As such, the filename must be all lowercase, just like the package name. Note that the exclamation point at the end of the name is no typo; that character is required. The other path we need to update for our chrome manifest is on the skin registration line. Here is the final version of our updated chrome manifest:
content tuttoolbar jar:chrome/tuttoolbar.jar!/content/ overlay chrome://browser/content/browser.xul chrome://tuttoolbar/content/tuttoolbar.xul skin tuttoolbar classic/1.0 jar:chrome/tuttoolbar.jar!/skin/

Creating the JAR File


The first package we need to create is our JAR file. This file will live within the chrome directory, and will contain all of our XUL, JavaScript, image, and CSS files. After we create this file, our file structure will look like the following:
+- TutToolbar/ +- install.rdf +- chrome.manifest +- chrome/ +- tuttoolbar.jar +- content/ +- tuttoolbar.xul +- tuttoolbar.js +- skin/

++++++-

combined.png gripper.png images.png main.png web.png tuttoolbar.css

The biggest mistake that people make when packaging a JAR or XPI file is omitting the relative path names of the files. If we were to pretend that our JAR file was a folder, this is what its contents would look like when we were finished:
+- content/ +- tuttoolbar.xul +- tuttoolbar.js +- skin/ +- combined.png +- gripper.png +- images.png +- main.png +- web.png +- tuttoolbar.css

In other words, each individual file has to have an associated relative path name. Here is how I would create the JAR file for this tutorial using the UNIX zip tool: I would first change to the chrome directory in my extensions folder (in a command prompt window), then I would issue the following command:
zip -r tuttoolbar.jar content/* skin/*

Creating the XPI File


Now that we have a JAR file created, we need to create our XPI file. This is what you will actually distribute to the end-user. We should create this file in the top-level folder of our extensions file structure. Once the file is created, our file structure will look like the following:
+- TutToolbar/ +- tuttoolbar.xpi +- install.rdf +- chrome.manifest +- chrome/ +- tuttoolbar.jar +- content/ +- tuttoolbar.xul +- tuttoolbar.js +- skin/ +- combined.png +- gripper.png +- images.png +- main.png +- web.png +- tuttoolbar.css

Like the JAR file before it, the XPI must retain relative path information. We only need to include 3 files in our XPI file for this tutorial: the installer manifest, the chrome manifest, and the JAR file we created moments ago. Again, if we consider our XPI file to be a folder, this is what its contents

would look like:


+- install.rdf +- chrome.manifest +- chrome/ +- tuttoolbar.jar

To create the XPI file using the UNIX zip tool, change to the top-level folder of your extensions file hierarchy (the same folder where the installer and chrome manifests live), and use the following command:
zip tuttoolbar.xpi install.rdf chrome.manifest chrome/tuttoolbar.jar

Test Installing Your Extension


Now that we have an XPI file, we can test out the installation process. This is something you should always do before you release an extension to the public: make sure it installs! We must not use our development profile to do installation testing, since we already have an "installed" version of our extension in that profile. In either your normal Firefox profile, or in yet another test profile, take the following action to install your extension: 1. Select the File Open File menu item (or press the Ctrl+O keyboard accelerator). 2. In the file selection dialog, browse to the location of your XPI file, select it, and click the Open button. If youve done everything correctly, the extension installer should appear. Tell it that you want to install, close Firefox when its finished installing, and start Firefox back up. Your toolbar should appear alongside all of the others. Congratulations on creating your first toolbar extension!

Speeding Up the Packaging Process


Packaging your extension by hand can quickly become tiresome. Why not write a script to do it? If you have a zip tool with a command line interface, you can easily automate the process. The following example shows a simple way to build our example toolbar using a DOS batch file and the UNIX zip tool. First create two text files: one in the top level folder (named xpizip.txt), and one in the chrome folder (named jarzip.txt). Each text file is a simple listing of the items we want to include in each package: xpizip.txt lists the files to go in the XPI file, while jarzip.txt lists the files to go in the JAR file. Feel free to take a look at the following two example files: [View xpizip.txt] [View jarzip.txt] Next, create a DOS batch file (in the extensions top-level folder) which you can run from the command line. The code I used in the batch file is shown below:
cd chrome zip -r tuttoolbar.jar -@ < jarzip.txt cd .. zip -r tuttoolbar.xpi -@ < xpizip.txt

As you can see, this script is extremely simple. Your scripts can be much more complex than this, however. The Perl script I use to build Googlebar Lite does a number of things: it automatically

updates all the version numbers for me, updates my chrome manifest, then packages the files. For the curious, Ive provided the script for you to look at. [View the Googlebar Lite Build Script]

Ant Support
If you would rather use an Ant task to build your extension, take a look at the sample XML file sent in by Brett Clippingdale. The script should be placed in the same folder as the installer manifest, and can be run using the ant command. ------------------------------------------------------------------------------------------------------------------------

Chapter 8: Testing Our Extension


The dynamic development feature we discussed back in chapter 4 has improved extension testing greatly, but there are a few other tricks a developer should know to get the most out of the testing process. JavaScript is a notoriously bad language to debug, and thankfully Firefox offers us some features that we can use to avoid those annoying alert() calls.

What to Do if Firefox Breaks


Sometimes an extension can have a bug so catastrophic, that Firefox refuses to start. When this happens, you first need to check for hung Firefox processes, killing off any that you find. Once you are sure that no Firefox instances are running, you need to uninstall your problematic extension. How you do this depends on whether or not you are using the dynamic development system. If you are developing dynamically, simply navigate to the extensions folder in your development profile (as we discussed in chapter 4), and move your extensions pointer file (in our case the file was named tuttoolbar@borngeek.com) to a temporary location. Restart Firefox using your development profile (allowing it to purge itself of the newly uninstalled extension), and close the browser again. After you fix the problem that was causing Firefox to hang, move your pointer file back to the extensions directory, and restart Firefox. If you are not developing dynamically, uninstalling your problematic extension involves starting Firefox in safe mode. You can do this in one of two ways: 1. Use the "Start Firefox in Safe Mode" shortcut that got created by the Firefox installer. In Windows XP, the default shortcut location is: Start All Programs Mozilla Firefox Mozilla Firefox (Safe Mode). 2. Add the -safe-mode command line parameter to an existing Firefox shortcut. In safe-mode, Firefox will not load any extensions or themes. Once in safe-mode, you can simply uninstall your problematic extension by using the extension manager as you normally would. After you have uninstalled the extension, remember to remove the -safe-mode command line parameter (if you manually added it to an existing shortcut).

Useful Browser Settings


There are two rather obscure browser settings that can make your development life much easier. Both can be set through the about:config interface, and both affect the output that gets sent to the JavaScript console. The first preference is javascript.options.showInConsole. When set to true, any errors or warnings that appear in your extensions chrome files will be sent to the JavaScript console. By default, this preference is set to false (so youll need to enable it). Its a handy way to track down existing problems. Next is the javascript.options.strict preference, which is also set to false by default. When true, the JavaScript parser within Firefox will be placed into strict mode, placing tighter restraints on your extensions code. This helps to improve your codes integrity and makes it easier to track down subtle code problems.

Logging to the JavaScript Console


One useful way to test JavaScript code is by printing out debug values to the JavaScript console, which you can access through the Tools JavaScript Console menu item. In order to do this, we must first obtain an instance of the nsIConsoleService interface. The following snippet of code does just that:
const TutTB_ConsoleService = Components. classes['@mozilla.org/consoleservice;1']. getService(Components.interfaces.nsIConsoleService);

Note that I have once again prefixed the variables name with "TutTB_", just as I did for all our other JavaScript functions and variables. Once we have obtained this console instance, we can use it to write our own messages. The following function will do the work for us:
function TutTB_Log(aMessage) { TutTB_ConsoleService.logStringMessage('Tut_Toolbar: ' + aMessage); }

In practice, you should change the My_Extension: portion of the message to whatever the name of your extension is. By prefixing each message with your extensions name, you can better tell which output messages are yours. Now that we have this function available, we can simply call it from anywhere in our code to print out a debug message:
TutTB_Log("The value of the URL variable is: " + URL);

Remember to always remove all calls to this function before releasing your extension to the public. Not only does logging to the console slow things down, it adds unnecessary clutter to the users JavaScript console window. For further reading on the JavaScript console, consult this Mozilla Developers Center article.

Logging to the Standard Console


An alternative method of logging debug information is available through the standard console mechanism. Before this method can be used, several modifications to the browser must be made. First, we need to add a new browser preference. In the URL bar in Firefox, type about:config and press enter. Right click in the list control and select the New Boolean menu item to create a new boolean preference. Give the preference a name of browser.dom.window.dump.enabled and set the value to true. The next step is to add the "-console" command line parameter to your Firefox startup shortcut. Using this parameter will cause the standard output console window to appear each time you run Firefox. Once this has been done, and Firefox has been started, any output produced by the dump() function will appear in this console window. The dump() function works just like the standard JavaScript alert() function, so the syntax is similar.

The DOM Inspector


One of the greatest aids to anyone designing a toolbar (or any other chrome for that matter) is the DOM (Document Object Model) Inspector, a tool which allows you to examine the structure of XML documents (which includes XUL and HTML). This tool comes with Firefox, but is not selected for install by default. You must perform an "Advanced" install to be able to select this tool for installation. Once the tool is available, a wealth of information can be harvested, so make sure you learn how to use it. A few guides on how to use the DOM Inspector are available on the web:

The DOM Inspector (from Creating Applications with Mozilla) DOM Inspector FAQ

This tool is best used to help troubleshoot XUL layout problems, as it allows you to view the styles being applied to various XUL elements. I highly recommend learning how to use the DOM Inspector. Its simple to pick up, and you will be glad you learned how to use it.

Das könnte Ihnen auch gefallen