Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objects in JavaScript defined and undefined at the same time (in a FireFox extension)

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?

like image 326
Alexey Romanov Avatar asked Feb 22 '10 23:02

Alexey Romanov


People also ask

What are the problems with JavaScript?

These days, most cross-browser JavaScript problems are seen: When poor-quality browser-sniffing code, feature-detection code, and vendor prefix usage block browsers from running code they could otherwise use just fine. When developers make use of new/nascent JavaScript features, modern Web APIs, etc.)

Why does JavaScript sometimes not work?

If there is no error in console and still JS code not working, may be you have not invoked the code. Check if the code is reachable. If none of the above works, there is a possibility that JS is disabled in the browser you are trying to run the code. Enabling JS should work.

What does it mean when something is not defined in JavaScript?

The JavaScript exception "variable is not defined" occurs when there is a non-existent variable referenced somewhere.

What is use of in JS?

The JavaScript in operator is used to check if a specified property exists in an object or in its inherited properties (in other words, its prototype chain). The in operator returns true if the specified property exists. Anatomy of a simple JavaScript object.


2 Answers

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);
}
like image 145
Mr. Shiny and New 安宇 Avatar answered Sep 30 '22 17:09

Mr. Shiny and New 安宇


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.

like image 22
flpmor Avatar answered Sep 30 '22 17:09

flpmor