I have made a programatically injected version of a Chrome extension in order to have the extension working on pages from hosts with different top-level domain names (cfr previous post). Now I would like to add a link to an options page to the popup menu. However I keep getting the following error message:
Unchecked runtime.lastError: Cannot access contents of url
"chrome-extension://••••••••••••••••/options.html".
Extension manifest must request permission to access this host.
Can anyone tell me how to request such a permission? In background.js, I have also tried chrome.tabs.create({url: "options.html"}); without success.
Note that the options page is displayed ok, but the error message keeps coming.
manifest.json:
{
"manifest_version": 2,
"name": "My Extension",
"version": "0.5",
"description": "Does what it does",
"icons": {"32": "icon32.png",
"48": "icon48.png",
"128": "icon128.png"
},
"options_page": "options.html",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"browser_action":{
"default_popup": "popup.html"
},
"optional_permissions":["tabs","https://*/*"],
"permissions": ["storage"]
}
popup.html:
<html>
<head>
</head>
<body>
<ul>
<li id="li_1">Enable My Extension</li>
<li id="li_2">Options</li>
</ul>
<script src="jQuery.js"></script>
<script src="popup.js"></script>
</body>
</html>
popup.js:
jQuery(function($){
var tabId = 0;
$(document).ready(function(){
$("#li_1").click(function(){ // this works
window.close();
chrome.permissions.request({
permissions: ['tabs'],
origins: ["https://*/*"]
}, function(granted) {
if (granted) {
chrome.runtime.sendMessage("granted");
} else {
alert("denied");
}
});
});
$("#li_2").click(function(){ // this sends request to background.js which then causes error
window.close();
chrome.runtime.sendMessage("openOptions");
});
});
});
background.js:
chrome.runtime.onMessage.addListener(
function(message) {
switch(message){
case "granted": //this works, please ignore
var tabId = 0;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
tabId = tabs[0].id;
injectScript(tabId);
chrome.permissions.contains({origins:["https://*/*"]}, function(perm) {
if (perm) {
chrome.tabs.onUpdated.addListener(function(tabId){
injectScript(tabId);
});
}
});
});
break;
case "openOptions": //this does not work – generates error msg
chrome.runtime.openOptionsPage();
break;
}
return true;
});
As suggested by wOxxOm in a comment above, the error was caused by he extension's attempt to inject the content script into the options.html page. One way to circumvent that would be to insert a condition into the injectScript() function (which was not shown in the question) in background.js, ensuring that only web pages are injected. A working version is shown below.
background.js
function injectScript(tab){
chrome.tabs.get(tab,function(thisTab){ // get tab info
if(thisTab.url.startsWith("http")){ // condition: is this a web page?
chrome.tabs.executeScript(tab,{ // if so, inject scripts
file: "jQuery.js"
});
chrome.tabs.executeScript(tab,{
file: "content.js"
});
}
});
}
chrome.runtime.onMessage.addListener(
function(message) {
switch(message){
case "granted":
var tabId = 0;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
tabId = tabs[0].id;
injectScript(tabId);
chrome.permissions.contains({origins:["https://*/*"]}, function(perm) {
if (perm) {
chrome.tabs.onUpdated.addListener(function(tabId){
injectScript(tabId);
});
}
});
});
break;
case "openOptions":
chrome.runtime.openOptionsPage();
break;
}
return true;
});
Related
I am trying to get some data from current tab to my extension. It's working fine if I change it to popup style but I am looking for the same functionality to open it in a new tab on extension click. Can anybody guide on this how I can achieve this? Thanks in advance
manifest.json.js
{
"manifest_version": 2,
"name": "Hello World",
"description": "A simple page-scraping extension for Chrome",
"version": "1.0",
"author": "#thomasforth",
"background": {
"scripts": ["popup.js"],
"persistent": true
},
"permissions": [
"tabs",
"http://*/",
"*://*/",
"activeTab"
],
"browser_action": {
"default_icon": "logo.png"
}
}
payload.js
// send the page title as a chrome message
chrome.runtime.sendMessage(document.title);
console.log(document.title)
popup.js
// Inject the payload.js script into the current tab after the popout has loaded
window.addEventListener('load', function (evt) {
chrome.extension.getBackgroundPage().chrome.tabs.executeScript(null, {
file: 'payload.js'
});;
});
// Listen to messages from the payload.js script and write to popout.html
chrome.browserAction.onClicked.addListener(function (tab) {
chrome.tabs.create({ url: "popup.html", selected: false })
chrome.runtime.onMessage.addListener(function (message) {
document.getElementById('pagetitle').innerHTML = message;
})
})
This the is error which I am getting
Use the id of the tab where onClicked was triggered and pass it to popup script using its URL:
chrome.browserAction.onClicked.addListener(function (tab) {
chrome.tabs.create({
url: `popup.html?tabId=` + tab.id,
selected: false,
});
});
// popup.js
const tabId = +new URLSearchParams(location.search).get('tabId');
chrome.tabs.executeScript(tabId, {
file: 'payload.js'
});
I'm working on Chrome extensions. I try to learn messaging between content and background. I develop simple project for this. But I have issue.
Basic idea is
User click button on extension popup
A function (bot.js) find image from content of tab then extension (background.js) will download it.
The issue is port.onMessage.addListener() in background.js fired twice.
When background.js sends message to contentscript.js there are two same messages in console or when I try to download in background.js (the code line "Do Something") it download the file twice.
How can I solve this problem?
popup.html
<!doctype html>
<html>
<head>
<title>Test Plugin</title>
<script src="background.js"></script>
<script src="popup.js"></script>
</head>
<body>
<h1>Test Plugin</h1>
<button id="btnStart">Button</button>
</body>
</html>
popup.js
document.addEventListener('DOMContentLoaded', function() {
var checkPageButton = document.getElementById('btnStart');
checkPageButton.addEventListener('click', function() {
GetImages("Some URL");
}, false);
}, false);
var tab_title = '';
function GetImages(pageURL){
// Tab match for pageURL and return index
chrome.tabs.query({}, function(tabs) {
var tab=null;
for(var i=0;i<tabs.length;i++){
if(tabs[i].url==undefined || tabs[i].url=="" || tabs[i]==null){}
else{
if(tabs[i].url.includes(pageURL)){
tab=tabs[i];
break;
}
}
}
if(tab!=null){
chrome.tabs.executeScript(tab.id, {
file: "bot.js"
}, function(results){
console.log(results);
});
}
});
}
bot.js
var thumbImagesCount = document.querySelectorAll('.classifiedDetailThumbList .thmbImg').length;
var megaImageURL=document.querySelectorAll('.mega-photo-img img')[0].src;
console.log(megaImageURL + " from bot.js");
port.postMessage({key:"download", text: megaImageURL});
background.js
chrome.runtime.onConnect.addListener(function (port) {
console.assert(port.name == "content-script");
port.onMessage.addListener(function(message) {
console.log(message);
if(message.key=="download"){
// Do Something
// Event fires twice
port.postMessage({key:"download", text: "OK"});
}
})
});
contentscript.js
console.log("content script loaded!");
var port = chrome.runtime.connect({name: "content-script"});
port.onMessage.addListener(function(message){
console.log(message);
});
manifest.json
{
"manifest_version": 2,
"name": "Test Extension",
"description": "This extension will download images from gallery",
"version": "1.0",
"icons": {
"16": "bot16.png",
"48": "bot48.png",
"128": "bot128.png" },
"browser_action": {
"default_icon": "bot48.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab",
"downloads",
"http://*/",
"https://*/"
],
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": ["contentscript.js"]
}
]
}
The background script declared in manifest.json already has its own page, a hidden background page where it runs, so you should not load it in the popup as it makes no sense in case there are listeners for API events, the background page is already listening for them. In this case the copy also creates the second listener while the popup is open.
Solution: don't load background.js in popup.
See also Accessing console and devtools of extension's background.js.
I'm working on a chrome extension currently, and I keep getting this error:
Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist
I'm trying to pass a message from my background script to my content script. The background script fetches the url of the current tab, and I'm trying to pass that URL to my content script. I've found a few different solutions to this error, but none of them are working for me. From what I understand, it has something to do with the content script not being loaded when the background script tries to send the message, though I've tried some workarounds for that and nothing has worked for me. This is my code:
Background script:
//use a query to get the current URL of the tab
chrome.tabs.query({
active: true,
lastFocusedWindow: true
}, function(tabs){
var currentTab = tabs[0];
var currentUrl = currentTab.url;
//send a message from background script to content script
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
const port = chrome.tabs.connect(tabs[0].id);
port.postMessage({url: currentUrl});
port.onMessage.addListener(function(response){
console.log(response);
});
});
}
);
Content Script:
chrome.runtime.onConnect.addListener(function(port){
port.onMessage.addListener(function(msg){
if(msg.url.includes("amazon")){
console.log("You are on amazon.com");
}
port.postMessage("This is my response!");
});
});
Here is my manifest as well:
{
"manifest_version": 2,
"name": "First Browser Extension",
"version": "1.0.0",
"description": "Add a better description later.",
"page_action": {
"default_icon": "icon.png",
"default_title": "BrowserExtension",
"default_popup": "index.html"
},
"background":{
"scripts": ["background.js"],
"persistent": false
},
"content_scripts":[
{
"matches": ["https://www.amazon.com/*"],
"js": ["content.js"]
}
],
"permissions": [
"tabs",
"activeTab",
"https://*/*"
],
"icons": {"48": "icon.png"}
}
I can't figure out what's going wrong. Any insight would be greatly appreciated!
Edit: updated code
Background
chrome.tabs.query({
active: true,
currentWindow: true //changed lastFocusedWindow to currentWindow
}, function(tabs){
var currentTab = tabs[0];
var currentUrl = currentTab.url;
console.log(currentUrl);
//----------NEW CODE---------------------------
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.contentScriptQuery === "getURL") {
sendResponse({url: currentUrl});
return true; // Will respond asynchronously.
}
});
}
);
Content
chrome.runtime.sendMessage(
{contentScriptQuery: "getURL"},
function(urlFromBackground){
console.log(urlFromBackground.url);
}
);
i am new to Javascript and am trying to implement a google chrome extension. I read the instructions (https://developer.chrome.com/extensions/getstarted), but still I have some troubles with my code.
I have got a popup menu with buttons and I want to get back the DOM content of the current page when a button is clicked.
Therefore i created a contentscript.js and a popup.js. The popup.js asks the contentscript to get the DOM (still needs to be implemented how I do that) and send back the DOM.
I receive the error:
Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.
This is my code:
popup.js
var ads = ["increase", "reduce", "blabla"];
function markAds(text) {
document.getElementById("markAd").innerHTML=ads[0];
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
alert(response.farewell);
});
});
}
document.addEventListener('DOMContentLoaded', function() {
var markAd = document.getElementById('markAd');
// onClick's logic below:
markAd.addEventListener('click', function() {
markAds();
});
});
mainfest.js
{
"name": "Test",
"description": "Test Description",
"version": "0.7",
"permissions": ["contextMenus","activeTab"],
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["contentscript.js"]
}],
"browser_action": {
"default_popup": "popup.html"
},
"manifest_version": 2
}
contentscript.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.greeting == "hello")
sendResponse({farewell: "goodbye"});
});
I've been trying for hours to get popup.js to talk with the rest of my chrome extension using chrome api's sendMessage and onMessage. For testing purposes, all I want right now is to log something onto my currently active tab when a button is pressed on popup.js. This seems like it should be simple, but I just can't figure out what the problem is. Would really appreciate any help and explanation!
popup.html
<!DOCTYPE html>
<body>
<p>testing</p>
<input type="submit" id="clickme" value="button">
</body>
popup.js
function popup(){
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var activeTab = tabs[0];
chrome.tabs.sendMessage(activeTab.id, {"message": "clicked_browser_action"});
}
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("clickme").addEventListener("click",popup)
});
content.js (I expect this to log 'started' onto console of my active tab)
// content.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if( request.message === "clicked_browser_action" ) {
console.log('started')
}
}
);
Just in case it applies, this is the manifest.json
{
"manifest_version":2,
"name": "extension",
"version": "0.1",
"content_scripts":[
{
"matches": [
"<all_urls>"
],
"js":["jquery-3.1.1.min.js","content.js"]
}],
"browser_action":{
"default_icon":"icon.png",
"default_popup":"popup.html"
},
"background":{
"scripts":["background.js"]
}
}