问题
I am trying to write a Firefox add-on for personal use and to learn a bit more about both JavaScript and the Firefox Add-on SDK. The add-on should open a vivo.sx
URL and then automatically start the player, but I have 2 issues. I hope you guys can help me.
The relevant add-on-code:
function vivoplay()
{
pageMod.PageMod({
include: "https://vivo.sx/*",
contentScriptFile: "./vivoplay.js",
onAttach: play
});
function play(worker) //Fires 2 Times
{
console.log("Timeout");
tmr.setTimeout(sendplay, 14000);
function sendplay()
{
var a = 0;
worker.port.emit("start", a);
}
}
}
content-script
self.port.on("start", function(a) {
console.log("Load");
flowplayer().load(); //ReferenceError: flowplayer is not defined
console.log("Loaded");
});
The first problem is that the function play
fires 2 times, but should only run once. It's probably the onAttach
that does not work correctly. What do you think about that?
The more important problem is the ReferenceError
. I have a Greasemonkey script where I use the function flowplayer().load();
. I thought the content script is running like a Greasemonkey script. So, I should be able to use this function. Is that correct? How can I fix this?
my greasemonkey script
// ==UserScript==
// @name 3. Vivo
// @namespace Autoplay
// @include https://vivo.sx/*
// @version 1
// @grant none
// ==/UserScript==
window.setTimeout(Play, 2000);
function Play()
{
flowplayer().load();
console.log("Loaded");
flowplayer().fullscreen();
console.log("Fullscreen started");
}
I am quite new to this so please be patience with me :)
If you need more information, please leave a comment.
回答1:
The problem you are experiencing is that you are not taking into account that your content script is executing in a different context than the scripts in the webpage (page scripts). Keeping content scripts separate from page scripts is a normal architecture for browser extensions which is done for security reasons. Your content script has higher privileges than are granted to page scripts. While you technically could execute a function provided by the page from within your content script context, for security reasons, you should never do so. If you do choose to do so, your extension will not pass review by Mozilla for being listed on AMO.
While you can expose functions which exist in your content script to page scripts, and create objects in the page script scope, the way to actually execute code from within the page script context is to add a <script>
element to the document
containing the code you desire to execute.
For the code in your question, this could be implemented as:
self.port.on("start", function(a) {
let newScript = document.createElement('script');
//The calls to console.log don't need to be in the page script.
// However, the code in the newScript is executed asynchronously. Thus, if the
// console.log("Loaded");
// is in the content script it will be executed prior to flowplayer().load() actually
// being called.
newScript.innerHTML = 'console.log("Load");'
+ 'flowplayer().load();'
+ 'console.log("Loaded");' ;
document.head.appendChild(newScript);
});
onAttach
/play
running more than once:
Without your full code and a screenshot of what the browser looked like it is impossible to be certain why this would occur.
The most likely reason is that you had more than one tab open to an address that matched "https://vivo.sx/*"
. Your onAttach
code will be called each time the content script is attached to a page. It will be attached once for each tab which is open to a matching URL. If you had two tabs open to matching URLs when the add-on was loaded, then the onAttach
code will be executed twice.
Another possibility is that you have executed vivoplay
more than once resulting in setting up multiple PageMod
s each of which would attach a separate copy of your content script to each tab. Given the name you used for this function, vivoplay
, you may be treating it as a play function which you are executing more than once. With how you have things organized within that function, you should not do so.
Overly complex for what is shown:
Your code is overly complex for what is shown. You are using the onAttach
event to sent start
to the content script. The content script is only loaded/executed when it is attached. Thus, informing the content script that it is attached by sending start
is redundant. This might be reasonable if you are intending to modify the code to only send start
in response to some other event (e.g. the user clicking a button). However, if it is your intent to always auto-start the Flowplayer, then there is no need to send a start
message to the content script. The content script can have the setTimeout
and just go ahead and execute that code when it is run.
来源:https://stackoverflow.com/questions/40167733/how-to-use-flowplayer-functions-in-a-content-script