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
andfr-FR
are both registered for the componentallcustom
. You can see the registration details inchrome.manifest
(Firefox, etc.) or ininstalled-chrome.txt
andchrome.rdf
(SeaMonkey). - When the XUL file,
allcustom.xul
is loaded, the DOCTYPE declaration near the top loads a DTD fromchrome://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
andmodern
are both registered for the componentallcustom
. You can see the registration details ininstalled-chrome.txt
andchrome.rdf
. - When the XUL file,
allcustom.xul
is loaded, thestylesheet
declaration near the top loads a stylesheet fromchrome://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 IDall-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.