I can find plenty of questions for sending a message from Bbackground to content scripts or from popup to background scripts, but I can't find any on how to send a message from options.js (triggered from my options page) to background.js for my Chrome extension
manifest.js
{
...
"manifest_version": 3,
"permissions": [
"alarms",
"contextMenus",
"notifications",
"storage"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html"
},
"options_page": "options.html",
"icons": {
"48": "/assets/icons/icon-48.png",
"128": "/assets/icons/icon-128.png"
}
}
Code in options.js
// Save options
document.querySelector('#save').addEventListener('click', ()=> {
// Check for selected regions
let selectedRegions = [];
regionChecks.forEach(elm => {
if (elm.checked)
selectedRegions.push(elm.id.replace('region-', ''))
});
// Save selections
chrome.storage.sync.set({ 'regions': selectedRegions });
// Check for refresh period
let refreshPeriod = document.querySelector('#refresh');
if (refreshPeriod) {
refreshPeriod = parseInt(refreshPeriod.value);
if (refreshPeriod === NaN) {
refreshPeriod = 5;
} else if(refreshPeriod < 2) {
refreshPeriod = 2;
} else if (refreshPeriod > 120) {
refreshPeriod = 120;
}
// Save period
chrome.storage.sync.set({ 'refresh': refreshPeriod });
}
// Loop through features and remove if region gone
chrome.storage.local.get(['features'], featuresData => {
let featureCount = 0;
if (featuresData.features) {
featureSet = featuresData.features;
Object.keys(featureSet).forEach(key => {
if (!selectedRegions.includes(featureSet[key].Region)) {
delete featureSet[key];
} else if (featureSet[key].Status !== "read") {
featureCount = featureCount + 1;
}
});
// Update features data
chrome.storage.local.set({ 'features': featureSet });
// Update the badge
if (featureCount > 0) {
chrome.action.setBadgeText({ text: featureCount.toString() });
} else {
chrome.action.setBadgeText({ text: '' });
}
}
});
// Trigger an update
chrome.runtime.sendMessage('', {
type: 'update'
});
// Close the options page
close();
});
Code in background.js
// Listen for messages
chrome.runtime.onMessage.addListener(data => {
console.log(data);
if (data.type === 'update') {
scheduleRequest();
}
});
But nothing is happening
I've tried using tabs.sendMessage, but even if I put tabs in permissions it tells me that it isn't defined when I add it to the function chrome.tabs.sendMessage(tabs[0].id, {...
My test results contradict your claim.
manifest.json
{
"manifest_version": 3,
"name": "hoge",
"version": "1.0",
"background": {
"service_worker": "background.js"
},
"options_page": "options.html"
}
background.js
// Listen for messages
chrome.runtime.onMessage.addListener(data => {
console.log(data);
if (data.type === 'update') {
console.log("hoge")
// scheduleRequest();
}
});
options.js
// Trigger an update
chrome.runtime.sendMessage('', {
type: 'update'
});
options.html
<html>
<body>
options page
<script src="options.js"></script>
</body>
</html>
After some input from #woxxom and #Norio, and a little bit more troubleshooting, this is how I managed to get it to work
option.js:
// Trigger an update
chrome.runtime.sendMessage({ type: 'update' }, result => {
// Close the options page
close();
});
I had to move the close(); event into the return function so it didn't prematurely close off the code. I also had to have a paramter in the return function for some reason otherwise it wouldn't run with an empty arrow function.
background.js:
// Listen for messages
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'update') {
startRequest(true).then(sendResponse);
return true;
}
});
My function to be triggered in the background.js file was already an async promise function, so I had to add a .then() for the onMessage response function to trigger once it had run. It also wouldn't work without having return true; in there.
Related
I am developing my first chrome extension, I want to have a toggle button on my popup which allows users to enable or disable the extension for that site, though not completely disable the extension but technically control the execution of the content.js for that particular domain.
Something similar to
popup.js
const toggleBtn = document.querySelector(".toggle");
toggleBtn.addEventListener("click", function(){
if(toggleBtn.checked === true){
console.log('inject content.js');
}else{
console.log('remove content.js');
}
});
I can see there is a way to inject it but there is no way to remove it.
chrome.scripting.executeScript({
target: {tabId},
files: ['content.js'],
});
Note, I don't want to reload the page but want to disable the content.js. How can I achieve this functionality inside my chrome extension. I see there are many extensions doing this like Adblocker and Wordtune.
I went through few SO threads like this one but most of them are for Manifest V2 and few packages that are recommended are obsolate now. I also could not find a complete example anywhere.
Todo
I should be able to turn the extension on/off for the current domain from within the Popup.
It should store the state inside a chrome.storage.sync so that next time I installed the extension I should not again turn on/off for the selected websites.
As soon as I toggle the button, the changes should be visible if I have opened the same domain in another tab.
The extension's icon should be changed in real time as well e.g grey icon for disabled status
If I close and open a website, the icon and the toggle button should be restored their on/off status and update the icon accordingly.
My Attempt (Solves #toDo 1,2,3,4,5)
background.js
const icons = {
enabled: {
'16': 'icon-16.png',
'19': 'icon-19.png',
'38': 'icon-38.png',
'48': 'icon-48.png',
'128': 'icon-128.png'
},
disabled: {
'16': 'icon-16-off.png',
'19': 'icon-19-off.png',
'38': 'icon-38-off.png',
'48': 'icon-48-off.png',
'128': 'icon-128-off.png'
}
};
const getExtensionStatus = host => new Promise((resolve, reject) => {
chrome.storage.sync.get(host, result => {
if (result[host] !== undefined) {
resolve(result[host]);
} else {
setExtensionStatus(host, true);
}
});
});
const setExtensionStatus = (host, toggleBtnStatus) => {
const data = { [host]: toggleBtnStatus };
chrome.storage.sync.set(data, () => {});
};
chrome.runtime.onInstalled.addListener((details) => {
if (details.reason === "install") {
chrome.action.setIcon({ path: icons.enabled });
}
});
const init = async tab => {
const url = new URL(tab.url);
if (url.protocol !== "chrome-extension:") {
const host = url.host;
const status = await getExtensionStatus(host);
const icon = status ? icons.enabled : icons.disabled;
chrome.action.setIcon({ path: icon });
}
};
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status === "complete") init(tab);
});
chrome.tabs.onActivated.addListener(info => {
chrome.tabs.get(info.tabId, init);
});
chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => {
if (request.type === "getExtensionStatus") {
const status = await getExtensionStatus(request.host);
sendResponse({ status });
return true;
} else if (request.type === "setExtensionStatus") {
setExtensionStatus(request.host, request.status);
const icon = request.status ? icons.enabled : icons.disabled;
chrome.action.setIcon({ path: icon });
}
});
popup.js
document.addEventListener("DOMContentLoaded", function () {
const toggleBtn = document.querySelector(".toggle");
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
const host = new URL(tabs[0].url).host;
chrome.runtime.sendMessage({ type: "getExtensionStatus", host }, (response) => {
toggleBtn.checked = response.status;
});
toggleBtn.addEventListener("click", () => {
chrome.runtime.sendMessage({ type: "setExtensionStatus", host, status: toggleBtn.checked });
});
});
});
What left?
The content.js is not available after some time of inactiveness of the tab. How can I inject the script again and avoid running event multiple times?
content.js
document.addEventListener("keydown", listenEnterkey);
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.type === "setExtensionStatus") {
console.log(request.status);
if (request.status) {
// Add event listener here
document.addEventListener("keydown", listenEnterkey);
} else {
// Remove event listener here
document.removeEventListener("keydown", listenEnterkey);
}
}
});
For example, if you add a button with a script, I don't think the added button will disappear even if you remove the script.
Therefore, the ON/OFF function is built into the script, and it is operated by the message.
manifest.json
{
"name": "content_scripts + popup",
"version": "1.0",
"manifest_version": 3,
"content_scripts": [
{
"js": [
"matches.js"
],
"matches": [
"<all_urls>"
]
}
],
"host_permissions": [
"<all_urls>"
],
"action": {
"default_popup": "popup.html"
}
}
matches.js
console.log("matches.js");
let isEnabled = true;
console.log(isEnabled);
chrome.runtime.onMessage.addListener((message) => {
switch (message) {
case "on":
isEnabled = true;
break;
default:
isEnabled = false;
break;
}
console.log(isEnabled);
});
popup.js
const send = (s) => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
chrome.tabs.sendMessage(tabs[0].id, s);
});
}
document.getElementById("on").onclick = () => {
send("on");
}
document.getElementById("off").onclick = () => {
send("off");
}
popup.html
<html>
<body>
<button id="on">on</button>
<button id="off">off</button>
<script src="popup.js"></script>
</body>
</html>
I wanted a "simple" extension:
It grabs some information of the initial site
It loads a new site (a local HTML file)
It takes the new site as a template and puts the information into the
right places.
I think I only need:
Content Script (to grab, save and replace the information form the old
to the new site)
Background Script (to act on the click on the extension)
Manifest
the local HTML template (to load it and to use it as a template)
The main problem is, that I get no output from the Content Script on the new loaded site (HTML template) even though there is no error message when passing a message from the Background Script to the Content Script..
Content Script:
chrome.runtime.onConnect.addListener(function (port) {
console.assert(port.name == "knockknock");
port.onMessage.addListener(function (msg, port) {
gotMessage(msg, port);
});
});
function gotMessage(message, port) {
if (message.txt == "Sammle Rechnungsinformationen") {
getBestellInformationen();
port.postMessage({ response: "true" });
}
else if (message.tee == "Aendere das Template") {
setBestellInformationen();
port.postMessage({ response: "true" });
}
}
function getBestellInformationen() {
let bestellInformationen = {};
let tables = document.getElementsByTagName('td');
for (elt of tables) {
elt.style['background-color'] = '#FF00FF';
}
for (i = 0; i < tables.length; i++) {
content = tables[i].textContent;
switch (content) {
...
case String(content.match("Net.Grand.Total:")):
bestellInformationen["Gesamtbetrag Netto"] = (tables[i + 1].textContent);
break;
}
}
// Save the current myArray value.
chrome.storage.local.set({ key: bestellInformationen }, function () {
console.log('Value is set to ' + bestellInformationen);
});
}
function setBestellInformationen() {
// Retrieve the the stored value, defaulting to an empty array.
chrome.storage.local.get(['key'], function (result) {
console.log('Value currently is ' + result.key);
let bestellInformationen = result.key;
// Aendere das geoeffnete Template
console.log("Template Bearbeiten");
console.log(bestellInformationen);
for (key in bestellInformationen) {
console.log(bestellInformationen[key]);
}
});
chrome.storage.local.clear(function () { console.log("storage cleared successfully"); });
}
Backgroud Script:
chrome.browserAction.onClicked.addListener(buttonClicked);
function buttonClicked(tab) {
var port = chrome.tabs.connect(tab.id, { name: "knockknock" });
if (!((String(tab.url.match("\X*Die_HTML_Datei.html"))) == "Die_HTML_Datei.html")) {
let msg = { txt: "Sammle Rechnungsinformationen" };
port.postMessage(msg);
port.onMessage.addListener(function (msg) {
if (msg.response == "true") {
oeffneDieRechnungHTML();
port.disconnect();
});
} else {
let msg = {txt: "Aendere das Template" };
port.postMessage({ txt: "Aendere das Template" });
port.onMessage.addListener(function (msg) {
});
port.disconnect();
}
}
function oeffneDieRechnungHTML() {
chrome.tabs.update({ url: chrome.runtime.getURL("Die_HTML_Datei.html") },
function () { console.log("Seite wurde Erfolgreich zur HTML-Rechnung gewechselt") });
}
Manifest:
{
"manifest_version": 2,
"name": "Codingtrain",
"version": "0.1",
"permissions": [ "activeTab", "tabs", "storage" ],
"web_accessible_resources": [ "Die_HTML_Datei.html" ],
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [ "content.js" ]
}
],
"background": {
"scripts": [ "background.js" ]
},
"browser_action": {
"default_icon": "get_started48.png"
}
}
EDIT: Reworded for easier understanding.
I want to make a simple browser extension like Font Face Ninja which toggles UI when page_action or browser_action is clicked.
The following code using browser_action works -
background.js
chrome.browserAction.onClicked.addListener(function(tab) {
console.log(`clicked browserAction`)
})
manifest.json
{
...
"browser_action": {
"default_icon": {
"19": "icon19.png",
"38": "icon38.png"
}
},
...
}
While the following code using page_action does not work -
background.js
chrome.pageAction.onClicked.addListener(function(tab) {
console.log(`clicked pageAction`)
})
manifest.json
{
...
"page_action": {
"default_icon": {
"19": "icon19.png",
"38": "icon38.png"
}
},
...
}
According to MDN docs,
Page actions are like browser actions, except that they are associated with particular web pages rather than with the browser as a whole. If an action is only relevant on certain pages, then you should use a page action and display it only on relevant pages. If an action is relevant to all pages or to the browser itself, use a browser action.
Which confirms I want to use page_action but its not working.
How do I make it work using page_action?
Page Action
A way to make page_action work can be found on my Github → https://github.com/deadcoder0904/insert-remove-ui-chrome-extension/tree/page_action
background.js
var hasExecutedOnce = false
function addUI(tabId) {
chrome.tabs.sendMessage(tabId, {
from: 'background',
subject: 'isUIAdded?',
})
}
chrome.runtime.onInstalled.addListener(function() {
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([
{
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { hostEquals: 'www.google.co.in' },
}),
],
actions: [new chrome.declarativeContent.ShowPageAction()],
},
])
})
})
chrome.pageAction.onClicked.addListener(function(tab) {
if (!hasExecutedOnce) {
chrome.tabs.executeScript(
tab.id,
{
file: 'contentScript.js',
},
function() {
addUI(tab.id)
},
)
hasExecutedOnce = true
}
addUI(tab.id)
})
contentScript.js
var body = document.getElementsByTagName('body')[0]
function insertUI() {
var div = document.createElement('div')
div.setAttribute('id', 'sample-extension-12345')
div.innerHTML = `<h1>Sample Extension</h1>`
body.appendChild(div)
}
function removeUI() {
document.getElementById('sample-extension-12345').remove()
}
function main() {
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.subject === 'isUIAdded?') {
const id = document.getElementById('sample-extension-12345')
if (id === null) insertUI()
else removeUI()
}
})
}
main()
Browser Action
It also has a solution for browser_action on the master branch → https://github.com/deadcoder0904/insert-remove-ui-chrome-extension/
background.js
var hasExecutedOnce = false
function addUI(tabId) {
chrome.tabs.sendMessage(tabId, {
from: 'background',
subject: 'isUIAdded?',
})
}
chrome.browserAction.onClicked.addListener(function(tab) {
if (!hasExecutedOnce) {
chrome.tabs.executeScript(
tab.id,
{
file: 'contentScript.js',
},
function() {
addUI(tab.id)
},
)
hasExecutedOnce = true
}
addUI(tab.id)
})
contentScript.js
var body = document.getElementsByTagName('body')[0]
function insertUI() {
var div = document.createElement('div')
div.setAttribute('id', 'sample-extension-12345')
div.innerHTML = `<h1>Sample Extension</h1>`
body.appendChild(div)
}
function removeUI() {
document.getElementById('sample-extension-12345').remove()
}
function main() {
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.subject === 'isUIAdded?') {
const id = document.getElementById('sample-extension-12345')
if (id === null) insertUI()
else removeUI()
}
})
}
main()
I am working with a webpage which have an <iframe> to hold the university website.
However, some of the link in the university website will open a new tab inside the browser, normally it is not a problem but my webpage is going to be display on a 55" touchscreen in full screen mode . Therefore, my webpage will be blocked by the new tabs.
So, now I am using Chrome Extension to handle the new tabs. I modified one of the Extension from internet to close and redirect the new tabs back to <iframe> by using contentscript and background. And it WORK for most of the new tabs. (not all new tabs)
Because some of the <a>s' href is using javascript like this one :
High Hybrid Reinforced Soil Slope as Runway Support - Tana Toraja Airport Case Study
tab.url didn't return anything (it return empty string). The alert() like
alert('link:'+tab.url)
this. Will become this :
alert('link:'+'')
Anyway to tackle this problem?
----Code for reference----
manifest.json
{
https://clients2.google.com/service/update2/crx",
"manifest_version": 2,
"name": "Inteset Chrome Kiosk Helper",
"short_name": "Kiosk Helper",
"description": "Traps network errors. Shows user friendly error page allowing user to return to previous page. Blocks new windows and new tabs.",
"version": "1.1.12",
"options_page": "options.html",
"options_ui": {
"page": "options.html",
"chrome_style": true
},
"content_scripts": [
{
"matches": ["http://localhost/newyear/index.php"],
"js": ["myjs.js"]
}
],
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"web_accessible_resources": [
"style.css",
"popup.js",
"options.js"
],
"permissions": [
"webNavigation",
"tabs",
"http://*/*", "https://*/*",
"history",
"activeTab",
"storage"
],
"icons": {
"16" : "Logo16x16.png",
"48" : "Logo48x48.png",
"128": "Logo128x128.png"
}
}
background.js I only modify the code inside : chrome.tabs.onCreated.addListener(...)
chrome.webNavigation.onErrorOccurred.addListener(function (data) {
var errs = "net::ERR_BLOCKED_BY_ADMINISTRATOR;net::ERR_NAME_NOT_RESOLVED;net::ERR_CONNECTION_FAILED;net::ERR_CONNECTION_RESET;net::ERR_EMPTY_RESPONSE;net::ERR_FAILED;net::ERR_CONNECTION_REFUSED;net::ERR_INTERNET_DISCONNECTED";
if (errs.indexOf(data.error) != -1) {
var Page = GetPageName( data.error )
chrome.tabs.update(data.tabId, {
url: Page
});
}
});
chrome.tabs.onCreated.addListener(function (tab) {
chrome.tabs.query(
{ currentWindow: true },
function (tabs) {
if (tabs.length > 1) {
chrome.storage.local.get({
blockWindows: false,
blockTabs: false
}, function (items) {
chrome.windows.getCurrent({}, function (window) {
if (window.state == "fullscreen"||true) {
if (items.blockTabs) {
setTimeout(function(){
var _url = tabs[tabs.length - 1].url;
alert("New tabs [" + tabs.length + "] { " + _url + " }");
for(var i=0;i<tabs.length;i++){
// alert(tabs[i].url);
if(tabs[i].url == "http://localhost/UST_VW_web/index.php"){
alert('bg found url ' + tabs[i].url + '\n' + _url);
chrome.tabs.sendMessage(tabs[i].id, {new_link:_url }, function(response) {
//alert('bg response ');
});
}
}
chrome.tabs.remove(tab.id);
},10000);
}
}
});
});
}
}
);
});
chrome.windows.onCreated.addListener(function (window) {
chrome.windows.getAll({populate: true}, function (windows) {
if (windows.length > 1) {
chrome.storage.local.get({
blockWindows: false,
blockTabs: false
}, function (items) {
if (items.blockWindows) {
// check if at least one window is in full screen
for (var i = 0; i < windows.length; i++) {
if (windows[i].state == "fullscreen") {
chrome.windows.remove(window.id);
alert("New windows are not allowed by administrator. :)");
RedirectNewPage("new Win", window.url);
break;
}
}
}
});
}
});
});
function RedirectNewPage(caller,url){
alert("RedirectNewPage");
var tabs_str = "";
chrome.windows.getAll({populate:true},function(windows){
windows.forEach(function(window){
window.tabs.forEach(function(tab){
//collect all of the urls here, I will just log them instead
console.log(tab.url);
});
});
});
chrome.windows.getAll({populate: true}, function (windows) {
windows.forEach(function(window){
window.tabs.forEach(function(tab){
console.log(tab.url);
tabs_str += (tab.id + "\t");
});
});
});
alert("tabs "+tabs_str);
}
function GetPageName( error ) {
var ErrText = new String(error);
if (ErrText.indexOf("net::ERR_BLOCKED_BY_ADMINISTRATOR") >= 0)
return "Error-Blocked-by-Administrator.html";
if (ErrText.indexOf("net::ERR_NAME_NOT_RESOLVED") >= 0)
return "Error-Name-not-Resolved.html";
if (ErrText.indexOf("net::ERR_CONNECTION_FAILED") >= 0)
return "Error-Connectoin-Failed.html";
if (ErrText.indexOf("net::ERR_CONNECTION_RESET") >= 0)
return "Error-Connection-Reset.html";
if (ErrText.indexOf("net::ERR_EMPTY_RESPONSE") >= 0)
return "Error-Empty-Response.html";
if (ErrText.indexOf("net::ERR_FAILED") >= 0)
return "Error.html";
if (ErrText.indexOf("net::ERR_CONNECTION_REFUSED") >= 0)
return "Error-Connection-Refused.html";
if (ErrText.indexOf("net::ERR_INTERNET_DISCONNECTED") >= 0)
return "Error-Internet-Disconnected.html";
return "Error.html";
}
myjs.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
document.getElementById("mainframe").src = request.new_link;
alert("GET 2 --- " + document.getElementById("mainframe").name);
alert(request.new_link);
//sendResponse(myFunc(request.args));
});
I managed to pass a message between two files/instances, namely my popup and my background scripts, but the callback function still returns undefined, so my popup script does not receive a reply. Can somebody assist me? My code is based on the docs from Google.
Background.js
chrome.runtime.onMessage.addListener(function (sender, sendResponse) {
var resp = {'navURL': "Not set yet"};
if (sender.greeting === "GetURL") {
sendResponse(resp);
}
});
popup.js
function getURL() {
chrome.runtime.sendMessage({
greeting: "GetURL"
},
function (response) {
// RESPONSE IS UNDEFINED //
console.log(response);
alert(response.navURL);
});
}
$("input[type='checkbox']").on('change', function () {
getURL();
});
Manifest.json
{
"name": "FaceBlock",
"description": "This extention gets rid of unwanted content on Facebook like sponsored posts, adds or annoying suggestions. The content you wish to see is enlarged for a better and richer social experience.",
"version": "0.0.1",
"manifest_version": 2,
"content_scripts": [
{
"matches": [
"http://*.facebook.com/*", "https://*.facebook.com/*"],
"css": ["css/popup.css"],
"js": ["js/jquery.min.js", "js/content.js"],
"run_at": "document_end",
"all_frames": true
}],
"options_page": "options.html",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html",
"default_title": "Faceblock"
},
"permissions": [
"activeTab",
"tabs",
"https://www.facebook.com/*",
"https://ajax.googleapis.com/",
"storage"
],
"background": {
"scripts": ["js/background.js"],
"persistent": false
},
"options_ui": {
// Required.
"page": "popup.html",
// Recommended.
"chrome_style": true
// Not recommended; only provided for backwards compatibility,
// and will be unsupported in a future version of Chrome (TBD).
//"open_in_tab": true
},
"web_accessible_resources": [
"images/faceblock.jpg",
"images/seigaiha.png",
"js/popup.js",
"icon.png",
"js/options.js",
"css/popup.css",
"popup.html",
"options.html"
]
}
Thanks in advance,
Niels Vermeiren
EDIT: I now have the following with the same problem
Background.js
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
sendResponse({msg: "Element " + sender.element + " zijn zichtbaarheid wordt nu: " + sender.checked});
return true;
});
Popup.js
function getCurrentTabUrl(callback) {
return new Promise(function (resolve, reject) {
// https://developer.chrome.com/extensions/tabs#method-query
var queryInfo = {
active: true,
currentWindow: true
};
chrome.tabs.query(queryInfo, function (tabs) {
if (callback(tabs[0].url)) {
return resolve();
} else {
return reject();
}
});
});
}
function changeFacebook(data) {
console.log(data);
chrome.runtime.sendMessage(
"changeFacebook",
data,
function (response //undefined) {
console.log(response.msg); // UNDEFINED
});
}
document.addEventListener('DOMContentLoaded', function () {
var callback = function getCurrentTab(tab) {
if (tab == "https://www.facebook.com/") {
return true;
} else {
return false;
}
}
getCurrentTabUrl(callback).then(function () {
alert('on facebook');
$('.section').hide();
}, function () {
alert('not on facebook');
});
$("input[type='checkbox']").on('change', function () {
var id = $(this).attr('id');
var check = this.checked;
var data = {
'element': id,
'checked': check
};
changeFacebook(data);
});
$('.menuItem').hide();
$('.menuItem:first').show();
jQuery('.navitem').on('click', function () {
var value = $(this).html().toLocaleLowerCase();
jQuery('.menuItem').hide();
jQuery('#' + value).show();
});
});
According to doc here:
https://developer.chrome.com/extensions/runtime#event-onMessage
In your background.js, it should be
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
...
});
Since you are missing the last argument, what you really have is this:
chrome.runtime.onMessage.addListener(function (request, sender) {
...
});
So your code pretty much renamed request => sender, sender => sendResponse.
Therefore, you are trying to invoke sender as a function. But the actual sendResponse callback function is undefined. If you inspect your background page (see tips for how), you should see the error.
Tips:
When developing chrome extension, you can Inspect views: background page in the chrome://extensions page if you have any background page running.
When your popup is opened, you can inspect the popup page just you normally do.
And you can throw debuggers wherever you want, and you will be able to play around with it.
Edit:
So I have tested your code, the issue is just missing argument as I stated above. I also noticed the doc says the first two arguments are optional (not sure what the fuzz that is). But if you change your code to as below, it will work.
Background.js
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
var resp = {'navURL': "Not set yet"};
if (request.greeting === "GetURL") {
sendResponse(resp);
}
});
Popup.js
function getURL() {
chrome.runtime.sendMessage({
greeting: "GetURL"
},
function (response) {
console.log(response);
alert(response.navURL);
});
}
To test it
Go to the background page inspect, and paste in the background page snippet.
Go to the popup page inspect (open your popup, and right click within the popup, then choose inspect)
Paste in the popup page snippet
In the popup page inspect, call getURL()