I have a content script which times how long a user views a page. To do this, I inject a content script into each page, start a timer and then emit a message back to the add-on when the onbeforeunload event is triggered.
The message never seems to get passed to the background script however.
Given that my main.js looks like this:
var pageMod = require('page-mod'),
self = require("self");
pageMod.PageMod({
include: "http://*",
contentScriptFile: [self.data.url('jquery.min.js'),
self.data.url('content.js')],
onAttach: function(worker) {
worker.port.on('pageView', function(request) {
console.log("Request received");
});
}
});
I can send a message to main.js using the following code no problem.
self.port.emit('pageView', { visitTime: time });
I run into a problem when I try to do it as the user leaves the page however. The message is never received when I do it like this:
$(window).bind('onbeforeunload', function(e) {
self.port.emit('pageView', { visitTime: time });
// This should prevent the user from seeing a dialog.
return undefined;
});
I've tried listening for beforeunload too, that doesn't work either. What could be the problem?
The window object that content scripts access in Firefox browser add-ons is a proxy object and can be a little temperamental. Using window.addEventListener will work.
window.addEventListener('beforeunload', function(e) {
# Do stuff then return undefined so no dialog pops up.
return undefined
});
The onbeforeUnload event is not synchronous, so the browser garbage collects the page before it is finished. Use a synchronous AJAX request:
function Data()
{
var client = new XMLHttpRequest();
client.open("GET", "/request", false); // third paramater indicates sync xhr
client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
client.send({ visitTime: time });
client.onreadystatechange = emitter;
}
function emitter()
{
self.port.emit('pageView', { visitTime: time });
}
or return a string as an alternative.
Related
This is the code, P.S: the service httpd in s10 is stopped
try {
var source = new EventSource("http://s10/server.php");
console.log(source);
} catch (e) {
console.log("ADSfasfasfasdfasdfas" + e)
}
this is the console:
why the heck the try catch is not catching the error ??
ofcourse I have onerror event and onclose event:
source.addEventListener('error', function(e) {
if (source.readyState == 2) {
connectionClosed();//to change some style
console.log("Disconnected");
}
}, false);
source.onerror = function(e) {
if (source.readyState != 0) {
connectionClosed();//to change some style
console.log("Disconnected");
}
};
source.onclose = function() {
connectionClosed();//to change some style
console.log('Connection closed');
}
When I run this in the Console on an arbitrary URL that isn't set up to handle SourceEvents, the Console successfully logs a SourceEvent instance. This is similar to what you're describing.
So my guess here is that there's no error to catch. The SourceEvent instance is successfully constructed, even though there's no actual connection. If you want to detect if the connection is working, use the EventSource.readyState property.
In my screenshot you can see that readyState = 0, which means that the connection is "connecting", but in reality it's never going to finish connecting because the server on the other side isn't set up to handle SourceEvents.
https://developer.mozilla.org/en-US/docs/Web/API/EventSource/readyState
I'm testing the same thing, the onerror doesn't provide really useful info. For example, if you shut down your server or if you send an empty response while your client is connected, you can't detect programmatically on the client side the specific cause, I can see that just inspecting the dev console.
I'm trying to extend some of the handling of messaging between my background process and content scripts. In the normal course of things my background process sends a message via postMessage() and the content script replies via another channel with a response. However I would like to now extend the background process to fall-back to something else if the content script can't find a valid thing on the page. It's when looking at this I discovered a problem when sending a message to blank or system pages. As the tabs don't have content scripts loaded there is nothing to receive the posted message. This generates warnings in the console logs but otherwise no ill effects. However:
// Called when the user clicks on the browser action.
//
// When clicked we send a message to the current active tab's
// content script. It will then use heuristics to decide which text
// area to spawn an edit request for.
chrome.browserAction.onClicked.addListener(function(tab) {
var find_msg = {
msg: "find_edit"
};
try {
// sometimes there is no tab to talk to
var tab_port = chrome.tabs.connect(tab.id);
tab_port.postMessage(find_msg);
updateUserFeedback("sent request to content script", "green");
} catch (err) {
if (settings.get("enable_foreground")) {
handleForegroundMessage(msg);
} else {
updateUserFeedback("no text area listener on this page", "red");
}
}
});
Doesn't work. I would expect the connect or the postMessage to throw an error I can trap, however the console log is filled with error messages including:
Port: Could not establish connection. Receiving end does not exist.
But I do not end up in the catch statement.
In the end I couldn't do it with connect, I had to use the one shot sendMessage() which has a call-back function when the response comes in. That can then be interrogated for success and the state of lastError. The code now looks like this:
// Called when the user clicks on the browser action.
//
// When clicked we send a message to the current active tab's
// content script. It will then use heuristics to decide which text
// area to spawn an edit request for.
chrome.browserAction.onClicked.addListener(function(tab) {
var find_msg = {
msg: "find_edit"
};
// sometimes there is no content script to talk to which we need to detect
console.log("sending find_edit message");
chrome.tabs.sendMessage(tab.id, find_msg, function(response) {
console.log("sendMessage: "+response);
if (chrome.runtime.lastError && settings.get("enable_foreground")) {
handleForegroundMessage();
} else {
updateUserFeedback("sent request to content script", "green");
}
});
});
I have a chrome extension that im making for my site, currently i have the extension checking the database every minute for updates.
Is it possible to have the extension listen for an event on the actual page?
Something like this
this.trigger('sendUpdate', data) //this happened on the page
this.on(sendUpdate, function(){ //this is what the chrome extension listens for
//do stuff with data
})
you need to add a content_script. content_script have full access to the DOM and you can bind to all events on page
just add this to the menifest file
"content_scripts":[{
"matches":["http://*/*","https://*/*"],
"js":"your injected script.js"
}]
you can get more info https://developer.chrome.com/docs/extensions/mv2/content_scripts/
also from your question it looks like you going to be working with a custom event so your content_scrip js is going to be something similar to this
document.addEventListener('yourEventName', function(e){
//send message to ext
var someInformation = {/*your msg here*/}
chrome.extension.sendMessage(someInformation, function(response) {
//callback
});
}, false);
the background page should listen for a message.
chrome.extension.onMessage.addListener(function(myMessage, sender, sendResponse){
//do something that only the extension has privileges here
return true;
});
then you can trigger the Event from all scripts on the page...
var evt = document.createEvent('Event');
evt.initEvent('yourEventName', true, true);
var some_element = document;
some_element.dispatchEvent(evt);
For anyone reading this in 2023, the sendMessage method has moved to chrome.runtime.sendMessage.
See documentation for manifest v3 (MV3): https://developer.chrome.com/docs/extensions/mv3/messaging/
I'm trying to create a firefox addon that will look for a certain page on startup and grab some info from it. I'm having trouble finding the page at load. Here's what I have so far:
var myfancyaddon = {
onLoad: function() {
var observerService = Components.classes["#mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
observerService.addObserver(function restored() {
observerService.removeObserver( restored, "sessionstore-windows-restored");
var browser = myfancyaddon.findMySite();
if (browser) {
alert("tree falling in the woods"); // THIS LINE NEVER RUNS
browser.contentWindow.addEventListener("load", function tab_loaded(){
browser.contentWindow.removeEventListener("load", tab_loaded(), false);
alert("mysite loaded!");
}, false);
}
}, "sessionstore-windows-restored", false);
},
findMySite: function() {
var browsers = gBrowser.browsers;
for ( var i = 0; i < browsers.length; i++ ) {
var browser = browsers[i];
if (!browser.currentURI.spec) continue;
if ( browser.currentURI.spec.match('^https?://(www\.)?mysite\.com/') ) return browser;
}
return null;
}
};
window.addEventListener("load", function ff_loaded(){
window.removeEventListener("load", ff_loaded, false); //remove listener, no longer needed
myfancyaddon.onLoad();
},false);
after some investigation it seems the currentURI.spec is "about:blank" for a short time before it becomes mysite.com. Any ideas?
Instead of filtering first and then adding the load listener, you could use gBrowser.addEventListener("DOMContentLoaded", myfunction, false); to listen for page loads on all tab documents and then only run your code based on the url.
https://developer.mozilla.org/en/XUL_School/Intercepting_Page_Loads
The "sessionstore-windows-restored" notification is sent when the tabs from the previous session have been restored and the loading in these tabs has been started (sometimes: "Don't load tabs until selected" option means that the load isn't even started in the background tabs). But the location of these tabs is still about:blank until the server is contacted because the address loaded might redirect or the server might be unreachable (meaning an internal redirect to about:neterror). Firefox only changes browser location when content is definitely being served from the new location.
It should be indeed better to intercept page loads rather than waiting for session restore.
I am writing a Firefox add-on and I need to be able to run some code after all the tabs have been loaded.
I tried something like:
window.addEventListener("load", function(e) {
gBrowser.addEventListener("load", function(ee) {
// code to run after all tabs have loaded
// thank user for installing my add-on
alert('Thank you for installing my add-on');
// add tab to my website
gBrowser.selectedTab = gBrowser.addTab("http://www.mywebsite.com/");
}, true);
}, false);
But this does not work because this will run the code for each tab after it is loaded. I want to wait until all of the tabs have loaded. I want to print an alert message when the Firefox restarts after the users installs my add-on. I also want to add a new tab to my website.
How do I do this?
I guess that you mean to wait until the session is restored when the browser starts up. There is a sessionstore-windows-restored notification sent out that you can listen to via observer service. Something like this:
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var observer =
{
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIObserver]),
observe: function(subject, topic, data)
{
observerService.removeObserver(observer, "sessionstore-windows-restored");
addTabNow();
}
};
var observerService = Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
observerService.addObserver(observer, "sessionstore-windows-restored", false);