Sending message from content script to browseraction in firefox webextension? - javascript

Is it possible to send a message from Content script to Browser action directly without using background page? Following is a simplified version of what my code looks like. The content script seems to be working fine, but I get the following error in the console:
Error: Error: Could not establish connection. Receiving end does not exist.
I am assuming it's because the Browser action is not always active. But I don't want to use a Background page because I don't want the script running constantly hogging memory. I am hoping to send message directly to Browser action and display a popup, sort of like browserAction.onClicked displaying a popup. This is my first extension that I am trying to build, so trying to figure things out. Thanks
[manifest.json]
{
"manifest_version": 2,
"name": "Test",
"version": "0.1",
"icons": {
"48": "icons/test.png"
},
"permissions": [
"activeTab"
],
"browser_action": {
"default_icon":"icons/test.png",
"default_title": "test",
"default_popup": "popup/popup.html",
"browser_style": true
},
"content_scripts": [
{
"matches": ["*://testwebsite"],
"js": ["content_scripts/content-script.js"]
}
]
}
[popup.js]
function handleMessage(request, sender, sendResponse) {
console.log("Message from the content script: " +
request.greeting);
sendResponse({response: "Response from background script"});
}
browser.runtime.onMessage.addListener(handleMessage);
[content-script.js]
function handleResponse(message) {
console.log(`Message from the background script: ${message.response}`);
}
function handleError(error) {
console.log(`Error: ${error}`);
}
function send_2_popup() {
var sending = browser.runtime.sendMessage({
greeting: "Greeting from the content script"
});
sending.then(handleResponse, handleError);
}
var btn = document.getElementById("btn");
btn.addEventListener("click", send_2_popup);

You can rather send a message from the popup to the background and get a response as well as a message from background.. this way the background will know that the popup exists and hence the message from background to popup will be successful.

Related

Firefox Extension / Webextensions: Why doesn't the MDN example of Connection Based Messaging work?

This is the first time I read about writing Firefox extensions.
What I need is obviously only viable via WebExtensions and both a background and a contentscript. I actually only want to write all open tabs as links in a new tab and then File->Save it. Another alternative Idea was to put it into a JSON Object and save that through a dialog, then I probably could even spare the contentscript but I haven't found anything in the API to download a JSON Object via asking the user to download it via Download Dialog.
Whatever. I think I need to communicate with the content-script then.
I tried to run the following example, but it is not working. When I load the manifest file and open the debugger for extensions, it doesn't log anything and nothing has happened except that the variables myPort and portFromCS seem to be declared without any value.
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#connection-based_messaging
// manifest.json
{
"manifest_version": 2,
"name": "Save Open Tabs",
"version": "1.0",
"description": "Save my tabs",
"background": {
"scripts": ["background.js"]
},
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["content.js"]
}
],
"permissions": [
"activeTab",
"tabs"
]
}
// content.js
let myPort=browser.runtime.connect({name:"port-from-cs"});
myPort.postMessage({greeting: "hello from content script"});
myPort.onMessage.addListener((m) => {
console.log("In content script, received message from background script: ");
console.log(m.greeting);
});
// background.js
let portFromCS;
function connected(p) {
portFromCS = p;
portFromCS.postMessage({greeting: "hi there content script!"});
portFromCS.onMessage.addListener((m) => {
portFromCS.postMessage({greeting: "In background script, received message from content script:" + m.greeting});
});
}
browser.runtime.onConnect.addListener(connected);
Why doesn't the example work? Maybe wrong URL matching in the manifest file?

Chrome extension timer - API issue?

I'm creating a Pomodoro timer program, and I can't figure out how to keep the timer running in the background, after I unfocus the popup.
I've been working on this for a bit, but I currently have all the code for the actual timer in the background script. I was hoping to use the runtime API in popup.js to send a one-time message to start the timer in background.js, and then whenever the user opens the extension, to return what the timer is set to.
I'm also not entirely sure I'm approaching the question correctly.
The code wasn't working, so I simplified it down to just sending the message and trying to get a response, which I found is the problem.
Code:
popup.js:
chrome.runtime.sendMessage({greeting: 'hello'}, function(response) {
console.log(response.farewell)
});
background.js:
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.greeting == 'hello') {
sendResponse({farewell: 'goodbye'})
toggleClock();
}
});
//working toggleClock() function
manifest.json:
"browser_action": {
"default_popup":"popup.html",
"default_title":"Flexidoro",
"default_icon":"flexidoro.png"
},
"background": {
"scripts": ["background.js"],
"persistent": false
},
"permissions": [ "storage", "alarms" ]
There aren't any errors in the extension error log, and there also isn't anything in the console.
Am I taking the right approach?
Thanks!

Content script not listening to message event

I am developing my first browser extension for my website.
What this extension should basically do is to have a browser action which opens a pop-up where you can edit specific cookie values for the current page.
However, cookie A can exist on the page / while cookie B can exist on the page /checkout. So I don't want to list every cookie inside the pop-up, only the one which is active on the current page.
So, I searched the documentation and found that in order to communicate between web page and add-on you have to use the message system as described here
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#Communicating_with_the_web_page
To do so, my website has a JavaScript file which is loaded on every page. In this JavaScript I'm executing the following code
window.postMessage({type: 'FROM_PAGE', data: visibleCookies}, '*');
This piece of code is definitely executed, because I put a console.log before or after that statement, I can see that it's being logged.
Now, in my content script I want to listen to this by executing the following code
// experimentManager.js
console.log('testd');
window.addEventListener('message', (event) => {
console.log(event);
if (event.source !== window) {
return;
}
});
However, the console.log(event); is never executed. The listener is never activated. When I press the browser action so that the popup opens testd is logged into console, but still, the listener doesn't get any events. It's just not getting executed.
I don't know which files are relevant, but this is my manifest.json
// manifest.json
{
"manifest_version": 2,
"name": "My first addon",
"version": "1.0",
"description": "My first addon description",
"icons": {
"48": "icons/icon.png"
},
"browser_action": {
"default_icon": "icons/icon.png",
"default_title": "My first addon",
"default_popup": "popup/manage_experiment.html",
"browser_style": true
},
"permissions": [
"tabs",
"cookies",
"<all_urls>"
],
"content_scripts": [
{
"matches": ["*://*.mydomain/*"],
"js": ["experimentManager.js"]
}
]
}
And inside the pop-up script I'm executing this code among other things
browser.tabs.executeScript({file: "/content_scripts/experimentManager.js"})
.then(manageExperiments)
.catch(handleError);
which is probably the reason why the console.log('testd') gets executed, but nothing else?
What am I missing?

