简体   繁体   English

在Firefox重新启动加载项中,如何在打开新窗口(监听窗口打开)时运行代码?

[英]In a Firefox restartless add-on, how do I run code when a new window opens (listen for window open)?

I am starting to build a restartless Firefox add-on and I am having trouble setting up the bootstrap.js. 我开始构建一个不会重启的Firefox插件,并且无法设置bootstrap.js。 Everyone seems to agree that the core of a bootstrap.js is pretty much boilerplate code, along these lines: 每个人似乎都同意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() {}

This code works and I can control things in the existing windows. 此代码有效,我可以控制现有窗口中的内容。 For example, domWindow.alert("text") successfully creates a standard alert saying "text" on every window that is currently open. 例如, domWindow.alert("text")成功创建一个标准警报,该警报在当前打开的每个窗口上显示“ text”。

However, I can't find any code that will allow me to do things in new windows; 但是,我找不到任何允许我在新窗口中执行操作的代码。 ie those created after the script runs. 即在脚本运行后创建的那些。 What is the correct way to handle the creation of new windows and gain control over them, to the point where I could get another "text" alert from one when it is created? 什么是处理新窗口并获得对它们的控制权的正确方法,以至于我可以在创建新窗口时从另一个窗口收到“文本”警报?

Edit: Using the nsWindowMediator class and the code sample from MDN, I now have this: 编辑:使用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);
}

However, there is still no output from the onOpenWindow call - the "text" alert does not appear, nor does the error alert in the catch block. 但是,onOpenWindow调用仍然没有输出-“文本”警报不会出现,在catch块中也不会出现错误警报。 I can confirm that onOpenWindow is actually being entered; 我可以确认onOpenWindow实际上是在输入的; if I put a Services.prompt.alert() at the beginning of onOpenWindow, I get the alert when I create a new window. 如果将Services.prompt.alert()放在onOpenWindow的开头,则在创建新窗口时会收到警报。 Unfortunately, I get an infinite loop of alerts and I have no idea why. 不幸的是,我收到了无限的警报循环,我也不知道为什么。

However, I can't find any code that will allow me to do things in new windows 但是,我找不到任何允许我在新窗口中执行操作的代码

When working with XPCOM objects you generally want to study their interfaces, which are often found on MDN. 使用XPCOM对象时,通常需要研究它们的接口,这些接口通常在MDN上找到。 In this case your starting point would be nsIWindowMediator , since that's the service you're using in line 5. 在这种情况下,您的起点将是nsIWindowMediator ,因为这是您在第5行中使用的服务。

As you can see it has an addListener function, which takes a parameter implementing nsIWindowMediatorListener . 如您所见,它具有addListener函数,该函数采用实现nsIWindowMediatorListener的参数。 There's a code-example right there on the page. 页面上有一个代码示例。

But let's assume for the moment there isn't a code example. 但是,让我们暂时假设没有代码示例。 You could search for the interface on MDN, but it isn't listed. 您可以搜索MDN上的接口,但未列出。 The next step would be searching MXR for the .idl . 下一步将在MXR搜索.idl idl = interface description language idl = 接口描述语言

Once you got the interface contract you can more or less just implement it in javascript, at least for listeners. 一旦获得了接口协定,您至少可以在监听器中或多或少地在javascript中实现它。 Implementing your own xpcom services would be a little more complicated . 实现自己的xpcom服务会有些复杂

Searching the addon sdk can often provide some hints too. 搜索插件sdk通常也可以提供一些提示。 In this case they don't seem to be using .addListener , but the file hints at another interesting service, which in turn you can find on MDN: nsIWindowWatcher . 在这种情况下,他们似乎没有使用.addListener ,但是文件提示了另一个有趣的服务,您可以在MDN上找到该服务: nsIWindowWatcher

Basically, if you're writing restartless addons you're rummaging through the entrails of firefox and will have to do some detective work to find the exact components you need. 基本上,如果您要编写不重启的插件,那么您将在Firefox的混乱中翻腾,并且必须做一些侦探性工作才能找到所需的确切组件。 If you want something more convenient I would recommend the addon sdk, which provides a more organized but also more restricted set of commonly used APIs 如果您想要更方便的东西,我建议您使用addon sdk,它提供了更有条理,但也更受限制的常用API集

