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

Latest commit

 

History

History
325 lines (245 loc) · 11.8 KB

implementing-simple-addon.md

File metadata and controls

325 lines (245 loc) · 11.8 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 that replaces selected text with its English translation.

Initializing Your Add-on

Create a directory called translator. 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 translator 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 translator directory. This contains information about your add-on and should look something like this:

  {
    "name":"translator",
    "fullName":"translator",
    "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 request = require("request");
var selection = require("selection");

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

  // Create a new context menu item.
  var menuItem = contextMenu.Item({

    label: "Translate Selection",

    // Show this item when a selection exists.

    context: contextMenu.SelectionContext(),

    // When this item is clicked, post a message to the item with the
    // selected text and current URL.
    contentScript: 'self.on("click", function () {' +
                   '  var text = window.getSelection().toString();' +
                   '  self.postMessage(text);' +
                   '});',

    // When we receive the message, call the Google Translate API with the
    // selected text and replace it with the translation.
    onMessage: function (text) {
      if (text.length === 0) {
        throw ("Text to translate must not be empty");
      }
      console.log("input: " + text);
      var req = request.Request({
        url: "http://ajax.googleapis.com/ajax/services/language/translate",
        content: {
          v: "1.0",
          q: text,
          langpair: "|en"
        },
        onComplete: function (response) {
          translated = response.json.responseData.translatedText;
          console.log("output: " + translated);
          selection.text = translated;
        }
      });
      req.get();
    }
  });
};

exports.onUnload = function (reason) {
  console.log(reason);
};

Importing Modules

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

  • context-menu enables add-ons to add new items to the context menu
  • request enables add-ons to make network requests
  • selection gives add-ons access to selected text in the active browser window

Creating a Context Menu Item

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

  • the name of the item to display: "Translate Selection"
  • 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. It uses Google's AJAX-based translation service to translate the selection to English and sets the selection to the translated text.

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 or exports.onUnload for anything, and only includes them to illustrate their 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 translator 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'

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

The ID that cfx generated the first time you executed cfx run is a unique identifier for you add-on called the Program ID and it is important. It is used by various tools and services to distinguish this add-on from any other.

To learn more about the Program ID refer to the Program ID document.

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 "Translate Selection":

translator context-menu

Select that item and the text you selected should be replaced with its English translation:

translator context-menu

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

  info: input: Le projet Mozilla est une communauté mondiale de personnes
  qui pensent que l'ouverture, l'innovation et la saisie des chances qui nous
  sont offertes sont les clés de la vitalité d'Internet. Nous travaillons
  ensemble depuis 1998 pour nous assurer qu'Internet se développe d'une manière
  qui bénéficie à tout le monde. On nous connaît surtout pour la création du
  navigateur Web Mozilla Firefox.
  info: output: The Mozilla project is a global community of people who believe
  that openness, innovation and seizing opportunities offered to us are the
  keys to the vitality of the Internet. We have been working together since
  1998 to ensure that the Internet develops in a way that benefits everyone.
  We are best known for creating the Mozilla Firefox Web browser.

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.

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:

  Exporting extension to translator.xpi.

The translator.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 translator.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.