Complete

This article is not finished yet. When it is finished, it will get a category and links from other pages.

This page is for readers who have followed the Custom Toolbar Button tutorial for Firefox, Thunderbird and Sunbird, or the Custom Toolbar Button:SeaMonkey tutorial for SeaMonkey, and who want to learn more about developing extensions.

Introduction

You can use the Custom Toolbar Button tutorial as a very simple introduction to extensions. However, because it is so simple it does not support some of the usual features of extensions.

This page describes how to structure the extension in a more conventional way.

This page is not a step-by-step tutorial. Instead it explains the missing features, and outlines how to add them.

If you want to see these techniques in action, then you can download and install the complete AllCustom extension:

allcustom.xpi (The link is external only because this wiki does not support XPI files.)

The extension does not contain any useful functions. It is just an extended code sample. To see the code, use a jar tool or zip tool to unpack the XPI file that you downloaded.

For more information about developing extensions, see the main Extensions page here.

Features of this extension

This extension is a more complex version of the original Custom Toolbar Button extension.

It provides a user interface in two languages (English and French).

It supports Firefox, Thunderbird, Sunbird and Flock—these are referred to as "Firefox etc." in the rest of this page. It also supports SeaMonkey.

In SeaMonkey it supports two themes (Classic and Modern).

It provides all five custom toolbar buttons on all the toolbars, and it provides corresponding menu choices in SeaMonkey's ChatZilla window.

The following sections describe this extension's overall structure, and how it implements languages and themes.

Overall structure

This extension's internal name is allcustom. It uses this name as the default file name throughout. Where you see a URL in the code with no file name, the application uses this default file name and an extension appropriate for the type of file expected.

The extension is supplied as a XPI, which is compressed to reduce download times. The XPI contains:

install.rdf Information about the extension
chrome.manifest Registration data for Firefox etc.
install.js Installation script for SeaMonkey
chrome Directory containing the extension code
chrome/allcustom.jar The extension jar
defaults/preferences Directory containing a preferences file

Inside the jar there are three directories:

content XUL, JavaScript and other content that does not depend on the locale or theme
locale Files for each locale
skin Files for each theme

Version checks

Firefox etc. check extensions for compatibility before installing them. These version checks depend on the version numbers specified in the install.rdf file. There are two approaches: pessimistic and optimistic.

The approach that is normally recommended is pessimistic. The extension is assumed to fail in any future version of the application. To adopt this approach, set the maxVersion to the latest actual version where you have tested your extension. The problem with this approach is that you have to release a new XPI every time there is a new release of any of the applications it supports. If you delay releasing a new XPI, you risk annoying users who cannot upgrade until you do.

The approach used here is optimistic. The extension is assumed to work in any future version of the application. To adopt this approach, set the maxVersion to a large number like 99. The problem with this approach is that when changes in an application do make the extension fail, users might have bad experiences ranging from error messages that they cannot understand to crashes and data loss.

For more information about version checks, see: Extension Versioning, Update and Compatibility

The installed jar

To use disk space efficiently on the end user's computer, the three directories (content, locale, skin) are packed in a jar file. It is normally uncompressed, trading off some disk space for speed.

This jar file will be installed as-is on the end user's computer, and unpacked at run-time by the application. To tell the application that the files it needs are in a jar, there are changes to chrome.manifest (for Firefox etc.) and to install.js (for SeaMonkey).

For example, chrome.manifest originally had:

content custombutton chrome/

Now it has:

content allcustom jar:chrome/allcustom.jar!/content/allcustom/

You can see the other changes if you unpack the XPI.

Languages

Extensions can be installed by users who have different language and regional preferences. A combination of language and regional preferences is known as a locale.

Locales are named with a two-part code. For example, the code en-US means English language (en) for the United States (US).

To make it eaiser to support different locales, developers usually place anything that might depend on the locale in separate files in a separate directory.

In the Custom Toolbar Button extension, the only things that might depend on the locale are the text strings displayed in the user interface. These are in the files button.xul and button.js.

XUL and JavaScript each have mechanisms for loading text strings from the correct locale directory. This extension only uses the XUL method. Its JavaScript code gets the text strings it needs from the XUL.

For more information about working with locales, see the main Localization page here.

How a text sting gets localized

When you press button 1 you see an message in English or French, depending on your application's locale. This is how it happens:

For example, if your locale is fr-FR, it loads:

locale/fr-FR/allcustom/allcustom.dtd

from inside the jar file.

  • When you restart after installing the extension, the locales en-US and fr-FR are both registered for the component allcustom. You can see the registration details in chrome.manifest (Firefox, etc.) or in installed-chrome.txt and chrome.rdf (SeaMonkey).
  • When the XUL file, allcustom.xul is loaded, the DOCTYPE declaration near the top loads a DTD from chrome://allcustom/locale/. The application's chrome registry converts this URL to the correct DTD file for the locale you are using.
  • The XUL toolbarbutton tag contains an entity &allcustom.alert.1;. The DTD resolves this into a text string in the appropriate language.
  • When you press the button, the code in the XUL element sends the text string to the extension's JavaScript code in allcustom.js. The extension's JavaScript code displays the text.

