Chrome extension: Get current tab from popup - javascript

I'm writing a Chrome extension and, in one part of it, I need to get the current tab's title and URL when a button on the popup page is clicked.
I've worked with Chrome's message passing system before and, after much effort, managed to get it to work, on many occasions. However, I've never had to use them with popup pages and, from what I've read, it's much more difficult to do.
The timeline I've managed to figure out so far is this:
popup.html / popup.js: Button is clicked
popup.html / popup.js: Request / message is sent to the content script
contentScript.js: Request / message is received from the popup page
contentScript.js: The title and URL of the current tab are stored in a variable
contentScript.js: The 2 variables are sent as a stringified response
popup.html / popup.js: The 2 variables are parsed from the response
Usually I'd be able to figure this out but, I've read a few things that have thrown a spanner in the works, such as:
chrome.tabs.getSelected can only be used in a background page / script. Does this mean that content scripts don't need to be used at all?
Messages cannot be sent directly from the content script to the popup page, they have to go via a background page
A popup window has to be confirmed as existing before a message can be passed to it (although, I think I know how to do this)
I already found Chrome's message passing system difficult enough but, this has totally confused me. Hence, this post.

chrome.tabs.getSelected is deprecated. You should use chrome.tabs.query instead.
chrome.tabs.query requires two parameters: a query object and a callback function that takes the array of resulting tabs as a parameter.
You can get the "current tab" by querying for all tabs which are currently active and are in the current window.
var query = { active: true, currentWindow: true };
Since the query will return a Tab array containing the current tab alone, be sure to take the first element in the callback
function callback(tabs) {
var currentTab = tabs[0]; // there will be only one in this array
console.log(currentTab); // also has properties like currentTab.id
}
Et voilĂ :
chrome.tabs.query(query, callback);

Another way is to send a message from the popup to the content script which then returns the URL window.location.href

Related

Simplest Way to get the current Tab Id?

I dont really unterstand how the Chrome Extension API works. It was a rough to understand how the background.js and the content.js works, but my current Problem is, that the function insertCSS(); seems to need the tabId, even if the official documentation says that its optional.
So, none of the Answers on this plattform could help me, because I dont even understand the Concept of the whole API.
So can anybody explain me, why something like this is not possible?
var tabInfo = chrome.tabs.getCurrentTab();
var id = tabInfo.tabId;
There are several questions to be answered here.
Literal question
So can anybody explain me, why something like this is not possible?
var tabInfo = chrome.tabs.getCurrentTab();
Short answer: because most of the Chrome API does not return a value; it is asynchronous, meaning that some other component of Chrome will work on getting the answer while JS execution resumes.
A comprehensive overview of JS asynchronicity can be read at this canonical question.
There are two ways to deal with it:
Use callbacks, and be aware that the actual callback execution happens after the rest of the calling code.
Use async/await and/or Promises. The WebExtension polyfill can help with that, but it's outside the scope of the question.
Question in title
Simplest Way to get the current Tab Id?
or "why chrome.tabs.getCurrentTab won't help you".
chrome.tabs.getCurrentTab() returns the tab ID of the calling page. See the docs.
This is of limited utility: only extension pages (and not content scripts) can call this API.
Extension pages are:
background (no tab ID),
popup (no tab ID),
options page (it's complicated as it's embedded in a Chrome page),
"other" extension pages opened in a visible tab (here, it works as expected).
It's not your use case, as established in the comments.
The actual way to get the current active tab is chrome.tabs.query() with the query {active: true, currentWindow: true}, but keep on reading.
Actual question you're having
As reconstructed from the comments, here's the actual scenario you're having:
I have an event in a content script. I need to call the tabs.insertCSS API, so I'm messaging the background page to do it for me. How do I get the tabId for this call?
Well, the key here is to take a closer look at the runtime.onMessage event listener signature:
The callback parameter should be a function that looks like this:
function(any message, MessageSender sender, function sendResponse) {...};
What's a MessageSender?
An object containing information about the script context that sent a message or request.
tabs.Tab (optional) tab
The tabs.Tab which opened the connection, if any. This property will only be present when the connection was opened from a tab (including content scripts), and only if the receiver is an extension, not an app.
[...]
Jackpot. We're sending the message from a content script, and the listener is handed the sender.tab information "for free". We just need a quick detour into tabs API docs to see what a Tab contains, and we have it:
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
chrome.tabs.insertCSS(sender.tab.id, {/*...*/});
});
Misconception
my current Problem is, that the function insertCSS() seems to need the tabId, even if the official documentation says that its optional
It doesn't. If you call it omitting the tabId, which makes the details object the first argument, then Chrome will assume you want the "the active tab of the current window".
It may seem that this doesn't work if you're trying to execute it in the Dev Tools window for the background page. That's because in this instance there's no such tab. The current window is the one you're putting the console command in. So what the call does without the tabId is very sensitive to what actually is the current window.
It may also be the case that you don't have the permissions to inject in the current active tab, that would also fail.
Generally, it pays to be specific with the tab ID, it removes uncertainty about the logic of the extension.

