对于我创建的附加组件即将推出的版本,我想检测在新标签页或窗口中打开了哪个标签(如果有)。
我的插件是一个缩放插件,如果用户在新标签或窗口中打开链接,我希望能够复制原始标签的缩放级别。
我已经知道如果用内容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中公开。
我可以使用什么类似的东西?
答案 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
上冒充contextmenu
,submit
和window
个事件并检查目标是否为表单或链接,然后检查他们的目标网址。如果新打开的标签位置与最后点击/提交的链接匹配,那么它可能来自之前的标签。