如何在pagemod和widget之间发出和监听事件?

时间:2014-02-25 09:00:57

标签: firefox firefox-addon firefox-addon-sdk

我正在使用addon-sdk。我有一个小部件,点击小部件我想对网站做一些事情(无论是修改页面还是阅读深度DOM)。

所以我在阅读https://developer.mozilla.org/en-US/Add-ons/SDK/High-Level_APIs/page-mod#Communicating_With_Content_Scripts后的想法是:

  1. 在匹配的网址上激活了网页广告(在本例中为ANY)
  2. 点击满足left-click事件的小部件。然后它会发出widget-click
  3. Pagemod收到widget-click事件并重新启动名为from-pagemod的事件。
  4. from-pagemod对网页做了一些事情。
  5. 我在stdout中看到以下输出:

    console.log: project: about to emit widget-click
    console.log: project: after emitting widget-click
    

    因此,pagemod没有收到该事件,或者从未设置过。我不确定这个简单的测试用例中缺少什么。任何帮助表示赞赏。

    以下是lib/main.js

    var widgets = require('sdk/widget');
    var pageMod = require("sdk/page-mod");
    var data = require("sdk/self").data;
    var tabs = require("sdk/tabs");
    
    exports.main = function() {
        var widget = widgets.Widget({
            label: "widget label",
            id: "widget-id",
            contentURL: data.url("off.png"),
            contentScriptFile: [data.url("widget.js"), data.url("page.js")]
        });
    
        widget.port.on("left-click", function() {
            console.log("about to emit widget-click");
            widget.port.emit("widget-click", "foo");
            console.log("after emitting widget-click");
        });
    
    
        var page = pageMod.PageMod({
            include: "*",
            contentScriptWhen: "end",
            contentScriptFile: data.url("page.js"),
            onAttach: function(worker) {
                worker.port.on("widget-click", function(msg) {
                    console.log("on widget-click, ready to emit from-pagemod event");
                    worker.port.emit("from-pagemod", "foo");
                });
            }
        });
    };
    

    以下是page.js

    self.port.on("from-pagemod", function(msg) {
        console.log("inside from-pagemod listener");
        // read DOM or modify the DOM
    });
    

    以下是widget.js

    this.addEventListener('click', function(event) {
      if(event.button == 0 && event.shiftKey == false)
        self.port.emit('left-click');
    }, true);
    

2 个答案:

答案 0 :(得分:3)

编辑2,回答实际问题:

如果您想在窗口小部件上执行某些操作,请在已附加内容脚本时单击,将widget侦听器注册到您有权访问page-worker的位置。您可以将widget.port.on代码放在pageMod的{​​{1}}内,但这只适用于最近添加的页面。使其正常运行的最佳方法是存储所有工作人员,然后在单击窗口小部件时检查当前选项卡是否有工作人员,如下所示:

main.js partial

onAttach()

<强> page.js

var workers = [];

widget.port.on("left-click", function() {
  console.log("about to emit widget-click");
  var worker = getWorker(tabs.activeTab);
  if (worker) {
    worker.port.emit("widget-click", "foo");
    console.log("after emitting widget-click");
  }
});

var page = pageMod.PageMod({
  include: "*", // TODO: make more specific
  contentScriptWhen: "end",
  contentScriptFile: data.url("page.js"),
  onAttach: function(worker) {
    workers.push(worker);
    worker.on('detach', function() {
      detachWorker(worker);
    });
    // could be written as
    // worker.on('detach', detachWorker.bind(null, worker);
  }
});

function detachWorker(worker) {
  var index = workers.indexOf(worker);
  if(index!==-1) workerArray.splice(index, 1);
}

function getWorker(workers, tab) {
  for (var i = workers.length - 1; i >= 0; i--) {
    if (workers[i].tab===tab) return worker;
  }
}

您的解决方案无法正常工作的原因是您认为事件以某种方式链接到文件而不是对象。


老答案:你太复杂了。

只需在点击时附加内容脚本(而不是将内容脚本添加到除了接收事件之外什么也不做的每个页面)

main.js

self.port.on("widget-click", function(msg) {
  console.log("inside widget-click listener");
  // read DOM or modify the DOM
});

page.js

var widgets = require('sdk/widget');
var data = require("sdk/self").data;
var tabs = require("sdk/tabs");

exports.main = function() {
    var widget = widgets.Widget({
        label: "widget label",
        id: "widget-id",
        contentURL: data.url("off.png"),
        contentScriptFile: data.url("widget.js")
    });

    widget.port.on("left-click", function() {
        console.log("about to attach script");
        var worker = tabs.activeTab.attach({
            contentScriptFile: data.url("page.js");
        });
        worker.port.on('message from content script', function(someVariable){
            //Now I can do something with someVariable in main.js
        });
    });
};

修改:阅读Modifying the Page Hosted by a Tab了解详情。此外,当您尝试使用SDK之前未执行的操作时,Tutorials页面是一个很好的起点。这是一个很好的方法,可以退后一步,考虑尝试实现目标的替代方案。

答案 1 :(得分:1)

port是内容脚本和附加组件之间的通信通道:您的Widget可以通过widget.js与其内容进行交互,并通过page.js将您的pagemod与匹配的网页内容进行交互。执行widget.port.emit("widget-click", "foo");时,widget.js只能使用self.port.on('widget-click')而不是pagemod实例来监听此消息。由于widget和pagemod是共享main.js范围的对象,因此只需访问其属性和方法即可相​​互通信。