Chrome extension, how to send message from panel to content script - javascript

My contentScript sends a message to backgroundScript which opens a popup/panel/window. This panel loads an external web page.
I'm injecting some javascript in the panel to interact with it.
What I'm trying do achieve now is to send data from the panel to the 'main page' (contentScript).
I have successfully managed to send messages from the panel to the backgroundScript.
What I don't understand/know is how to pass the data from the backgoundScript to the contentScript.
Updated script from #Haibara Ai's comment
manifest.js
{
"name": "My extension",
"version": "0.1",
"manifest_version": 2,
"description": "description",
"permissions": ["activeTab", "tabs","http://*/*","https://*/*"],
"content_scripts": [
{
// Change 'matches' attribute to load content
// script only in pages you want to.
"matches": ["SomeUrl"],
"js": ["jquery.min.js", "contentscript.js", "notifier.js"]
}
],
"background": {
"scripts": ["eventPage.js"],
"persistent": false
}
}
contentscript.js
$(document).ready(function() {
var link = document.getElementById('inputLink');
// onClick's logic below:
link.addEventListener('click', function() {
chrome.runtime.sendMessage({
action: 'createWindow',
url: $('input[name=link]').val()
}, function(message) {
console.log(message);
})
});
});
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
alert('a');
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting == "hello")
sendResponse({farewell: "goodbye"});
});
eventPage.js
chrome.runtime.onMessage.addListener(function(request) {
if (request && request.action === 'createWindow' && request.url) {
chrome.windows.create(
{
url: request.url,
focused: true,
incognito: true,
type: "panel"
}, function (newWindow) {
chrome.tabs.executeScript(newWindow.tabs[0].id, {
file: "jquery.min.js"
}, function() {
chrome.tabs.executeScript(newWindow.tabs[0].id, {
file: "htmlselection.js"
});
});
chrome.tabs.insertCSS(newWindow.tabs[0].id, {file: "htmlselection.css"});
});
} else {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
console.log(chrome.tabs);
chrome.tabs.sendMessage(tabs[0].id, {action: "SendIt"}, function(response) {});
});
}
});
htmlselection.js (injected in the popup/panel/window)
[...]
//After a click within the popup/panel/window
chrome.runtime.sendMessage({ text: 'test' });
[...]
Thank you for your help.

Updated
If you want to send message inside chrome.runtime.onMessage, just use the callback sendResponse or use sender.tab.id as tabId to send back the message.
And there are other problems with your code:
Since you are use Programming injection to inject script, you should declare them in "web_accessible_resources" in manifest.json
"web_accessible_resources": [
"htmlselection.js",
"jquery.min.js",
"htmlselection.css"
]
In your contentscript.js, just remove message part, since you didn't receive anything in this script.
For eventpage.js, use sendResponse instead of tab.query.
else {
console.log("2");
sendResponse({ action: "SendIt" });
}
Previous
Take a look at Message Passing, you could send a message from background page using the following code snippets:
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});
});

Fixed version of the snippet:
chrome.tabs.query({active: true, currentWindow: false}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});
});
Set the currentWindow:false and it worked.

Related

Chrome extension messages not getting through

manifest.json:
{
"manifest_version": 2,
"name": "chrome-extension-bar",
"description": "Chrome Extension Bar",
"version": "1.0",
"browser_action": {
"default_title": "Chrome Extension Bar",
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"background": {
"service_worker": "background.js"
},
"permissions": [
"<all_urls>",
"tabs"
],
"content_security_policy": "script-src 'self' https://ajax.googleapis.com/ https://maxcdn.bootstrapcdn.com ; object-src 'self'"
}
background.js:
console.log("In background.js")
chrome.runtime.onMessage.addListener (
function (request, sender, sendResponse) {
console.log("In listener");
// to send back your response to the current tab
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {fileData: response}, function(response) {
sendResponse({farewell: "goodbye"});
});
});
return true;
}
);
content_script.js:
var current_title_bar = document.getElementById("global-nav");
console.log("Title bar:" + current_title_bar);
current_title_bar.appendChild(extension_bar); // <= GODD, getting here
document.getElementById("idStartButton").addEventListener('click', function () {
console.log('Sending start button message: ' + document.getElementById("idNumSecondsPerPage").value);
chrome.runtime.sendMessage({numSecondsPerPage : document.getElementById("idNumSecondsPerPage").value}, function(response) {
console.log('Got response: ' + response.farewell);
});
});
document.getElementById("idStopButton").addEventListener('click', function () {
console.log('Sending stop button message: ' + document.getElementById("idNumPages").value);
chrome.runtime.sendMessage({numPages : document.getElementById("idNumPages").value}, function(response) {
console.log('Got response: ' + response.farewell);
});
});
The messages seem to be getting sent, but there's I'm not getting anything back from the receiver.
Console log on the page into which the form was injected:
Entering content_script.js
content_script.js:156 Title bar:[object HTMLElement]
content_script:161 Sending start button message: 67
content_script:168 Sending stop button message: 76
Why aren't the messages sent by background.js received by content_script.js? Are they even sent?
If you want to send a message from the background.js script to the content_script.js then you need to set an onMessage listener on the content script.
What you might do in this case is, after receiving the event on the background script, just call the callback function, instead you're sending a new event with a callback function than when it is executed, calls the callback function of the first event.
Instead of doing this:
console.log("In listener");
// to send back your response to the current tab
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {fileData: response}, function(response) {
sendResponse({farewell: "goodbye"});
});
});
just do this
console.log("In listener");
// send back your response
sendResponse({farewell: "goodbye"});

Sending data from Chrome extension to local python file

