How do I determine that all tabs have been loaded in Firefox? - javascript

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);

Related

How can I change the User Agent in just one tab of Firefox?

I'm developing a Firefox extension and I need to change the user agent of a single tab. I have used extensions such as User Agent Switcher, but it only let me change the user agent in the entire browser. Do you know if that is possible? Where can I read about?
Thanks a lot,
G.
this is a fun addon. i wanted to make an addon which enabled proxy only in single tab, i think this here helping u will lead me to make that sometime soon
copy paste code. it will spoof user-agent in all things loaded in tab 1. in all other tabs it will let the load go through. however if there is no loadContext you wont be able to tell which tab its coming from, so probably just ignore it and let it go.
we need advice from ppl more experienced then me. in what cases do we get a null loadContext?
on to the copy paste code
const {classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu, results: Cr, manager: Cm} = Components;
Cu.import('resource://gre/modules/Services.jsm');
var myTabToSpoofIn = Services.wm.getMostRecentBrowser('navigator:browser').gBrowser.tabContainer[0]; //will spoof in the first tab of your browser
var httpRequestObserver = {
observe: function (subject, topic, data) {
var httpChannel, requestURL;
if (topic == "http-on-modify-request") {
httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
var goodies = loadContextGoodies(httpChannel)
if (goodies) {
if (goodies.aTab == myTabToSpoofIn) {
httpChannel.setRequestHeader('User-Agent', 'user agent spoofeddddd', false);
} else {
//we arent spoofing in this tab so ignore it
}
} else {
//no goodies so we dont know what tab its from, im not sure when we dont have a loadContext we need to ask other ppl
//no goodies for this channel, so dont know what tab its in so probably just load this, your decision though, make it option to user, if cannot find associated load context ask user if they want the data to be loaded with default user agent or just not load it at all
//httpChannel.cancel(Cr.NS_BINDING_ABORTED); //uncomment this to abort it
}
}
}
};
Services.obs.addObserver(httpRequestObserver, "http-on-modify-request", false);
//Services.obs.removeObserver(httpRequestObserver, "http-on-modify-request", false); //run this on shudown of your addon otherwise the observer stags registerd
//this function gets the contentWindow and other good stuff from loadContext of httpChannel
function loadContextGoodies(httpChannel) {
//httpChannel must be the subject of http-on-modify-request QI'ed to nsiHTTPChannel as is done on line 8 "httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);"
//start loadContext stuff
var loadContext;
try {
var interfaceRequestor = httpChannel.notificationCallbacks.QueryInterface(Ci.nsIInterfaceRequestor);
//var DOMWindow = interfaceRequestor.getInterface(Components.interfaces.nsIDOMWindow); //not to be done anymore because: https://developer.mozilla.org/en-US/docs/Updating_extensions_for_Firefox_3.5#Getting_a_load_context_from_a_request //instead do the loadContext stuff below
try {
loadContext = interfaceRequestor.getInterface(Ci.nsILoadContext);
} catch (ex) {
try {
loadContext = subject.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
} catch (ex2) {}
}
} catch (ex0) {}
if (!loadContext) {
//no load context so dont do anything although you can run this, which is your old code
//this probably means that its loading an ajax call or like a google ad thing
return null;
} else {
var contentWindow = loadContext.associatedWindow;
if (!contentWindow) {
//this channel does not have a window, its probably loading a resource
//this probably means that its loading an ajax call or like a google ad thing
return null;
} else {
var aDOMWindow = contentWindow.top.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
var gBrowser = aDOMWindow.gBrowser;
var aTab = gBrowser._getTabForContentWindow(contentWindow.top); //this is the clickable tab xul element, the one found in the tab strip of the firefox window, aTab.linkedBrowser is same as browser var above //can stylize tab like aTab.style.backgroundColor = 'blue'; //can stylize the tab like aTab.style.fontColor = 'red';
var browser = aTab.linkedBrowser; //this is the browser within the tab //this is where the example in the previous section ends
return {
aDOMWindow: aDOMWindow,
gBrowser: gBrowser,
aTab: aTab,
browser: browser,
contentWindow: contentWindow
};
}
}
//end loadContext stuff
}
also a note. because you want to change user request make sure that third parameter is set to false in httpChannel.setRequestHeader('MyCustomRequestHeader', 'hiiii', false); otherwise it will merge the pre-existing user agent with the new one you supply

Chrome extension: have an extension listen for an event on a page?

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/

Emit message to add-on from content script onbeforeunload?

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.

Using gBrowser and observerService to find a tab on startup

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.

The equivalent to a content script in a Firefox extension?

I am quite new to Firefox and its extensions. Is there something like a script using JavaScript that runs every time a page loads? My chrome extension injects a css file creating a link tag using js. How do I port this to Firefox?
You want the pageMod API.
var pageMod = require("page-mod");
pageMod.PageMod({
include: "*.example.org",
contentScript: 'window.alert("Page matches ruleset");'
});
You can use mozIJSSubScriptLoader to execute the JavaScript (chrome://myExtension/content/script.js) every time a webpage loads. Here is the sample code that you need to modify according to your chrome directory
window.addEventListener("load", function load(event){
window.removeEventListener("load", load, false); //remove listener, no longer needed
myExtension.init();
},false);
var myExtension = {
init: function() {
var appcontent = document.getElementById("appcontent"); // browser
if(appcontent){
appcontent.addEventListener("DOMContentLoaded", myExtension.onPageLoad, true);
}
var messagepane = document.getElementById("messagepane"); // mail
if(messagepane){
messagepane.addEventListener("load", function(event) { myExtension.onPageLoad(event); }, true);
}
},
onPageLoad: function(aEvent) {
var doc = aEvent.originalTarget; // doc is document that triggered "onload" event
// do something with the loaded page.
// doc.location is a Location object (see below for a link).
// You can use it to make your code executed on certain pages only.
var loader = Components.classes["#mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader);
loader.loadSubScript("chrome://myExtension/content/script.js", doc);
// add event listener for page unload
aEvent.originalTarget.defaultView.addEventListener("unload", function(event){ myExtension.onPageUnload(event); }, true);
},
onPageUnload: function(aEvent) {
// do something
}
};
I used to use Greasemonkey on Firefox. In fact, Chrome Extensions began as a mimic of Greasemonkey, and were the origin of content scripts.

Categories