What's in an Opera extension?

By Chris Mills

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.

Contents

Introduction

In this article we give you an overview of what is included inside an Opera Extension, and we'll have a brief look at some of the APIs. You'll find more extensive Opera Extensions API reference documentation.

Extension files

Opera extensions are based on the W3C Widgets specification (e.g. for features like the config.xml). An extension can contain all of the following files:

  • /config.xml
  • /index.html
  • /background.js
  • /popup.html
  • /icons/example.png
  • /locales/no/index.html
  • /locales/no/background.js
  • /locales/no/popup.html
  • /options.html

Let's go through these parts in turn and explain what they do:

config.xml

This is the configuration file, which provides valuable meta data for the extension — this is actually one of the two only mandatory part of the extension package (the other is the index.html), although you won't be able to get it to do very much on its own. Since Opera extensions are based on W3C Widgets, the config.xml files are the same — see the W3C Widgets spec configuration document section. There are lots of different things you could include in here, and we would recommend that you include at least the following:

  • Name of extension
  • Unique ID to identify your extension, ideally a URL
  • Author name
  • Description
  • Icon: this is to be used in the Opera extensions download site, and other places. See the section on icons below.

Here’s an example config.xml file:

<?xml version="1.0" encoding="utf-8"?>
<widget xmlns="http://www.w3.org/ns/widgets"
           id="http://www.example.org/example">
  <name>My test extension</name>
  <description>API experiments and testing.</description>
  <author href="http://foo-bar.example.org/"
          email="foo-bar@example.org">Foo Bar Corp</author>
  <icon src="icons/example.png"/>
</widget>

Additional functionality can be enabled by adding <feature> elements to the config.xml, for example, cookie sharing, content blocking, and enabling an extension to live in the Speed Dial. See The ins and outs of config.xml for a more details.

index.html

In widget speak, this is called a "start file". A start file is always needed and serves as the extension's background process (if you want, you can point to a different file using a <content> element in the config.xml).

This file can also include JavaScript to create UIItems like the UI button and callout. For example:

<!doctype html>
<html>
  <head>
    <script>
      window.addEventListener("load", function(){
        var theButton;
        var UIItemProperties = {
          disabled: false,
          title: "101 - createItem w popup big",
          icon: "icon.png",
          popup: {
            href: "popup.html",
            width: 250,
            height: 500
          }
        }
        theButton = opera.contexts.toolbar.createItem( UIItemProperties );
        opera.contexts.toolbar.addItem( theButton );
      }, false);
    </script>
  </head>
  <body>
  </body>
</html>

background.js

Here is where you include your so-called background scripts, which control the extension's background process. Note that you can have as many as you like, and you don't have to call them background.js.

This file (or files — you can have more than one in a single extension) simply contains the contents of the popup window(s) triggered from the background process. Note that instead of having a popup window specified in one of these files, you can instead specify an external URL as the contents of one of these popups, e.g. http://www.opera.com.

icons/example.png

This includes an icon to be used in the extension (see the icons section below for more details).

includes (injected scripts)

Any JS files in this folder will be injected to pages you visit while browsing. These files can be made to target certain sites, like youtube.com. To learn more about how injected scripts work, visit our UserJS documentation pages.

locales

The contents of the locales directory are optional translations for when you have an extension you want to provide translated versions for. Inside the locales directory you provide a separate directory for each translation, named the same as the language code for that language and dialect. For example, in our above directory tree we have provided a no folder for a Norwegian translation, but you could provide en-gb, pt-br, ru, cz, jp, and as many others as you like (note that they should always be kept lower case, to avoid compatibility problems - this is required by the W3C Widgets Packaging specification). Inside each folder you provide translated alternatives to your default index.html, injectables, etc.

An Opera Extension's UI is constructed from the UI elements added to a webpage via injected scripts, the buttons in Opera's toolbar, which are created using the UIItems API in the background process, and Popups, which, as explained below, are populated from supplied HTML documents or an external website via its URL.

options.html

When the browser finds an options.html file in the extension, it makes a "Preferences" option available for that extension in the extension manager (Tools > Extensions > Manage Extensions). That way, when a user clicks on the extension's "Preferences" dropdown menu item in the extensions manager, the browser will fire up its options page.

Generally, the options page is used for setting preferences or notes such as acknowledgements. Take a look at the Opera extensions options page article for a more detailed explanation.

Breakdown of architecture and APIs

The architecture of an Opera Extension involves the interaction of the following four basic parts:

Injected script <-> Background Process <-> Button/badge <-> Popup
These parts communicate through cross-document messaging, and do the following:

Injected scripts

This part provides the scripting that gets injected to targeted sites.

Background Process

The background process is what weaves the architecture together — this is the central place where all messaging is routed through, and where most of the interaction with the Extension APIs occurs. The background process triggers the creation of UI items further down the chain via the following methods:

  • opera.contexts.toolbar.createItem( { ...properties... } )
  • opera.contexts.toolbar.addItem( uiItem )
  • opera.contexts.toolbar.removeItem( uiItem )

Note: toolbar is currently the only context available, but more of these will be available later.

