首页 > 解决方案 > Firefox 扩展,上下文识别

问题描述

我已经构建了一个 AddIn,一个国际象棋游戏可视化器,它在桌面浏览器 Firefox、Chrome、Opera、Safari 和 IE 上工作了很多年。插件在从上下文菜单调用时运行,并解析当前页面中的选定文本。所选文本应为Chess Notation Format,可以是 FEN 或 PGN。
这是第二次在 FF 版本更改时插件与 Firefox 不兼容,我必须进行架构更改。新的 firefox 架构是为了与 Chrome 兼容,但它只是部分兼容,所以我不能完全重用 chrome 的代码。我还使用 了将弹出窗口中的数据通信到由弹出窗口注入的内容脚本中的信息,执行脚本()使用 executeScript() 将数据从弹出窗口传递到由弹出窗口注入的内容脚本

以下是我的问题:

  1. 看background.js的代码,在pop.js调用browser.runtime.onMessage.addListener之前调用了browser.runtime.sendMessage。在完全创建由 browser.windows.create 打开的窗口、所有脚本结束执行并完全加载文档后,我不明白如何从 background.js 发送消息。我也不能在调用时这样做document.addEventListener('DOMContentLoaded',当我调用 browser.runtime.onMessage.addListener 时,它会生成错误Error: sendRemoveListener on closed conduit b212f9bfb4f0394efe56168a583c91346caf2d00@temporary-addon.412316861125并且可能根本没有执行。也许有我可以处理的特殊事件,我没有看到太多的文档。在 Chrome 中,方法大多相似,但效果很好。
  2. 在一些不可用的情况下,我仍然可以捕获从 background.js 发送的消息:如果我打开了两个窗口,但对于调试目的还是很好的。document.innerHTML问题是,无论我尝试做什么,在 pop.js 的处理程序内部都是未定义的。我无法处理来自扩展 api 处理程序的窗口内容。我认为该文档已完全加载,因为它由两个打开的窗口中的第一个处理。

注意,我可以通过调用 URL 参数将选择文本发送到新打开的弹出窗口。它有效,但我认为这是一种解决方法。我在 Opera 和 Safari 上使用它,它也适用于 Firefox,但我正在考虑尽可能摆脱它。

有一个场景,简化:
background.js:

{//Firefox create context menus
   var id      = chrome.contextMenus.create({"title": "Chess game", "contexts":["selection", "page"]});
   var childId = chrome.contextMenus.create
                    ({
                       "title": "Play Small","contexts":["selection", "page"],
                       "parentId": id,
                       "onclick": (info, tab) => { playBoard   (info, tab, "mini18"); }
                    });
}


function onCreated(windowInfo, request)
{
   browser.windows.get(windowInfo.id).then
   (
      (wnd) => { browser.runtime.sendMessage(request); }
   );
}

function playBoard (info, tab, imagePath)
{
   let creating = browser.windows.create({ type:"detached_panel", url:"pop.html", width:250, height:100 });
   creating.then
   (
      (inf) =>
      {onCreated
         (
            inf,
            {
               chessObject:
               {
                  gametype : "PGN_OR_FEN_board",
                  content : selection,
                  imgPath : info.selectionText
               }
            }
         )
      }
   );
}

pop.js:

browser.runtime.onMessage.addListener
(
   (request) =>
   {
      console.log("popup chrome listen to game: " + request.chessObject.content);
      console.log("popup chrome listen to game: document inner html: " + document.innerHTML);
   }
);

弹出.html:

<!DOCTYPE html>
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
   <title>hello world</title>
   <script language="javascript" src="pop.js"></script>
</head>
<body>
   hello popup
</body>
</html>

清单.json:

{
  "manifest_version": 2,
  "name": "Roatta Waaayyyy!!!",
  "version": "1.0.0.4",

  "description": "Chess AddIn for Firefox",

  "icons": { "32": "icons/roatta_32_32.jpg" },
  "permissions": [ "contextMenus" ],
  "background": { "scripts": ["background.js"] }
}

这里的参考是 GIT 上的完整源代码,我现在尝试实现的是 Firefox65,它旨在取代以前的 Firefox。基本版本是用于 Chrome 的版本,最初是用于 Firefox 的版本。

标签: javascriptfirefox-addonfirefox-addon-webextensions

解决方案


正如@wOxxOm 所建议的,我应用了反向消息模式,并且它有效。
现在 background.js 注册一个监听器并等待被调用,然后它会移除监听器:

{//Firefox
   console.log("Creating context menus");
   var id      = chrome.contextMenus.create({"title": "Chess game", "contexts":["selection", "page"]});
   var childId = chrome.contextMenus.create
                    ({
                       "title": "Play Small","contexts":["selection", "page"],
                       "parentId": id,
                       "onclick": (info, tab) => { playBoard   (info, tab, "mini18"); }
                    });
}

function playBoard (info, tab, imagePath)
{
   var createData =
   {
      type  : "detached_panel",
      url   : "pop.html",
      width : 250,
      height: 100

   };

   let requestData =
      {
         chessObject:
         {
            gametype : "PGN_OR_FEN_board",
            content  :  info.selectionText,
            imgPath  : imagePath
         }
      };
   try
   {
      console.log ("Play Board: " + imagePath);
      console.log ("Selection: " + info.selectionText);

      let creating = browser.windows.create(createData);
      
      function onGameDataExchange(request)
      {
          browser.runtime.onMessage.removeListener(onGameDataExchange);
          return Promise.resolve(requestData);
      }

      browser.runtime.onMessage.addListener (onGameDataExchange);

      console.log ("opened pop.html");

   }
   catch (err)
   {
      console.log ("Error: main background playBoard() " + err);
   }
}

pop.js 是请求消息的那个:

document.addEventListener('DOMContentLoaded',
   function (event)
   {
      browser.runtime.sendMessage (  { chessObject: { gametype : "PGN_OR_FEN_board" } }  )
                .then
                (
                   (request) =>
                   {
                       console.log("on DOMContentLoaded message: " + request.chessObject.gametype);
                       console.log("on DOMContentLoaded message: " + request.chessObject.content);
                       console.log("on DOMContentLoaded message: " + request.chessObject.imgPath);
                   }
                );
      console.log("Popup DOMContentLoaded send message end");

   }
);

推荐阅读