Mozilla 扩展:如何在后台脚本中获取 window 对象

Mozilla extension: How to get a window object in Background script

我想在 Firefox Extension 中使用不同的 XPCOM 接口,这里是从他们的 API:

中获取的示例
var domWindowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                     .getInterface(Components.interfaces.nsIDOMWindowUtils);

但我不能在后台脚本中使用它,因为对象 Window 未定义:

window.QueryInterface is not a function

请指导我正确的方向。

P.S。后台脚本在全局范围内实际可用的是什么?我似乎无法在文档中找到任何线索。

问题是 Firefox 扩展不会 运行 在任何特定 window 的上下文中。因此,他们通常没有定义 window 对象,或者如果您不熟悉编写扩展代码,它被定义为您不期望的东西。如果您是从编写 JavaScript 以在 HTML 页面中使用的角度来看这一点,则尤其如此。扩展程序在一个更大的上下文中运行,其中包括整个浏览器和所有 windows 和选项卡。因此,没有自动适当的 window 用作 window 对象。在扩展的上下文中,每个 HTML 页面只是整体的一部分。

您可以通过使用nsIWindowMediator. The following function, from MDN获取每个主浏览器window,每次打开window时将运行您传递给它的函数一次:

Components.utils.import("resource://gre/modules/Services.jsm");
function forEachOpenWindow(todo)  // Apply a function to all open browser windows
{
    var windows = Services.wm.getEnumerator("navigator:browser");
    while (windows.hasMoreElements())
      todo(windows.getNext().QueryInterface(Components.interfaces.nsIDOMWindow));
}

您通常希望找到用户最近访问的 browser/tab 的 window。以下代码将定义 window 变量并将其设置为最近使用的 browser/tab。它将在附加 SDK 或 overlay/bootstrap 扩展中运行,具体取决于您取消注释的部分。

有关在 Firefox 扩展中使用 windows 的更多信息,您应该查看 Working with windows in chrome code and perhaps Tabbed browser

if (window === null || typeof window !== "object") {
    //If you do not already have a window reference, you need to obtain one:
    //  Add a "/" to un-comment the code appropriate for your add-on type.
    /* Add-on SDK:
    var window = require('sdk/window/utils').getMostRecentBrowserWindow();
    //*/
    /* Overlay and bootstrap (from almost any context/scope):
    var window=Components.classes["@mozilla.org/appshell/window-mediator;1"]
                         .getService(Components.interfaces.nsIWindowMediator)
                         .getMostRecentWindow("navigator:browser");        
    //*/
}

交替使用Services.jsm to access nsIWindowMediator

/* Overlay and bootstrap:
Components.utils.import("resource://gre/modules/Services.jsm");
//*/
if (window === null || typeof window !== "object") {
    //If you do not already have a window reference, you need to obtain one:
    //  Add a "/" to un-comment the code appropriate for your add-on type.
    /* Add-on SDK:
    var window = require('sdk/window/utils').getMostRecentBrowserWindow();
    //*/
    /* Overlay and bootstrap (from almost any context/scope):
    var window = Services.wm.getMostRecentWindow("navigator:browser");
    //*/
}

以下是一些可能有用的附加变量,具体取决于您在做什么:

if (typeof document === "undefined") {
    //If there is no document defined, get it
    var document = window.content.document;
}

if (typeof gBrowser === "undefined") {
    //If there is no gBrowser defined, get it
    var gBrowser = window.gBrowser;
}

var tab = gBrowser.selectedTab;
var browserForTab = gBrowser.getBrowserForTab( tab );
var notificationBox = gBrowser.getNotificationBox( browserForTab );
var ownerDocument = gBrowser.ownerDocument;

注意:本回答的内容主要取自我的回答here and here, but is based on code from MDN. For me, the code to traverse all open browser windows has its origin in the original article the MDN article How to convert an overlay extension to restartless是基于.

一种快速而肮脏的测试方式,有时真正的应用是 Services.wm.getMostRecentWindow('navigator:browser'),或者您可以使用 null 或任何其他 windowType