Establish a communication link between content script and background page - javascript

Developing a chrome extension using javascript is one of my university projects.
I don't know how to establish a communication link between content script and background page using messaging. I need some help in this establishing the connection
background.html
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {method: "getHTML"}, function(response) {
console.log(response.data);
});
});
content_script.js
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.method == "getHTML")
sendResponse({data: document.getElementById('header').innerHTML});
else sendResponse({});
});

A few major issues:
You're depending on some element on the page having the ID header. Such IDs are at the discretion of the site designer, so very few pages actually do have that (including Google). Maybe go for something a little more universal, like the title of the page (document.title).
What does "the extension button" mean? If it means a browser action, that's a part of your extension, so you're correct in wanted to send something from the background script. This is also an easier case, as it's probable that (aside from the issue above of no Google pages having an element of ID header), you're just not capturing the browser action click event. If it's some injected button, however, it's the other way around.
What you want (browser action version)
background.html (inline):
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, { method: "getHTML"}, function(response) {
console.log(response.data);
});
});
});
content_script.js
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.method === "getHTML") {
sendResponse({data: document.title});
} else {
sendResponse({});
}
});
What you might want (injected button click version)
background.html:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.method === "getHTML") {
console.log(request.data);
}
});
content_script.js:
function buttonClick() {
chrome.extension.sendRequest({method: "getHTML", data: document.title});
}
Code for response to comment below
Very important recommendation: Chrome's developer reference is probably one of the friendliest out there. If you want to know what parts of the chrome.* API are available, start there.
function getHtml(tabId) {
chrome.tabs.sendRequest(tabId, { method: "getHTML"}, function(response) {
console.log(response.data);
});
}
// Note that this will only work once a tab has loaded
chrome.tabs.onSelectionChanged.addListener(function(tabId) {
getHtml(tabId);
});
// This fires the first time a page is loaded
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo) {
if (changeInfo.status === "complete") {
getHtml(tabId);
}
});
Code for second response to comment below
background.html
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.method === "getHTML") {
console.log(request.data);
}
});
content_script.js
document.addEventListener("keypress", function(e) {
chrome.extension.sendRequest({method: "getHTML", data: e.which});
});

Related

Difficulty passing messages between background and content script in chrome extension

I'm attemtping to send a message from the content script to the background script, and send a response in return.
This is what I've got in my background script:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log("Message received");
if(request.activeStatusRequest == "disable"){
sendResponse({activeStatusUpdate: "disable"});
}else if(request.activeStatusRequest == "enable"){
sendResponse({activeStatusUpdate: "enable"});
}
return true;
});
This is what I've got in my content script:
printReviews.onclick = function(element) {
if(printReviews.classList.contains("activeButton")){
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.executeScript(
tabs[0].id,
{code: `${injectionLiteralGETURL}`}
);
});
toggleClasses(printReviews, "activeButton", "inactiveButton");
chrome.runtime.sendMessage({activeStatusRequest: "disable"}, function(response){
console.log("response received");
console.log(response.activeStatusUpdate);
});
}
else {
toggleClasses(printReviews, "inactiveButton", "activeButton");
chrome.runtime.sendMessage({activeStatusRequest: "enable"}, function(response){
console.log("response received");
console.log(response.activeStatusUpdate);
});
}
};
The rest of the above code works as expected, except that the none of the console logs in the content script run. The console log in the background script does run, however.
Anyone got any ideas as to what I've done wrong?
If you want to try another method, you could try to add a listener in the content script
Content.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log("Message received from background", response.type, response.activeStatusUpdate);
switch(request.type){
case 'SomeFirstAction'
break;
case 'SomeSecondAction'
break;
}
});
Background.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log("Message received");
if(request.activeStatusRequest == "disable"){
sendMessageToCurrentTab({type: 'SomeFirstAction', activeStatusUpdate: "disable"});
}else if(request.activeStatusRequest == "enable"){
sendMessageToCurrentTab({type: 'SomeSecondAction', activeStatusUpdate: "enable"});
}
// return true; -> not needed with that method
});
function sendMessageToCurrentTab(message){
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, message);
}
}
To have played with callbacks between popup/background/content-script, I prefer just play with messages,because when using sendResponse, the manner it works, it open a port to communicate, but if something change (tab close, popup close), you will have an error because the port will be closed too.
Using the 'Full send message manner', the background need to clearly target the receiver tab.
I also recommand you to use a type or some unique action attribute, because all listener will listen to all action. It will identify the action and it's purpose.
Here I just used a switch in the content script, but the background could use the same logic.
Maybe it's not the greatest way of doing things, but it works well for me.
Hope this can help you

