如何在 Firefox 附加组件中获取右键单击选项卡的 URL

How to get the right-clicked tab's URL in a Firefox add-on

我正在编写一个 Firefox 扩展,它向浏览器的选项卡上下文菜单添加一个菜单项,以将选项卡的 URL 发送到 Web 服务。我的菜单项有一个 command 事件侦听器,它会在选择菜单项时触发并且工作正常。

我遇到的问题是根据我收到的事件确定右击了哪个选项卡。从菜单项本身(command 事件的目标)到选项卡似乎没有简单的路径,因为选项卡上下文菜单不是 XUL 领域中选项卡的子项。当然,我不能只获取当前选项卡,因为用户可能右键单击了非活动选项卡。

我目前使用的解决方案是在每个选项卡上放置一个contextmenu事件处理程序,将选项卡的URL存储在一个全局变量中,并在我的[=12]中使用这个全局变量=] 事件处理程序。这很好用,而且我对全局变量有点安心,因为实际上不可能同时调出多个上下文菜单。

但是有没有更好的办法呢?我想用一个包含 URL 的闭包来更新我的 command 事件处理程序,但这样做的缺点是在添加新事件处理程序之前需要删除旧事件处理程序,这只会使事情进一步复杂化。

我当前的代码如下所示:

var tabs = require("sdk/tabs");
var xultabs = require("sdk/tabs/utils");
var viewFor = require("sdk/view/core").viewFor;

var itemid = "my-extension-name";
var xulns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";

// global variable to hold tab URL and function to set it on right-click of tab
taburl = "";
function getTabURL(e) { taburl = xultabs.getTabURL(e.target); }

tabs.on('ready', function(tab) {
  // set up event listener to get tab URL when tab is right-clicked
  let vtab = viewFor(tab);
  vtab.addEventListener("contextmenu", getTabURL); 

  // add our context menu item if it's not already there
  let doc = viewFor(tab.window).document;
  if (!doc.getElementById(itemid)) {
    let menu = doc.getElementById("tabContextMenu");
    let item = doc.createElementNS(xulns, "menuseparator");
    menu.appendChild(item);
    item = doc.createElementNS(xulns, "menuitem");
    item.setAttribute("label", "My Menu Item");
    item.setAttribute("id", itemid);
    item.addEventListener("command", function() { pushURL(taburl) });
    menu.appendChild(item);
  }
});

function pushURL(url) {
   // pushes the URL to the service
}

显示上下文菜单时,您可以通过执行以下操作找出触发弹出窗口显示的元素:

e.target.ownerDocument.popupNode

这可能会有用,但实际上您需要的只是 ownerDocument.defaultView

我认为甚至还有一个 e.view 属性 可以容纳浏览器 window。

例如:

function contextMenuShowing(e) {
    console.log('context menu showing', 'popupNode:', e.target.ownerDocument.popupNode);
    var currentWindow = e.target.ownerDocument.defaultView; // can try var currentWindow = e.view;
    if (currentWindow.gBrowser) {
          var tabURL  = gBrowser.selectedBrowser.currentURI;
    }
}

cToolbarContextMenu.addEventListener('popupshowing', contextMenuShowing, false);

另一种方法,是因为在右键单击时,这显然意味着 window 被聚焦。所以你可以这样做:

const { getMostRecentBrowserWindow } = require('sdk/window/utils');

cToolbarContextMenu.addEventListener('popupshowing', function() {
    var currentWindow = getMostRecentBrowserWindow();
    if (currentWindow.gBrowser) {
         var tabURL = currentWindow.gBrowser.selectedBrowser.currentURI.spec;
    }
}, false);