New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A way to generate and download CSV files client-side #175

Closed
mholt opened this Issue Feb 23, 2015 · 39 comments

Comments

Projects
None yet
@mholt
Owner

mholt commented Feb 23, 2015

There seems to be a lot of confusion about how to properly generate a file client-side and have it downloaded in modern browsers. I know how to do it (it's not hard, but it uses a modern web API) and it could potentially be a valuable addition to the library.

Something like:

Papa.download(Papa.parse(csv), "data.json");   // download JSON file
Papa.download(Papa.unparse(data), "data.csv"); // download CSV file

Might take no more than about 20-30 lines of code. Should I do it?

@bluej100

This comment has been minimized.

Show comment
Hide comment
@bluej100

bluej100 Feb 23, 2015

Contributor

My impression is that it's currently not possible in Safari: see eligrey/FileSaver.js#12 . I think it's an awesome feature, though, and would support including it with that caveat noted.

Contributor

bluej100 commented Feb 23, 2015

My impression is that it's currently not possible in Safari: see eligrey/FileSaver.js#12 . I think it's an awesome feature, though, and would support including it with that caveat noted.

@mholt

This comment has been minimized.

Show comment
Hide comment
@mholt

mholt Feb 23, 2015

Owner

This seems to work in all modern browsers:

var blob = new Blob([csvString]);
if (window.navigator.msSaveOrOpenBlob)  // IE hack; see http://msdn.microsoft.com/en-us/library/ie/hh779016.aspx
    window.navigator.msSaveBlob(blob, "filename.csv");
else
{
    var a = window.document.createElement("a");
    a.href = window.URL.createObjectURL(blob, {type: "text/plain"});
    a.download = "filename.csv";
    document.body.appendChild(a);
    a.click();  // IE: "Access is denied"; see: https://connect.microsoft.com/IE/feedback/details/797361/ie-10-treats-blob-url-as-cross-origin-and-denies-access
    document.body.removeChild(a);
}

I used this for a project at my last work. If there's no objection, I'll be happy to build it into 4.2 or something.

Owner

mholt commented Feb 23, 2015

This seems to work in all modern browsers:

var blob = new Blob([csvString]);
if (window.navigator.msSaveOrOpenBlob)  // IE hack; see http://msdn.microsoft.com/en-us/library/ie/hh779016.aspx
    window.navigator.msSaveBlob(blob, "filename.csv");
else
{
    var a = window.document.createElement("a");
    a.href = window.URL.createObjectURL(blob, {type: "text/plain"});
    a.download = "filename.csv";
    document.body.appendChild(a);
    a.click();  // IE: "Access is denied"; see: https://connect.microsoft.com/IE/feedback/details/797361/ie-10-treats-blob-url-as-cross-origin-and-denies-access
    document.body.removeChild(a);
}

I used this for a project at my last work. If there's no objection, I'll be happy to build it into 4.2 or something.

@bluej100

This comment has been minimized.

Show comment
Hide comment
@bluej100

bluej100 Feb 23, 2015

Contributor

Very cool.

Contributor

bluej100 commented Feb 23, 2015

Very cool.

@Gribbs

This comment has been minimized.

Show comment
Hide comment
@Gribbs

Gribbs May 13, 2015

Yes please! Awesome library. But yeah, really hard to find any clear documentation on how to get the Papa.unparse(data) into a csv file

Gribbs commented May 13, 2015

Yes please! Awesome library. But yeah, really hard to find any clear documentation on how to get the Papa.unparse(data) into a csv file

@JedWatson

This comment has been minimized.

Show comment
Hide comment
@JedWatson

JedWatson Oct 27, 2015

Looks like this didn't go anywhere, but it would be awesome if it did land in a new version. I'll use your snippet in the meantime, @mholt - thanks!

Looks like this didn't go anywhere, but it would be awesome if it did land in a new version. I'll use your snippet in the meantime, @mholt - thanks!

@mholt

This comment has been minimized.

Show comment
Hide comment
@mholt

mholt Oct 27, 2015

Owner

I haven't abandoned this -- still on my list for the next version, along with a million other little fixes. Just been busy with another project the last few months. Gotta encrypt the Web!!

Owner

mholt commented Oct 27, 2015

I haven't abandoned this -- still on my list for the next version, along with a million other little fixes. Just been busy with another project the last few months. Gotta encrypt the Web!!

@JedWatson

This comment has been minimized.

Show comment
Hide comment
@JedWatson

JedWatson Oct 27, 2015

Awesome, thanks for the update and totally understand!

Awesome, thanks for the update and totally understand!

@jhawthor

This comment has been minimized.

Show comment
Hide comment
@jhawthor

jhawthor Dec 5, 2015

Here is what I changed to based on the Google Article here: https://developers.google.com/web/updates/2012/06/Don-t-Build-Blobs-Construct-Them?hl=en
Note that I do not need to append and remove the link from the body.

var csvData = new Blob([str], {type: 'text/csv;charset=utf-8;'});
var csvURL = window.URL.createObjectURL(csvData);
var tempLink = document.createElement('a');
tempLink.href = csvURL;
tempLink.setAttribute('download', 'ActiveEvent_data.csv');
tempLink.click();

jhawthor commented Dec 5, 2015

Here is what I changed to based on the Google Article here: https://developers.google.com/web/updates/2012/06/Don-t-Build-Blobs-Construct-Them?hl=en
Note that I do not need to append and remove the link from the body.

var csvData = new Blob([str], {type: 'text/csv;charset=utf-8;'});
var csvURL = window.URL.createObjectURL(csvData);
var tempLink = document.createElement('a');
tempLink.href = csvURL;
tempLink.setAttribute('download', 'ActiveEvent_data.csv');
tempLink.click();
@mholt

This comment has been minimized.

Show comment
Hide comment
@mholt

mholt Dec 5, 2015

Owner

Oooo, that's nice. Thanks! Will need to check browser compatibility, but I like that better.

Owner

mholt commented Dec 5, 2015

Oooo, that's nice. Thanks! Will need to check browser compatibility, but I like that better.

@jhawthor

This comment has been minimized.

Show comment
Hide comment
@jhawthor

jhawthor Dec 15, 2015

Update: Fix for IE11

var csvData = new Blob([str], {type: 'text/csv;charset=utf-8;'});
var csvURL =  null;
if (navigator.msSaveBlob) {
    csvURL = navigator.msSaveBlob(csvData, 'download.cv');
} else {
    csvURL = window.URL.createObjectURL(csvData);
}
var tempLink = document.createElement('a');
tempLink.href = csvURL;
tempLink.setAttribute('download', 'download.cv');
tempLink.click();

Update: Fix for IE11

var csvData = new Blob([str], {type: 'text/csv;charset=utf-8;'});
var csvURL =  null;
if (navigator.msSaveBlob) {
    csvURL = navigator.msSaveBlob(csvData, 'download.cv');
} else {
    csvURL = window.URL.createObjectURL(csvData);
}
var tempLink = document.createElement('a');
tempLink.href = csvURL;
tempLink.setAttribute('download', 'download.cv');
tempLink.click();
@AkshayHarshe

This comment has been minimized.

Show comment
Hide comment
@AkshayHarshe

AkshayHarshe Jan 26, 2016

This is a great discussion!! This helped me a lot.. Thanks everyone who contributed to this thread.

This is a great discussion!! This helped me a lot.. Thanks everyone who contributed to this thread.

@lneffa

This comment has been minimized.

Show comment
Hide comment
@lneffa

lneffa Jan 27, 2016

👍 yes this would be a helpful add to the api, considering the newer HTML 5 file api

lneffa commented Jan 27, 2016

👍 yes this would be a helpful add to the api, considering the newer HTML 5 file api

@hamidzokaee

This comment has been minimized.

Show comment
Hide comment
@hamidzokaee

hamidzokaee Feb 8, 2016

Thank you for your efforts. Please publish version 4.2 as soon as possible.

Thank you for your efforts. Please publish version 4.2 as soon as possible.

@mholt

This comment has been minimized.

Show comment
Hide comment
@mholt

mholt Feb 8, 2016

Owner

I want to, but right now this project is being squeezed out by another project of mine that has funding. (Gotta pay the bills, you know.) If somebody is willing to fund the development of this project then I will be able to afford to put time into it sooner!

Owner

mholt commented Feb 8, 2016

I want to, but right now this project is being squeezed out by another project of mine that has funding. (Gotta pay the bills, you know.) If somebody is willing to fund the development of this project then I will be able to afford to put time into it sooner!

@hamidzokaee

This comment has been minimized.

Show comment
Hide comment
@hamidzokaee

hamidzokaee Feb 8, 2016

hi
I can not help you. I love your work. Thank

On Mon, Feb 8, 2016 at 11:27 PM, Matt Holt notifications@github.com wrote:

I want to, but right now this project is being squeezed out by another
project of mine that has funding. (Gotta pay the bills, you know.) If
somebody is willing to fund the development of this project then I will be
able to afford to put time into it sooner!


Reply to this email directly or view it on GitHub
#175 (comment).

hi
I can not help you. I love your work. Thank

On Mon, Feb 8, 2016 at 11:27 PM, Matt Holt notifications@github.com wrote:

I want to, but right now this project is being squeezed out by another
project of mine that has funding. (Gotta pay the bills, you know.) If
somebody is willing to fund the development of this project then I will be
able to afford to put time into it sooner!


Reply to this email directly or view it on GitHub
#175 (comment).

@mholt

This comment has been minimized.

Show comment
Hide comment
@mholt

mholt Feb 8, 2016

Owner

That's alright, thank you! I'll try to seek funding for this before the end...

Owner

mholt commented Feb 8, 2016

That's alright, thank you! I'll try to seek funding for this before the end...

@jessewmc

This comment has been minimized.

Show comment
Hide comment
@jessewmc

jessewmc Mar 3, 2016

Unfortunately, none of these solutions work in Safari 9.0.3 for the same reasons @bluej100 posted above. I just tested them all, and they all still open raw text in a new browser tab and do not download.

jessewmc commented Mar 3, 2016

Unfortunately, none of these solutions work in Safari 9.0.3 for the same reasons @bluej100 posted above. I just tested them all, and they all still open raw text in a new browser tab and do not download.

@SergMuller

This comment has been minimized.

Show comment
Hide comment
@SergMuller

SergMuller Mar 9, 2016

jesse, it may work if you change "text/csv" to "attachment/csv", but the file name would be just some default one.

jesse, it may work if you change "text/csv" to "attachment/csv", but the file name would be just some default one.

@Ginolan

This comment has been minimized.

Show comment
Hide comment
@Ginolan

Ginolan Mar 17, 2016

If you use dispatchEvent of a new MouseEvent click, instead .click(), it will work also on Internet Explorer and Edge(so you can accomunate code, without use mssaveblob). The only browser i have problem to get working is Safati. I don't have any idea about the way to make it work there.

Ginolan commented Mar 17, 2016

If you use dispatchEvent of a new MouseEvent click, instead .click(), it will work also on Internet Explorer and Edge(so you can accomunate code, without use mssaveblob). The only browser i have problem to get working is Safati. I don't have any idea about the way to make it work there.

@Am1rr3zA

This comment has been minimized.

Show comment
Hide comment
@Am1rr3zA

Am1rr3zA Mar 18, 2016

I am having the same issue with type = 'application/vnd.ms-excel'; I am on safari 9.0.3 and your solution doesn't work.

I am having the same issue with type = 'application/vnd.ms-excel'; I am on safari 9.0.3 and your solution doesn't work.

@keemor

This comment has been minimized.

Show comment
Hide comment
@keemor

keemor Mar 25, 2016

For modern browsers solution goes like this, tested: IE11, FF & Chrome

var csvData = new Blob([arg.data], {type: 'text/csv;charset=utf-8;'});
//IE11 & Edge
if (navigator.msSaveBlob) {
    navigator.msSaveBlob(csvData, exportFilename);
} else {
    //In FF link must be added to DOM to be clicked
    var link = document.createElement('a');
    link.href = window.URL.createObjectURL(csvData);
    link.setAttribute('download', exportFilename);
    document.body.appendChild(link);    
    link.click();
    document.body.removeChild(link);    
}

keemor commented Mar 25, 2016

For modern browsers solution goes like this, tested: IE11, FF & Chrome

var csvData = new Blob([arg.data], {type: 'text/csv;charset=utf-8;'});
//IE11 & Edge
if (navigator.msSaveBlob) {
    navigator.msSaveBlob(csvData, exportFilename);
} else {
    //In FF link must be added to DOM to be clicked
    var link = document.createElement('a');
    link.href = window.URL.createObjectURL(csvData);
    link.setAttribute('download', exportFilename);
    document.body.appendChild(link);    
    link.click();
    document.body.removeChild(link);    
}
@orenmagen100

This comment has been minimized.

Show comment
Hide comment
@orenmagen100

orenmagen100 May 10, 2016

any news about safari? not found a valid solution for safari...

any news about safari? not found a valid solution for safari...

@export-mike

This comment has been minimized.

Show comment
Hide comment
@export-mike

export-mike May 23, 2016

@keemor so does this need to be appended to the document.body for support reasons?

@keemor so does this need to be appended to the document.body for support reasons?

@mockpit

This comment has been minimized.

Show comment
Hide comment
@mockpit

mockpit Jun 13, 2016

Has anybody found a way to handle this in Safari?

mockpit commented Jun 13, 2016

Has anybody found a way to handle this in Safari?

@SergMuller

This comment has been minimized.

Show comment
Hide comment
@SergMuller

SergMuller Jun 13, 2016

My data was generated as a JSON and fetched by AJAX to a front-end app. Then it had options of dispaying as a table and downloading a file.The original all-JS solution had to be dropped because it didn't show consistent results across browsers (what my customers insisted on).
I ended up using a sub-form that will drop that content to a tiny PHP script, that will just stick a proper header and return right back. I didn't want to over-complicate API to adopt a set of methods for returning CSV.

HTML

<form id="fileDownload" method="post" action="index.php?p=reportsGenerateFile">
<input type="hidden" name="filename" value="default.csv">
<input type="hidden" name="data_csv" value="">
</form>

JS

$('#fileDownload input[name="filename"]').val(filename);
$('#fileDownload input[name="data_csv"]').val(encodeURI(csvContent.join('\n')));
$('#fileDownload').submit();
$('#fileDownload input[name="filename"]').val('default.csv');
$('#fileDownload input[name="data_csv"]').val('');

PHP

if (array_key_exists('filename', $_POST)) $filename = $_POST['filename'];
else $filename = 'default.csv';

if (array_key_exists('data_csv', $_POST)) $filecontent = urldecode($_POST['data_csv']);
else $filecontent = '';

header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$filename\"");
echo $filecontent;

