Getting started with extension development

From MozillaZine Knowledge Base
Revision as of 19:22, 18 August 2013 by Frank Lion (talk | contribs) (Old link deleted and broken link fixed.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

This page is part of the extension development documentation project.

Ask your questions in MozillaZine Forums. Also try browsing example code.

Note: development documentation is in process of being moved to Mozilla Development Center (MDC).

Two major extension developers' features introduced in Firefox 1.5 were the greatly simplified chrome registration scheme and the reworked Extension Manager. These changes make it even easier to start writing extensions.

This article describes steps needed to get started with extensions development. Last two sections have a few development tips and packaging information. Most of it is targeted at beginners in extension development, although the setup tips should be useful for everybody. This article is concise and doesn't go into discussing the technologies involved; it's more of a crash-course. Another, more detailed tutorial, is available at developer.mozilla.org.

It's a wiki page, so feel free to make improvements to this page and to add your feedback on the Talk page. However questions and requests for help are better suited for the forums.

Extensions created in this way will only work on Firefox/Thunderbird 1.5 and later, but you should be able to make changes to ensure your extension is compatible with Firefox 1.0 quite easily.

Again, this will work only in Firefox/Thunderbird 1.5 or later, not 1.0.x! Not 1.0.6, 1.0.7 or anything like that. Only 1.5 or later.

Setting up your environment

This article focuses on Firefox extensions, although it also applies to other Toolkit applications, such as Thunderbird.

The first thing you need to do is download a recent version of your application. You can get Firefox here. As was mentioned above, you need Firefox 1.5 or later, setup tips from this article will not work in earlier versions.

For further instructions, see Setting up extension development environment. Do read that page, it will save you many hours when developing and debugging your extension. In particular, you must set the javascript.options.showInConsole pref to true.

What this Extension Does

This extension adds an item called 'Hello World!' to the Tools Menu in Firefox. It's a good example of creating an extension that pops up a new window when you activate it.

Planning your extension

You should plan what you need for your extension; we will use an example that provides a new menu option that creates a message in a window. The following files are required, choose your own names if you like (but if you change any names remember to update all references to them), except for the folders and files 'chrome.manifest' and 'install.rdf'.

Filename Purpose
chrome.manifest Tells Firefox where your chrome files are and what to do with them
install.rdf The description file for your extension ("Install manifest")
overlay.xul The file describing UI elements to add to the browser window
overlay.js The file with scripts to run in the browser window
overlay.dtd Contains translation for text string codes in overlay.xul
hello.dtd Contains translation for the strings in hello.xul
overlay.css Lets you adjust appearance of UI elements with CSS
hello.xul The file describing the UI of the new window
helloworld@mozilla.doslash.org A pointer to your extension files

Creating stub extension files

As you should already know, extensions usually modify an application's UI ("chrome") and behavior by providing overlays to already existent windows/documents. Those overlays are a part of the extension's content package (content provider). Most extensions also have one or more locales and skins. (If you didn't know that, we advise you to read The Developer.Mozilla.org XUL Tutorial.

This section describes what directory structure and what files are needed in order to make Firefox register your extension's files.

You can download the ZIP file with all necessary stub files and appropriate folder structure and skip to Registering your extension in the Extension Manager. It's recommended that you nonetheless read the below subsections, as they explain the function of each file in the package and provide links to other resources.

Folder structure

Below is the folder structure we will use. You may use a different structure, as long as you also update your chrome.manifest (see below) accordingly. Create the following structure in the folder where you intend to develop your project:

helloworld/
  chrome.manifest
  install.rdf
  content/
    overlay.js
    overlay.xul
    hello.xul
  locale/
    en-US/
      overlay.dtd
      hello.dtd
  skin/
      overlay.css

The folders are traditionally named "content", "locale" and "skin", and you should follow the tradition. You may call the files inside those folders whatever you want (except chrome.manifest and install.rdf).

Note: This folder structure is for development, you'll need different folder structure when packaging your extension.

Stub files

chrome.manifest

Recent versions of Firefox read a simple plaintext chrome.manifest file (instead of the old and confusing contents.rdf) to determine what packages and overlays your extension provides. The format of this file is described in the Chrome Registration document. In the following example we'll create a chrome.manifest file for our folder structure.

It looks like this (assuming your extension's package name is "helloworld"):

1
2
3
4
5
6
7

content helloworld content/
overlay chrome://browser/content/browser.xul chrome://helloworld/content/overlay.xul

locale helloworld en-US locale/en-US/

skin helloworld classic/1.0 skin/
style chrome://global/content/customizeToolbar.xul chrome://helloworld/skin/overlay.css

What each line of the file does:

  • Line 1 registers a content provider: it maps the contents of chrome://helloworld/content/ to the content folder.
  • Line 2 registers an overlay for chrome://browser/content/browser.xul location, allowing you to modify Firefox's main window UI from your overlay.xul file.
  • Line 4 registers a en-US locale provider.
  • Line 6 registers a default skin provider.
  • Line 7 applies your overlay.css style file to chrome://global/content/customizeToolbar.xul document (used, for example, when creating toolbar buttons). You could instead register an overlay and include the stylesheet in the overlay using the <?xml-stylesheet?> processing instruction.

Warning: Don't forget the end slash at the end of the paths : "content/" works, whereas "content" doesn't. Also note that the package name ('helloworld' in this case) has to be all lowercase.

Note: this file will be a bit different when you create an XPI for your extension, see the Packaging section below.

overlay.xul

overlay.xul is a simple XUL overlay. You can read more about overlays at XUL Planet and MDC.

A simple overlay looks like this:

1
2
3
4
5
6
7
8
9
10
11
12

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://helloworld/skin/overlay.css" type="text/css"?>
<!DOCTYPE overlay SYSTEM "chrome://helloworld/locale/overlay.dtd">
<overlay id="helloworld-overlay"
    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <script src="overlay.js"/>

  <menupopup id="menu_ToolsPopup">
    <menuitem id="helloworld-hello" label="&helloworld;"
        oncommand="Helloworld.onMenuItemCommand(event);"/>
  </menupopup>
</overlay>

What each line of the file does:

  • Line 1 is the XML declaration, specifying the version of XML being used. It can also be used to specify file's encoding, but that should seldom be needed, as you should put localizable strings in the DTD file.
  • Line 2 is optional and can be used to apply a stylesheet to the base document.
  • Line 3 is also optional, but recommended if you include any user-visible strings in your overlay. It is used to make your overlay localizable.
  • Lines 4-5 define the root element of the overlay. It must be a XUL <overlay> element.
  • Line 6 is optional and can be used to attach a JavaScript file to the base document. See next section for more information.
  • Lines 8-10 add a menu item to the Tools menu in Firefox main window. See Adding items to menus for more information.

overlay.js

As you may know, JavaScript files are used to define application's behavior. Please refer to the list of JavaScript development resources for information on JavaScript in general.

An important issue you should be aware of is that all scripts that are loaded for a given document (the scripts used by the window itself, and scripts loaded from overlays to that document) share the same scope. This means you should use unique names for global identifiers in your extensions to avoid clashing with other extensions. It's usually accomplished by prefixing all global identifiers with the name of your extension or by putting most/all of your variables and functions in an object with an unique name.

Typical JavaScript file for an overlay looks like this:

var Helloworld = {
  onLoad: function() {
    // initialization code
    this.initialized = true;
  },

  onMenuItemCommand: function() {
    window.open("chrome://helloworld/content/hello.xul", "", "chrome");
  }
};

window.addEventListener("load", function(e) { Helloworld.onLoad(e); }, false); 

overlay.dtd

DTD files are used to make XUL/XBL/XHTML and other XML files in Mozilla chrome localizable. Basically, instead of hard-coding the strings in your XUL file, you use XML entities, which expand to the values declared in the DTD file referenced at the top of the XUL file.

It makes your extension localizable, because there may be a few different locale providers for your extension, and Mozilla is able to choose between them at run-time.

DTD files used for localization purposes consist of entity declarations like the one below:

<!ENTITY helloworld "Hello World!">

hello.dtd

This is the file for the new window.

<!ENTITY title.label "Hello World">
<!ENTITY separate.label "This is a separate window!">
<!ENTITY close.label "Close">

hello.xul

In addition to modifying existing windows, you can create new windows for your extensions. The UI of your own windows is also described in XUL files, but unlike overlays, the root element is a <window> or a <dialog>, and not <overlay>. Another difference from overlays is that you don't have to register each of new windows in chrome.manifest.

The example package includes file hello.xul, which is used to describe a simple window.

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/global.css"  type="text/css"?>
<!DOCTYPE window SYSTEM "chrome://helloworld/locale/hello.dtd">

<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" 
        title="&title.label;">

<hbox align="center">
  <description flex="1">&separate.label;</description>
  <button label="&close.label;" oncommand="close();"/>
</hbox>

</window>

install.rdf

install.rdf file is used by the Extension Manager when installing an XPI file and when registering an extension at specified location. In Firefox 1.5 and later it's only used to provide EM metadata, such as extension's ID, version, description, author etc. For more information, see install.rdf article.

<?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">
   
    <em:id>helloworld@mozilla.doslash.org</em:id>
    <em:name>Hello World (Firefox 1.5 or later edition)</em:name>
    <em:version>1.0</em:version>
    <em:description>Classic first extension from MozillaZine KB</em:description>
    <em:creator>Nickolay Ponomarev</em:creator>
    <!-- optional items -->
    <em:contributor>A person who helped you</em:contributor>
    <em:contributor>Another one</em:contributor>
    
    <em:homepageURL>http://kb.mozillazine.org/Getting_started_with_extension_development</em:homepageURL>
    <!-- em:optionsURL>chrome://sampleext/content/settings.xul</em:optionsURL>
    <em:aboutURL>chrome://sampleext/content/about.xul</em:aboutURL>
    <em:iconURL>chrome://sampleext/skin/mainicon.png</em:iconURL>
    
    <em:updateURL>http://sampleextension.mozdev.org/update.rdf</em:updateURL-->
    
    <!-- Firefox -->
    <em:targetApplication>
      <Description>
        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
        <em:minVersion>1.5</em:minVersion>
        <em:maxVersion>2.0.0.*</em:maxVersion>
      </Description>
    </em:targetApplication>
    
  </Description>

</RDF>

overlay.css

overlay.css is used by Firefox to apply a specific look to the extension component(s) you are installing. In this case, we want to color the helloworld menuitem red.

NOTE: The coloring of menuitems is not recommended. This is only an example.

/* This is just an example. You shouldn't do this. */
menuitem#helloworld-hello {
  color: red !important;
}

Registering your extension in the Extension Manager

Before releasing your extension to the public you must thoroughly test it. To avoid problems during this phase it is advisable to create and use a new profile for testing it.

Once you have created the files described above and have placed them in the appropriate folder structure, registering them in the Extension Manager is trivial. With Firefox closed, create a "pointer" file with the same name as your extension's ID in profile folder/extensions/ and edit it so that it contains the path to your folder containing install.rdf and chrome.manifest files.

E.g. helloworld's ID is helloworld@mozilla.doslash.org and we would like to register it in X:\Dev\helloworld\ (i.e. there is X:\Dev\helloworld\install.rdf file etc.). Just put a single line into the file at this path: profile folder/extensions/helloworld@mozilla.doslash.org

X:\Dev\helloworld

Start Firefox, and check that your extension is installed. Then test it.

Development cycle

Once you have registered your extension following the steps above, developing your extension is quite easy. If you've set the development preferences, your development cycle will be like this:

  1. Edit your extension files.
  2. Reopen the window(s) that modified files apply to, or use Reload chrome feature of Extension Developer Extension. Because the Reload Chrome feature of the Extension Developer Extension does not work for Thunderbird, you can alternately use the Reloadchromezilla extension for Thunderbird and Firefox 1.5.
    • If you changed chrome.manifest, you'll have to restart.
    • If you changed install.rdf, you need to touch the extension folder specified in your "pointer" file (update its Last modified time) and restart.
(i.e. If you update c:\dev\helloworld\install.rdf you need to make sure the folder c:\dev\helloworld has a different timestamp.
A quick way to do this on windows is to rename c:\dev\helloworld to c:\dev\helloworld-tmp, make a new helloworld folder, then copy the contents of the helloworld-tmp folder into the new helloworld folder. Alternatively, display the folder in Explorer, right click on the right hand side pane, and select New>Folder - then just delete the New Folder.
On linux you could just use the touch command.)


It's much more convenient compared to the edit-rezip-restart cycle many extension authors were using or the pleasure of editing chrome.rdf file or similar setup tricks.

Packaging

As it was mentioned, the folder structure and chrome.manifest file must be changed before packaging. Compare:

DevelopingPackaging
Folder structure
helloworld/
  chrome.manifest
  install.rdf
  components/
  defaults/
    preferences/
      mydefaults.js
  content/
    overlay.js
    overlay.xul
  locale/
    en-US/
      overlay.dtd
  skin/
    overlay.css
helloworld.xpi/
  chrome.manifest
  install.rdf
  components/
  defaults/
    preferences/
      mydefaults.js
  chrome/
    helloworld.jar
      content/
        overlay.js
        overlay.xul
      locale/
        en-US/
          overlay.dtd
      skin/
        overlay.css
chrome.manifest (note extra "jar:chrome/helloworld.jar!/" in the right column)
content	helloworld content/
overlay	chrome://browser/content/browser.xul	chrome://helloworld/content/overlay.xul

locale	helloworld	en-US	locale/en-US/

skin	helloworld	classic/1.0	skin/
style	chrome://global/content/customizeToolbar.xul	chrome://helloworld/skin/overlay.css
content	helloworld jar:chrome/helloworld.jar!/content/
overlay	chrome://browser/content/browser.xul	chrome://helloworld/content/overlay.xul

locale	helloworld	en-US	jar:chrome/helloworld.jar!/locale/en-US/

skin	helloworld	classic/1.0	jar:chrome/helloworld.jar!/skin/
style	chrome://global/content/customizeToolbar.xul	chrome://helloworld/skin/overlay.css

Packaging your chrome files into a JAR file brings some benefits such a smaller download size however it also introduces unnecessary complexity and for many starting out it is generally easier to not use JAR files.

Some links and tools are available at Packaging extensions.

Resources