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

标签 javascript firefox firefox-addon xul

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

我的附加组件是缩放附加组件,如果用户在新选项卡或窗口中打开链接,我希望能够复制原始选项卡的缩放级别。

我已经弄清楚如何在使用内容 JavaScript 中的 window.open() 打开链接时检测开启器(这相当简单),但是我不知道如何实现确定是否从上下文菜单(在新选项卡/新窗口中打开链接)或 Ctrl//Shift打开了新选项卡/窗口kbd>+单击。

为了检测它是否是从 content-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+单击在新选项卡或窗口中打开链接时,topWindow.opener 等于 null,但如果我使用 Ctrl+Shift+ 打开附加组件管理器AtopWindow.opener 将是 ChromeWindow 的实例。

所以,看来我走在正确的轨道上,但并不完全正确,因为我只对用户在新选项卡或窗口中发起的内容链接打开感兴趣。

我所追求的目标可行吗?

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

我可以利用类似的东西吗?

最佳答案

我成功地通过拦截 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;

关于javascript - 检测打开新选项卡/窗口的原始选项卡(如果有),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28550228/

相关文章:

javascript - Google Charts 表格的动态样式

html - Firefox 和 Chrome 坚持使用 blue::selection 背景

javascript - 火狐扩展 opendialog 开启器 null

javascript - Firefox 扩展未运行内容脚本

javascript - 如何从 Firefox 扩展重新启动 Mozilla Firefox 浏览器

JavaScript Azure Blob 存储移动 Blob

Javascript计数动画以逗号停止计数

Firefox:证书不受信任,因为颁发者证书未知

javascript - 在最大数之后 - 将所有剩余的 li 项目包装到 ul

firefox - Firefox网络面板中的彩条代表什么?