Button/Badge

This is where the UI elements of the extension are put together and displayed, for example buttons that you press, badges that display information, and in future releases, menu items.

Buttons

You can create a button for the browser toolbar by using the opera.contexts.toolbar.createItem() function, and then add it using opera.contexts.toolbar.addItem(). Here's an example index.html file that simply adds a button, and fires a callout when the button is clicked:

<!doctype html>
<html>
  <head>
    <script>
      window.addEventListener("load", function(){

        var theButton; // the button variable
        var toolbar = opera.contexts.toolbar; //the Opera toolbar

        var props = { // options for the button
          disabled: false,
          title: "My first extension!",
          icon: "opera.ico",
          popup: {
            href: "http://www.google.com",
            width: 300,
            height: 200
          }
        }

        theButton = toolbar.createItem( props ); // create the button

        toolbar.addItem( theButton ); // add button to UI

      }, false);
    </script>
  </head>
  <body>
  </body>
</html>

You can remove the button using the function opera.contexts.toolbar.removeItem(theButton);. You can also handle onclick events on the button by adding onclick: function(){ /* do something */ } to the button.

Icons

If you include a button in the UI, you should include an icon for it. The button icon is rendered 18 x 18 pixels in size, and anything above or below this will be scaled. For best results we recommend that you supply an icon that is exactly 18 x 18 pixels.

Additionally, you will be asked to supply an icon that is 64 x 64 pixels or larger when uploading your extension to our Opera extensions website. This icon will be used in our online catalog next to a title and description of the extension, as well as in the Opera Extension manager in the browser. The title, description, and path to the icon are stored in and retrieved from the config.xml.

Popups

Popups can be defined by simply adding the popup properties when creating a button:

var props = { // options for the button
  disabled: false,
  title: "My first extension!",
  icon: "opera.ico",
  popup: {
    href: "http://www.google.com",
    width: 300,
    height: 200
  }
}

The above example will create a popup containing the google.com home page. You can also define a local HTML page as the contents of the popup, for example:

popup: {
  href: "popup.html",
  width: 300,
  height: 300
}

Badges

A badge is a notification that appears as an overlay on top of an extension button. You add badges by making a dictionary of properties for your button:

var props = { // options for the button
  disabled: false,
  title: "My first extension!",
  icon: "opera.ico",
  popup: {
    href: "popup.html",
    width: 300,
    height: 200
  },
  badge: {
    textContent: '123'
  }
}

You can also customize the background and foreground color of the badge using the simple style properties, like so:

backgroundColor: '#ffeedd',
color: '#404040',

Finally, the content of the badge can be updated by changing textContent property:

theButton.badge.textContent = "45"

Different types of extension

There are many different types of extension you could build, although the functionality required for all of these is not yet available. We will update this and provide more tutorials in later release phases. Essentially, the different parts of the extensions architecture approximate to this:

Injected script <-> Background <-> Button/badge <-> Popup

The different types of extension you can build are different permutations of these components:

  1. Injected script + index.html: This is just an injected script, and an empty index.html + config.xml, packaged up as an extension. It will work fine, but it won't take advantage of any of the extension-specific APIs and other features.
  2. Button + Popup: You can write an extension that creates a button in Opera's toolbar, which when clicked creates a popup with a third-party URL. For example, you could create a popup frame containing mobile-specific web pages so you could use them on your desktop.
  3. A bookmarklet extension: You can write an extension that, when clicked, executes a bookmarklet function from the background process, performing it on the current tab, rather than having to do it with a javascript: URL in the address bar.
  4. Content analysis: An extension could be made so that the injected script processes the DOM and send resulting data to the background process, to send it to the button/popup when the time is right.
  5. Content-aware action: You can write an extension to create a button that, when clicked, posts a message to the injected script, which then triggers a method there, and sends the data back along the chain to be used by the popup, and so on. For example, selecting an address on a page, clicking a "Map" button, and having a Google map of the address appear in a popup window.
  6. Auto-action: The background process can regularly poll a service and update the badge with information, for example polling your mail service and displaying your unread mail count in a badge on the UI.

Note: The background has cross-domain XHR abilities, just like widgets. To find more out about using cross-domain XHR, read our article Opera Widgets and Ajax connecting to multiple servers.

Chris Mills is a web technologist, open standards evangelist and education agitator, currently working at Opera Software in the developer relations team. He spends most of his time writing articles about web standards for dev.opera.com and other publications (such as .net mag and A List Apart), giving talks at universities and industry conferences, and lobbying universities to improve their web education courses. He believes that education is the answer to everything, but in particular he is passionate about using education to improve the overall content quality, accessibility, usability and future-viability of the Web.

He is the creator of the Opera Web standards curriculum, contributor to the WaSP InterACT project, and coauthor of InterACT with web standards: A Holistic Approach to Web Design. In August 2011, he also accepted the position of co-chair of the newly-formed Web Education Community Group.

Outside work he is a heavy metal drummer, proud father of three and lover of good beer.


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

Comments

The forum archive of this article is still available on My Opera.

No new comments accepted.