Chrome extension: callback in backgroud.js to popup.js - google-chrome-extension

I have simple Chrome extension to show temperature from Json.
Background.js: how to pass response temp to ??? in popup.html????
Manifest ist OK.
manifest:
{
"name": "AlarmText",
"version": "0.0.1",
"manifest_version": 2,
"permissions": ["alarms", "http://api.openweathermap.org/data/2.5/weather?q=London"],
"icons": { "128": "icons/icon128.png",
"64": "icons/icon64.png",
"32": "icons/icon32.png" },
"browser_action": {
"default_title": "Alarm test",
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.js"],
"persistent": true
}
}
In popup I will show temp from URL. In div id="out", popup.html:
<!doctype html>
<html>
<head>
<title>popup</title>
<script src="popup.js"></script>
<script src="background.js"></script>
</head>
<body>
<div id="out">???</div>
<button id="checkPage">Refresh</button>
</body>
</html>
In popup.js is call alarm to get temp. popup.js:
document.addEventListener('DOMContentLoaded', function() {
var checkPageButton = document.getElementById('checkPage');
checkPageButton.addEventListener('click', function() {
chrome.runtime.sendMessage({greeting: "alert"}, function(response) {
alert("response");
document.getElementById('out').innerHTML = response.farewell;
document.getElementById('checkPage').innerHTML = response.farewell;
});
}, false);
}, false);
In background.js is problem :-) How write data to div in popup.html? Why don't work sendResponse in callback function?
background.js
function getTemp(callback) {
var xhr = new XMLHttpRequest();
xhr.open ("GET", "http://api.openweathermap.org/data/2.5/weather?q=London", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
// defensive check
if (typeof callback == "function") {
// apply() sets the meaning of "this" in the callback
callback.apply(xhr);
}
}
}
// send the request *after* the event handler is defined
xhr.send();
}
//alarm
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.greeting == "alert"){
alert("alert alarm");
getTemp(function() {
responseArray = JSON.parse(this.responseText);
//#TODO how to pass response temp to <div id="out">???</div> in popup.html????
alert("response get temp: " + responseArray["main"]["temp"]);
sendResponse({farewell: "goodbye"});
});
}
}
);
Thank :-)

Related

How do I send messages from a react app to my chrome extension?

I am trying to send session data in the form of a message from my React app to a chrome extension (MV3). According to the documentation, I should be using
chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
function(response) {
if (!response.success)
handleError(url);
});
However, doing so gives me the following error: TypeError: Cannot read property 'sendMessage' of undefined
Is there any way to resolve this? I've added /*global chrome*/ at the top of my file which got rid of the chrome undefined error, but now it's runtime that's undefined.
manifest.json:
"action": {
"default_popup": "popup.html",
"default_icon": "icon-34.png"
},
"permissions": ["storage", "tabs", "activeTab" , "scripting"],
"chrome_url_overrides": {
"newtab": "newtab.html"
},
"externally_connectable": {
"ids": ["extension_id"],
"matches": ["http://localhost:3001/"]
},
App.js (of the react app):
import React from 'react'
import { useState } from 'react'
import logo from './logo.svg';
import './App.css';
import { Auth } from 'aws-amplify';
const App = () => {
function test() {
const extensionId = 'extension_id';
const session = "session";
chrome.runtime.sendMessage(extensionId, session,
function(response) {
console.log(response);
});
}
const [loggedIn, setLoggedIn] = useState(false)
const signInHandler = (event) => {
test();
}
return (
<div>
<button onClick={signInHandler}>Sign in</button>
</div>
)
}
Listener in Background.js:
chrome.runtime.onMessageExternal.addListener(
function (request, sender, sendResponse) {
if (request.session) {
console.log(request);
}
sendResponse("OK");
});
You have to use https instead of http, chrome.runtime api is only exposed to secured webpages.

Chrome extension: content script to popup?