I'm trying to send some data from a Chrome extension content script to a background script to my local python file. It goes from the content script to the background script fine, but when I try to send it to the python file, I just get "POST http://localhost:5000/bootstrap 400 (BAD REQUEST)." Can't figure out what's going on. I'm new to this. Many thanks!
background.js
// Sending messages from background / event page
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if (changeInfo.status == 'complete') {
chrome.tabs.query({ active: true }, function(tabs) {
const msg = "Hello from background 🔥";
chrome.tabs.sendMessage(tabs[0].id, { "message": msg });
})
}
});
// Listening to messages page
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
console.log(request);
var articleData = request
// Callback for that request
$.ajax({
type: 'POST',
url: 'http://localhost:5000/bootstrap',
data: articleData,
success: function (newArticle){
alert('success');
}
})
sendResponse({ message: "Background has received that message 🔥" });
});
relevant part of fakenews.py
#app.route('/bootstrap', methods=['GET', 'POST'])
def bootstrap():
posted = 1
print ("bootstrap")
global article
if request.method == 'POST':
if not request.form['title'] or not request.form['url'] or not request.form['image_url'] or not request.form['snippet']:
flash('Please enter all the fields', 'error')
else:
article = Article(request.form['title'], request.form['url'], request.form['image_url'],
request.form['snippet'])
db.session.add(article)
try:
db.session.commit()
except exc.SQLAlchemyError:
flash('Article url already exists, failed to post new article')
posted = 0
#return render_template('/error.html', article_url=article.url)
article_list = Article.query.filter_by(url=article.url)
if posted == 1:
flash('Record was successfully added')
else:
db.session.rollback()
article_list = Article.query.filter_by(url=article.url)
article=article_list[0]
print ("article.id=" + str(article.id))
vote_choices = VoteChoice.getVoteChoiceList()
return render_template('/votefor.html', article_id=article.id,
article_title=article.title,
article_url=article.url, vote_choices=vote_choices
)
relevant part of content.js
chrome.runtime.sendMessage({ message: [title, image, url] }, function(response) {
console.log(response);
});
// Listening to messages in Context Script
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
console.log(request);
// Callback
sendResponse({ message: 'Content script has received that message âš¡' })
})
});
manifest.json
{
"manifest_version": 2,
"name": "OrangeBox",
"version": "1.0",
"permissions": ["http://localhost/" ,"tabs"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["contentScript.js"]
}
],
"background": { "scripts": ["jquery-3.4.1.js", "background.js"], "persistent": false },
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": ["jquery-3.4.1.js", "waitForKeyElements.js", "content.js"]
}
]
}
Problem
In content.js you're sending
message: [title, image, url]
The background.js is just passing this on to fakenews.py, and this is where things break...
fakenews.py is expecting a request object that looks like
{
title: <some time>,
url: <some url>,
image_url: <...>,
snippet: <...>
}
but what it's getting looks like
{
message: [
<some title>,
<some image>,
<some url>
]
}
Fix
The quick fix is changing the content.js line to be
chrome.runtime.sendMessage({"title": title, "image_url": image, "url": url, "snippet": "test"}, function(response) {
Note I'm putting a placeholder for snippet because the backend is expecting a value for it

Browser tab query "Receiving end does not exist" which works on chrome

Background script
browser.runtime.onMessage.addListener(function (event) {
if( event.type === 'authenticate' ) {
browser.tabs.query({active: true}, function(tab) {
browser.tabs.sendMessage(tab[0].id, {
method: 'main',
auth0: "test"
}, function() {});
});
}
});
Content script
browser.runtime.sendMessage({
type: "authenticate"
});
browser.extension.onMessage.addListener(function(request, sender, sendResponse) {
if( request.method == 'main' ) {
login();
} else if( request.method == 'logout' ) {
logout();
}
sendResponse({});
});
The event goes through and the tab id is correct, but the debug info from firefox shows "Error: Could not establish connection. Receiving end does not exist."
On chrome the event callback goes through. Anyone know what the issue is? Looking through google I found something about the id not being correct but I'm not sure what the issue is here.
Using browser.runtime.onMessage and changing
browser.tabs.query({active: true}, function(tab) {
browser.tabs.sendMessage(tab[0].id, {
method: 'main',
auth0: "test"
}, function() {});
});
to
browser.tabs.query({active: true, currentWindow: true}, function(tab) {
chrome.tabs.sendMessage(tab[0].id, {
method: 'main',
auth0: "test"
});
});
fixed it for me.

Chrome extension modify newtab page body?

I have chrome extension, which add new div to page body. But it doesnt work when i`m trying to run it on newtab page.
Here is my background.js:
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null, {file: "commonAddWidget.js"};
});
I found that it can be resolved by adding content script, and sending a message to it after clicking on extension icon on browser.
background.js:
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.query({'active': true, 'lastFocusedWindow': true}, function (tabs) {
var url = tabs[0].url;
if (url.indexOf('chrome://newtab') > -1) {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {someObject: someValue});
});
}
}); });
contentScript.js:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {// this code can modify NewTab page, and will modify only it });

How to send a message between Chrome extension popup and content script?

Following the Google tutorial, I am sending a message from a popup script to a content script. The message passes correctly but when I call the response callback I get the following error:
Attempting to use a disconnected port object
This is popup.js:
chrome.tabs.query(
{ active: true, currentWindow: true },
function(tabs) {
chrome.tabs.sendMessage(
tabs[0].id,
{ greeting: "hello" },
function(response) {
console.log(response);
});
});
This is content.js:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
sendResponse('goodbye'); // <- Error here
});
How can I send this message and get the response back?
This turned out to be due to an alert on the content page which caused the popup window to close. This in turn breaks the connection between the popup and the content script.
This example demonstrates sending a message to the content script in the selected tab.
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});
});
reference Link

Categories

Resources