Chrome Extension: Close opened tab, regardless of if its the current one - javascript

This is the background.js of my chrome extension. I am a newbie on programming chrome extensions.
How can I close the tab that is opened in this example regardless of if the tab is the current one or not?
chrome.tabs.onCreated.addListener(function() {
chrome.tabs.query({'active': true, 'lastFocusedWindow': true},
function (tabs) {
url = tabs[0].url;
if (url=="http://www.example.com"){
setTimeout(function(){
//would be nice to have this executed after EVERYTHING on the page is loaded
chrome.tabs.executeScript(null, {file:"jquery-1.11.1.min.js"});
chrome.tabs.executeScript(null, {file:"contentscript.js"});
},17000);
setTimeout(function(){
tabs[0].remove();
alert('tab removed');
},25000);
}
}
);
});

The comment from gui47 is correct - just use chrome.tabs.remove(... the tab id you want to remove ...)

A lot of this code could use improvement, assuming I understood your intent.
Imagine that you middle-click a link in a tab. It creates a tab in the background, and calls onCreated listener for it.
Yet you query for the active tab, and get the initial tab, not the new one.
You should use the fact that the tab information is passed into onCreated.
chrome.tabs.onCreated.addListener(function(tab) { // Can have a parameter!
/* use tab.url and tab.id */
});
When you call executeScript, it still obeys the run_at parameter, which is by default at document_idle. That means it will not execute until the static DOM is ready at least.
So no need for the timeout. To be extra safe, you can wrap your content script code in $(document).ready()
If you want to wait until the resources like images are loaded, you can use load event of the body.
If you need to wait until a specific event happens / some scripts execute in the page, you can use timeout and/or something like MutationObserver. However, it would make more sense then to add this waiting to contentscript.js and not the injecting code.
chrome.tabs.onCreated.addListener(function(tab) { // Can have a parameter!
// Assuming you want to check the address contains that and not exactly it
if(~tab.url.indexOf("http://www.example.com")) {
chrome.tabs.executeScript(tab.id, {file:"jquery-1.11.1.min.js"});
chrome.tabs.executeScript(tab.id, {file:"contentscript.js"});
}
});
Finally, if you want to close the page, you could call chrome.tabs.remove(tab.id).
But it might be better to simply close it from the content script - it might know better when to do it.
From the content script, you can simply use window.close() if your extension opened the tab.

You should use chrome.tabs.remove(tab.id); to close the tab.
See chrome.tabs.remove( ).

Use chrome.tabs.remove(tabId);
Whereas tabId is the id of your tab. If you don't know where to get the tabId you can use the below code in your background.js.
chrome.tabs.query(
{
active:true,
windowType:"normal",
currentWindow: true
},
function(d)
{
tabId = d[0].id;
});

Related

In background script, listen for newly opened tab

In my background script, or anywhere but a content script, I am trying to listen for the active tab, or a newly opened tab.
I have this, but this is apparently incorrect:
What I am trying to do is to inject a content-script into the active tab. I don't want my content script to run for every tab/window, just for select tabs.
Does anyone know how to inject a content script for certain tabs? I can't figure it out. I assume the best way to inject content scripts is from the background script.
If you want to run a code in already activated tab (chrome.tabs.query):
chrome.tabs.query({active: true, currentWindow: true}, function(foundTabs) {
const activeTabId = foundTabs[0].id;
chrome.tabs.executeScript(activeTabId, {
file: 'inject.js'
});
})
In case you want to inject a file into every newly activated tab (chrome.tabs.onActivated):
chrome.tabs.onActivated.addListener(function(activeInfo) {
chrome.tabs.executeScript(activeInfo.tabId, {
file: 'inject.js'
});
});
Be sure to check if you have injected the file already, in order to prevent multiple injections.
For both cases, permissions should include tabs.
I was missing the:
"webNavigation"
permission in manifest.json. After adding that permission, I now have:
chrome.webNavigation.onDOMContentLoaded.addListener(function (details) {
const tabId = details.tabId;
chrome.tabs.executeScript(tabId, {
file: 'inject.js'
});
});
now it works.
some chrome API we cant access in content script in that case do that code in background.js and do according action from background js. if you want to do some action in content script in that case you need to communicate using send message

