【问题标题】:How to identify tab close event for browser element [XUL/firefox]如何识别浏览器元素的选项卡关闭事件 [XUL/firefox]
【发布时间】:2014-04-18 16:46:52
【问题描述】:

我在一个插件上工作,它观察所有的 http 请求并填充与每个选项卡对应的一些信息。我想清除我关闭的选项卡的数据。但是,我无法以更清洁/更明智的方式识别标签关闭事件。 所以我有发出请求的contentWindow (LoadContext -> associatedWindow),以及那个内容窗口(用于选项卡)的browser

  1. 我意识到要执行browser.addEventListener,我将不得不监听DOMNodeRemoved 事件——即deprecated as per MDN(并且应该使用突变观察者)。此外,当弹出窗口关闭时,我不会收到事件。
  2. 如果我执行contentWindow.addEventListener 并查找unload 事件,结果是非常不可预测的。有时,我根本不了解这些事件。
  3. 如果我从gBrowser.tabs 获得这个tab 元素并监听TabClose 事件,我可以获得选项卡的所有关闭事件。但话又说回来,它不会通知任何弹出窗口关闭(尽管我确实得到了弹出窗口的 tab 元素)

那么了解任何选项卡/弹出窗口关闭的最简单/最干净的方法是什么?顺便说一句,我不使用插件 SDK。

编辑:寻找更简单、适用于所有情况的解决方案。 IE。我收到关闭事件的通知,无论是选项卡还是弹出窗口(或任何其他类型的窗口,如果它们存在!)。我相信这可能是可能的,因为我持有一个包含 DOM 窗口的浏览器元素,并且 DOM 在关闭时被删除(卸载)。

EDIT-2:意识到所有问题都归结于一件事:当最后一个选项卡关闭(即窗口关闭)时,Firefox 没有 TabClose 事件。如果我们被通知在窗口关闭时关闭的选项卡,生活会容易得多。无论如何,我将使用@Noitidart 解决方案的修改版本 - 除了TabClose 侦听器之外,还有一个单独的窗口侦听器。并在其中找到tab 元素并进行清理。叹! 将对此进行更多搜索,看看这是否符合错误/增强的条件。 感谢@Noitidart 和@Blargh 的建议。

【问题讨论】:

  • 与 Edit2 相同。仅供参考:当带有标签的新浏览器窗口打开时,不会触发 TabOpen 事件。不过问题是,当一个窗口关闭时有多个选项卡会发生什么,我认为这些选项卡中的任何一个都没有TabClose 事件吧?
  • 没错。当窗口关闭时没有TabClose。我所做的是查找其中的所有选项卡并进行清理。事实上,我为每个选项卡的 browser 元素有一个 expando 属性,我用它来索引我的缓存数组。如果你真的想要,我可以更新我的答案。
  • 是的,请您将其发布为解决方案,而不是在主题问题中进行编辑。感谢智能车队,我在这里学到了很多东西。
  • @Noitidart 我刚刚发布了。

标签: javascript dom firefox-addon xul xpcom


【解决方案1】:

我说保持对标签的引用。这就是我在插件 MouseControl 和 WorkspaceHopper 中的做法。

所以喜欢检查:

if (tab.parentNode) {

}

也尝试捕捉,如果捕捉到,则标签显然不存在。

但是对于 tabClos​​e,你还不如使用 tabclose 事件,对于弹出窗口,使用 windowsMediator 监听器并监听 onWindowClose

var windowListener = {
    //DO NOT EDIT HERE
    onOpenWindow: function (aXULWindow) {
        // Wait for the window to finish loading
        let aDOMWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
        aDOMWindow.addEventListener('load', function () {
            aDOMWindow.removeEventListener('load', arguments.callee, false);
            windowListener.loadIntoWindow(aDOMWindow);
        }, false);
    },
    onCloseWindow: function (aXULWindow) {},
    onWindowTitleChange: function (aXULWindow, aNewTitle) {},
    register: function () {

        // Load into any existing windows
        let DOMWindows = Services.wm.getEnumerator(null);
        while (DOMWindows.hasMoreElements()) {
            let aDOMWindow = DOMWindows.getNext();
            windowListener.loadIntoWindow(aDOMWindow);
        }
        // Listen to new windows
        Services.wm.addListener(windowListener);
    },
    unregister: function () {
        // Unload from any existing windows
        let DOMWindows = Services.wm.getEnumerator(null);
        while (DOMWindows.hasMoreElements()) {
            let aDOMWindow = DOMWindows.getNext();
            windowListener.unloadFromWindow(aDOMWindow);
        }

        //Stop listening so future added windows dont get this attached
        Services.wm.removeListener(windowListener);
    },
    //END - DO NOT EDIT HERE
    loadIntoWindow: function (aDOMWindow) {
        if (!aDOMWindow) {
            return;
        }

        //do stuff here

    },
    unloadFromWindow: function (aDOMWindow) {
        if (!aDOMWindow) {
            return;
        }
        //do stuff here
    }
};

