Context Menu API

By Opera Software

From Opera 15 onward, Opera 11 & 12’s extension format is no longer supported, and instead, we’ve switched to Chromium’s extension model. Check out our new documentation for developing extensions for Opera 15 and higher and start building your own extensions.

opera.contexts.menu.createItem()
Creates a new MenuItem available for use in the context menu.
opera.contexts.menu.addItem()
Add a specified MenuItem to the context menu.
opera.contexts.menu.item()
Returns the specified node in a collection of MenuItem objects.
opera.contexts.menu.removeItem()
Remove a specified MenuItem from the context menu.
opera.contexts.menu.length
A read-only property representing the number of MenuItem objects in a collection.
opera.contexts.menu.onclick
A click event handler for the context menu, containing a MenuEvent.
MenuItem.addItem()
Add a specified MenuItem to an existing MenuItem.
MenuItem.item()
Returns the specified node in a collection of MenuItem objects.
MenuItem.removeItem()
Remove a specified MenuItem from an existing MenuItem.
MenuItem.contexts
An attribute defining the contexts in which a MenuItem should appear, e.g. "page", "link", "image", etc.
MenuItem.disabled
An attribute defining whether a button is disabled. Set to false by default (meaning the item is enabled).
MenuItem.documentURLPatterns
An attribute defining which domains a MenuItem should be activated for.
MenuItem.icon
The URL of the MenuItem's icon.
MenuItem.id
A property representing the id of the MenuItem.
MenuItem.onclick
A click event handler for a MenuItem, containing a MenuEvent.
MenuItem.parent
A read-only property representing the parent object of the MenuItem, set to null by default.
MenuItem.targetURLPatterns
An attribute defining which hyperlink target domains a MenuItem should be activated for.
MenuItem.title
The title of the MenuItem shown to the user.
MenuItem.type
A property representing the type of the MenuItem.
MenuEvent.documentURL
The containing frame URL of the element on which a MenuEvent was activated.
MenuEvent.isEditable
Whether the element on which a MenuEvent was activated is editable or not.
MenuEvent.linkURL
The link URL of the element on which a MenuEvent was activated.
MenuEvent.mediaType
The type of media on which a MenuEvent was activated.
MenuEvent.pageURL
The URL of the top-level document of the current web page.
MenuEvent.selectionText
The run of text selected by the user.
MenuEvent.source
A MessagePort to the tab in which a MenuEvent was fired.
MenuEvent.srcElement
The in-page DOMNode object on which a MenuEvent was fired.
MenuEvent.srcURL
The value of an element's src attribute on which a MenuEvent was activated.
MenuEvent.target
A MenuItemProxy object created from the MenuItem object on which the event was fired.

Overview

The Context Menu API enables an extension to add an item to the context menu, otherwise known as the right-click menu. An extension may only add one item to the context menu, but this item may contain various layers of sub-items, similar to a folder/sub-folder structure. You can specify whether a context menu item should only appear on certain domains or on certain types of element, e.g. links only, images only, etc. When a context menu item is clicked, it is possible to get data such as the URL of the current element or any text the user has selected.

Menu items can only be created within an extension's background process, but the opera.contexts.menu object is also accessible from injected scripts, for example using a click event listener. It's also possible to pass messages between a MenuItem and an injected script using the MenuEvent's source attribute. See the examples below and in the individual method/attribute pages.

To enable the context menu, the opera:contextmenus feature needs to be added as a feature element to the extension's config.xml file.

Examples

What follows are some examples designed to make clear the major use cases of the Context Menu API.

Example 1: Background process only

In this example, a menu item is added to the context menu for any domain. When the menu item is clicked, the current page opens in a new private tab.

<!-- 
  The configuration file ('config.xml').
-->
<?xml version='1.0' encoding='utf-8'?>
<widget xmlns="http://www.w3.org/ns/widgets">
    ...
    <feature name="opera:contextmenus"/>
    ...
</widget>
//
// The background process (e.g. '/background.js'). 
//

window.addEventListener('DOMContentLoaded', function() {
  // Check the Context Menu API is supported
  if (opera.contexts.menu) {
    var menu = opera.contexts.menu;
    // Create a menu item properties object
    var itemProps = {
      title: 'Privatize',
      onclick: function(event) {
        // Create a tab properties object
        var tabProps = {
          url: event.pageURL,
          private: true
        };

        // Create a tab with the specified properties
        var tab = opera.extension.tabs.create(tabProps);
      }
    }

    // Create a menu item with the specified properties
    var item = menu.createItem(itemProps);
    // Add the menu item to the context menu
    menu.addItem(item);
  } else {
      console.error('Context Menu API not supported.');
  }
}, false);

Example 2: Background process and injected script

In this example, a menu item is added to the context menu for editable elements only. When the menu item is clicked, a message is sent to the current tab's injected script. The message data (an email address) is then inserted into the editable element.

<!-- 
  The configuration file ('config.xml').
-->
<?xml version='1.0' encoding='utf-8'?>
<widget xmlns="http://www.w3.org/ns/widgets">
    ...
    <feature name="opera:contextmenus"/>
    ...
</widget>
//
// The background process (e.g. '/background.js'). 
//

window.addEventListener('DOMContentLoaded', function() {
  // Check the Context Menu API is supported
  if (opera.contexts.menu) {
    var menu = opera.contexts.menu;
    var mail = 'operafan@example.com';

    // Create a menu item properties object
    var itemProps = {
      contexts: ['editable'],
      title: 'Mail autofill',
      onclick: function(event) {
        // Send a message to the injected script in the originating tab
        event.source.postMessage({message: mail});
      }
    }

    // Create a menu item with the specified properties
    var item = menu.createItem(itemProps);
    // Add the menu item to the context menu
    menu.addItem(item);
  }
}, false);
//
// An injected script (e.g. '/includes/injected.js').
//

(function() {
  // Listen for the context menu being clicked
  opera.contexts.menu.onclick = function(menuEvent) {

    // Listen for a message from the background process
    opera.extension.addEventListener('message', function(event) {
      // Insert message from the event.data object into the source element
      menuEvent.srcElement.value = event.data.message;
    }, false);
  };
})();

This article is licensed under a Creative Commons Attribution 3.0 Unported license.

Comments

  • photo

    Martin Kadlec

    Sunday, September 9, 2012

    Possibility to add item to context menu of the extension button would be also great. :)
  • photo

    Daniel Davis

    Monday, September 17, 2012

    Hi Martin,
    Thanks for the suggestion - that's a good idea. I'll raise this with the extensions team later in the week.
    Daniel
  • photo

    Christoph

    Sunday, November 4, 2012

    IMHO the implementation of document.oncontextmenu interaction with this API is wrong. The context menu event is cancelable. Thus, the event is fired before the context menu opens, which is correct and can be seen if you assign an "alert()" to it.
    However, if you manipulate the context menu within the assigned function, the change will not be instantaneous but it will only be visible in subsequent invocations!
    Please fix this! It'll give us the opportunity to make adjustments to the entries in the moment it is needed (I'm doing that by listening to rightclicks atm, which is OK, but not optimal)
  • photo

    Matthew Wilcoxson

    Thursday, November 15, 2012

    Can we also add menuitems to the right click of a speeddial extension please!
No new comments accepted.