Chrome Extension automatically refreshing options page UI

In the options page of my extension, I display the username of the person logged in, along with an option to log out. If they log out, I display instead a link asking them to log in. As well as being able to log in via the options page, they can also do so via the popup.html. The logged-in status is stored in localStorage, which I can access from the options page js.
I would like to be able to listen, in some way, for a change to this status, and update the UI accordingly. If changes are made via the options page, then I of course can change it. However, the issue is if a user logs in whilst via the popup, whilst already on the options page. In that situation, I would still like the options page UI to alter, to now reflect the updated logged-in status. I have thought of 2 different approaches:
(1) Have the background script send a message using chrome.runtime.sendMessage() to the options script every time I change the logged in status.
(2) Add a listener on the localStorage that fires when the logged-in status is changed.
I have tried both approaches, and failed. How can I automatically refresh the UI of my options page depending on the value of a localStorage variable which can be altered from different scripts within the extension?
The answer may be in (1) or (2), however my experience with chrome extensions is limited, so I might have got it programatically wrong and given up too early. Any help would be appreciated.
So I found an answer that allows me to send me message between the background and option page scripts. I had previously tried with chrome.runtime.sendMessage, etc..., however must have made a mistake in the way I implemented it.
options.js script:
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
switch(request.type) {
case "loggedin-status-change":
alert(request.data.myProperty);
break;
}
return true;
});
and the background.js script:
chrome.extension.sendMessage({
type: "loggedin-status-change",
data: {
myProperty: "1"
}
});

message passing in a Google chrome extension

There are a few questions about this but none met my needs. I have created an extension and I am trying to communicate between a content script and my options.html. I have been trying to use the chrome.extension.onRequest.addListener and the chrome.extension.sendRequest and neither work at all. No commands are executed or anything. Here is my code:
content script:
chrome.extension.sendRequest({command:value}, function(response) {});
options.html
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
alert("in onRequest request.command = " + request.command);
decide_command(trim(request.value));
sendResponse({});
});
none of the alerts are executed and none of the functions are executed. I even tried using the example in the messaging API page and it didn't trigger any alerts or anything. I have tried a bunch of different combinations like putting the extension ID in the sendRequest to make sure its going to the right place, I have excluded the sendResponse to make sure it wasn't ending too quick. I have debug alerts all over and none get triggered except for the ones before and after the send request command in my content script. So I would assume it either gets executed and fails or something like that. Any help would be greatly appreciated I have been working on this for days.
I believe Chris noted an issue already: an extension's option page isn't running all the time, and is therefore not available to receive or generate messages. Background pages are better for this sort of communication, as they're always running, always available, and therefore always capable of responding to messages.
I'd suggest reworking your extension's architecture a bit such that the content script gathers relevant information and sends it to the background page. When the options page is opened, it can request the state from the background page. The background page is then responsible for maintaining state in a reasonable way, and for pushing information back and forth between the other pieces of your extension.
Does that make sense?

Detect if a form POST browser window is open in Javascript?

I have a form post method, which is used to show a new page. Its done this way so that the arguments used cannot be seen in the location bar.
Each window is given a unique name, but I want to be able to detect if this browser window is already open, so that calling this form again will not force that current browser window to auto-fresh.
Any suggestions?
I assume you're opening new windows in Javascript. So, assign a variable name to your new window (e.g. var newWin1 = window.open(...))
Then test to see if the document of your window exists:
if(newWin1.document) { alert("Window is open!"); }
else { alert("Window is gone!"); }
For a security note: people can still see the post data you're sending with any HTTP header tool. Check out LiveHTTPHeaders for Firefox (or a million others) to see what I mean.
Another note: Not sure what you're doing, but people don't like when a webpage does things without them asking it to (like opening windows). You may want to consider improving your design to a more user-friendly method.

Saving data in chrome:// document

I'm making Firefox extension and I have a problem with
variables. Extension works with file (chrome://myextension/content/document.html) opened in few tabs.
I want it to store a value in each tab, so I decided to store it in
one of the html objects, that have got "Object" id:
data="foobar"
node=gBrowser.contentDocument.getElementById("ObjectId");
node.setUserData('data', data, {handle:function () {}});
For some reason, this doesn't work, when I want to get this variable
in this way:
data=node.getUserData("data");
Can you spot an error in my code?
PS. This two pieces of code are separated methods. The html file is on
a hard disk
Do you set it and get it in the same document (tab) without reloading in between? That works for me.
If you're trying to persist the stored value across the reloads or share a value between all tabs that have the same document loaded, you've picked the wrong API as far as I can tell (the spec is rather long and I didn't bother to confirm that).
What are you actually trying to do?

Categories