I have already searched and tried different acceptable answers from SO to this problem but none of them are working in my case. I'm pretty sure I'm not understanding something. I just started this chrome extension journey 24 hours ago so I admit I have so many things to learn.
Nevertheless, I'm trying to create a downloader for a specific website. I have three javascript files:
manifest.json
{
"name": "Dummy Extension",
"version": "1.0",
"manifest_version": 2,
"description": "This is a dummy extension.",
"browser_action": {
"default_title": "Download Images from Anywhere",
"default_popup": "popup.html"
},
"content_scripts" : [
{
"matches": ["https://dummywebsite.com/*"],
"js": ["script_injection.js"],
"css": ["style.css"]
}
],
"permissions": [
"storage",
"downloads",
"activeTab",
"declarativeContent"
],
"web_accessible_resources": ["injection_ui.js"],
"background" : {
"scripts" : ["jquery.js", "background.js"],
"persistent" : true
}
}
script_injection.js
var s = document.createElement('script');
s.src = chrome.runtime.getURL('background.js');
s.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(s);
injection_ui.js
$(document).ready(function(){
$(".image-thumbnail").each(function(){
var src = $(this).attr("src");
$(this).append("<a class='DummyAddedButton' download='"+ src +"'>Download</button>");
});
$(".DummyAddedButton").off().on("click", function(){
var source = $(this).attr("src");
chrome.runtime.sendMessage("mlbcmjpahokfgkghabmfjgmnafffphpd", source, function(){
console.log("sending success: " + source);
});
});
});
background.js
chrome.runtime.onMessage.addListener(
function(message, callback) {
chrome.downloads.download({url:message, filename:"image.jpg"});
});
When clicking a button, it displays a message on a console log as dictated by the sendMessage. However, it also displays an error: "Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist."
Disclaimer. If I use the same button on a popup.js, it downloads the image. But I want to bind the functionality on a button injected on the website, not via the extension panel.
Currently you're injecting code in page context which is both an unnecessary overcomplication and wrong as you inject the background script which already runs in the hidden separate background page of the extension that's not related to the web page. See how to open background.js devtools and console.
Remove script_injection.js, injection_ui.js and web_accessible_resources
section and unnecessary permissions from manifest.json as well as jquery.js.
Declare parameters of onMessage listener correctly per the documentation.
Use "persistent": false
, more info.
{
"name": "Dummy Extension",
"version": "1.0",
"manifest_version": 2,
"description": "This is a dummy extension.",
"browser_action": {
"default_title": "Download Images from Anywhere",
"default_popup": "popup.html"
},
"content_scripts": [{
"matches": ["https://dummywebsite.com/*"],
"js": ["content.js"],
"css": ["style.css"]
}],
"permissions": [
"storage",
"downloads"
],
"background": {
"scripts": ["background.js"],
"persistent": false
}
}
Let's use a standard name content.js with standard JS inside, no jquery. If you still want jquery, then declare it in manifest.json as "js": ["jquery.js", "content.js"]
content.js:
for (const thumb of document.querySelectorAll('.image-thumbnail')) {
thumb.appendChild(Object.assign(document.createElement('button'), {
className: 'DummyAddedButton',
textContent: 'Download',
}));
}
document.addEventListener('click', e => {
if (e.target.matches('.DummyAddedButton')) {
chrome.runtime.sendMessage(e.target.closest('.image-thumbnail').src);
}
});
background.js:
chrome.runtime.onMessage.addListener((message, sender, sendMessage) => {
chrome.downloads.download({url: message, filename: 'image.jpg'});
});
Don't forget to reload the extension on chrome://extensions
page and the web page tab after you edit manifest.json or the content scripts.