【讨论】:

  • 我确实做到了。但这对关闭弹出窗口没有帮助!有没有一体化解决方案?
  • 这就是我在 WorkspaceHopper 中的做法:addons.mozilla.org/en-US/firefox/files/browse/237376/file/…
  • btw 在 tabclose 函数中,如果你这样做 function (e) { var tab = e.target } 那么在关闭时你可以在引用数组中找到你的标签并将其删除。
  • 如果保持参考,if (window) 并不总是在窗口关闭时返回 false,你必须去 if (!window && window.closed) 我认为窗口不会马上去垃圾收集
  • 谢谢。我正在寻找一种更简单、适用于所有情况的解决方案。 IE。我收到关闭事件的通知,无论是选项卡还是弹出窗口(或任何其他类型的窗口,如果它们存在!)。我相信这可能是可能的,因为我持有一个包含 DOM 窗口的 browser 元素,并且 DOM 在关闭时被删除(卸载)。否则你的答案可能是要走的路。如果我找不到简单的解决方案,我会回来接受您的回答;)
【解决方案2】:

这是我修改后的@Noitidart 答案。我使用 browser 上的 expando 属性(例如:_myextensionTabId)来索引我的缓存数组。

var WindowListener = {
/* Same as @Noitidart's listener */
  onOpenWindow : function(xulWindow) {
    /* Get DOM window, call other window specific modules init */
    myExtension.initWindow(domWindow);
    myHttpObserver.initWindow(domWindow);
  },
  onCloseWindow: function(xulWindow) {
    /* Get DOM window, call other window specific modules uninit */
    myExtension.uninitWindow(domWindow);
    myHttpObserver.uninitWindow(domWindow);
  },
};

var myHttpObserver = {
    ..  
    initWindow: function(window) {
      window.gBrowser.tabContainer
              .addEventListener('TabClose', tabClosed, false);
    }, 

    uninitWindow: function(window) {
      dump ("Uninit window http observer\n");
      window.gBrowser.tabContainer
                .removeEventListener('TabClose', tabClosed);
      for (var browser of window.gBrowser.browsers) {
        if (browser._myextensionTabId) {
          // Do any cleanup.
        }
      }
    },
  .. 
    /* Other http observer stuff, methods that sets the expando property etc. */
};

function tabClosed(e) {
  var browser = Services.wm.getMostRecentWindow("navigator:browser")
                           .gBrowser.getBrowserForTab(e.target);
  dump("Tab closed. \n");
  if (browser._myextensionTabId) {
    dump("My extension tab id : " + browser._myextensionTabId);
    // Do any cleanup
  }
}

【讨论】:

    【解决方案3】:

    对于一个适合选项卡和窗口的解决方案,您可以尝试窗口观察器: https://developer.mozilla.org/en-US/docs/Observer_Notifications#Windows

    可能想使用outer-window-destroyed 观察者,我认为选项卡中的每个浏览器元素都是一个外部窗口。我不知道。它可能会在每次文档更改时触发,因此您必须 QI 并获取选项卡并检查其是否关闭/关闭或仍然打开。

    试试看,和我们分享你学到的东西,我很感兴趣。关闭时,我认为它会被破坏。

    【讨论】:

    • 不错的建议。刚才试了一下。不幸的是,每当窗口关闭时,我都会收到大约 4 次outer-window-destroyed。当新标签打开时,我会得到一个!此外,除了获取该窗口的唯一 64 位 id 之外,无法直接访问 window [根据此处的答案:stackoverflow.com/questions/11345543/…]
    • 添加观察者听起来是正确的做法,尤其是在 MDN 描述中 “缓存窗口信息的扩展可能希望观察这一点,以便在窗口被销毁时释放信息” 。我还和其他观察者dom-window-destroyedxul-window-destroyed 一起玩,但是通知太多了,即使我们不希望得到一个。最后我们没有得到window
    • 出于好奇,窗口关闭了,您收到了 4 个带有 outer-window-destroyed 的消息,该窗口中是否有三个打开的​​标签页?
    • @Noitidart:不。我只打开了最后一个标签。可能可以确定哪个窗口已关闭等。但这并不像 Wladimir Palant 给出的答案那么简单(参见上面的链接)。所以我没有进一步追究。然后拥有单独的选项卡和窗口侦听器是要走的路。这整个问题是由于一件事造成的 - 当最后一个选项卡关闭时没有TabClose 事件。我已经更新了我的问题。见 EDIT-2。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-27
    • 2014-02-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多