SergMuller commented Jun 13, 2016

My data was generated as a JSON and fetched by AJAX to a front-end app. Then it had options of dispaying as a table and downloading a file.The original all-JS solution had to be dropped because it didn't show consistent results across browsers (what my customers insisted on).
I ended up using a sub-form that will drop that content to a tiny PHP script, that will just stick a proper header and return right back. I didn't want to over-complicate API to adopt a set of methods for returning CSV.

HTML

<form id="fileDownload" method="post" action="index.php?p=reportsGenerateFile">
<input type="hidden" name="filename" value="default.csv">
<input type="hidden" name="data_csv" value="">
</form>

JS

$('#fileDownload input[name="filename"]').val(filename);
$('#fileDownload input[name="data_csv"]').val(encodeURI(csvContent.join('\n')));
$('#fileDownload').submit();
$('#fileDownload input[name="filename"]').val('default.csv');
$('#fileDownload input[name="data_csv"]').val('');

PHP

if (array_key_exists('filename', $_POST)) $filename = $_POST['filename'];
else $filename = 'default.csv';

if (array_key_exists('data_csv', $_POST)) $filecontent = urldecode($_POST['data_csv']);
else $filecontent = '';

header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$filename\"");
echo $filecontent;
@orenmagen100

This comment has been minimized.

