Menu

Note: This page documents the Jetpack Prototype, which has since been replaced by the Add-on SDK. Please see the wiki page and online documentation for more information on how to use the Add-on SDK.

Jetpack's menu API allows features to access and modify the browser's built-in menus.  Features can also create new menus and attach them almost anywhere, chrome or content, as popup menus or context menus.

Two namespaces are associated with this API: jetpack.menu, which provides access to the browser's menus, and jetpack.Menu, the constructor for making new menus.  The API is fairly comprehensive, so you may want to start by reading through some examples.

Because it is still under development, the API currently lives in the future and must be imported before it is used:

jetpack.future.import("menu");

All menus in Jetpack are jetpack.Menu objects, including both built-in Firefox menus and menus that features create.  To create a new menu, use one of the jetpack.Menu constructors below.

Constructors

jetpack.Menu()

Creates an empty menu.

jetpack.Menu(menuitems)

Creates a menu with the given items.

Parameters
menuitems
An array of menuitems.

jetpack.Menu(properties)

Creates a menu with specific properties.

Parameters
properties
An object defining any of the properties below. The items property may be used to define an array of menuitems.

Properties

Property Type Description
beforeHide function A function invoked just before the menu is hidden. If the menu is a context menu, it is called as beforeHide(menu, context) and otherwise as beforeHide(menu). menu is the Menu object to which beforeHide is attached. context is an object describing the context in which the menu was shown.
beforeShow function A function invoked just before the menu is shown. If the menu is a context menu, it is called as beforeShow(menu, context) and otherwise as beforeShow(menu). menu is the Menu object to which beforeShow is attached. context is an object describing the context in which the menu was shown. beforeShow may modify the menu, and when the menu is shown, it will reflect the changes.
isShowing boolean True if the menu is currently visible and false otherwise. Read-only.
items array An array of menuitems in the menu. Read-only.

Methods

add(items)
clear()
contextOn(node)
hide()
insertBefore(newItems, target)
item(target)
popupOn(node)
remove(target)
replace(target, newItems)
reset()
set(items)
show(anchorNode)

add(items)

Adds items to the menu. The position at which the items are added is at Jetpack's discretion. This method and set() are the recommended methods of adding items to a menu.

Parameters
items
A single menuitem or an array of menuitems.

clear()

Removes all items from the menu, even items not added by the feature.

contextOn(node)

Binds the menu to a given node as its context menu.

Parameters
node
The menu is attached to this node, which may be either a raw DOM node or a DOM node wrapped by jQuery.

hide()

Hides the menu if it is showing.

insertBefore(newItems, target)

Inserts new items before an existing item.

Parameters
newItems
A single menuitem or an array of menuitems.
target
Indicates the existing item. See Targets. If no such target exists, the position at which the items are added is at the discretion of Jetpack.

item(target)

Returns an item in the menu. The item may be modified. If the menu is hidden, it will reflect the changes when it is next shown. If the menu is visible, it will reflect the changes immediately.

Parameters
target
Indicates the existing item. See Targets.
Return value

A Menuitem object, or null if no such target exists.

popupOn(node)

Binds the menu to a given node. The menu will be shown when the node is left-clicked.

Parameters
node
The menu is attached to this node, which may be either a raw DOM node or a DOM node wrapped by jQuery.

remove(target)

Removes an item from the menu.

Parameters
target
Indicates the existing item to remove. See Targets. If no such target exists, the call silently fails.

replace(target, newItems)

Replaces an item with new items.

Parameters
target
Indicates the existing item to replace. See Targets. If no such target exists, the call silently fails.
newItems
A single menuitem or an array of menuitems.

reset()

Reverts all the changes to the menu that the feature has made. For menus that the feature creates, this is equivalent to clear().

set(items)

Equivalent to calling reset() and then add(items). This method and add() are the recommended methods of adding items to a menu.

Parameters
items
A single menuitem or an array of menuitems.

show(anchorNode)

Shows the menu immediately.

Parameters
anchorNode
The menu will pop up on this node, which may be either a raw DOM node or a DOM node wrapped by jQuery.

