Skip to content
This repository has been archived by the owner on Feb 26, 2022. It is now read-only.

Latest commit

 

History

History
313 lines (234 loc) · 11 KB

implementing-simple-addon.md

File metadata and controls

313 lines (234 loc) · 11 KB

Implementing a Simple Add-on

This section of the tutorial takes you through the process of implementing, running and packaging a simple add-on using the SDK. The add-on will add a menu item to Firefox's context menu, to appear when anything in the page is selected. The menu item displays a popup dialog containing the Wikipedia entry for the selected text.

Initializing Your Add-on

Create a directory called wikipanel. This is where we will keep all the files for this add-on.

You do not have to create this directory under the SDK root: once you have called source bin/activate from the SDK root, cfx will remember where the SDK is, and you will be able to reference SDK packages from any directory.

Keeping your add-on code outside the SDK is good practice as it makes it easier for you to update the SDK and to manage your code using a version control system.

Next we'll use cfx init to create a skeleton structure for your add-on. Navigate to the wikipanel directory and execute cfx init. You should see something like this:

  * lib directory created
  * data directory created
  * test directory created
  * doc directory created
  * README.md written
  * package.json written
  * test/test-main.js written
  * lib/main.js written
  * doc/main.md written

  Your sample add-on is now ready for testing:
      try "cfx test" and then "cfx run". Have fun!"

First, cfx init creates the directory structure your add-on needs:

When you create add-ons using the SDK, you might create two different sorts of scripts. All add-ons will create at least one script under `/lib`. Some add-ons will also create "content scripts" stored under `/data`. For more information on the difference between these two sorts of files, see [Two Types of Scripts](dev-guide/addon-development/two-types-of-scripts.html).
  • /data contains resources such as icons or HTML files, as well as any content scripts included with your add-on. You can access the content of the data subdirectory from within your add-on's code using the Add-on SDK's self module.

  • /doc contains any documentation for your add-on.

  • /lib contains the JavaScript modules implementing your add-on.

  • /test contains unit test code.

Next, cfx init creates a file called package.json in the root wikipanel directory. This contains information about your add-on and should look something like this:

  {
    "name":"wikipanel",
    "fullName":"wikipanel",
    "description":"This is an example of addon description.",
    "author":"",
    "license":"MPL",
    "version":"0.1"
  }

Finally, cfx init creates some example files under doc, lib, and test: we will replace those.

Adding Your Code

In the lib directory, open the file called main.js and replace its contents with the following:

// Import the APIs we need.
var contextMenu = require("context-menu");
var panel = require("panel");

exports.main = function(options, callbacks) {
  console.log(options.loadReason);

  // Create a new context menu item.
  var menuItem = contextMenu.Item({
    label: "What's this?",
    // Show this item when a selection exists.
    context: contextMenu.SelectionContext(),
    // When this item is clicked, post a message back with the selection
    contentScript: 'self.on("click", function () {' +
                   '  var text = window.getSelection().toString();' +
                   '  self.postMessage(text);' +
                   '});',
    // When we receive a message, look up the item
    onMessage: function (item) {
      console.log('looking up "' + item + '"');
      lookup(item);
    }
  });
};

function lookup(item) {
  wikipanel = panel.Panel({
    width: 240,
    height: 320,
    contentURL: "http://en.wikipedia.org/w/index.php?title=" +
                item + "&useformat=mobile"
  });
  wikipanel.show();
}

Importing Modules

The first two lines are used to import two SDK modules from the addon-kit package:

  • context-menu enables add-ons to add new items to the context menu
  • panel enables add-ons to display popup windows

Creating a Context Menu Item

Next, this code constructs a context menu item. It supplies:

  • the text to appear in the menu: "What's this?"
  • a context in which the item should be displayed: SelectionContext(), meaning: include this item in the context menu whenever some content on the page is selected
  • a script to execute when the item is clicked: this script sends the selected text to the function assigned to the onMessage property
  • a value for the onMessage property: this function will now be called with the selected text, whenever the user clicks the menu.

The supplied function loads the Wikipedia entry for the selection into a panel.

Listening for Load and Unload

The code which creates the context menu is wrapped in a function which we have assigned to the main property of the global exports object.