However, I can't find any code that will allow me to do things in new windows; 但是,我找不到任何允许我在新窗口中执行操作的代码。 ie those created after the script runs. 即在脚本运行后创建的那些。 What is the correct way to handle the creation of new windows and gain control over them, to the point where I could get another "text" alert from one when it is created? 什么是处理新窗口并获得对它们的控制权的正确方法,以至于我可以在创建新窗口时从另一个窗口收到“文本”警报?

The correct way to act on each window when it opens is to use addListener() from nsIWindowMediator . 对每个打开的窗口进行操作的正确方法是使用nsIWindowMediator中的 addListener() The example code below does this. 下面的示例代码执行此操作。 The nsIWindowMediator is included in Services.jsm and is accessed through Services.wm.addListener(WindowListener) . nsIWindowMediator包含在Services.jsm中 ,可以通过Services.wm.addListener(WindowListener)访问。 In order to use a window listener, you have to pass it an nsIWindowMediatorListener ( ref2 ) object. 为了使用窗口侦听器,您必须向其传递nsIWindowMediatorListenerref2 )对象。 An nsIWindowMediatorListener contains three keys: onOpenWindow , onCloseWindow , and onWindowTitleChange . nsIWindowMediatorListener包含三个键: onOpenWindowonCloseWindowonWindowTitleChange Each should be defined as a function which will be called when the appropriate event occurs. 每个函数都应定义为一个函数,当发生适当的事件时将调用该函数。

The MDN document How to convert an overlay extension to restartless in " Step 9: bootstrap.js " contains an example of a basic bootstrap.js which will run the code in the function loadIntoWindow(window) for each currently open browser window and any browser window which opens in the future. MDN文档“ 如何第9步:bootstrap.js中将覆盖扩展名转换为不重启 ,包含一个基本bootstrap.js的示例,它将为每个当前打开的浏览器窗口和任何浏览器运行loadIntoWindow(window)函数中的代码将来打开的窗口。 I have used code modified from this in a couple of different add-ons. 我在几个不同的附件中使用了从中修改的代码。 The example is substantially similar to the code you are already using. 该示例与您已经在使用的代码基本相似。 The example is (slightly modified): 示例是(稍作修改):

const Ci = Components.interfaces;

Components.utils.import("resource://gre/modules/Services.jsm");

function startup(data,reason) {
    // Load this add-ons module(s):
    Components.utils.import("chrome://myAddon/content/myModule.jsm");
    // Do whatever initial startup stuff is needed for this add-on.
    //   Code is in module just loaded.
    myModule.startup();  

    // Make changes to the Firefox UI to hook in this add-on
    forEachOpenWindow(loadIntoWindow);
    // Listen for any windows that open in the future
    Services.wm.addListener(WindowListener);
}

function shutdown(data,reason) {
    if (reason == APP_SHUTDOWN)
        return;

    // Unload the UI from each window
    forEachOpenWindow(unloadFromWindow);
    // Stop listening for new windows to open.
    Services.wm.removeListener(WindowListener);

    // Do whatever shutdown stuff you need to do on add-on disable
    myModule.shutdown();  

    // Unload the module(s) loaded specific to this extension.
    // Use the same URL for your module(s) as when loaded:
    Components.utils.unload("chrome://myAddon/content/myModule.jsm"); 

    // HACK WARNING: The Addon Manager does not properly clear all add-on related caches
    //               on update. In order to fully update images and locales, their
    //               caches need clearing here.
    Services.obs.notifyObservers(null, "chrome-flush-caches", null);
}

function install(data,reason) { }

function uninstall(data,reason) { }

function loadIntoWindow(window) {
    /* call/move your UI construction function here */
}

function unloadFromWindow(window) {
    /* call/move your UI tear down function here */
}

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(Ci.nsIDOMWindow));
}

