PageM将worker多次附加到同一URL

时间:2014-03-13 14:45:18

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

找到清洁解决方案

我发现了一个非常干净的解决方案,这使得整个问题毫无意义,我确信当我提出这个问题时它就存在了......我非常无知也在寻找它。

attachTo: 'top'构造函数中使用PageMod只会将脚本附加到顶级文档,而不会附加到任何iframes

因此,如果您发现PageMod多次为您的插件附加,则可能是因为它附加到iframes以及顶级标签文档。添加attachTo: 'top'作为传递给PageMod构造函数的对象的属性,您无需担心iframes

对于下面的问题,解决方案将是

var _workers = [];

var pageMod = require("sdk/page-mod").PageMod({
    include: /https?:\/\/www\.websitename\.net.*/,
    contentScript: "self.port.on('hello', function() { " +
                   "console.log('['+document.location.href+']: " +
                   "My worker said hello to me!');",
    contentScriptWhen: "end",
    attachTo: 'top',   //<-- add this property to only attach to top level document
    onAttach: function(worker) {
        _workers.push(worker);
        worker.on("detach", function() {
            var ind = _workers.indexOf(this);
            if(ind !== -1) {
                _workers.splice(ind, 1);
            }
        });
        worker.port.emit("hello");
    }
});

当然,如果没有@ Noitidart的帮助,我永远不会指出原因是iframes

旧问题

我正在尝试为Firefox编写一个附加组件,用于修改特定网站的页面。我认为PageMod是完美的选择,但我遇到了一些问题。工人似乎多次附加到同一个URL(4到2),我也不知道为什么会发生这种情况。

我在附加组件的 main.js 中尝试了以下代码:

var _workers = [];

var pageMod = require("sdk/page-mod").PageMod({
    include: /https?:\/\/www\.websitename\.net.*/,
    contentScript: "self.port.on('hello', function() { " +
                   "console.log('['+document.location.href+']: " +
                   "My worker said hello to me!');",
    contentScriptWhen: "end",
    onAttach: function(worker) {
        _workers.push(worker);
        worker.on("detach", function() {
            var ind = _workers.indexOf(this);
            if(ind !== -1) {
                _workers.splice(ind, 1);
            }
        });
        worker.port.emit("hello");
    }
});

在运行此代码并在单个单独的选项卡中打开https://www.websitename.net时,控制台有2到4个实例

[https://www.websitename.net/]: My worker said hello to me!

这意味着同一页面附加了多个工作人员。 我不知道为什么会发生这种情况,我当然不希望这样,因为我打算稍后使用_workers数组与附加的脚本进行通信。

编辑

感谢@Noitidart,我现在已经确认了多个工作者,只有一个是实际页面,其他是iframe,这就是为什么每个工作人员的内容脚本可用的DOM内容不同。

但问题仍然存在。如何确保工作人员(以及内容脚本)没有附加到iframe?

我可以确保未附加到iframe的工作者是推送到_workers的工作者,但是一旦我确保了,就有办法将内容脚本附加到工作人员身上这是正确的吗?我不希望多次附加相当大的内容脚本。

编辑2

再次感谢@Noitidart,我认为我有一些解决方案:如果检测到工作人员被附加到iframe,则销毁。

更好的解决方案是仅将主要内容脚本附加到正确的工作者,但目前我无法找到将内容脚本附加到正确的工作者的方法(worker.contentScriptFile = data.url("file.js")似乎没有工作)。

所以,目前的黑客攻击:

verify.js

if(window.top !== window) {
    self.port.emit('iframe');
}
else {
    self.port.emit('hi');
}

main.js

var _workers = [];

var pageMod = require("sdk/page-mod").PageMod({
    include: /https?:\/\/www\.websitename\.net.*/,
    contentScriptFile: [data.url("verify.js"), data.url("my_main_script.js")],
    contentScriptWhen: "end",
    onAttach: function(worker) {
        worker.on("detach", function() {
            var ind = _workers.indexOf(this);
            if(ind !== -1) {
                _workers.splice(ind, 1);
            }
        });

        worker.port.on("hi", function() {
            //Not iframe, keep this one.
            //If there is a way, attach 'my_main_script.js'
            //to this worker now, and not before.

            _workers.push(worker);

            //Emit 'ack' to tell my_main_script.js
            //that we're good to go.
            worker.port.emit('ack');
        });

        worker.port.on("iframe", function() {
            //iframe, get rid of it.
            worker.destroy();
        });
    }
});

我应该注意,这些程序在contentScriptFile中出现的顺序并不重要,两个脚本都会为每个附件加载。所以没有必要希望 verify.js 在加载 my_main_script.js 之前销毁工作人员。

同样,这个解决方案还没有完成。如果我在这一点上没有足够强调,我真的希望有一种方法可以将 my_main_script.js 附加到正确的工作者,而不是为所有工作者加载它。如果有这样的方式,请评论/回答。

2 个答案:

答案 0 :(得分:4)

在contentScript或网站上运行的任何内容(我对sdk不太了解),检查if (window.frameElement == true)如果它的真实而不是它的帧,那么你想要取消附加。

编辑: 也许window.frameElement不会在框架内工作。如果它不起作用,请执行此if (window.top != window),然后是一个框架

答案 1 :(得分:2)

以下是您可以使用attachTo设置的Mozilla documentation链接。 “所有”的默认设置包括iframe,因此您应该执行以下操作

var pageMod = require("sdk/page-mod");
  pageMod.PageMod({
  include: "*",
  contentScript: "",
  attachTo: ["existing", "top"],
  onAttach: function(worker) {
   console.log(worker.tab.url);
 }
});