Unable to receive message in popup once popup closes on tab change

I've made a chrome extension that downloads some stuff from a certain site. Basically, it goes around through all links I'm interested in, stores them in an array and then downloads it one by one. The thing is, the storing is done in a separate file called download.js. Then, I proceed to send a message to popup.js using chrome.extension.sendRequest. I pick it up in popup.js with chrome.extension.onRequest.addListener. It works perfectly when I don't switch my tab, but I'd like it to work while I'm browsing some other stuff in the meantime. I can see the code reaching the point to send the request to popup.js through a console log, but I can't see what's going on in popup.js because when I switch my tab the popup console immediately closes.
download.js:
// logic behind link gathering and storing that works
...
gatherLinks().then(function() {
// logs is defined, don't worry
chrome.extension.sendRequest(logs);
)};
popup.js:
document.addEventListener('DOMContentLoaded', function() {
var downloadButton = document.getElementById('download');
downloadButton.addEventListener('click', downloadStuff);
});
function downloadStuff() {
chrome.tabs.executeScript({
file: 'jquery-3.1.1.min.js'
});
chrome.tabs.executeScript({
file: 'download.js'
});
chrome.extension.onRequest.addListener(function(message_logs) {
message_logs.forEach(function(log) {
chrome.downloads.download({
url: log.link,
filename: log.filename
});
}
}
manifest.json:
{
...
"permissions": [
"tabs",
"activeTab",
"downloads"
],
"background": {
"scripts": ["download.js"]
}
}
When you switch away, the popup window closes.
It does not hide the popup, the popup is properly closed, as you would close a tab. Therefore, its code is no longer executing and there's nothing to listen for your messages.
This is a job for background (or better, event) pages. They exist, invisibly, independent of what you're doing with the browser. Therefore, such a page should be the one to receive commands when the popup may not exist.
Also,
BIG SCARY WARNING!
If your content script and your background script are the same, there is a 99% probability you're doing something wrong. Do not try to reuse code in both, unless it's some auxilliary library - main logic should never be the same in those very different contexts.

How do I make it so my Chrome extension will only inject a script once?

I'm using programmatic injection to inject my extension's code into a page only when the browser action is clicked.
This is what I have on my extension's event page (per the example in the documentation):
chrome.browserAction.onClicked.addListener(function callback(tab){
chrome.tabs.executeScript(null, {file: "content-script.js"});
});
However, the way this works, the script is injected every time the button is clicked.
How can I change it so that the script is not injected on subsequent button presses - so that it is inserted only the first time the button is clicked on that page?
Put a global variable in your contentscript to judge if the contentscript has been executed.
if (something) { return; }
One way I can think of right now (easy and simple) is to use html5webstorage. Since you are running this code from your background or popup page it will be ok.
if(!localStorage.getItem("isAlreadyInjected")){
localStorage['isAlreadyInjected'] = "true";
chrome.browserAction.onClicked.addListener(function callback(tab){chrome.tabs.executeScript(null, {file: "content-script.js"});});}
So, the very first time when storage value "isAlreadyInjected" does not exist, the listener will be added. Afterwards, even when the browser closes and opens again this value will remain stored and so the listener will not be added to your extension.
UPDATE
As your background page loads only once at the beginning, it can keep variable that is not re-initialized with the browser action click. So you can use that variable to do your job!
background.js
var isAlreadyInjected =false;
function isInjected(){
if(!isAlreadyInjected ){
isAlreadyInjected=true;
return false;
}
else
return true;
}
popup.js
var bgpage=chrome.extension.getBackgroundPage();
if(!bgpage.isInjected()){
chrome.browserAction.onClicked.addListener(function callback(tab) {chrome.tabs.executeScript(null, {file: "content-script.js"});});
}
or
var bgpage=chrome.extension.getBackgroundPage();
chrome.browserAction.onClicked.addListener(function callback(tab) {
if(!bgpage.isInjected()){
chrome.tabs.executeScript(null, {file: "content-script.js"});
}});
I know this is an older question but I encountered the issue now that Manifest V3 is out and persistent background pages have been replaced with service workers. I figured I'd give what I used as a solution in case anyone else needs it. Code must be executed within the global context of the content script. Anytime it tries to inject it again, the relevant code will only be executed if the global variable is not defined.
if (typeof hasBeenExecuted === 'undefined') {
// Code that needs to execute only once goes here
}
var hasBeenExecuted = true;
Hopefully this is helpful for someone else who comes across the question.

Is it possible to run the injected script without reload?

I did a simple auto form filler, by sending info from a created html to the background and then the content script, so the injected script can change the info on the form.
I know the content script run once the page is load. I want to know if I can run the content script again, without the need of reloading the page.
I got sendRequest function in the content script, that I use to make sure it gets the info, only when the page is ready. It then add the info to the form, and wait for me to send it.
In the content script, I added a onRequest and it works (it get the info). but, I don't see the changes on the form, unless I am realoding the page.
I want to know if it is possible to do and if it does what subjects should I learn to implent this.
I am new to chrome extentions and I am still learning :)
in 1 of the pages, I use jQuery, so an answer with jQuery would be good too.
i found out that if we create a chrome.tabs.sendRequest from background we can use chrome.extestion.onRequest from content script and it will execute every time becuse they both run allmost in the same time.
so i did from background:
chrome.tabs.query({}, function (tabs) {
for (var i = 0; i < tabs.length; i++) {
chrome.tabs.sendRequest(tabs[i].id, {...requests u want to send }, function (response) {
});
}
});
from content script:
chrome.extension.onRequest.addListener(function (request, sender, sendRespons) {
//get requested info here
//call functions.
sendResponse({}); //send info back to background page.
});
form's target could be an iframe which would avoid page reload. not sure how useful it'd be.
The correct way to execute a content script again is by using the chrome.tabs.executeScript method. It receives two arguments. The first argument is the tabId, which can be obtained in many ways, such as one of the chrome.tabs events. Use null to execute the content script in the currently selected tab (caution: this may also be an active dev tools window!).
Examples:
// Reloads the current tab
chrome.tabs.executeScript(null, {code:'location.reload();'});
// Executes contentscript.js in the current tab
chrome.tabs.executeScript(null, {file:'contentscript.js'});
// Executes contentscript.js in all frames in the current tab
chrome.tabs.executeScript(null, {file:'contentscript.js', allFrames: true});
// Receives message from content script, and execute a content script:
chrome.extension.onMessage.addListener(function(details) {
if (details.message === 'load a content script') {
chrome.tabs.executeScript(details.sender.tab.id, {file: 'a_script.js'});
}
});
// The previous one is activated from a content script, as follows:
chrome.extension.sendMessage('load a content script');
(onMessage and sendMessage have to be used instead of onRequest and sendRequest, since Chrome 20)

Pass variables to current tab via chrome extension

I am writing my first chrome extension, and I want to pass a variable to the currently opened tab and manipulate the DOM with it.
My extension has a button, and when clicked, is executing this code:
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.executeScript(tab.id, {
file: 'tabscript.js'
});
});
This works fine, but I see no way to pass a variable to tabscript.js so it can be used on the opened tab.
What do you need to pass a variable in to? Do you have a function you are calling in your script?
It must be noted that you don't have access to the pages Javascript, just the DOM.
If you have a particular function that you have to call with specific parameters then you should investigate content scripts and message passing.
Content scripts can get run on every page load (or a selection of pages), and you would use message passing to send a message from your extension button to the function in the content script.
Alternativly, and closer to your original idea you can construct the function you want to call at run time using the following:
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.executeScript(tab.id, {
code: 'function(){ ...... your code built dynamically ......}'
});
});

Categories