I managed to build Ripple Emulator open source (https://github.com/apache/incubator-ripple).
I built it per the instructions (Jake build), which create the Chrome Extension Target that allows me to test my web apps via a chrome extension of my built, as per https://github.com/apache/incubator-ripple/blob/master/doc/chrome_extension.md.
I successfully loaded the unpacked extension onto chrome, but when I enable it nothing happens, though the page reloads the extension does not work, instead I get 2 errors:
Uncaught ReferenceError: webkitNotifications is not defined
webkitNotifications.createHTMLNotification('/views/update.html').show();
Unchecked runtime.lastError while running tabs.executeScript: Cannot access a chrome:// URL
chrome.tabs.executeScript(tabId, {
How do I solve this problem?
Full background.js:
if (!window.tinyHippos) {
window.tinyHippos = {};
}
tinyHippos.Background = (function () {
var _wasJustInstalled = false,
_self;
function isLocalRequest(uri) {
return !!uri.match(/^https?:\/\/(127\.0\.0\.1|localhost)|^file:\/\//);
}
function initialize() {
// check version info for showing welcome/update views
var version = window.localStorage["ripple-version"],
xhr = new window.XMLHttpRequest(),
userAgent,
requestUri = chrome.extension.getURL("manifest.json");
_self.bindContextMenu();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
var manifest = JSON.parse(xhr.responseText),
currentVersion = manifest.version;
if (!version) {
_wasJustInstalled = true;
}
if (version !== currentVersion) {
webkitNotifications.createHTMLNotification('/views/update.html').show();
}
window.localStorage["ripple-version"] = currentVersion;
}
};
xhr.open("GET", requestUri, true);
xhr.send();
chrome.extension.onRequest.addListener(function (request, sender, sendResponse) {
switch (request.action) {
case "isEnabled":
console.log("isEnabled? ==> " + request.tabURL);
sendResponse({"enabled": tinyHippos.Background.isEnabled(request.tabURL)});
break;
case "enable":
console.log("enabling ==> " + request.tabURL);
tinyHippos.Background.enable();
sendResponse();
break;
case "version":
sendResponse({"version": version});
break;
case "xhr":
var xhr = new XMLHttpRequest(),
postData = new FormData(),
data = JSON.parse(request.data);
console.log("xhr ==> " + data.url);
$.ajax({
type: data.method,
url: data.url,
async: true,
data: data.data,
success: function (data, status) {
sendResponse({
code: 200,
data: data
});
},
error: function (xhr, status, errorMessage) {
sendResponse({
code: xhr.status,
data: status
});
}
});
break;
case "userAgent":
case "lag":
case "network":
// methods to be implemented at a later date
break;
default:
throw {name: "MethodNotImplemented", message: "Requested action is not supported!"};
break;
};
});
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (tinyHippos.Background.isEnabled(tab.url)) {
chrome.tabs.executeScript(tabId, {
code: "rippleExtensionId = '" + chrome.extension.getURL('') + "';",
allFrames: false
}, function () {
chrome.tabs.executeScript(tabId, {
file: "bootstrap.js",
allFrames: false
});
});
}
});
}
function _getEnabledURIs() {
var parsed = localStorage["tinyhippos-enabled-uri"];
return parsed ? JSON.parse(parsed) : {};
}
function _persistEnabled(url) {
var jsonObject = _getEnabledURIs();
jsonObject[url.replace(/.[^\/]*$/, "")] = "widget";
localStorage["tinyhippos-enabled-uri"] = JSON.stringify(jsonObject);
}
_self = {
metaData: function () {
return {
justInstalled: _wasJustInstalled,
version: window.localStorage["ripple-version"]
};
},
bindContextMenu: function () {
var id = chrome.contextMenus.create({
"type": "normal",
"title": "Emulator"
});
// TODO: hack for now (since opened tab is assumed to be page context was called from
// eventually will be able to pass in data.pageUrl to enable/disable when persistence refactor is done
chrome.contextMenus.create({
"type": "normal",
"title": "Enable",
"contexts": ["page"],
"parentId": id,
"onclick": function (data) {
_self.enable();
}
});
chrome.contextMenus.create({
"type": "normal",
"title": "Disable",
"contexts": ["page"],
"parentId": id,
"onclick": function (data) {
_self.disable();
}
});
},
enable: function () {
chrome.tabs.getSelected(null, function (tab) {
console.log("enable ==> " + tab.url);
_persistEnabled(tab.url);
chrome.tabs.sendRequest(tab.id, {"action": "enable", "mode": "widget", "tabURL": tab.url });
});
},
disable: function () {
chrome.tabs.getSelected(null, function (tab) {
console.log("disable ==> " + tab.url);
var jsonObject = _getEnabledURIs(),
url = tab.url;
while (url && url.length > 0) {
url = url.replace(/.[^\/]*$/, "");
if (jsonObject[url]) {
delete jsonObject[url];
break;
}
}
localStorage["tinyhippos-enabled-uri"] = JSON.stringify(jsonObject);
chrome.tabs.sendRequest(tab.id, {"action": "disable", "tabURL": tab.url });
});
},
isEnabled: function (url, enabledURIs) {
if (url.match(/enableripple=/i)) {
_persistEnabled(url);
return true;
}
// HACK: I'm sure there's a WAY better way to do this regex
if ((url.match(/^file:\/\/\//) && url.match(/\/+$/)) || url.match(/(.*?)\. (jpg|jpeg|png|gif|css|js)$/)) {
return false;
}
enabledURIs = enabledURIs || _getEnabledURIs();
if (url.length === 0) {
return false;
}
else if (enabledURIs[url]) {
return true;
}
return tinyHippos.Background.isEnabled(url.replace(/.[^\/]*$/, ""), enabledURIs);
}
};
initialize();
return _self;
}());
Full manifest.json:
{
"version": "1",
"manifest_version": 2,
"name": "Ripple Emulator (Beta)",
"background": {
"page": "views/background.html"
},
"web_accessible_resources": [],
"icons":{
"16":"images/Icon_16x16.png",
"128":"images/Icon_128x128.png",
"48":"images/Icon_48x48.png"
},
"browser_action":{
"default_popup":"views/popup.html",
"default_icon":"images/Icon_48x48.png",
"default_title":"Ripple"
},
"content_scripts":[{
"run_at": "document_start",
"js": ["controllers/Insertion.js"],
"matches": ["http://*/*","https://*/*","file://*"]
},
{
"run_at": "document_start",
"js": ["controllers/frame.js"],
"matches": ["http://*/*","https://*/*","file://*"],
"all_frames": true
}],
"permissions": ["tabs", "unlimitedStorage", "notifications", "contextMenus", "webRequest", "<all_urls>"],
"description": "A browser based html5 mobile application development and testing tool"
}
"Check" runtime.lastError by "reading" it in the callback.
Code
chrome.tabs.executeScript(tabId, {
//..
}, _=>chrome.runtime.lastError /* "check" error */)
Eg
Show it via..
chrome.tabs.executeScript(tabId, {
//..
}, _=>{
let e = chrome.runtime.lastError;
if(e !== undefined){
console.log(tabId, _, e);
}
});
Both of these errors explain the problem well:
"webkitNotifications is not defined" - this is because webkitNotifications has been removed. I found Chrome webkitNotification not found : api missing which explains what is going on.
"Cannot access a chrome:// URL" - you must be trying to execute the script on a chrome:// URL (like chrome://settings, chrome://extensions) which is illegal. To avoid the error printing like that, you can either
- check chrome.runtime.lastError
- make sure not to inject onto chrome:// pages.
Related
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.
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 have an extension that declaratively specifies using a content_script:
manifest.json:
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_end"
}
],
I'm reading that by instead specifying the activeTab permission, it won't alert about permissions during installation:
https://developer.chrome.com/extensions/activeTab
My question is: how can you switch to using
"permissions":["activeTab"]
from using content_scripts?
Here's my popup.js code that calls the content_script:
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
chrome.tabs.sendMessage(tabs[0].id, { action: "checkForCode" }, function (response) {
if (!!response) { showResults(response.results); }
});
});
and the content_script's event handler:
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
if (request.action == "checkForCode") {
getCode(request, sender, sendResponse);//method sends callback.
return true;
}
});
This code works just fine, but I'm wondering how to use it with the activeTab permissions. Should I just add the content.js via chrome.tags.executeScript(), then reference it the same way?
In your manifest.json you need to set
"permissions": ["activeTab", "tabs"],
and
"background": {
"scripts": ["content.js"],
"persistent": false
},
your content.js as example:
// metaCode will be injected and executed in the current tab
// the returned results you can use in callbackFunction
var metaCode = 'var descr = document.querySelector("meta[name=\'description\']");'
+ 'var keyw = document.querySelector("meta[name=\'keywords\']");'
+ 'if (descr) var descr = descr.getAttribute("content");'
+ 'if (keyw) var keyw = keyw.getAttribute("content");'
+ '({'
+ ' description: descr || "",'
+ ' keywords: keyw || "",'
+ '})';
chrome.tabs.executeScript(
tab.id,
{code: metaCode}, // get meta key words
callbackFunktion
);
function callbackFunktion(results) {
var result = results[0];
var description = result.description;
var keywords = result.keywords;
// and so on ... whatever you want
// to do with results from the
// injected script from 'metaCode'
}
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()