Windows And Tabs In Fennec
My work on the windows and tabs module support for Fennec has landed! finally.
There are many differences between the two platforms related to windows and tabs, so that’s worth writing about, but most of these things are minor and I’m guessing that most use cases for the windows and tabs modules are covered for Fennec now!
What Works
windows
Typically one wants a reference to the activeWindow, that works. Why do they want a reference to the activeWindow? Well, probably to see what tabs it has, activeWindow.tabs, that works. One might also want to loop through the open windows for each (let window in require('windows').browserWindows) that works as well.
tabs
Tabs are more interesting than windows. On Fennec, you can’t open windows, so tabs are the next option, and it is the better option anyhow, so forget about using windows in any add-on that you develop, please.
var tabs = require('tabs');
tabs.open('https://mozilla.org') // works
Opening tabs works.
tabs.open({
url: 'https://mozilla.org',
inBackground: true,
onReady: function(tab) {
tab.attach({
contentScript: 'alert("hello tab ;)")'
});
}
});
Opening tabs, and saying hi via content script when the tab is ready, works.
for each (let tab in tabs) {
tab.url = 'https://mozilla.org';
}
Sending all open tabs to mozilla.org works!
tabs.on('activate', function(tab) {
borg.consume({
url: tab.url,
index: tab.index,
title: tab.title,
isPinned: tab.isPinned
})
tab.close();
});
Sending the Borg all of the data on the pages you read, works!
Oops.
What Doesn’t Work
windows
Since Fennec only has a single window, attempts to open new windows, and closing the only available open window had to be prevented. This means:
-
require('windows').activeWindow.close()won’t do anything. -
require('windows').open(URL)won’t do anything.
I thought long and hard about this. It was suggested that open would open a tab instead, then I thought about making fake windows, with fake tab collections consisting of a tab subset based on how the window was created. In this latter case, require('windows').open({url: URL, onOpen: function(window) window}), The window would be a fake window object, the window.tabs would be a subset of require('windows').activateWindow.tabs. This would mean that window.close() would only close the tab for URL.
It wasn’t a easy picture to paint, and in general opening a tab instead of a window would increase the amount of effort it would take one to understand the complexity of the API, which would be important in this case. Also it was clear that tabs is the more important module of the two, so it would be better to promote that module.
tabs
There are a number of minor things that don’t work here, and we have bugs for.
-
Setting the
tab.indexliketab.index = 1doesn’t work, it’s not yet possible to change the order of the tabs, bug 782461. -
Pinning tabs is not possible, that is bug 782819, which means opening a pinned tab does not work either.
-
Finally,
tab.faviconandtab.getThumbnail()both don’t work because they would need to be async methods, so bug 794320 is fortab.faviconand bug 791098 is fortab.getThumbnail(). I think these methods should be deprecated in favor of separate async module(s), but we’ll see.
Example: Tab Usage
Somewhere on the internet there is a video of Aza Raskin talking about a simple little Jetpack called “Tab Usage Statistics” if I recall correct. It was a simple demo for the Jetpack prototype, and since I needed a simple example for the tabs module that would work for Firefox and Fennec, I decided to rip the idea off :)
Sadly I could not just take and code and morph it for the sdk because I couldn’t find the epic source anywhere. So I moved forward and recreated it.
This add-on is called Tab Usage, it displays a graph of the number of tabs you have open over time. T0 starts when you open the graph. You open the graph via a button in the preferences for the add-on, because that was a place I could depend on for Fennec and Firefox.

The main.js file here is simple
var tabs = require("tabs");
var { setTimeout, clearTimeout } = require("timers");
var sp = require("simple-prefs");
var { data } = require("self");
var { PageMod } = require("page-mod");
var URL = data.url("page.html");
function updateTabCount() {
this.port.emit("update", tabs.length);
}
The function above will send the total number of tabs to the graph with a "update" event.
sp.on("open-page", function() {
tabs.open({
url: URL,
onReady: function(tab) {
var mod = tab.attach({
contentScriptFile: data.url("page.js"),
});
var update = updateTabCount.bind(mod);
tabs.on("open", update);
tabs.on("close", update);
mod.on("detach", function() {
tabs.removeListener("open", update);
tabs.removeListener("close", update);
});
update();
}
});
});
This simple-prefs listener is waiting for the “Open” button to be pressed, at which point it opens a new tab for the graph, when that page has loaded a content script is attached to the page which will hear the "update" event mentioned above and do the graph updates.
Summary
I hope you enjoy! It should be pretty easy to make add-ons such as Tab Usage for Firefox on Android now. I have a few more add-ons in mind which will be using tabs and they will be coming out soon!
This change will be released with v1.12 of the Add-on SDK.