Menus in Jetpack contain Menuitem objects, including both built-in Firefox menus and menus that features create. No Menuitem constructor is exposed, because Jetpack automatically boxes simple JavaScript objects into Menuitem objects.

Creating menuitems

To pass a new menuitem into the API, pass one of the following types:

null

A simple menu separator. (Note that any falsey value will suffice, including undefined, null, and the empty string. null is recommended because it stands out.)

function

A menuitem that will update itself when its menu is shown.

The function is invoked just before the item's menu is shown and when the items array of the item's menu is retrieved. It must return a non-function menuitem. If the item belongs to a context menu, the function is called as function(context) and otherwise function(). context is an object describing the context in which the menu was shown.

string

A simple menuitem with the given string label.

object

A menuitem with specific properties. The object may define any of the properties listed below.

Properties

Property Type Description
command function

A function that will be called when the menuitem is clicked. If the menu property is present, command will instead be called when any of the item's descendants is clicked. In that case, the commands of descendants will be invoked first. In either case, it is called as command(clickedMenuitem), where clickedMenuitem is the menuitem that was clicked.

Due to a platform bug in Firefox, on OS X only, for menus in the menu bar only, command functions defined on menuitems with submenus are not called when descendant menuitems are clicked.  See bug 534014 for details and a workaround.
data string An arbitrary string that the feature may associate with the menuitem.
disabled boolean If true, the menuitem is disabled.
icon string The URL of an icon to display in the menuitem. Note that some environments, notably Gnome 2.28, do not support menuitem icons either by default or at all.
label string The label of the menuitem.
menu jetpack.Menu If defined, the menuitem expands into a submenu.
mnemonic string A character that is used as the item's shortcut key while the menu is open. It should be one of the characters that appears in the item's label. On some platforms this character is underlined in the label.
type string Currently only "separator" is supported. If this property is undefined, the item is a normal menuitem. Note that when type == "separator", any other properties (such as label) may be specified. Fancy separators may behave differently on different platforms, however.
xulId string The ID of the menuitem's backing XUL element, exposed for the benefit of advanced developers.

jetpack.menu

When you need to expose functionality through a menu but no menu in particular, do The Right Thing by using jetpack.menu, the "Jetpack menu." jetpack.menu is a jetpack.Menu object corresponding to a menu or region within a menu that Jetpack sets aside for features. The actual menu is up to Jetpack, but currently it is the Tools menu. In the future it may be a submenu of the Tools menu, for example.

Features meant for wide release should prefer jetpack.menu to the jetpack.menu.* menus because:

  • Firefox's menus are subject to change and in fact will be changing in Firefox 3.7. By exposing functionality through jetpack.menu, a feature is guaranteed an easy transition.
  • Many users, especially those new to Firefox, don't realize the distinction between add-ons and the browser itself. If a user forgets or is unable to tell whether a certain menuitem is part of Firefox or provided by a feature, she does not know where to turn when she has problems with it.
  • If many features' menus are local to one area, the user need not hunt and peck through many menus trying to find a particular item of a feature.
  • No one likes it when add-ons clutter her Tools menu willy-nilly.
  • It's less code. (OK, slightly less.)

This is only a recommended practice; developers are of course free to do as they wish.

jetpack.menu.file

The browser's File menu. A jetpack.Menu object.

jetpack.menu.edit

The browser's Edit menu. A jetpack.Menu object.

jetpack.menu.view

The browser's View menu. A jetpack.Menu object.

jetpack.menu.history

The browser's History menu. A jetpack.Menu object.

jetpack.menu.bookmarks

The browser's Bookmarks menu. A jetpack.Menu object.

jetpack.menu.tools

The browser's Tools menu. A jetpack.Menu object.

Context menus

Context menus behave a little differently from other menus. Unlike the Tools menu, which is always in the same place and whose items basically remain constant, context menus don't really exist until they pop up in a certain context. For example, the items of the page's context menu change depending on what the user clicks: images have a context menu, links have a context menu, and so on. Does the page have a single context menu or many?

ContextMenuSet

