I'm build an SDK Firefox Add-on that is supposed to read a tab's URL and parse it. To this end, I'm listening to the 'ready' event in lib/main.js,
var tabs = require('sdk/tabs');
tabs.on('open', function(tab){
tab.on('ready', function(tab){
console.log(tab.url);
});
});
as described in Mozilla's documentation.
When debugging with cfx run, this appears to work well for new tabs. The tab that's already open on cfx run, however does not fire the open and ready events.
What's the reason for this and how to fix it?
To list all tabs that were open at the moment of loading the addon you could just use the tabs object you got after requiring sdk/tabs
var tabs = require('sdk/tabs');
for (var tab of tabs) {
console.log(tab.url);
}
So the code from your example could be transformed to something like this:
var tabs = require('sdk/tabs');
for (let tab of tabs) {
processTab(tab);
}
tabs.on('open', function(tab){
tab.on('ready', processTab);
});
function processTab(tab) {
console.log(tab.url);
}
Related
I wrote a Web Extension which starts surfing specified websites automatically (to simulate/train user profiles by "collecting" website cookies) after the Chrome browser is opened.
I know that you can disable the popup by whitelisting it for your own Web Extension:
Disable developer mode extensions pop up in Chrome
But: My Web Extension has to run automatically on 8-16 virtual machines on Linux without a GUI and i don't know whether it is possible and how to do it.
My Extension opens the first URL as expected, but then the popup comes into play and stops further surfing. If i open another tab per hand it continues to work, but opening a tab via Javascript doesn't do the trick. My code usually doesn't have to handle multiple tabs, because everything is done with one tab. Maybe i'm executing the code at the wrong time. The code works perfectly, when the popup doesn't come.
My code without tab opening:
background.js
var shouldMessageBeSent = true;
chrome.windows.onCreated.addListener(function() {
chrome.tabs.update({url:"https://stackoverflow.com/"}); // placeholder URL
});
chrome.webNavigation.onCompleted.addListener(function() {
if (shouldMessageBeSent == true) {
chrome.tabs.query({"currentWindow": true}, function(tabs) {
shouldMessageBeSent = false;
chrome.tabs.sendMessage(tabs[0].id, {txt: "newURLvisited"}, function(response) {});
});
}
});
chrome.runtime.onMessage.addListener(gotMessage);
function gotMessage(message) {
if (Array.isArray(message)) { // It's an array in my code
linksToVisit = message;
}
visitLinks(linksToVisit); // visits all the given links (the links are filtered in my code)
}
Content.js (highly simplified)
chrome.runtime.onMessage.addListener(gotMessage);
function gotMessage(message) {
if (message.txt === "newURLvisited") {
var allLinks = document.getElementsByTagName("a");
chrome.runtime.sendMessage(allLinks);
}
}
Any ideas what to fix? It may have to do something with active window/tab focus.
Apparently you can install a policy for Chrome, provided as a template from Google, which you can edit to your taste before that; I suppose you can do a similar thing on Mac and Linux just in a JSON editor.
I have the following code to introduce my Chrome Extension.
// detect if this is the first time running
var first_run = false;
if (!localStorage['ran_before']) {
first_run = true;
localStorage['ran_before'] = '1';
}
// if not, start the intro() script
if (first_run) intro();
// intro script
function intro() {
window.open("intro/index.html", '_blank');
}
But sadly, when I click the extension, it doesn't open the popup.html but just opens the intro page.. it needs to keep the popup.html open and I'm sure there is a way to do this. I want to open them both at the same time.
What is the best way to do this?
the method you are using is valid and should work, but you should probably
just use the onInstalled event for consistency:
chrome.runtime.onInstalled.addListener(function(info){
if(info.reason == "install"){
console.log("Installed!");
}else if(info.reason == "update"){
console.log("Updated!");
}
});
It doesn't require new permissions, and will keep your install code clearly separated from the rest of your code.
While Marc Guiselin's answer is excellent, it may be useful to know how to open a tab without closing a popup.
You could open the tab in the background, that way it won't close your popup.
chrome.tabs.create({
url: chrome.runtime.getURL("intro/index.html"),
active: false
});
In general, you should avoid using window.open in extensions and use chrome.tabs and chrome.windows API instead.
I am trying to develop a simple add-on for Firefox which should work something like this:
User clicks item in context menu.
New tab is opened.
Content (innerHTML) of the new tab is overridden using content script.
Also, the content script should only be executed once, so that if the user would enter a website in the new tab the script should not be executed.
I've got it working with editing the new tabs content, but my only problem is to have the content script run only once when the tab is opened. In the code I have at the moment the script run every time a page has been loaded in the tab:
var contextMenu = require("sdk/context-menu");
var tabs = require("sdk/tabs");
var menuItem = contextMenu.Item({
label: "Test",
contentScript: 'self.on("click", function () { self.postMessage(); })',
onMessage: function (data) {
newTab();
}
});
function newTab () {
tabs.open("about:blank");
tabs.activeTab.on('ready', function (tab) {
tab.attach({
contentScript: 'document.body.innerHTML = "testing";'
});
});
}
I'm guessing there's a way to have this run only the first time the tab is "ready". Seems like a simple task but I can't figure out how to do this. Anyone got any tips?
Use tabs.activeTab.once(); instead of tabs.activeTab.on();.
This way the listener gets detached once it intercepts the first message.
I have a page action popup that works when loaded from the manifest file. However I want to get the tab information for the tab that was clicked to launch the popup. I can get the tab information from chrome.pageAction.onClicked.addListener but I don't know how to launch popup.html from inside pageAction.onClicked.
You cannot have both a pageAction.onClicked:
onClicked
This event will not fire if the page action has a popup.
What you can do, though, is fetching the current tab information with the Tabs module when the popup is loaded:
chrome.tabs.getCurrent(function(tab) {
// tab contains information about the current tab
});
I found a workaround for what I wanted to do. On the background page:
chrome.tabs.onActiveChanged.addListener(OnActiveChanged);
function OnActiveChanged( tabId, selectInfo )
{
chrome.tabs.get( tabId, function( tab ){
window.activeTab = tab;
} );
}
This captures the tab each time the tab changes. Then in my popup's function gets the tab from the background page:
function OnLogin( )
{
backgroundWindow = chrome.extension.getBackgroundPage();
var activeTab = backgroundWindow.activeTab;
...
}
Be careful when you debug the code though. The debugger causes a tab change event which changes the tab away from the tab that launched the popup.
I am writing an page action extension for Google Chrome. The extension injects the following script into a search page after it loads. After the script finds all the occurrences of class "f_foto" (typically 10 items), it finds the first link in each of them, puts these hrefs in an array and then iterates thru the array opening a new window for each link and examining the result. That's what it is supposed to do.
Everything works ok in this code except the last part. The new window opens in a new tab (I have tabs permission) but it only finishes loading after the script finishes. Each new window overwrites the previous one in the same tab which would be ok if I had a chance to examine the contents first. So if I run it without using the debugger when the script finishes the new tab contains the last item in the array and focus is on the new tab. As far as I can see, handleResponse is never called.
If I run it in the DOM inspector and stop it at window.open, I can see that the new tab opens with "About Blank" in the title and the tab shows a spinning thingy showing that it is loading. Stepping thru the code, detailWin remains undefined even after detailWin=window.open(profileLinks[i], "Detail Window"); is executed. I've tried replacing window.onload = handleResponse; with detailWin.onload =handleResponse; but in this case detailWin is undefined.
It seems to me I need to add an event listener that fires when the new window is loaded and executes handleResponse. Yes? No?
//PEEK.JS//
var req;
var detailWin;
var profileLinks = new Array();
function handleResponse()
{
// var contentDetail = document.getElementsByClassName("content");
alert("Examine Detail Page Here");
};
//drag off the f_foto class
var searchResult = document.getElementsByClassName("f_foto");
alert("Found Class f_foto "+searchResult.length+" times.");
//collect profile links
for (var i = 0; i<searchResult.length; ++i)
{
var profileLink=searchResult[i].getElementsByTagName("a");
profileLinks[i]=profileLink[0].href;
// alert(i+1+" of "+searchResult.length+" "+profileLinks[i]+" length of "+profileLinks[i].length);
}
for (var i = 0; i<searchResult.length; ++i)
{
//DYSFUNCTIONAL CODE: New window finishes loading only after script completes, how to execute handleResponse?
detailWin=window.open(profileLinks[i], "Detail Window");
window.onload = handleResponse;
}
Option #1: make two separated content scripts - one for the search page only, one for the profile page only. Search script would only open profile link, profile script would only process it (contains code inside your handleResponse())
Option #2 If for some reasons you don't want to inject profile script to all profile pages, only to those you opened yourself from the search page, then instead of opening windows from a content script you should send a message to a background page asking it to open a profile link in a new tab and inject your profile script.
You still will have two content scripts.
search.js (injected to search pages only):
//PEEK.JS//
var req;
var detailWin;
//drag off the f_foto class
var searchResult = document.getElementsByClassName("f_foto");
alert("Found Class f_foto "+searchResult.length+" times.");
//collect profile links
for (var i = 0; i<searchResult.length; ++i)
{
var profileLink=searchResult[i].getElementsByTagName("a");
profileLinks[i]=profileLink[0].href;
// alert(i+1+" of "+searchResult.length+" "+profileLinks[i]+" length of "+profileLinks[i].length);
}
for (var i = 0; i<searchResult.length; ++i)
{
//tell bkgd page to open link
chrome.extension.sendRequest({cmd: "openProfile", url: profileLinks[i]});
}
profile.js (will be injected to profile pages you opened)
var contentDetail = document.getElementsByClassName("content");
alert("Examine Detail Page Here");
background.html:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if(request.cmd == "openProfile") {
chrome.tabs.create({url: request.url}, function(tab){
//profile tab is created, inject profile script
chrome.tabs.executeScript(tab.id, {file: "profile.js"});
});
}
});
Option #3: Maybe you don't need to create profile window at all? If all you need is to find something in the page source, then you can just load that page through ajax and parse it (you would need to do it in a background page).