If your add-on exports a function called main, that function will be called when the add-on is loaded.

exports.main = function (options, callbacks) {};

options is an object describing the parameters with which your add-on was loaded. In particular, options.loadReason is one of the following strings describing the reason your add-on was loaded: install, enable, startup, upgrade, or downgrade.

Conversely, if your add-on exports a function called onUnload, that function will be called when the add-on is unloaded.

exports.onUnload = function (reason) {};
Note that if your add-on is unloaded with reason `disable`, it will not be notified about `uninstall` while it is disabled: see bug [571049](https://bugzilla.mozilla.org/show_bug.cgi?id=571049).

reason is one of the following strings describing the reason your add-on was unloaded: uninstall, disable, shutdown, upgrade, or downgrade.

You don't have to use exports.main or exports.onUnload. You can just place your add-on's code at the top level instead of wrapping it in a function assigned to exports.main: it will be loaded in the same circumstances, but you won't get access to the options or callbacks arguments.

This particular add-on doesn't need to use exports.main for anything, and only includes it to illustrate its use.

Logging

Note the calls to console.log() here. console is a global object accessible by any module, which you can use to write error, warning, or informational messages.

For an add-on which has been packaged as an XPI file and installed into Firefox, the messages are sent to Firefox's Error Console. If you are launching Firefox from the command line using cfx, as you will be for development and debugging, then the messages are sent to the command shell from which you launched Firefox.

For more information on the console object see its documentation page.

Running It

To run your program, navigate to the wikipanel directory and type:

  cfx run

The first time you do this, you'll see a message like this:

  No 'id' in package.json: creating a new ID for you.
  package.json modified: please re-run 'cfx run'
The ID that `cfx` generated the first time you executed `cfx run` is a unique identifier for your add-on. To learn more about it refer to the [Program ID](dev-guide/addon-development/program-id.html) document.

Run it again, and it will run an instance of Firefox with your add-on installed.

Once cfx run has launched Firefox you can try out the new add-on. Load a page containing some text that is not in English, for example: http://www.mozilla.org/about/manifesto.fr.html

Select some text on that page and right-click to activate the context menu. You should see a new item labeled "What's this?":

wikipanel context-menu

Select that item and you'll see a popup panel showing the Wikipedia entry for the selection:

wikipanel panel

You will also see output like this appear in your command shell:

  info: looking up "Jetpack"

Preparing Your Add-on for Deployment

Once you have finished testing your add-on you can package it for deployment like any other Firefox add-on, as a XPI file. The Add-on SDK simplifies the packaging process by generating this file for you.

Specifying an Icon

You can specify an icon for your add-on. This icon will appear beside your add-on in Firefox's Add-ons Manager and on addons.mozilla.org.

To specify an icon, save it as "icon.png" in your add-on's root directory. To give the icon a different name or to store it in a different location under the root, use the "icon" key in your package.json file. See the Package Specification for more details.

cfx xpi

To package your program as a XPI, navigate to the root of your package directory in your shell and run cfx xpi. You should see a message like:

  Exporting extension to wikipanel.xpi.

The wikipanel.xpi file can be found in the directory in which you ran the command.

Installing the Package

Test that the package installs correctly by adding it to your own Firefox installation.

You can do this by pressing the Ctrl+O key combination (Cmd+O on Mac) from within Firefox. This will bring up a file selection dialog: navigate to the wikipanel.xpi file, open it and follow the prompts to install the add-on.

Alternatively:

  • Open the Firefox Add-ons Manager from within Firefox, either from the Add-ons item on the Tools menu, or by typing about:addons into the address bar.

  • In the Firefox Add-ons Manager there is a gears icon next to the search bar. Click the icon and select "Install Add-on From File..." from the menu that appears. Again, this will bring up a file selection dialog which you can use to find and open the XPI file.

Once you have installed the add-on you can test it in exactly the same way as in the "Running It" section above.

Distributing It

To distribute your program, you can upload it to addons.mozilla.org. Eventually, this step may be automated via the SDK, streamlining the distribution process further.

In the next section we'll introduce CommonJS, which provides the infrastructure for the SDK.