window.open returns undefined in chrome extension

醉酒当歌 提交于 2019-11-29 10:22:06
Rob W

Note: This answer is obsolete. window.open() in a Chrome extension always returns either null (when the popup is blocked) or a window 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] and frames['frameName'], (normally referring to the the frame's containing global window object) is undefined.
  • var iframe = document.getElementById('frameName');
    • iframe.contentDocument returns a document object of the containing frame, because content scripts have access to the DOM of a page. This property is null when the Same origin policy applies.
    • iframe.contentDocument.defaultView (refers to the window 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 a window object which has a reliable closed 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 an chrome.tabs.onRemoved and/or chrome.tabs.onUpdated event. When these event listeners are triggered, they should remove themselves, and notify the original caller (content script) using the sendResponse function of chrome.extension.onMessage.

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!");
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!