window.open returns undefined in chrome extension
Solution 1
Note: This answer is obsolete.
window.open()
in a Chrome extension always returns eithernull
(when the popup is blocked) or awindow
object. The information below only applies to very old (2012) versions of Chrome.
Content scripts do not have any access to a page's global window
object. For content scripts, the following applies:
- The
window
variable does not refer to the page's global object. Instead, it refers to a new context, a "layer" over the page. The page's DOM is fully accessible. #execution-environment
Given a document consisting of <iframe id="frameName" src="http://domain/"></iframe>
:
- Access to the contents of a frame is restricted by the Same origin policy of the page; the permissions of your extension does not relax the policy.
-
frames[0]
andframes['frameName']
, (normally referring to the the frame's containing globalwindow
object) isundefined
. -
var iframe = document.getElementById('frameName');
-
iframe.contentDocument
returns adocument
object of the containing frame, because content scripts have access to the DOM of a page. This property isnull
when the Same origin policy applies. -
iframe.contentDocument.defaultView
(refers to thewindow
object associated with the document) is undefined. -
iframe.contentWindow
is undefined.
-
As you can see, window.open()
does not return a Window
instance (neither does window.opener
, and so forth).
Alternatives
-
Inject the code in the page, so that it runs in the context of the page. Note: Only use this method if the page you're operating on can be trusted. To communicate between the injected script and the content script, you could use:
var login_url = 'http://example.com/'; var event_name = 'robwuniq' + Math.random().toString(16); // Unique name document.addEventListener(event_name, function localName() { document.removeEventListener(event_name, localName); // Clean-up // Your logic: Backbone.history.navigate('index', true); }); // Method 2b: Inject code which runs in the context of the page var actualCode = '(' + function(login_url, event_name) { var loginWin = window.open(login_url, 'LoginWindow', "width=655,height=490"); console.log(loginWin); // Check every 100 ms if the popup is closed. var finishedInterval = setInterval(function() { console.log('checking if loginWin closed'); if (loginWin.closed) { clearInterval(finishedInterval); console.log('popup is now closed'); // Notify content script var event = document.createEvent('Events'); event.initEvent(event_name, false, false); document.dispatchEvent(event); } }, 1000); } + ')(' + JSON.stringify(login_url+'') + ', "' + event_name + '")'; var script = document.createElement('script'); script.textContent = actualCode; (document.head||document.documentElement).appendChild(script); script.parentNode.removeChild(script);
Launch the window from the background page using
window.open()
. This returns awindow
object which has a reliableclosed
property. See the next bullet point for more details on the communication flow.- From the content script, pass a message to the background page. In the background page, use
chrome.windows.create
to open a window. In the callback, assign anchrome.tabs.onRemoved
and/orchrome.tabs.onUpdated
event. When these event listeners are triggered, they should remove themselves, and notify the original caller (content script) using thesendResponse
function ofchrome.extension.onMessage
.
Solution 2
In my case, Chrome was blocking the popup and the user had to unblock by clicking the "blocked popup" icon in the upper-right corner of the window. (They can also enable/disable exceptions under "Content settings..." in Chrome settings.)
I would suggest adding some code after window.open() so that the user knows what to do. For example:
if (!loginWin)
alert("You must first unblock popups and try again for this to work!");
user1566788
Updated on July 21, 2022Comments
-
user1566788 almost 2 years
I have content script based Chrome extension. I initiate the sign in process through a popup window in the content script.
I open a popup window using the below code and then wait till its closed.
However, I get an 'undefined' from
window.open
method. Does anybody know why this happens?loginwin
isundefined
in below code although the popup window opens up fine with the specifiedlogin_url
. The code below is called from my content script.var loginWin = window.open(login_url, 'LoginWindow', "width=655,height=490"); console.log(loginWin); // Check every 100 ms if the popup is closed. var finishedInterval = setInterval(function() { console.log('checking if loginWin closed'); if (loginWin.closed) { clearInterval(finishedInterval); console.log('popup is now closed'); Backbone.history.navigate('index', true); } }, 1000);