Jetpack's solution is to expose ContextMenuSet objects. A ContextMenuSet represents a set of context menus. jetpack.menu.context.page is the set of context menus that appear on the page: the image menu, link menu, and so on.

ContextMenuSet defines many of the same methods that jetpack.Menu does. Features can use these methods to modify all the menus in a set at once. They are:

  • add(items)
  • clear()
  • insertBefore(newItems, target)
  • remove(target)
  • replace(target, newItems)
  • reset()
  • set(items)

The following jetpack.Menu properties can also be defined on a ContextMenuSet:

  • beforeHide
  • beforeShow

Note that a jetpack.Menu object is passed to beforeHide and beforeShow, since they are called during a context menu's invocation. They may then modify the menu.

Individual menus are drawn from the set using on():

on(selector)

Returns a new ContextMenuSet whose context menus are those that arise from nodes that match the given CSS selector(s).  The selector must be a true CSS selector, not a jQuery or other type of pseudo-selector.

Note: Selectors don't automatically include the children of nodes they match.  For example, jetpack.menu.context.page.on("a[href]") does not match images contained in links.  To match links and all elements contained in links, use jetpack.menu.context.page.on("a[href], a[href] *").  A future version of Jetpack may change this behavior; see bug 527924.  What do you think?  Leave a comment on that bug or send a message to the mailing list.

Parameters
selector
One or more CSS selectors.  A string.  Examples: "a[href]", "a[href] > img", "a[href], img".
Return value

A new ContextMenuSet object.

jetpack.menu.context

The feature's context menu. All of the feature's context menus are exposed through jetpack.menu.context, including slidebar, panel, toolbar, and status bar item context menus. A ContextMenuSet object.

jetpack.menu.context.browser

The chrome context menu. This is the context menu that appears when right-clicking on an element in Firefox's interface, such as a bookmark on the bookmarks toolbar. A ContextMenuSet object.

Note: Sometimes jetpack.menu.context.browser.on() does not work as expected.  For example, jetpack.menu.context.browser.on("*").add("foo") does not add "foo" to the tab strip's and location bar's context menus, but it does on the bookmark toolbar's context menu.  To work around this limitation, try using beforeShow and examining the node that the user clicked.  For example, to add an item to the tabs' context menu, try:

jetpack.menu.context.browser.beforeShow = function (menu, context) {
  menu.reset();
  if (context.node.localName === "tab")
    menu.add("Hey, a tab!");
};

