nsIWebProgressListener and Add-on SDK (jpm)

I’m developing my first add-on with Add-on SDK, jpm (because i need to support old versions of Firefox)

I need to track URL changes in address bar, i have found that such thing can be done with using of a nsIWebProgressListener interface. I was not able to apply snippets from web (stackoverflow, mozilla site, etc), for some reason they don’t works for me.

Please, show me a working example use of nsIWebProgressListener for add-on SDK project.

Here is an example of mine. It is in an object progressListener - https://github.com/Noitidart/NativeShot/blob/master/resources/scripts/MainFramescript.js#L256-L336

As you see, it’s run from a framescript, so its local to the tab. Then you see on startup I do progressListener.register() and on shutdown I do progressListener.unregister(). It is seriously awesome stuff!

Thank you. The next problem is docShell, i don’t know how use it with SDK…

You get this from the framescript:

As we see on the docs its a global docShell.

But it turns out that Add-on SDK uses content scripts preferentially , not frame scripts (https://developer.mozilla.org/en-US/Add-ons/SDK/High-Level_APIs/page-mod). Content scripts have not access to frame script environment, including docShell. May be, is it possible to get access to docShell in the main add-on script (main.js, bootstrap.js)?

APIs that need direct access to the web content are only available in the content process(es) and not in the background process (once e10s is active).

If those APIs are not exposed to content scripts (very few are) than the only way to (reliably) access them is through process/frame scripts.

Setting up a framescript unfortunately isn’t nearly as trivial as attaching a content script. If you want to you can use most of the code from this folder almost without modifications: sdk (the content/ folder and the attach.js contains the relevant parts).

1 Like

To use a framescript from SDK do it like this:

var { Cu } = require('chrome');
Services.mm.loadFrameScript(self.data.url('my-framescript.js'), true);

The SDK actually has very nice infrastructure for frame scripts, including messaging, which will also load it within an SDK context, which this does not. I would thus say @NilkasG’s solution to try and re-use the SDK’s frame script infrastructure is superior. As I’ve not used it actively before I can not provide an equivalent snippet, so if anyone else can, that’d probably be appreciated.

nsIWebProgressListener can be used from either the parent process or the content process. In the parent process, you will not have access (except through shims) to the content window and its children. In the content process, you can access all that, but there are other APIs that you won’t be able to use. It depends what you wish to do when your listener is called.

When deciding where your progress listener should be placed, it is important to realise that there are three different kinds of progress listener: gBrowser.addTabsProgressListener; gBrowser.addProgressListener; and browser.addProgressListener. Note that not all of them strictly use the nsIWebProgressListener interface although they all look as if they do. There are lots of examples, but they don’t usually make it clear which type of progress listener is being used and why. addTabsProgressListener has some very useful “extras” such as onLocationChange() from tab switches, but obviously can’t be used in the content process.

Pick the right kind of listener for what you need and use it in the right place, it will save a whole bunch of headaches down the road.

2 Likes