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

时间:2016-08-31 05:52:08

标签: javascript firefox firefox-addon firefox-addon-sdk message-passing

我试图从面板脚本(popup.js)发送一个click事件到内容脚本(content.js),这是我尝试过的代码。所需的输出不会在控制台上打印。

  

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(主)

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
});

1 个答案:

答案 0 :(得分:1)

为了将消息从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();
    }
});

数据/ JS / content.js

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

数据/ 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.
    });
}

数据/ 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"
    ]
}