var WindowListener = {
    onOpenWindow: function(xulWindow) {
        var window = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIDOMWindow);
        function onWindowLoad() {
            window.removeEventListener("load",onWindowLoad);
            // Only add UI changes if this is a browser window
            if (window.document.documentElement.getAttribute("windowtype") 
                                                                == "navigator:browser")
                loadIntoWindow(window);
        }
        window.addEventListener("load",onWindowLoad);
    },
    onCloseWindow: function(xulWindow) { },
    onWindowTitleChange: function(xulWindow, newTitle) { }
};

While there is quite a bit more that your might want to do in your bootstrap.js code, the above is organized reasonably well and keeps all of the code to load into the Firefox UI within loadIntoWindow(window) and unloading the UI within unloadFromWindow(window) . 虽然有相当多的,你可能想在你的bootstrap.js代码做的,上面是组织得相当好,并保持所有的代码加载到内Firefox的UI loadIntoWindow(window)和卸载中的UI unloadFromWindow(window) However, it should be noted that some UI elements you should only be adding/removing once (eg australis widgets, like buttons) and other elements (eg direct changes to the Firefox DOM) have to be added once in each window. 但是,应该注意的是,您应该只添加/删除一次的某些UI元素(例如,澳大利亚小部件,例如按钮),而其他元素(例如,直接更改Firefox DOM)则必须在每个窗口中添加一次。

Unfortunately, I get an infinite loop of alerts and I have no idea why. 不幸的是,我收到了无限的警报循环,我也不知道为什么。

One of the significant differences between this example and what you are currently using is the test for the type of window that has opened. 此示例与当前使用的示例之间的重大区别之一是测试已打开的窗口的类型。 This is done so that we are only acting on newly opened windows which are browser windows instead of all newly opened windows: 这样做是为了使我们仅在新打开的窗口(即浏览器窗口)上起作用,而不是在所有新打开的窗口上起作用:

if (window.document.documentElement.getAttribute("windowtype") == "navigator:browser")
    loadIntoWindow(window);

The problem you describe of getting an infinite loop of alert() popups is caused by not checking to make sure that you are only acting on browser windows. 您描述的出现一个无限循环的alert()弹出窗口的问题是由于未检查确保仅在浏览器窗口上执行操作而引起的。 The alert() popup is a window. alert()弹出窗口是一个窗口。 Thus, you are calling alert() for every alert() window you open which, of course, just opens another alert() window on which you call alert() . 因此,您要为打开的每个alert()窗口调用alert() ,当然,只打开另一个在其上调用alert() alert()窗口。 This is your infinite loop. 这是您的无限循环。

Additional references: 其他参考:
1. Working with windows in chrome code 1. 使用chrome代码的Windows

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何从firefox插件获取浏览器的窗口高度? - How do I get browser's window height from firefox add-on? Firefox附加组件:如何判断窗口是否在后台 - Firefox add-on: how to tell if a window is in the background Firefox附加组件不会以新的xul窗口形式打开其自己的文件。 - Firefox add-on won't open its own file as a new xul window. 当用户在新窗口中打开时,如何使onclick“ window.location”也起作用 - javascript - How do I make onclick“window.location” also work when user opens in new window 在Firefox附加组件中,如何在将事件侦听器添加到整个浏览器窗口时解决错误“未定义窗口”? - In a Firefox Add-on how to resolve the error “window is not defined” when adding an eventlistener to the overall browser window? 从apps脚本附加菜单中打开一个新窗口 - Open a new window from the apps script add-on menu 如何创建一个使用PHP打开新窗口的链接? - How do I create a link that opens up a new window with PHP? Firefox链接到javascript函数在不打算时打开一个新窗口 - Firefox link to javascript function opens a new window when not intended window.open(url,windowname,opts)在新选项卡中打开,而不是在Firefox中打开新窗口 - window.open(url, windowname, opts) opens in new tab instead of new window in Firefox 我该如何编辑 <head> 当我使用window.open打开一个新窗口时 - How do I edit the <head> when i am opening a new window using window.open
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM