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"
}
Related
My google chrome extension has a background.js and content script that communicate with port.OnMessage but I have noticed that when I run my extension in Chrome://extension it throws an error because it is not a url and the same happens with a new google tab chrome which has no url. How could I block them?
On the internet I got information that said that they were blocked with
"exclude_matches": [
"chrome://extensions/"
]
however, this doesn't work for the version 3 manifest. Also how could it tell you not to run the extension in a new tab (no url)
this is my manifest v3
"name":"Certified Records Full Certificate",
"description":"Esta extensión permite grabar la pantalla o hacer capturas de pantalla",
"version": "1.0",
"manifest_version":3,
"background":{
"service_worker":"background.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content-script.js"],
"exclude_matches": [
"chrome://extensions/"
]
}],
"permissions":["storage","activeTab","scripting","tabs","desktopCapture"],
"action":{
"default_popup":"popup.html",
"default_icon":{
"16":"/images/logo-16.png",
"32":"/images/logo-32.png",
"48": "/images/logo-48.png",
"128": "/images/logo-128.png"
}
},
"icons":{
"16":"/images/logo-16.png",
"32":"/images/logo-32.png",
"48": "/images/logo-48.png",
"128": "/images/logo-128.png"
} }
this is my background.js
chrome.runtime.onConnect.addListener(function (port) {
port.onMessage.addListener(function(msg){
if (msg.type === 'SS_UI_REQUEST') {
requestScreenSharing(port,msg);
}
});
});
function requestScreenSharing(port, msg) {
const sources = ['window'];
const tab = port.sender.tab;
desktopMediaRequestId = chrome.desktopCapture.chooseDesktopMedia(
sources,
port.sender.tab,
streamId => {
if (streamId) {
msg.type = 'SS_DIALOG_SUCCESS';
msg.streamId = streamId;
msg.text ="sharing";
} else {
msg.type = 'SS_DIALOG_CANCEL';
msg.text ="cancel";
}
var tab = getTabId();
tab.then((value) => {
const respuesta = chrome.tabs.connect(value.id, {
name: "respuesta",
});
respuesta.postMessage(msg);
});
}
);
}
async function getTabId() {
let queryOptions = { active: true, currentWindow: true };
let [tab] = await chrome.tabs.query(queryOptions);
return tab;
}
this is my content-script.js
chrome.runtime.onConnect.addListener(function (port) {
port.onMessage.addListener(function(msg){
if (msg.type === 'SS_UI_REQUEST') {
console.log(msg);
var background = chrome.runtime.connect();
background.postMessage(msg);
}
if (msg.type === 'SS_DIALOG_SUCCESS') {
console.log(msg);
startScreenStreamFrom(msg.streamId);
}
if (msg.type === 'SS_DIALOG_CANCEL') {
console.log(msg);
}
if(msg.type === "SS_UI_TAKESCREENSHOT")
{
console.log("tomar screenshot");
TakeScreenShot();
}
});
});
function startScreenStreamFrom(streamId) {
console.log("compartiendo pantalla");
navigator.mediaDevices
.getUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: streamId
}
}
})
.then(stream => {
window.stream = stream;
});
}
async function TakeScreenShot(){
setTimeout(async () => {
const screen = window.stream;
const track = screen.getVideoTracks()[0];
const imageCapture = new ImageCapture(track);
await imageCapture.grabFrame()
.then(function(bitmap) {
track.stop();
var canvas = document.createElement('canvas');
canvas.width = bitmap.width
canvas.height = bitmap.height
const context = canvas.getContext('2d')
context.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height)
const image = canvas.toDataURL()
var link = document.createElement('a');
link.download = 'FullCertificateCaptureScreen.png';
link.href = image
link.click();
})
.catch(function(error) {
track.stop();
console.log('grabFrame() error: ', error);
});
}, 1000);
}
this is the popup script
document.getElementById("btn-share").addEventListener("click", function(){
var tab = getTabId();
tab.then((value) => {
chrome.storage.local.set({'pestaña': value.id});
const port = chrome.tabs.connect(value.id, {
name: "conexion",
});
port.postMessage({ type: 'SS_UI_REQUEST', text: 'start' }, '*');
}); //fin de tab.then()
})//fin de click addEventListener
document.getElementById("btn-capture").addEventListener("click", async function(){
chrome.storage.local.get('pestaña', function (result) {
const port = chrome.tabs.connect(result.pestaña, {
name: "tomarScreenShot",
});
port.postMessage({ type: 'SS_UI_TAKESCREENSHOT', text: 'takescreenshot' }, '*');
window.close();
});
});
async function getTabId() {
let queryOptions = { active: true, currentWindow: true };
let [tab] = await chrome.tabs.query(queryOptions);
return tab;
}
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!
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 :-)
I want to let the user choose and upload a file from the chrome extension popup. But, as soon as the file-chooser dialog opens the popup loses focus and closes immediately. From this answer, the workaround seems to be that I can move the dialog opening logic to the background-page, which is not affected by loss of focus.
I have tried the answer, but the file-chooser does not appear at all. It is weird that fileChooser.click() event does actually occur (I was able to verify it by creating a click listener for fileChooser). Below is a simplified version just to focus on the problem.
popup.html
<button id="uploadCSV">Upload CSV</button>
popup.js
$('#uploadCSV').click(function() {
chrome.extension.sendMessage({ action: 'browseAndUpload' });
});
background.js
var fileChooser = document.createElement('input');
fileChooser.type = 'file';
chrome.extension.onMessage.addListener(function (msg) {
if (msg.action === 'browseAndUpload') {
fileChooser.click();
}
});
Popup.js
var file = document.getElementById('#file')[0].files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
chrome.runtime.sendMessage({
"uploadFile": true,
blob: reader.result,
file: { name: file.name }
}, x => { })
};
reader.onerror = function (error) {
console.log('Error: ', error);
};
Background.js
function dataURLtoFile(dataurl, filename) {
var arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
}
function uploadFile(msg) {
var file = msg.file;
let nfile = dataURLtoFile(msg.blob, file.name)
var formData = new FormData();
formData.append('cvFile', nfile);
var settings = {
"async": true,
"crossDomain": true,
"url": "endpoint",
"method": "POST",
"headers": {
"accept": "application/json",
"cache-control": "no-cache",
},
"processData": false,
"contentType": false,
"mimeType": "multipart/form-data",
"data": formData
}
$.ajax(settings).done(function (response) {
console.log(response);
});
}
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
switch (!0) {
case 'uploadFile' in msg: uploadFile(msg); break;
}
})
We are using following JQuery code (within JSF) to invoke Autocomplete. Everything seems to work fine when user keys in data but when user copies and pastes Autocomplete will be invoked on second attempt. I am testing following code in IE 8. Any inputs are appreciated
<pre>
<code>
<script type="text/javascript">
$(function () {
$(document).on('keyup.autocomplete','##{resp.workItemResponse.wiResponseId}', function() {
$('##{resp.workItemResponse.wiResponseId}').autocomplete({
minLength: 3,
source: function( request, response){
$.ajax({
type: 'GET',
url: "/iaportal/autoCompleteServlet",
cache: false,
delay: 200,
data: {
'respId':'#{resp.workItemResponse.wiResponseId}',
'type': '#{autoCompleteType}',
'term':request.term
},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data){
response($.map(data.acctNum, function (item) {
return {
label: item.label,
value: item.label
}
}));
},
error: function(message){
alert("error "+message);
}
});
},
select: function( event, ui ) {
var selectedObj = ui.item;
var text = selectedObj.value;
$('.autoComplete#{resp.workItemResponse.wiResponseId}').attr('value', text);
$('.autoComplete#{resp.workItemResponse.wiResponseId}').trigger('change');
}
});
$('##{resp.workItemResponse.wiResponseId}').keyup(function(){
var text = this.value;
if(text == '' || text.length == 0){
$('.autoComplete#{resp.workItemResponse.wiResponseId}').attr('value', "");
$('.autoComplete#{resp.workItemResponse.wiResponseId}').trigger('change');
}
});
}); // on Ends
var textElem;
$(document).on('paste','##{resp.workItemResponse.wiResponseId}',function() {
textElem = this;
setTimeout(invokeOnPaste , 100);
});
function invokeOnPaste(){
var text = $(textElem).val();
if(text.length == 14){
$('.autoComplete#{resp.workItemResponse.wiResponseId}').attr('value', text);
$('.autoComplete#{resp.workItemResponse.wiResponseId}').trigger('change');
} else if(text.length != 0){
$('##{resp.workItemResponse.wiResponseId}').trigger('search','autocomplete');
}
}
});
</script>
</code>
</pre>