views:

300

answers:

2

I am chasing down a bug in a FireFox extension. I've finally managed to see it for myself (I've only had reports before) and I can't understand how what I saw is possible.

One error message from my extension in the Error Console is "gBrowser is not defined". This by itself would be surprising enough, since the overlay is over browser.xul and navigator.xul, and I expect gBrowser to be available from both. Even worse is the actual place where it happens: line 101 of nextplease.js. That is, inside the function isTopLevelDocument, which is only called from onContentLoaded, which is only called from onLoad here:

gBrowser.addEventListener(this.loadType, function (event) {
    nextplease.loadListener.onContentLoaded(event);
},
true);

So gBrowser is defined in onLoad, but somehow undefined in isTopLevelDocument.

When I tried to actually use the extension, I got another error: "nextplease is not defined". The interesting thing is that it happened on lines 853 and 857. That is, inside the functions

nextplease.getNextLink = function () {
    nextplease.getLink(window.content, nextplease.NextPhrasesMap, nextplease.NextImagesMap, nextplease.isNextRegExp, nextplease.NEXT_SEARCH_TYPE);
}

nextplease.getPrevLink = function () {
    nextplease.getLink(window.content, nextplease.PrevPhrasesMap, nextplease.PrevImagesMap, nextplease.isPrevRegExp, nextplease.PREV_SEARCH_TYPE);
}

So nextplease is somehow defined enough to call these functions, but isn't defined inside them.

Finally, executing typeof(nextplease) in Execute JS returns "object". Same for gBrowser.

How can this happen? Any ideas?

+2  A: 

For the second case:

nextplease.getNextLink = function () {
    nextplease.getLink(window.content, nextplease.NextPhrasesMap, nextplease.NextImagesMap, nextplease.isNextRegExp, nextplease.NEXT_SEARCH_TYPE);
}

nextplease.getPrevLink = function () {
    nextplease.getLink(window.content, nextplease.PrevPhrasesMap, nextplease.PrevImagesMap, nextplease.isPrevRegExp, nextplease.PREV_SEARCH_TYPE);
}

I'd try this instead:

nextplease.getNextLink = function () {
    this.getLink(window.content, this.NextPhrasesMap, this.NextImagesMap, this.isNextRegExp, this.NEXT_SEARCH_TYPE);
}

nextplease.getPrevLink = function () {
    this.getLink(window.content, this.PrevPhrasesMap, this.PrevImagesMap, this.isPrevRegExp, this.PREV_SEARCH_TYPE);
}
Mr. Shiny and New
That might be worth a try.
Alexey Romanov
+1  A: 

I'm not sure what's happening (in which context the code is running and therefore why it's not seeing the gbrowser and other global variables) but an easy workaround for gbrowser being undefined would be to get a reference to the main window and access it from there:

var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                     .getInterface(Components.interfaces.nsIWebNavigation)
                     .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
                     .rootTreeItem
                     .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                     .getInterface(Components.interfaces.nsIDOMWindow);

mainWindow.gbrowser.addEventListener( ... )

This should work independently of the context where the code is running since you would not rely on global variables.

fms