How to fix issues sending data from web page to chrome extension?

I am trying to pass data from my webpage to the chrome extension.
manifest.json (I am trying to do this in my local environment first)
"externally_connectable": {
"matches": ["*://localhost/*"]
}
In listen.js (a background script):
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
if (sender.url == blacklistedWebsite)
return; // don't allow this web page access
if (request.openUrlInEditor)
alert('test2');
alert(request.openUrlInEditor);
});
None of the alerts display above.
I got the extension ID of the unpacked chrome extension by viewing the ID when I navigate to chrome://extensions/. In my webpage in localhost environment
// DEVELOPMENT extension ID
var editorExtensionId = "fppgjikaoolnlcmdjalbfkmlcadcckmb";
var url = 'test';
// Make a simple request:
chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
function(response) {
if (!response.success)
handleError(url);
});
When I run this. in the browser, I get an error saying:
Error in event handler for (unknown): TypeError: Cannot read property 'success' of undefined
I'm not sure where to begin debugging this.
After making a few changes in your code I am able achieve your goal.
See below the complete code.
manifest.json
{
"manifest_version": 2,
"name": "CS to Bg Communication",
"version": "0.1",
"background": {
"scripts": ["listen.js"]
},
"content_scripts": [
{
"all_frames" : true,
"matches": ["<all_urls>"],
"js": ["contentscript.js"]
}
],
"browser_action": {
"default_popup": "popup.html"
},
"externally_connectable": {
"matches": ["*://localhost/*"]
}
}
listen.js - the background script
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
blacklistedWebsite = 'http : / / yourdomain . com /';
if (sender.url == blacklistedWebsite)
return; // don't allow this web page access
if (request.openUrlInEditor) {
alert('test2 - ' + request.openUrlInEditor);
sendResponse({"success": true, "AckFromBG": "I have received your messgae. Thanks!"}); // sending back the acknowlege to the webpage
}
});
contentscript.js - the content script - actually does nothing
console.log("this is content script");
web-page.html - The local web page
<html>
<body>
This page will will send some message to BG script
<script type="text/javascript">
// DEVELOPMENT extension ID
var editorExtensionId = "fjaedjckfjgifecmgonfmpaoemochghb"; // replace with your extension ID
var url = 'test';
chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url}, function(response) {
console.log(response);
if (!response.success)
handleError(url);
});
function handleError(url) {
console.log(url);
}
</script>
</body>
</html>
Summary of changes:
Defined blacklistedWebsite - this was undefined.
Added sendResponse({"success": true, "AckFromBG": "I have received
your messgae. Thanks!"}); to send back the acknowledgment to the
webpage.
Define function handleError(url) {
console.log(url);
} this was not defined.
That's it. Hope this will solve your issue.
The error you are getting indicates that chrome.runtime.sendMessage is executed. This means that external messaging is set up correctly: otherwise, chrome.runtime.sendMessage wouldn't be exposed to your page's code.
I think the problem is here:
if (sender.url == blacklistedWebsite)
return; // don't allow this web page access
I suspect the problem is blacklistedWebsite being undefined; the code fails with a ReferenceError and no meaningful response is being sent. Since the onMessage listener terminates (even with an error), the calling code gets an undefined response.
Check your background console to confirm if that's the case; if you copied this partial example code but aren't using this blacklisting functionality, delete this branch.
In future, please make sure you understand what every line of code you copy does!

Notifying background task when content script wants

I have one main task (background.js) that runs some stuffs.
I need to create a new trigger event on the background script of my app, so that he will create a new timeout of one day (24 hours). But, i don't want to check every page i enter, on my background, What i want to do is to send some sort of "message" trough one content_script page, to my background task (the same app).
What i need: run a function on my background, from my content_script.
Is it possible? How?
Yes, it is possible with message Passing. You can refer following script as a reference
Demonstration
The following code will execute a function in background page when triggered from content script.
manifest.json
Registered background and content script with extension and added necessary permissions
{
"name": "Run Background page function from content script",
"description": "",
"version": "1",
"manifest_version": 2,
"background": {
"scripts": [
"background.js"
]
},
"content_scripts": [
{
"matches": [
"https://www.google.co.in/*"
],
"js": [
"myscript.js"
]
}
],
"permissions": [
"https://www.google.co.in/*"
]
}
background.js
It contains some trivial function and a listener for triggering call for function
//Some Trivial Function
function runme() {
console.log("I am executed ... ");
}
//Listener fired when message is recieved
chrome.extension.onMessage.addListener(function (content) {
if (content.message == "Hey i am from Google.co.in Page please run runme function") { // Check for correct message
runme(); // Invoke function
}
});
myscript.js
//Trigger background page through message passing
chrome.extension.sendMessage({
message: "Hey i am from Google.co.in Page please run runme function" //Some message
});
Output
You can see background function running when trigger is invoked.
Reference
Message Passing.

Categories

Resources