This extension scans DOM for text with V + digits e.g. V123, V333, V1, V21321321, and if the text is hovered it will send an API request from content.js and returns data. But the data should be displayed in popup and I can't seem to set it using document.getElementById('headline').innerHTML = data because it is null. Is there a way around it?
manifest.json
{
"manifest_version": 2,
"name": "AAAAA",
"description": "AAAAA Descriptionnnnnn",
"version": "1.0",
"browser_action": {
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["content.js"],
"run_at": "document_end"
}
],
"permissions": [
"*://*/*"
]
}
popup.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="headline" class="headline" style="background-color: #ccc; width: 300px;">
This is a headline
</div>
</body>
</html>
content.js
const elements = document.getElementsByTagName('*')
// loop through all element
for (let x = 0; x < elements.length; x++) {
let element = elements[x]
// loop through all nodes in an element
for (let y = 0; y < element.childNodes.length; y++) {
let node = element.childNodes[y]
// if node is a text node
if (node.nodeType === 3) {
const searchText = new RegExp(/V\d+/gi)
const text = node.nodeValue
const matchFound = text.match(searchText)
if (matchFound) {
element.classList.add('serialcode')
}
}
}
}
const serials = document.getElementsByClassName('serialcode')
const url = 'https://jsonplaceholder.typicode.com/todos/1'
Array.from(serials).forEach((serial) => {
serial.addEventListener('mouseover', () => {
let getData = async () => {
const response = await fetch(url, {
method: 'get'
})
return response.json()
}
getData().then(data => {
document.getElementById('headline').innerHTML = data
console.log(data)
})
})
})

Sending message from popup to content script - Chrome Extension

I want to update the html in popup.html when I open it through the browser action button. The popup.js should send a message to the content script running on the current tab, and should receive a response and update the html. However the content script does not receive any message, therefore not sending a proper response.
Content.js
var text = "hello";
chrome.runtime.onMessage.addListener(
function(message, sender, sendResponse) {
switch(message.type) {
case "getText":
sendResponse(text);
break;
}
}
);
Popup.js
chrome.tabs.getCurrent(function(tab){
chrome.tabs.sendMessage(tab.id, {type:"getText"}, function(response){
alert(response)
$("#text").text(response);
});
});
Manifest.json
{
"manifest_version": 2,
"name": "It's Just A Name",
"description": "This extension is able to",
"version": "1.0",
"permissions" : ["tabs"],
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html",
"default_title": "Click here!"
},
"content_scripts": [
{
"matches": ["https://*/*"],
"js": ["jquery.min.js","content.js"]
}]
}
Popup.html
<!doctype html>
<html>
<head>
<title>Title</title>
<style>
body {
font-family: "Segoe UI", "Lucida Grande", Tahoma, sans-serif;
font-size: 100%;
}
#status {
white-space: pre;
text-overflow: ellipsis;
overflow: hidden;
max-width: 400px;
}
</style>
<script src="popup.js"></script>
</head>
<body>
<p id="text"></p>
</body>
</html>
chrome.tabs.getCurrent uses for:
Gets the tab that this script call is being made from
Your popup.js should be:
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {type:"getText"}, function(response){
alert(response)
$("#text").text(response);
});
});
To add to above answer, You often want to send a msg from a popup to all tabs, so
popup:
chrome.tabs.query({}, tabs => {
tabs.forEach(tab => {
chrome.tabs.sendMessage(tab.id, msgObj);
});
});
content script:
chrome.runtime.onMessage.addListener(msgObj => {
// do something with msgObj
});
As per the latest docs you can also try the following:
popup:
(async () => {
const [tab] = await chrome.tabs.query({active: true, lastFocusedWindow: true});
const response = await chrome.tabs.sendMessage(tab.id, {greeting: "hello"});
// do something with response here, not outside the function
console.log(response);
})();
content_script:
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"});
}
);
Message passing docs!

phantomjs+ mocha + node + opening a web page

I'm trying to do something very simple. Or so I thought.
All I want to do is use phantomjs to open a webpage and assert its title.
I'm using mocha-phantomjs to invoke my test runner that looks like:
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="../../node_modules/mocha/mocha.css" />
</head>
<body>
<div id="mocha"></div>
<script src="../../node_modules/mocha/mocha.js"></script>
<script src="../../node_modules/chai/chai.js"></script>
<script>
mocha.ui('bdd');
mocha.reporter('html');
</script>
<script src="test.js"></script>
<script>
if (window.mochaPhantomJS) { mochaPhantomJS.run(); }
else { mocha.run(); }
</script>
</body>
</html>
and my test file looks
(function() {
var page, url;
page = require('webpage');
page = webpage.create();
url = "http://localhost:3000";
page.open(url, function(status) {
var ua;
if (status !== "success") {
return console.log("Unable to access network");
} else {
ua = page.evaluate(function() {
return document.title.should.equal('blah');
});
phantom.exit();
}
});
describe('Sanity test', function() {
return it('true should be true', function() {
return true.should.equal(true);
});
});
}).call(this);
when run using mocha-phantomjs it complains that it doesn't know what require is but i need to require the webpage.
How can I solve this?
You might want to do it with casper.js, it's easier:
casper.test.begin('my test', function suite(test) {
casper.start("your url", function() {
test.assertTitle("expected title");
});
casper.run(function() {
test.done();
});
});

