Firefox 插件 (JPM) - 如何将消息从面板的脚本传递到内容脚本?

Firefox addon(JPM) - How to pass message from panel's script to content script?

我正在尝试将点击事件从面板脚本 (popup.js) 发送到内容脚本 (content.js) 她的代码是我 tried.and 所需的输出未打印控制台。

popup.html

<button id="start-btn" onclick="myFunction()">Clip</button>

popup.js

function myFunction() {
  addon.port.emit('message', 'hello world');
}

content.js

self.port.on("message", function(text) {
  console.log(text);
});

index.js(main)

var panels = require("sdk/panel");
var self = require("sdk/self");
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*",
  contentScriptWhen: 'ready',
  contentScriptFile:
  [data.url("js/jquery-3.1.0.min.js"),
  data.url("js/content.js")]
});

var panel = panels.Panel({
 contentURL: self.data.url("popup.html"),
 onHide: handleHide
});

为了将消息从 sdk/panel 传递到内容脚本,您必须通过后台脚本中继它。所以,通信看起来像面板脚本⟷后台脚本⟷内容脚本。

由于您可能有许多不同的内容脚本,所以这很复杂。您甚至可以为每个选项卡设置多个内容脚本。因此,您必须在内容脚本附加时跟踪它们,并至少按选项卡组织它们。这样您就可以最终将消息中继到正确的内容脚本。

面板,因为它是一个用户界面,通常会向活动选项卡发送消息。另一方面,它可能希望将消息发送到特定选项卡或特定选项卡中的特定脚本。您需要确定附加组件所需的粒度级别。

以下脚本将通过 Page-Mod 将内容脚本加载到每个选项卡中(根据问题,包含的 URL 是 '*')。每个内容脚本都按选项卡进行跟踪。没有规定每个选项卡有多个内容脚本。为了使内容脚本列表中的条目无效,应该真正监听 Tab 事件。然而,在这个例子中没有这样做。单击 ActionButton 将显示该面板。单击面板中的按钮时,面板会向后台脚本发送 relay 消息,然后后台脚本解码 relay 消息并将其发送到适当的内容脚本。

我为 relay 消息设置了一种格式。该格式为:

{
     target: {
        type:targetType, //Currently, the only valid targetType is 'content'.
        id:targetId //A tab ID, or 'activeTab'
    },
    emitType:emitType, //The type of emit message that will be sent.
    data:message //The contents of the relayed message.
}

代码:

index.js:

var panels = require("sdk/panel");
var self = require("sdk/self");
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");
var tabs = require("sdk/tabs");

//Open the Browser Console
var utils = require('sdk/window/utils');
activeWin = utils.getMostRecentBrowserWindow();
activeWin.document.getElementById('menu_browserConsole').doCommand();

var workers={};

//PageMod
pageMod.PageMod({
    include: "*",
    contentScriptWhen: 'ready',
    contentScriptFile: [
        //data.url("js/jquery-3.1.0.min.js"),
        data.url("js/content.js")
    ],
    onAttach: attachWorker
});

function attachWorker(worker){
    if(!workers.hasOwnProperty(worker.tab.id)){
        //Have not previously had this tab
        workers[worker.tab.id]={};
    }
    //This does not account for the possibility of having multiple workers
    //  per tab at one time.
    //Remember the worker
    console.log('index.js: Attached worker on tab=',worker.tab.id);
    workers[worker.tab.id].worker = worker;
}


//Panel
var panel = panels.Panel({
    contentURL: self.data.url("popup.html"),
    onHide: handleHide
});

panel.port.on('message',receiveMessage);
panel.port.on('relay',receiveRelay);

function handleHide(){
}

function receiveMessage(message){
    console.log('index.js: received message:',message);
}

function receiveRelay(data){
    console.log('index.js: received relay:',data);
    let emitPort;
    let targetId;
    if(typeof data !== 'object'){
        console.log('index.js: received relay: data was not an object');
        return;
    }//else
    if(!data.hasOwnProperty('target')){
        console.log('index.js: received relay: No target specified');
        return;
    }//else
    if(data.target.type === 'content'){
        if(data.target.id && data.target.id === 'activeTab'){
            targetId = tabs.activeTab.id;
        }else{
            targetId = data.target.id;
        }
        console.log('index.js: received relay: target ID: ', targetId);
        if(!workers.hasOwnProperty(targetId) || !workers[targetId].worker){
            console.log('index.js: received relay: No target worker available for ID: '
                        , targetId);
            return;
        }//else
        emitPort = workers[targetId].worker.port;
    }else{
        //None  yet defined
        console.log('index.js: received relay: Target type not understood. Type: '
                    , data.target.type);
        return;
    }
    console.log('index.js: received relay: emitType=', data.emitType, ' ::data='
                , data.data);
    emitPort.emit(data.emitType,data.data);
}


//Action button
var ui = require("sdk/ui");

var action_button = ui.ActionButton({
    id: "panel-show-button",
    label: "Show panel",
    icon: "./icon.png",
    onClick: function(state) {
        panel.show();
    }
});

data/js/content.js:

console.log('In  content.js');
self.port.on("message", function(text) {
  console.log('content.js: received message:',text);
});

data/popup.js:

function myFunction() {
    console.log('popup.js: Button clicked. Sending relayed message');
    //addon.port.emit('message', 'hello world');
    sendRelay('content','activeTab','message','Button clicked in panel');
}

function sendRelay(targetType,targetId,emitType,message) {
    addon.port.emit('relay', {
        target: {
            type:targetType, //Currently, the only valid targetType is 'content'.
            id:targetId //A tab ID, or 'activeTab'
        },
        emitType:emitType, //The type of emit message that will be sent.
        data:message //The contents of the relayed message.
    });
}

data/popup.html:

<html>
    <head>
        <meta charset='utf-8'>
        <script type="text/javascript" src="popup.js"></script>
    </head>
    <body>
        <button id="start-btn" onclick="myFunction()">Clip</button>
    </body>
</html>

package.json:

{
    "title": "Demo passing a message panel-background-content",
    "name": "relaymessge",
    "id": "relaymessage@ex",
    "version": "0.0.1",
    "description": "Demonstrate passing a message from a panel -> background script -> content script.",
    "main": "index.js",
    "author": "Makyen, vivek",
    "engines": {
        "firefox": ">=38.0a1",
        "fennec": ">=38.0a1"
    },
    "keywords": [
        "jetpack"
    ]
}