Chrome extension create tab and send msg to it

I tried different things, but it doesn't work.
In my popup.html i've created a button. When i click it, i wan't to create a new tab and send to it a message. Here is the code:
$("#openLink").click(function () {
chrome.tabs.create({url: 'http://jquery.com'}, function (tab) {
console.log(tab.id);
alert(tab.id);
chrome.tabs.sendMessage(tab.id, 'hello');
});
});
And in the content script i try to use this:
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
alert('message received');
});
But it doesn't alert me nothing.
Please help.

Stop event listener

I made a button which openning new page in new tab for example https://google.com. And I'm sending a message to the background script to start taking the URL of new opened page. The problem is that I don't know how to stop the listener after retrieving the URL. So it's continue the execution even after I closed that tab.
Popup.js
$('#click').click(function(e)
{
chrome.tabs.create({url: 'https://google.com'});
chrome.runtime.sendMessage({greeting: "googleisopened"}, function(response) {
console.log(ok);
});
});
Background.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.greeting == "googleisopened")
{
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
alert(changeInfo.url);
});
}
});
I think you're insterested in this function http://api.jquery.com/off/
It removes all of the events from the object so in your case you could just plug it anywhere in your click event like this:
$(this).off('click');
// Or like this if you want to be specific
$('#click').off('click');
Thanks to everyone who tried to help me. I found a solution by myself.
Instead of using listener I started to use tabs.getSelected to retrieve page URL only when needed (not in cycle as in onUpdated.addListener).
So the background script will be next:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.greeting === "googleisopened")
{
chrome.tabs.getSelected(null, function(tab)
{
chrome.tabs.onUpdated.addListener(mylistener);
function mylistener (tabId, changeInfo, tab)
{
alert(changeInfo.url);
chrome.tabs.onUpdated.removeListener(mylistener);
}
});
}
});

Open chrome extension page programmatically in same tab as website

I am making an chrome-extension-based editor, and I want the user to be able to open a file within the extension when they receive a link like this: http://myeditor.com/link.html?file=xxxx
When going to that website I would like that:
if the person opening the url has the extension, open chrome-extension://blahblah/?file=xxx
else show a read-only version of the file and a link to install the extension.
Now to do that, I have in the link.html file a script that looks like this:
if (window.chrome) {
if (chrome.app.getDetails() === null) {
chrome.runtime.sendMessage(chromeId, { message: "isInstalled" }, function (reply) {
if (reply) {
chrome.runtime.sendMessage(chromeId, { gotoUrl: document.location.search });
}
});
}
}
and in the extension's background.html:
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
if (request) {
if (request.message) {
if (request.message == "isInstalled") {
sendResponse(true);
}
}
if (request.gotoUrl) {
var url = chrome.extension.getURL(request.gotoUrl);
chrome.tabs.create({url: url}); // how do I open this in the same tab rather than create a new tab?
}
}
return true;
});
The issue is that the code creates a new tab, is there a way I can open the extension page in the same tab as the page I called it from?
Actually chrome.tabs.update instead of chrome.tabs.create works fine...

Chrome Extension Message Passing - Code included

I have a contentscript called file.js that creates variable "found". I want to send the values of varibale "found" to a textbox in popup.html
In file.js (I know varible found is working, tested using an alert).
chrome.extension.sendRequest({foundlinks: found}, function(response) {
console.log(response);
});
In Popup.html:
function pulllinks(){
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
document.getElementById("box").value = request.foundlinks;
sendResponse({});
});
And on the form in popup.html:
<input type = "button" onclick="pulllinks();" name = "box" id="box" value = "Grab Links From Page" />
However, its not doing anything. Any ideas?
Thanks!
You need to be sending requests in the opposite direction - from popup to content script:
popup.html:
function pulllinks(){
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {cmd: "findLinks"}, function(response) {
document.getElementById("box").value = response.foundlinks;
});
});
}
file.js:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if(request.cmd == "findLinks") {
//calculate "found" value and send it back
sendResponse({foundlinks: found});
}
});
First of all, your listener for onRequest should exist from the start, so move it outside of the pulllinks function. Secondly, how are you making sure that your sendRequest is being fired while the popup is open?

Categories