检测打开新选项卡/窗口的原始选项卡(如果有)

时间:2015-02-16 20:57:53

标签: javascript firefox firefox-addon xul

对于我创建的附加组件即将推出的版本,我想检测在新标签页或窗口中打开了哪个标签(如果有)。

我的插件是一个缩放插件,如果用户在新标签或窗口中打开链接,我希望能够复制原始标签的缩放级别。

我已经知道如果用内容JavaScript中的window.open()打开一个链接(这很容易),如何检测开启者,但是我不知道如何弄清楚是否一个从上下文菜单(新选项卡/新窗口中的打开链接)或 Ctrl / / Shift +单击打开新选项卡/窗口。

要检测它是否是从内容-Javascript打开的,我使用:

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

let windowTracker = {
  observe: function( subject, topic, data ) {
    if( 'chrome-document-global-created' == topic && subject instanceof Ci.nsIDOMWindow ) {
      // here I can use subject.opener
    }
  }
}

let observerService = Cc[ '@mozilla.org/observer-service;1' ].getService( Ci.nsIObserverService );
observerService.addObserver( this, 'chrome-document-global-created', false );

要检测任何可能的非内容JavaScript开启者,我已经在observe()中尝试了这一点:

let windowTracker = {
  observe: function( subject, topic, data ) {
    if( 'chrome-document-global-created' == topic && subject instanceof Ci.nsIDOMWindow ) {
      let topWindow = subject.QueryInterface( Ci.nsIInterfaceRequestor )
                             .getInterface( Ci.nsIWebNavigation )
                             .QueryInterface( Ci.nsIDocShellTreeItem )
                             .rootTreeItem
                             .QueryInterface( Ci.nsIInterfaceRequestor )
                             .getInterface( Ci.nsIDOMWindow );
      // here I tried topWindow.opener, with mixed results
    }
  }
}

......但结果好坏参半。

当我使用上下文菜单打开新标签页或窗口中的链接或 Ctrl / / Shift +单击时,{{ 1}}等于topWindow.opener,但是如果我,例如,使用 Ctrl + Shift + A 打开附加组件管理器,null将是topWindow.opener的实例。

所以,我似乎有点走上正轨,但并不完全,因为我只是对用户在新标签页或窗口中打开内容链接感兴趣。

我可以用的是什么?

在检查Firefox的源代码时,我注意到可能有一种方法(除非我误解了它的目的)会给我一些我想要的东西:getOpener() in { {3}}。但是,该方法未在脚本API中公开。

可以使用什么类似的东西?

2 个答案:

答案 0 :(得分:2)

我设法通过使用ChromeWindow.openLinkIn()对象拦截Proxy来实现目标:

// window is a top level ChromeWindow
window.openLinkIn = new Proxy( window.openLinkIn, {
  apply: function( target, thisArg, argumentsList ) {

    let url    = argumentsList[ 0 ];
    let where  = argumentsList[ 1 ];
    let params = argumentsList.length > 2 ? argumentsList[ 2 ] : {};

    // links opened through the context menu or Ctrl/⌘/Shift+click
    // don't have params.fromChrome = true
    if( !url || !where || params.fromChrome ) {
      return target.apply( thisArg, argumentsList );
    }

    switch( where ) {
      case 'tab':
        // break intentionally omitted
      case 'tabshifted':
        let tabBrowser = window.gBrowser;
        tabBrowser.tabContainer.addEventListener( 'TabOpen', function onTabOpen( event ) {
          tabBrowser.tabContainer.removeEventListener( 'TabOpen', onTabOpen, true );

          let tab = event.target;
          // do something with the new tab
        }, true );

        break;
      case 'window':
        let windowTracker = {
          init: function() {
            observerService.addObserver( this, 'toplevel-window-ready', false );
          },
          destroy: function() {
            observerService.removeObserver( this, 'toplevel-window-ready' );
          },
          observe: function( subject, topic, data ) {
            let self = this;
            let chromeWindow = subject;
            if( 'toplevel-window-ready' == topic && chromeWindow instanceof Ci.nsIDOMWindow ) {
              chromeWindow.addEventListener( 'DOMContentLoaded', function onChromeWindowDOMContentLoaded( event ) {
                this.removeEventListener( 'DOMContentLoaded', onChromeWindowDOMContentLoaded, true );

                if( 'navigator:browser' == this.document.documentElement.getAttribute( 'windowtype' ) ) {

                  // do something with the new chromeWindow

                  // destroy the windowTracker
                  self.destroy();
                }
              }, true );

            }
          }
        }
        windowTracker.init();

        break;
    }

    return target.apply( thisArg, argumentsList );
  }
} );

PS。:当您禁用扩展程序时,请务必清理并重新安装原始功能。你可以这样做:

let originalOpenLinkIn = window.openLinkIn;
window.openLinkIn = new Proxy( window.openLinkIn, {
  apply: /* implementation from above */
} );

// then when cleaning up:
window.openLinkIn = originalOpenLinkIn;

答案 1 :(得分:1)

  

但是我不知道如何确定是否从上下文菜单(新标签/新窗口中的打开链接)或Ctrl /⌘/ Shift +单击打开了新标签/窗口。

在这种情况下,特别是如果在新窗口中打开它们,该选项卡实际上没有所有者。它们被认为等同于用户只需在地址栏中输入URL。

您可以执行的操作是安装system event listener,以便在每个click上冒充contextmenusubmitwindow个事件并检查目标是否为表单或链接,然后检查他们的目标网址。如果新打开的标签位置与最后点击/提交的链接匹配,那么它可能来自之前的标签。