When executing a content script from a popup is there a way for that content script to return a value to the popup where the script was executed.
Referring to Google's Docs, use the following code:
contentscript.js
chrome.runtime.sendMessage({value: "hello"}, null);
popup.html
chrome.runtime.onMessage.addListener(
function myFunc(request, sender, sendResponse) {
doStuffWithValue(request.value);
chrome.runtime.onMessage.removeListener(myFunc); //if you want to stop listening after receiving the message
});
Related
I want x to increase each time a new tab opens. Why isn't it working?
var x = 0;
function increase(){
x++;
}
chrome.tabs.onCreated.addListener(function (tab) {
increase();
});
Your issue is that the tabs api cannot be used within a content script (check out the docs here for what can and can't).
In order to achieve what your trying to do, you need to place your tab counting code in the background script. If you need access to the variable x within your content script you'll have to pass the data between your background and content scripts using message passing.
For example you could setup your background script to increase x whenever a new tab is opened, then whenever your content script needed this value it could ask the background script for it:
Background.js:
var x = 0;
function increase(){
x++;
}
chrome.tabs.onCreated.addListener(function (tab) {
increase();
});
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.action == "tabCount")
sendResponse({count: x});
});
Content-Script.js:
chrome.runtime.sendMessage({action: "tabCount"}, function(response) {
console.log(response.count);
});
I am working on a Chrome extension. I have a content script and an event page. From the content script, I send a message using chrome.runtime.sendMessage() to the event page. On the event page, I use onMessage event listener to send back a reponse -- however, I would like to send this reponse AFTER chrome has detected that a file has started downloading.
contentScript.js
window.location.href = download_link; //redirecting to download a file
chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
console.log(response.farewell);
});
eventPage.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
chrome.downloads.onCreated.addListener(function(DownloadItem downloadItem) {
sendResponse({farewell: "goodbye"});
return true;
});
});
Now, I haven't tried chrome.downloads.onCreated listener before, but I'm assuming this is the correct syntax. However, the code is not working, and the console is returning this error:
Error in event handler for (unknown): Cannot read property 'farewell' of undefined
Stack trace: TypeError: Cannot read property 'farewell' of undefined
at chrome-extension://dlkbhmbjncfpnmfgmpbmdfjocjbflmbj/ytmp3.js:59:31
at disconnectListener (extensions::messaging:335:9)
at Function.target.(anonymous function) (extensions::SafeBuiltins:19:14)
at EventImpl.dispatchToListener (extensions::event_bindings:395:22)
at Function.target.(anonymous function) (extensions::SafeBuiltins:19:14)
at Event.publicClass.(anonymous function) [as dispatchToListener] (extensions::utils:65:26)
at EventImpl.dispatch_ (extensions::event_bindings:378:35)
at EventImpl.dispatch (extensions::event_bindings:401:17)
at Function.target.(anonymous function) (extensions::SafeBuiltins:19:14)
at Event.publicClass.(anonymous function) [as dispatch] (extensions::utils:65:26)
I have tried this without the chrome.downloads.onCreated listener and it works, the response is fetched by the content script. I read online that you need to add return true; in order to make it work, but it's not working for me. I suspect it's because of the second event listener, which enters a new scope meaning that sendResponse cannot be called from there -- if that's the case, how do I call the sendResponse function?
You return true; from the wrong place.
The purpose of that return is to say "I have not called sendResponse yet, but I'm going to".
However, you are returning it from inside the onCreated callback - it is too late by then, as right after the listener is added your original onMessage handler terminates. You just have to move the line:
chrome.runtime.onMessage.addListener( function(request, sender, sendResponse) {
chrome.downloads.onCreated.addListener( function(DownloadItem downloadItem) {
sendResponse({farewell: "goodbye"});
});
return true;
});
bacground.js
chrome.tabs.create({url: "http://www.google.com", "active":true}, function(tab) {
console.log(tab.id);// 315
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});
});
contentscript.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting == "hello")
sendResponse({farewell: "goodbye"});
});
});
logs:
Port: Could not establish connection. Receiving end does not exist.
How to fix it?
This error seems to be happening because the content script has not yet been injected into the page when your background script sends the message. Hence, the "receiving end does not exist."
I'm assuming (because I don't have more than 50 rep to be able to comment on your question and clarify this first, so correct me if I am wrong) that in your manifest.json file, you specify it in the following way:
"content_scripts": [{
"matches": ["*://xyz.com/*"],
"js": ["contentscript.js"]
}]
If this is indeed how you are injecting the content script, then you need to know that the content script only gets injected after the DOM has finished rendering. (Search for 'run_at' on the following link: http://developer.chrome.com/extensions/content_scripts.html) This means that when you send that message from the background script, the content script is still "loading."
The good news is that you can specify when the content script should be loaded by adding a third key-value pair to the content_scripts parameter in the manifest.json file, like so:
"content_scripts": [{
"matches": ["*://xyz.com/*"],
"js": ["contentscript.js"],
"run_at": "document_start"
}]
This tells the extension that you want to inject the contentscript.js before the DOM is constructed or any other script is run (i.e. as early as possible).
If the above technique still gives you the same error, that's an indication that even document_start is not early enough. In that case, let's consider another approach entirely. What you are attempting to do presently is to have the background script connect to the content script. Why not have the content script connect to the background script instead when it has successfully been injected into the page? The background page is always running so it is guaranteed to be able to receive the message from the content script without complaining about "the receiving end does not exist." Here is how you would do it:
In background.js:
chrome.runtime.onConnect.addListener(function(port) {
console.log("background: received connection request from
content script on port " + port);
port.onMessage.addListener(function(msg) {
console.log("background: received message '" + msg.action + "'");
switch (msg.action) {
case 'init':
console.log("background script received init request
from content script");
port.postMessage({action: msg.action});
break;
}
});
});
In contentscript.js:
var port_to_bg = chrome.runtime.connect({name: "content_to_bg"});
port_to_bg.postMessage({action: 'init'});
port_to_bg.onMessage.addListener(function(msg) {
switch (msg.action) {
case 'init':
console.log("connection established with background page!");
break;
}
}
Feel free to ask more questions for clarification! I'd be curious to learn if the first approach worked. If not, the second approach is a sure win.
I want to bring the tab the extension is running on to the front of my window as soon as the match is found, even if I am currently working in a second window.
So far I have this code in my content_script.js, but it doesn't seem to work.
The commented lines were my last failed tries.
The alert gave me -1, which seems to be quite the weird tab id.
if(output == 'found') {
sendResponse({findresult: "yes"});
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
//chrome.tabs.update(sender.tab.id, {selected: true});
//chrome.tabs.update(sender.tab.id, {active: true});
alert(sender.tab.id);
});
}
I've tried some things in the background.html too and all kinds of things already posted here, all with no luck.
What do I need to do to make this work?
EDIT
manifest.json script inclusion
"background": {
"scripts": ["background.js"]
},
"content_scripts": [ {
"all_frames": false,
"js": [ "jquery.js", "content_script.js" ],
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_idle"
}
background.js (the alert won't even show up)
alert("here");
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
your_tab_Id = sender.tab.id);
});
chrome.tabs.update(your_tab_Id,{"active":true,"highlighted":true},function (tab){
console.log("Completed updating tab .." + JSON.stringify(tab));
});
content_script.js jQuery change background (sendResponse works, but if I activate the background changing line the script stops working)
if(found === true) {
//$('td:contains('+foundItem+')').css("background", "greenyellow");
sendResponse({findresult: "yes"});
}
jsFiddle I tested the jQuery code in
EDIT 2
extension download
You can not use chrome.tabs API() from content script
References
Content Scripts
tabs API
To get tab id put your code to background.js
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
your_tab_Id = sender.tab.id);
});
and add this to background.js page
chrome.tabs.update(your_tab_Id,{"active":true,"highlighted":true},function (tab){
console.log("Completed updating tab .." + JSON.stringify(tab));
});
Use only content script to send messages
chrome.extension.sendMessage("Awesome message");
Edit 1:
Your code do not work because of syntax error
Some point to consider:
Use onMessage instead of onRequest ( onRequest is deprecated in favour of onMessage)
All the used API's are asynchronous so make sure they are called synchronously.
Use sendMessage in content script as well ( sendRequest is deprecated in favour of sendMessage)
After applying above changes your code turns as shown here.
alert("here");
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
your_tab_Id = sender.tab.id;
chrome.tabs.update(your_tab_Id,{"active":true,"highlighted":true},function (tab){
console.log("Completed updating tab .." + JSON.stringify(tab));
});
});
Let me know if you need more information.
I work on a little extension on Google Chrome, I want to create a new tab, go on the url "sample"+i+".com", launch a content script on this url, update the current tab to "sample"+(i+1)+".com", and launch the same script. I looked the Q&A available on stackoverflow and I google it but I didn't found a solution who works. This is my actually code of background.js (it works), it creates two tabs (i=21 and i=22) and load my content script for each url, when I tried to do a chrome.tabs.update Chrome launchs directly a tab with i = 22 (and the script works only one time) :
function extraction(tab) {
for (var i =21; i<23;i++)
{
chrome.storage.sync.set({'extraction' : 1}, function() {}); //for my content script
chrome.tabs.create({url: "http://example.com/"+i+".html"}, function() {});
}
}
chrome.browserAction.onClicked.addListener(function(tab) {extraction(tab);});
If anyone can help me, the content script and manifest.json are not the problem. I want to make that 15000 times so I can't do otherwise.
Thank you.
I guess chrome.tabs.create is an async function so you need to create a separate function so that the i variable is copied each time:
try this:
var func = function(i)
{
chrome.storage.sync.set({'extraction' : 1}, function() {}); //for my content script
chrome.tabs.create({url: "http://example.com/"+i+".html"}, function() {});
}
function extraction(tab) {
for (var i =21; i<23;i++)
{
func(i);
}
}
chrome.browserAction.onClicked.addListener(function(tab) {extraction(tab);});
You need to make sure that the tab finished loading, and that your content script finished running, before updating the tab to the next url. One way to achieve that would be by sending a message from the content script to the background page. You can include the following in your content script:
chrome.extension.sendMessage("finished");
In your background script you can do the following:
var current = 21, end = 23;
chrome.extension.onMessage.addListener(
function(request, sender) {
if( request == "finished" && current <= end ) {
chrome.tabs.update( sender.tab.id,
{url: "http://example.com/"+current+".html"});
current++;
}
}
);
chrome.tabs.create({url: "http://example.com/"+current+".html"});