Progress Listeners

Progress Listeners

Progress listeners allow extensions to be notified of events associated with documents loading in the browser and with tab switching events. Progress listeners implement the nsIWebProgressListener interface.

Note that if you just want to execute your code each time a page loads, you can use an an easier method, onPageLoad(). Note that onPageLoad does not fire for back button clicks.

In the examples below the progress listener is attached to the tabbrowser, which means you don't get any notifications for inactive tabs. Firefox 3.5 includes a way to set up a listener for all tabs, selected and not: Listening to events on all tabs.

Example

  1. Create an object which implements nsIWebProgressListener:
    const STATE_START = Ci.nsIWebProgressListener.STATE_START;
    const STATE_STOP = Ci.nsIWebProgressListener.STATE_STOP;
    var myListener = {
        QueryInterface: XPCOMUtils.generateQI(["nsIWebProgressListener",
                                               "nsISupportsWeakReference"]),
    
        onStateChange: function(aWebProgress, aRequest, aFlag, aStatus) {
            // If you use myListener for more than one tab/window, use
            // aWebProgress.DOMWindow to obtain the tab/window which triggers the state change
            if (aFlag & STATE_START) {
                // This fires when the load event is initiated
            }
            if (aFlag & STATE_STOP) {
                // This fires when the load finishes
            }
        },
    
        onLocationChange: function(aProgress, aRequest, aURI) {
            // This fires when the location bar changes; that is load event is confirmed
            // or when the user switches tabs. If you use myListener for more than one tab/window,
            // use aProgress.DOMWindow to obtain the tab/window which triggered the change.
        },
    
        // For definitions of the remaining functions see related documentation
        onProgressChange: function(aWebProgress, aRequest, curSelf, maxSelf, curTot, maxTot) {},
        onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage) {},
        onSecurityChange: function(aWebProgress, aRequest, aState) {}
    }
  2. Attach the progress listener to a <browser> or a <tabbrowser> element using AddProgressListener, for example for Firefox put the following code in a load listener of a main window:
    gBrowser.addProgressListener(myListener);

    When used with a browser, the second argument is a mask which determines the type of events that will be received. Note that the browser uses a weak reference to your listener object, so make sure to keep an external reference to your object to ensure that it stays in memory.

    When used with a tabbrowser, you cannot choose which types of events that will be received. Instead, you receive those events that the tabbrowser is interested in, except that the onLinkIconAvailable and onRefreshAttempted notifications are optional. The tabbrowser uses a strong reference to your listener object.

Gecko 2.0 note

Starting in Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1), all events are optional. The tabbrowser only notifies you of the events for which you provide a callback.

Remember to change myListener to a unique identifier.

Example: Notification when the value in Address Bar changes

A commonly asked question is how to get notified whenever the URL in the address bar (also known as location bar) changes. Using the following code, you will get notified when user navigates to another page (by clicking a link, using the back/forward button, by typing an address in the Location Bar, etc.) and also when user switches tabs.

var myExtension = {
    oldURL: null,

    init: function() {
        gBrowser.addProgressListener(this);
    },

    uninit: function() {
        gBrowser.removeProgressListener(this);
    },

    processNewURL: function(aURI) {
        if (aURI.spec == this.oldURL) return;

        // now we know the url is new...
        alert(aURI.spec);
        this.oldURL = aURI.spec;
    },

    // nsIWebProgressListener
    QueryInterface: XPCOMUtils.generateQI(["nsIWebProgressListener",
                                           "nsISupportsWeakReference"]),

    onLocationChange: function(aProgress, aRequest, aURI) {
        this.processNewURL(aURI);
    },

    onStateChange: function() {},
    onProgressChange: function() {},
    onStatusChange: function() {},
    onSecurityChange: function() {}
};

window.addEventListener("load", function() { myExtension.init() }, false);
window.addEventListener("unload", function() { myExtension.uninit() }, false);

Note: If you use the same listener for more than one tab/window, use aWebProgress.DOMWindow in the callback methods to obtain the tab/window which triggers the state change or event.

Example: Example of listener for anchor change

The above example "Notification when the value in Address Bar changes" fires multiple times, one of which is when the tab is changed. In some cases you want to catch only a location change when the anchor changes. To do this the optional aFlags parameter of the onLocationChange listener is used.

var myExt_urlBarListener = {
    onLocationChange: function (aProgress, aRequest, aURI, aFlags) {
        if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
            //anchor clicked!
            var domWin = aProgress.DOMWindow;
            var domDoc = domWin.document;
        }
    }
};

You can learn about this here: nsIWebProgressListener - Location Change Flags