admin管理员组

文章数量:1410705

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 = '.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 = '.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.

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/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/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.

Share Improve this question edited May 23, 2017 at 11:58 CommunityBot 11 silver badge asked Dec 25, 2012 at 19:54 toby88toby88 1152 silver badges5 bronze badges 5
  • 1 Wait a couple of months, and the chrome.downloads API is widely available. About the CSP error: a is a link, whose toString property returns the target of the link. So, if you use setTimeout(a, 300);, it attempts to evaluate the target of the link. String-as-code evaluation is forbidden by default, so you get the error. If you use setTimeout(function() {a.click();}, 300);, the file is still not getting downloaded, though. – Rob W Commented Dec 25, 2012 at 20:36
  • Did you find a temp solution to this problem? – coneybeare Commented Mar 11, 2013 at 4:13
  • I think it's no possible for security problem. If it would be possible, then virtually I could open infinite popup/download with a single click. – Luca Rainone Commented Mar 11, 2013 at 16:06
  • Since activity around this question has picked up again, here's what I ended up doing: I've followed Rob W's suggestion and am using the chrome.downloads.download(DownloadOptions options, function callback) method. It works perfectly. My Chrome extension is only for internal use, so everyone who uses it does so with Chrome Canary (google./intl/en/chrome/browser/canary.html). – toby88 Commented Mar 13, 2013 at 21:27
  • I am not working on an extension (just pasting snippets into Console), but I got it working using el.dispatchEvent(clickEvent) (see answer by zertosh), bined with setTimeout(function() { download_next() }, 500). 500 ms is reasonable; when using 100 ms or less, some files didn't download. – Tomasz Gandor Commented May 8, 2018 at 9:37
Add a ment  | 

2 Answers 2

Reset to default 5 +50

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.

Instead of using the .live() methode which is no longer remended try .on()

$(document).on("click", "a", function( event ){
    // do whatever
});

here is the documentation

本文标签: jqueryJavaScript click() method only works once in Chrome extensionStack Overflow