Show comment
Hide comment
@orenmagen100

orenmagen100 Jul 18, 2016

@dannynoeloconnor
managed to get it work in Safari 9 for a month (I'm using angular but it can work without) with:

this.$window.open('URL_TO_SERVER_ENDPOINT_?$FILENAME_PARAM', '_self');

but I think the last safari update ruined it. Doesn't work again.

@dannynoeloconnor
managed to get it work in Safari 9 for a month (I'm using angular but it can work without) with:

this.$window.open('URL_TO_SERVER_ENDPOINT_?$FILENAME_PARAM', '_self');

but I think the last safari update ruined it. Doesn't work again.

@raza2022

This comment has been minimized.

Show comment
Hide comment
@raza2022

raza2022 Aug 2, 2016

@mholt Any update on that ?

raza2022 commented Aug 2, 2016

@mholt Any update on that ?

@mholt

This comment has been minimized.

Show comment
Hide comment
@mholt

mholt Aug 2, 2016

Owner

Nope, sorry :-/ I haven't worked on this project in a while, been very busy with other things.

Owner

mholt commented Aug 2, 2016

Nope, sorry :-/ I haven't worked on this project in a while, been very busy with other things.

@raza2022

This comment has been minimized.

Show comment
Hide comment
@raza2022

raza2022 Aug 3, 2016

@mholt can i submit PR, code checked with E11, FF Chrome & Safari 9

raza2022 commented Aug 3, 2016

@mholt can i submit PR, code checked with E11, FF Chrome & Safari 9

@mholt

This comment has been minimized.

Show comment
Hide comment
@mholt

mholt Aug 3, 2016

Owner

Sure, I have time for a quick look at a PR.

Owner

mholt commented Aug 3, 2016

Sure, I have time for a quick look at a PR.

@whoisglover

This comment has been minimized.

Show comment
Hide comment
@whoisglover

whoisglover Aug 10, 2016

@raza2022 any luck with pull request? Banging my head against same issue with Safari 9

@raza2022 any luck with pull request? Banging my head against same issue with Safari 9

@Philip-Nunoo

This comment has been minimized.

Show comment
Hide comment
@Philip-Nunoo

Philip-Nunoo Aug 31, 2016

_downloadCSV: function(csv) {
var blob = new Blob([csv]);
var a = window.document.createElement("a");
a.href = window.URL.createObjectURL(blob, {type: "text/plain"});
a.download = "contacts.csv";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}

_downloadCSV: function(csv) {
var blob = new Blob([csv]);
var a = window.document.createElement("a");
a.href = window.URL.createObjectURL(blob, {type: "text/plain"});
a.download = "contacts.csv";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}

@datafunk

This comment has been minimized.

Show comment
Hide comment
@datafunk

datafunk Sep 29, 2016

In case it's any help, check this out: http://stackoverflow.com/questions/16376161/javascript-set-file-in-download which evolved into https://github.com/rndme/download/

Doesn't seem to work in Safari (Safari's fault I think), but I used it in my project with the proviso of limited browser support (it's a utility for a small group with specific needs).

In case it's any help, check this out: http://stackoverflow.com/questions/16376161/javascript-set-file-in-download which evolved into https://github.com/rndme/download/

Doesn't seem to work in Safari (Safari's fault I think), but I used it in my project with the proviso of limited browser support (it's a utility for a small group with specific needs).

@suhailtaj

This comment has been minimized.

Show comment
Hide comment
@suhailtaj

suhailtaj Oct 18, 2016

Works for Safari Version 10.0 or above, Google Chrome Version 54.0.2840.59 or above and Mozilla Firefox.

Used node-rest-client to overcome CORS and basic authentication on API server.

Created a Node Proxy and set headers as:

router.get("/downloadList/:Id/:fileName", function(req, res) {
    // Set hedders to CSV and giving file name
    res.setHeader('Content-disposition', 'attachment; filename=' + req.params.fileName + '.csv');
    res.set('Content-Type', 'text/csv');
    var url = 'https://' + host_name + '/v1/downloadCsv/' + req.params.Id;
    client.get(url, function(data) {
        dateReceived(data);
    });

    function dateReceived(data) {
        var outerData = data;
        res.send(outerData);
    }
});

From client side, request pointing to node JS route:

function downloadCSV(Id) {
 // Create file name and pass it to nodeJS
 var fileName = "yourFileName";
 var e = document.createElement('a');
 e.href = window.location.origin + "/api/v1/home/downloadList/" + Id + "/" + fileName;
 e.target = '_blank';
 document.body.appendChild(e);
 e.click();
 document.body.removeChild(e);
}

suhailtaj commented Oct 18, 2016

Works for Safari Version 10.0 or above, Google Chrome Version 54.0.2840.59 or above and Mozilla Firefox.

Used node-rest-client to overcome CORS and basic authentication on API server.

Created a Node Proxy and set headers as:

router.get("/downloadList/:Id/:fileName", function(req, res) {
    // Set hedders to CSV and giving file name
    res.setHeader('Content-disposition', 'attachment; filename=' + req.params.fileName + '.csv');
    res.set('Content-Type', 'text/csv');
    var url = 'https://' + host_name + '/v1/downloadCsv/' + req.params.Id;
    client.get(url, function(data) {
        dateReceived(data);
    });

    function dateReceived(data) {
        var outerData = data;
        res.send(outerData);
    }
});

From client side, request pointing to node JS route:

function downloadCSV(Id) {
 // Create file name and pass it to nodeJS
 var fileName = "yourFileName";
 var e = document.createElement('a');
 e.href = window.location.origin + "/api/v1/home/downloadList/" + Id + "/" + fileName;
 e.target = '_blank';
 document.body.appendChild(e);
 e.click();
 document.body.removeChild(e);
}
@elfenheart

This comment has been minimized.

Show comment
Hide comment
@elfenheart

elfenheart Nov 1, 2016

With the multiple solutions posted here, have anybody tried downloading a large file? There is an existing bug in V8 where Blob size is limited to 500mb.

ref: https://bugs.chromium.org/p/chromium/issues/detail?id=375297

elfenheart commented Nov 1, 2016

With the multiple solutions posted here, have anybody tried downloading a large file? There is an existing bug in V8 where Blob size is limited to 500mb.

ref: https://bugs.chromium.org/p/chromium/issues/detail?id=375297

@amruta1885

This comment has been minimized.

Show comment
Hide comment
@amruta1885

amruta1885 Jun 9, 2017

Hi All,

For me data is getting downloaded in CSV file, but my requirement is to add a border to the table. Only to the contents in the CSV file.

Can someone help me out here?

Thanks,
Amruta.

Hi All,

For me data is getting downloaded in CSV file, but my requirement is to add a border to the table. Only to the contents in the CSV file.

Can someone help me out here?

Thanks,
Amruta.

@pokoli

This comment has been minimized.

Show comment
Hide comment
@pokoli

pokoli Jun 9, 2017

Collaborator

@amruta1885 The CSV file does not contain any styles (only data), so you should generate an spreadsheet in order to add styles to the table. And this is out of the scope of PapaParse.

Collaborator

pokoli commented Jun 9, 2017

@amruta1885 The CSV file does not contain any styles (only data), so you should generate an spreadsheet in order to add styles to the table. And this is out of the scope of PapaParse.

@pokoli

This comment has been minimized.

Show comment
Hide comment
@pokoli

pokoli Sep 26, 2017

Collaborator

Indeed there are other libraries providing this functionality, so we should not reinvent the wheel. See #421 (comment) as and example.

Collaborator

pokoli commented Sep 26, 2017

Indeed there are other libraries providing this functionality, so we should not reinvent the wheel. See #421 (comment) as and example.

@pokoli pokoli closed this Sep 26, 2017

dirwin517 pushed a commit to dirwin517/ng-csv that referenced this issue Mar 26, 2018

@DenVdmj

This comment has been minimized.

Show comment
Hide comment
@DenVdmj

DenVdmj Jun 9, 2018

function openSaveFileDialog (data, filename, mimetype) {

  if (!data) return;

  var blob = data.constructor !== Blob
    ? new Blob([data], {type: mimetype || 'application/octet-stream'})
    : data ;

  if (navigator.msSaveBlob) {
    navigator.msSaveBlob(blob, filename);
    return;
  }

  var lnk = document.createElement('a'),
      url = window.URL,
      objectURL;

  if (mimetype) {
    lnk.type = mimetype;
  }

  lnk.download = filename || 'untitled';
  lnk.href = objectURL = url.createObjectURL(blob);
  lnk.dispatchEvent(new MouseEvent('click'));
  setTimeout(url.revokeObjectURL.bind(url, objectURL));

}

DenVdmj commented Jun 9, 2018

function openSaveFileDialog (data, filename, mimetype) {

  if (!data) return;

  var blob = data.constructor !== Blob
    ? new Blob([data], {type: mimetype || 'application/octet-stream'})
    : data ;

  if (navigator.msSaveBlob) {
    navigator.msSaveBlob(blob, filename);
    return;
  }

  var lnk = document.createElement('a'),
      url = window.URL,
      objectURL;

  if (mimetype) {
    lnk.type = mimetype;
  }

  lnk.download = filename || 'untitled';
  lnk.href = objectURL = url.createObjectURL(blob);
  lnk.dispatchEvent(new MouseEvent('click'));
  setTimeout(url.revokeObjectURL.bind(url, objectURL));

}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment