I'm trying to download multiple files in a Chrome extension. The following code creates a dummy link to a file, then triggers the .click() event which downloads the file. The problem is that only the first .click() event triggers a download. Subsequent .click() events are ignored.
Here the manifest.json:
{
"name": "Simple File Downloader",
"version": "0.1",
"permissions": ["contextMenus", "http://*/"],
"background": {
"persistent": false,
"scripts": ["sample.js"]
},
"content_security_policy": "script-src 'self'; object-src 'self'",
"manifest_version": 2
}
Here the sample.js:
function onClickHandler(info, tab) {
var a = document.createElement('a');
a.href = 'http://or.cdn.sstatic.net/chat/so.mp3';
a.download = 'so.mp3';
document.body.appendChild(a);
a.click(); // this click triggers the download
// this timeout violates content security policy
// setTimeout(a, 300);
a.click(); // this click doesn't do anything
document.body.removeChild(a);
a = document.createElement('a');
a.href = 'http://or.cdn.sstatic.net/chat/so.mp3';
a.download = 'so.mp3';
document.body.appendChild(a);
a.click(); // this click doesn't do anything either
document.body.removeChild(a);
};
chrome.contextMenus.onClicked.addListener(onClickHandler);
chrome.runtime.onInstalled.addListener(function() {
chrome.contextMenus.create({"title": "Download File", "id":"download_file"});
});
I've tried:
different approaches for downloading files as described in Chrome Extension write to file system using FileSaver.js, with the exact same result, first file is downloaded, second one is not
adding timeouts as described in Is it possible to make two .click method calls in javascript, resulting in content-security-policy violation, which I tried to work around using the approach described in Content-Security-Policy error in google chrome extension making, but without success
using the jQuery .live method as described in JQuery click event works only once, also without success, but I'm not 100% sure I implemented this one correctly (can post code later if people think this approach should solve it)
Surprised why it's so hard to simply save multiple files. Appreciate any help.
The trick is not to use the element.click
method but rather to create multiple MouseEvent
. For this to work, you'd need to create one MouseEvent
for each time you need a click.
function clicker(el, clickCount) {
var mousedownEvent;
while(clickCount--) {
mousedownEvent = document.createEvent("MouseEvent");
mousedownEvent.initMouseEvent("click", true, true, window, 0, null, null, null, null, false , false, false, false, 0, null);
el.dispatchEvent(mousedownEvent);
}
}
clicker(a, 3);
// your anchor 'a' gets clicked on 3 times.
When using this method in Chrome though, you get a warning from the browser asking "This site is attempting to download multiple files. Do you want to allow this? [Deny] [Allow]". So, if you do this inside an extension's background page, the background page receives the warning, the user can't see it, so the user has no way to click "Allow".
A (gross/nasty) workaround is to create a tab that "clicks" the anchor. Something like this:
function _anchorDownloader(url, filename) {
var timeout = 500;
return 'javascript:\'<!doctype html><html>'+
'<head></head>' +
'<script>' +
'function initDownload() {'+
'var el = document.getElementById("anchor");'+
'el.click();' +
'setTimeout(function() { window.close(); }, ' + timeout + ');' +
'}'+
'</script>' +
'<body onload="initDownload()">' +
'<a id="anchor" href="' + url + '" download="'+ filename + '"></a>'+
'</body>' +
'</html>\'';
};
function downloadResource(info, tab) {
// ...
chrome.tabs.create( { 'url' : _anchorDownloader( url, filename ), 'active' : false } );
// ...
}
chrome.contextMenus.create({"title": "Save Image…", "contexts":["image"], "onclick": downloadResource });
For this to work, the extension has to have "tabs"
as a permission
in the manifest.json. You can tweak the timeout to close the tab, however, if you close it too fast then no download will happen.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With