Archive for 5th July 2009

A Wrench in the Works – Multiple Tabs in Firefox

The code from my previous post worked great with a single tab open in Firefox.  However, using multiple tabs exposed a problem – all tabs in a single Firefox window share the same status bar.  Another issue is that the event “DOMContentLoaded” gets fired any time a page finishes loading, regardless of what tab you’re on.  This means that the information in the status bar may or may not actually match the tab that you’re on.

I also found some better techniques for placing my code in a namespace/module that are described here and here.  It’s also worth noting that Mozilla’s Developer Center has documentation for their Javascript APIs and objects.  Unfortunately, the documentation usually isn’t very good and I wind up spending an awful lot of time looking for simple pieces of information.

After a bit of work, I came up with the code below to do what I wanted.  This code only works for Firefox 3.5 because that’s when event data was added for the TabOpen, TabClose, and TabSelect events.  In the code below, event.data is a BrowserTab object.

// Create a global variable for the addon
var g17of26 = {};

g17of26.eHowEarningsTracker = function ()
{
    // Private functions
    var updateStatusBar = function(msg)
    {
        var statusBar = window.document.getElementById("ehow_earnings_tracker_statusbar");

        if(statusBar)
        {
            statusBar.setAttribute("label", msg);
        }
    }

    return {  // This brace must stay on the same line as the return - it's a Javascript quirk

        // This function is called when the browser is first launched
        onBrowserLoad : function()
        {
            Application.activeWindow.events.addListener("TabOpen", g17of26.eHowEarningsTracker.onTabOpen);    
            Application.activeWindow.events.addListener("TabClose", g17of26.eHowEarningsTracker.onTabClose);
            Application.activeWindow.events.addListener("TabSelect", g17of26.eHowEarningsTracker.onTabSelect);

            Application.activeWindow.activeTab.events.addListener("load", g17of26.eHowEarningsTracker.onTabLoad);
        },

        // This function is called when the browser quits
        onBrowserUnload : function()
        {
            window.removeEventListener("load", g17of26.eHowEarningsTracker.browserLoad, false);
            window.removeEventListener("unload", g17of26.eHowEarningsTracker.browserUnload, false);        

            Application.activeWindow.events.removeListener("TabOpen", g17of26.eHowEarningsTracker.onTabOpen);
            Application.activeWindow.events.removeListener("TabClose", g17of26.eHowEarningsTracker.onTabClose);
            Application.activeWindow.events.removeListener("TabSelect", g17of26.eHowEarningsTracker.onTabSelect);
        },

        // This function is called when a tab is opened
        onTabOpen : function(event)
        {
            event.data.events.addListener("load", g17of26.eHowEarningsTracker.onTabLoad);
        },

        // This function is called when a tab is closed
        onTabClose : function(event)
        {
            event.data.events.removeListener("load", g17of26.eHowEarningsTracker.onTabLoad);
        },

        // This function is called when a tab is selected
        onTabSelect : function(event)
        {
            updateStatusBar(Application.activeWindow.activeTab.uri.spec);
        },

        // This function is called when a page finishes loading in a tab
        onTabLoad : function(event)
        {
            if(event.data.uri.spec == Application.activeWindow.activeTab.uri.spec)
            {
                updateStatusBar(event.data.uri.spec);
            }
        }
    };
}(); // the parens here cause the anonymous function to execute and return

// Hook up events
window.addEventListener("load", g17of26.eHowEarningsTracker.onBrowserLoad, false);
window.addEventListener("unload", g17of26.eHowEarningsTracker.onBrowserUnload, false);