File structure

In the new file structure, there is a locale directory for all the locales. Each locale has its own directory there.

In each locale's directory, there is an allcustom directory. This is useful when files from various components and extensions and all unpacked in the same place—it keeps each set of files separate.

In the allcustom directory, the file allcustom.dtd contains the translated strings. The file contents.rdf contains registration data used by SeaMonkey.

Localizing the description

Firefox etc. display a description of the extension in the Extensions window. The description in install.rdf is the default. For each supported locale, a description in install.properties overrides the default.

A preference setting in defaults/preferences/allcustom.js makes the connection between the description and the properties file, specifying the URL:

chrome://allcustom/locale/install.properties

Again, the application's chrome registry converts this URL to the correct file for the locale you are using.

For example, if your locale is fr-FR, it gets the description from:

locale/fr-FR/allcustom/install.properties

Testing a locale

To test the alternative locale, install the extension in the normal way.

Restart the application using the command line switch:

-uiLocale fr-FR

(Of course, if your application is already in French, specify en-US here to switch the extension to English.)

Notes:

  • If you use a shortcut or launcher icon to start the application, then you can add the command line switch by editing the icon's properties.
  • The application's user interface only switches language if you have the appropriate language pack installed. But this extension switches between English and French without needing any language pack.
  • Some versions of Firefox etc. have a bug that prevents this from working. To work around the bug, close the application, delete the file XUL.mfl in its profile, then restart it with the command line switch.
  • Firefox etc. support specifying the language alone, without any region—for example, just: -uiLocale fr SeaMonkey does not support this.

Themes

A theme changes the appearance of the user interface, affecting fonts, colours, graphics, and sometimes layout.

A theme consists of a skin for each component. This extension is just one component, allcustom, so it contains a skin for this component in each of the themes that it supports. These themes are:

  • Classic for Firefox etc.
  • Classic for SeaMonkey
  • Modern for SeaMonkey

To make it easier to support different themes, developers place anything that might depend on the theme in separate files in a separate directory.

In this extension, the only things that depend on the theme are the icon images on the buttons and the CSS style rules.

For more information about themes, see the main Themes page here.

How a button gets themed

When you look at button 1 in SeaMonkey, you see an image or style that depends on your theme. This is how it happens:

This extension does not support modern in Firefox etc., but you can see the registration details for classic in chrome.manifest.

For example, if you are using Modern, it loads:

skin/modern/allcustom/seamonkey/allcustom.css

from inside the jar.

  • When you restart after installing the extension, the skins classic and modern are both registered for the component allcustom. You can see the registration details in installed-chrome.txt and chrome.rdf.
  • When the XUL file, allcustom.xul is loaded, the stylesheet declaration near the top loads a stylesheet from chrome://allcustom/skin/. The application's chrome registry converts this to the correct CSS file for the theme you are using.
  • The XUL toolbarbutton tag has an ID all-custom-1. The CSS stylesheet uses the corresponding selector #all-custom-1 to provide the appropriate image: button-1.png

File structure

In the new file structure, there is a skin directory for all the themes. Each theme has its own directory there.

In each theme's directory, there is an allcustom directory. This is useful when files from various components and extensions and all unpacked in the same place—it keeps each set of files separate.

The allcustom directory contains the icon images and the CSS stylesheet. The file contents.rdf contains registration data used by SeaMonkey.

Testing a theme

To test a theme in SeaMonkey, choose View – Apply Theme, then choose the theme. Restart SeaMonkey.

Application differences

Some differences between Firefox etc. and SeaMonkey cause complications for this extension.

To resolve the differences, the extension uses Firefox etc. and SeaMonkey's different registration mechanisms to register different files where this is needed.

Toolbar conflicts

There are some conflicts between toolbars in Firefox etc. and toolbars in SeaMonkey. To avoid these conflicts, this extension uses a separate XUL file for SeaMonkey.

Firefox etc. use: content/allcustom/allcustom.xul This file is specified in chrome.manifest, which only Firefox etc. use.

SeaMonkey uses: content/allcustom/seamonkey/allcustom.xul This file is specified in content/allcustom/contents.rdf, which only SeaMonkey uses.

Theme conflicts

The Classic theme for Firefox etc. is different from the Classic theme for SeaMonkey, but the internal name classic/1.0 is the same.

To resolve the conflict, this extension registers SeaMonkey's skins in a seamonkey subdirectory.

Firefox etc. use: skin/classic/allcustom/ This directory is specified in chrome.manifest, which only Firefox etc. use.

SeaMonkey uses: skin/classic/allcustom/seamonkey/ This directory is specified in install.js, which only SeaMonkey uses.

A similar structure is used for Modern, even though there is no conflict.

Package structure

Here is the complete package structure for this extension.

This diagram shows all the directories but only a few of the files. You can see all the files if you unpack the XPI and the jar.

Image:allcustom-package-structure.png