PageM将worker多次附加到同一URL

Rik*_*tor 9 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");
    }
});
Run Code Online (Sandbox Code Playgroud)

当然,如果没有@ 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");
    }
});
Run Code Online (Sandbox Code Playgroud)

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

[https://www.websitename.net/]: My worker said hello to me!
Run Code Online (Sandbox Code Playgroud)

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

编辑:

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

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

我可以确保没有附加到a的工作者是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');
}
Run Code Online (Sandbox Code Playgroud)

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();
        });
    }
});
Run Code Online (Sandbox Code Playgroud)

我应该注意,contentScriptFile脚本出现的顺序并不重要,两个脚本都为每个附件加载.所以毫无疑问,在加载my_main_script.js之前,verify.js会破坏worker .

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

Noi*_*art 4

在 contentScript 或网站中运行的任何内容中(我对 sdk 不太了解),检查if (window.frameElement == true)它是否比它的框架更真实,然后你想取消附加。

编辑:也许 window.frameElement 无法在框架内工作。如果它不起作用,if (window.top != window)那么它是一个框架