Not receiving any data from webpage to content.js of chrome extension

I am trying to send a message from a button click even on my website which is opened in a tab by chrome extension.
But, I'm not able to get any message from the webpage and I get a port error.
My content.js:
var port = chrome.extension.connect();
port.onMessage.addEventListener("message", function(event) {
// We only accept messages from ourselves
if (event.source != window)
return;
if (event.data.type && (event.data.type == "FROM_PAGE")) {
console.log("Content script received: " + event.data.text);
port.postMessage(event.data.text);
}
}, false);
chrome.tabs.onMessage.addListener(function(tabId, changeInfo, tab) {
alert(changeInfo);
});
Popup.js
$("#linkify").click(function() {
chrome.tabs.create({
'url': 'http://localhost:3000/signin'
}, function(tab) {
// Tab opened.
chrome.tabs.executeScript(tab.id, {
file: "jquery.js"
}, function() {
console.log('all injected');
chrome.tabs.executeScript(tab.id, {
file: "content.js"
}, function() {
console.log('all injected');
chrome.tabs.sendMessage(tab.id, function() {
console.log('all injected');
});
});
});
});
//getlink();
});
});
function checkUserAuth() {
console.log(localStorage.getItem("apiKey"));
if (localStorage.getItem("apiKey") != null) {
document.getElementById('openBackgroundWindow').style.visibility = 'hidden';
}
}
var port = chrome.extension.connect({
name: "Sample Communication"
});
port.postMessage("Hi BackGround");
port.onMessage.addListener(function(msg) {
console.log("message recieved" + msg);
});
My background.js
chrome.extension.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
});
Script that sends message from the web url:
document.getElementById("theButton").addEventListener("click", function() {
console.log("message being sent");
window.postMessage({ type: "FROM_PAGE", text: "Hello from the webpage!" }, "*");
}, false);
Where am I going wrong here that I am not receiving any message?
After making some changes to your scripts i got it running :)
This question covers message passing from extension page -- > background, content page -- > background, extension page --> content page
Output from destination page (In my case it is http://www.google.co.in/ for you it is http://localhost:3000/signin)
Output from popup.js
Output from background.js
I have added a connection listener for var port = chrome.extension.connect({name: "Sample Communication"}); code in your popup.js in background.js it solved problem of Receiving end do not exist
background.js
chrome.extension.onConnect.addListener(function(port) {
port.onMessage.addListener(function(content) {
console.log("Connected ..." + content);
});
});
chrome.extension.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
});
Eliminated script injection right at the time of new tab creation and injected script after tab status is complete by looking for tabs.onUpdated Listener
popup.js
flag = false;
function customFunction() {
chrome.tabs.create({
'url': 'http://www.google.co.in/'
}, function(tab) {
flag = true;
// Tab opened.
});
}
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if (flag) {
if (changeInfo.status === 'complete') {
console.log("Inject is called");
injectScript(tab);
}
}
});
function injectScript(tab) {
chrome.tabs.executeScript(tab.id, {
file: "jquery.js",
"runAt": "document_start"
}, function() {
console.log('all injected');
chrome.tabs.executeScript(tab.id, {
file: "content.js",
"runAt": "document_start"
}, function() {
console.log('all injected');
chrome.tabs.sendMessage(tab.id, function() {
console.log('all injected');
});
});
});
}
window.onload = function() {
document.getElementById("linkify").onclick = customFunction;
};
var port = chrome.extension.connect({
name: "Sample Communication"
});
port.postMessage("Hi BackGround");
port.onMessage.addListener(function(msg) {
console.log("message recieved" + msg);
});
Eliminated window.postMessage() from web page and injected a custom script to send message to popup.js on click of button(Here i have chosen google logo)
content.js
function bindFunction() {
console.log("message being sent");
chrome.extension.sendMessage({ type: "FROM_PAGE", text: "Hello from the webpage!" });
}
window.onload = function() {
document.getElementById("hplogo").onclick = bindFunction;
};
Sample Page where linkify button is similar to login button
popup.html
<html>
<head>
<script src="popup.js"></script>
</head>
<body>
<button id="linkify">Linkify</button>
</body>
</html>
Ensured all code has permissions in manifest.json for injected script files,tabs etc in a complete manifest.json file
manifest.json
{
"name": "Complex Calls",
"description": "Complex Calls Demo",
"manifest_version": 2,
"background": {
"scripts": ["background.js"]
},
"browser_action": {
"default_popup": "popup.html",
"default_icon": "screen.png"
},
"permissions": [
"tabs", "<all_urls>"
],
"version": "1"
}

Resources