(The reason this problem exists is because document.querySelectorAll() does not match anonymous content in XUL.  Many parts of Firefox's interface are actually anonymous content.  A future version of Jetpack will hopefully provide a better solution.)

jetpack.menu.context.page

The content context menu. This is the context menu that appears when right-clicking on a Web page. A ContextMenuSet object.

Context objects

Some callbacks passed into the API are called with a context object, such as ContextMenuSet.beforeShow(). Context objects are objects that describe the context in which a context menu is shown. They have the following properties:

Property Description
node The DOM node on which the menu is shown. This is the node the user clicked to open the menu. Be careful when dealing with nested nodes. For example, if the user clicks on an image inside a link, this property will be set to the image, not the link. Similarly, if the user clicks a node within a div, this property will be the node, not the div.
document The content document in which the menu is shown.
window The content window in which the menu is shown.

Targets

Some methods act on existing items within a menu. Existing items are always identified using targets. A target is a string, regular expression, or integer.

A string target is case-insensitively matched against the label, id, and xulId properties of menuitems.

A regular expression target is tested against the label, id, and xulId properties of menuitems.

An integer target indicates a zero-based index within a menu. Integer targets can be negative: -1 indicates the last item in a menu, -2 the second-to-last, and so on.

Multiple items in a menu may match a target, but action is only ever taken on the first matching item.

Examples

Before running any examples, import the API from the future:

jetpack.future.import("menu"); 

Snippets

Add a single, static menuitem to the Jetpack menu that doesn't do anything:

jetpack.menu.add("Two Drink Holders and a Captain's Chair");

Add a menuitem to the Jetpack menu that displays the current date and time each time it's opened:

jetpack.menu.add(function () new Date().toString());

Click an item in the Jetpack menu to be notified of the current date and time:

jetpack.menu.add({
  label: "Show Current Date and Time",
  command: function () jetpack.notifications.show(new Date())
});

The same, except on the content context menu:

jetpack.menu.context.page.add({
  label: "Show Current Date and Time",
  command: function () jetpack.notifications.show(new Date())
});

Create a submenu within the content context menu. When the user clicks an item, she's notified of her choice. Note that the submenu contains many items, including a menu separator:

jetpack.menu.context.page.add({
  label: "Ice Cream",
  icon: "http://example.com/ice-cream.png",
  menu: new jetpack.Menu(["Vanilla", "Chocolate", "Pistachio", null, "None"]),
  command: function (menuitem) jetpack.notifications.show(menuitem.label)
});

Add an item to the hyperlink context menu that tweets the link:

jetpack.menu.context.page.on("a").add(function (context) {
  return {
    label: "Tweet",
    command: function () jetpack.lib.twitter.statuses.update({
      status: context.node.href
    })
  };
));

Add an item to the page's context menu depending on some complex criteria that can't be completely expressed via a CSS selector:

jetpack.menu.context.page.beforeShow = function (menu, context) {
  menu.reset();
  if (matchesMyCriteria(context))
    menu.add("Match!");
};

Add an item to both the hyperlink context menu and the image context menu:

jetpack.menu.context.page.on("a, img").set("A Link or Image");

Add an item to the image context menu, but only for images contained in hyperlinks:

jetpack.menu.context.page.on("a > img").set("An Image Inside a Link");

Add a "Recent Tweets" submenu to the Jetpack menu. (Assume we've defined a getRecentTweets(), which invokes a callback with an array of strings.) When the menu is shown, it displays a "Loading..." item. If the menu remains open when getRecentTweets() receives data from the network and calls done(), the "Loading..." item is replaced with the tweets, one item per tweet:

This example will not work on OS X due to a platform bug in Firefox.  Replace jetpack.menu with jetpack.menu.context.page to see the effect on the content context menu.  See bug 526382 for more information.
jetpack.menu.add({
  label: "Recent Tweets",
  menu: new jetpack.Menu({
    beforeShow: function (menu) {
      menu.set("Loading...");
      getRecentTweets(function done(tweets) menu.set(tweets));
    }
  })
});

When the user selects some text on a page, the context menu normally displays a simple item that searches for it. Replace that item with a menu that lets the user search either Google or Wikipedia:

jetpack.menu.context.page.replace("Search", function (context) {
  return {
    label: "Search for " + jetpack.selection.text,
    menu: new jetpack.Menu([
      {
        label: "Google",
        icon: "http://www.google.com/favicon.ico",
        data: "http://www.google.com/search?q="
      },
      {
        label: "Wikipedia",
        icon: "http://en.wikipedia.org/favicon.ico",
        data: "http://en.wikipedia.org/wiki/"
      }
    ]),
    command: function (menuitem) {
      context.window.location.href = menuitem.data + jetpack.selection.text;
    }
  };
});

Create some div buttons (e.g., in a slidebar or status bar item) and specify their context menu:

for (let i = 0; i < 10; i++) {
  var button = $('<div class="button" />', document);
  buttonContainer.append(button);
}
jetpack.menu.context.on(".button").add(["Do This", "Do That"]);

Create a div button (e.g., in a slidebar or status bar item) and attach menus directly to it. contextMenu becomes the button's context menu. Left-click the button to show popupMenu:

var button = $("<div />", document);
button.text("Click Me");
var contextMenu = new jetpack.Menu(["Do This", "Do That", "And the Other"]);
contextMenu.contextOn(button);
var popupMenu = new jetpack.Menu(["Frumpy", "Frimpy", "Frompy"]);
popupMenu.popupOn(button);

Complete jetpacks

See a complete, real-word example that you can install in the simple storage documentation.  Check also jetpacks tagged with "tutorial" at the Jetpack Gallery.

See also

Document Tags and Contributors

 Contributors to this page: Sheppy, jswisher, Canuckistani, MykMelez, adw, kurt_cagle, Aza
 Last updated by: Sheppy,