Javascript 在Firefox无重启插件中,当新窗口打开时,如何运行代码(侦听窗口打开)?

Javascript 在Firefox无重启插件中,当新窗口打开时,如何运行代码(侦听窗口打开)?,javascript,firefox-addon,firefox-addon-restartless,Javascript,Firefox Addon,Firefox Addon Restartless,我开始构建一个无重启的Firefox插件,但我在设置bootstrap.js时遇到了问题。每个人似乎都同意bootstrap.js的核心几乎都是样板代码,大致如下: const Cc = Components.classes; const Ci = Components.interfaces; function startup() { let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindow

我开始构建一个无重启的Firefox插件,但我在设置bootstrap.js时遇到了问题。每个人似乎都同意bootstrap.js的核心几乎都是样板代码,大致如下:

const Cc = Components.classes;
const Ci = Components.interfaces;

function startup() {
  let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
  let windows = wm.getEnumerator("navigator:browser");
  while (windows.hasMoreElements()) {
    let domWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow); 
    // then can control what happens with domWindow.document
  } 
}
function shutdown() {}
function install() {}
function uninstall() {}
这段代码有效,我可以控制现有窗口中的内容。例如,
domWindow.alert(“text”)
成功地在当前打开的每个窗口上创建了一个标准警报,上面写着“text”

但是,我找不到任何允许我在新窗口中操作的代码;i、 e.脚本运行后创建的。什么是正确的方法来处理新窗口的创建并获得对它们的控制,从而在创建时可以从其中一个窗口获得另一个“文本”警报

编辑:使用nsWindowMediator类和MDN中的代码示例,我现在有了以下内容:

var windowListener = {
onOpenWindow: function (aWindow) {
  try {
    let domWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
    domWindow.addEventListener("load", function () {
      domWindow.removeEventListener("load", arguments.callee, false);
      //window has now loaded now do stuff to it
      domWindow.alert("text");
    }, false);
  } catch (err) {
    Services.prompt.alert(null, "Error", err);
  }
},
onCloseWindow: function (aWindow) {},
onWindowTitleChange: function (aWindow, aTitle) {}
};

function startup(aData, aReason) {
  // Load into any existing windows
  try {
    let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
    let windows = wm.getEnumerator("navigator:browser");
    while (windows.hasMoreElements()) {
      let domWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
      loadIntoWindow(domWindow);
    }
  } catch (err) {
    Services.prompt.alert(null, "Error", err);
  }

  Services.wm.addListener(windowListener);
}
但是,onOpenWindow调用仍然没有输出-catch块中不会出现“文本”警报,也不会出现错误警报。我可以确认onOpenWindow实际上正在输入;如果我在onOpenWindow的开头放置了一个
Services.prompt.alert()
,则在创建新窗口时会收到该警报。不幸的是,我得到了一个无限的警报循环,我不知道为什么

但是,我找不到任何允许我在新窗口中操作的代码

在使用XPCOM对象时,通常需要研究它们的接口,这些接口通常可以在MDN上找到。在这种情况下,您的起点是,因为这是您在第5行中使用的服务

正如您所看到的,它有一个
addListener
函数,它接受一个实现
nsiWindowMediaListener
的参数。页面上有一个代码示例

但是让我们假设目前没有一个代码示例。您可以在MDN上搜索接口,但它没有列出。下一步是。idl=

一旦获得了接口契约,您就可以或多或少地用javascript实现它,至少对于侦听器是这样。实现您自己的xpcom服务将非常困难

也可以提供一些提示。在本例中,他们似乎没有使用
.addListener
,但该文件提示了另一个有趣的服务,您可以在MDN上找到它:

基本上,如果你写的是无重启插件,你就是在翻找firefox的内部,需要做一些检测工作才能找到你需要的确切组件。如果你想要更方便的东西,我建议你使用插件sdk,它提供了一套更有组织但也更受限制的

但是,我找不到任何允许我在新窗口中操作的代码;i、 e.脚本运行后创建的。什么是正确的方法来处理新窗口的创建并获得对它们的控制,从而在创建时可以从其中一个窗口获得另一个“文本”警报

当每个窗口打开时,正确的操作方法是使用from。下面的示例代码就是这样做的。nsIWindowMediator包含在中,可通过
Services.wm.addListener(WindowListener)
访问。为了使用窗口侦听器,必须向其传递一个()对象。NSIWindowMediaListener包含三个键:
onOpenWindow
onCloseWindow
onWindowTitleChange
。每一个都应定义为一个函数,当适当的事件发生时将调用该函数

“”中的MDN文档包含一个basic示例,它将为当前打开的每个浏览器窗口和将来打开的任何浏览器窗口运行函数
loadIntoWindow(window)
中的代码。我在几个不同的附加组件中使用了由此修改的代码。该示例与您正在使用的代码基本相似。示例如下(稍作修改):

虽然在bootstrap.js代码中还有很多您可能想做的事情,但上面的代码组织得相当好,并将所有要加载到Firefox UI中的代码都保存在
loadIntoWindow(window)
中,并在
unloadFromWindow(window)
中卸载UI。但是,需要注意的是,某些UI元素只需添加/删除一次(例如,australis小部件,如按钮),其他元素(例如,对Firefox DOM的直接更改)必须在每个窗口中添加一次

不幸的是,我得到了一个无限的警报循环,我不知道为什么

此示例与您当前使用的示例之间的一个显著差异是对已打开窗口类型的测试。这样做是为了我们只对新打开的窗口(即浏览器窗口)而不是所有新打开的窗口进行操作:

if (window.document.documentElement.getAttribute("windowtype") == "navigator:browser")
    loadIntoWindow(window);
您描述的获取无限循环的
alert()
弹出窗口的问题是由于未检查以确保您仅在浏览器窗口上执行操作而导致的。
alert()
弹出窗口是一个窗口。因此,您正在为每个打开的
alert()
窗口调用
alert()
,当然,该窗口只会打开另一个调用
alert()
alert()窗口。这是你的无限循环

其他参考资料:

1.

这显示了一个简单的演示如何搞乱窗口:这一个为所有窗口添加了一个热键为什么要使用所有这些
alert
s?我们生活在21世纪,我们有
console.log
dump()
。还有一个编辑,它显著地改变了问题的内容(从“打开新窗口时如何运行代码?”改为“这里包含代码,为什么我会有无限的警报循环?”。另一次,问一个新问题比把你的问题改成明显不同的问题更合适。考虑到它们是相关的,从新问题链接到这个问题是合适的。所以我试着
if (window.document.documentElement.getAttribute("windowtype") == "navigator:browser")
    loadIntoWindow(window);