找到清洁解决方案
我发现了一个非常干净的解决方案,这使得整个问题毫无意义,我确信当我提出这个问题时它就存在了......我非常无知也在寻找它。
在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 附加到正确的工作者,而不是为所有工作者加载它。如果有这样的方式,请评论/回答。
答案 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);
}
});