Bug exporting files via JavaScript?

So I have this piece of code here for my WebExtension to export some data using JavaScript in the options page.

function downloadTextFile(arr) {
var txt = "";
arr.forEach(function(row) {
    txt += row;
    txt += "\n";
});


var hiddenElement = document.createElement('a');
hiddenElement.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(txt);
hiddenElement.target = '_target';
hiddenElement.download = 'URLS.txt';
document.body.appendChild(hiddenElement);
hiddenElement.click();
document.body.removeChild(hiddenElement);
}  

The only problem is that in Firefox it just displays the text file without downloading it, while in Chrome, the text file actually downloads.

Because Firefox ask you if you want to open or download the file.
You can change your Firefox’s preferences.

Yes it asks you normally outside of WebExtensions. However, if that code is part of the settings menu in a WebExtension, then it just displays the output without asking to save or open. Here’s what I did to test:

manifest.json

{
“manifest_version”: 2,
“name”: “Test”,
“version”: “1.0”,

“description”: “Tests exporting a file.”,

“options_ui”: {
“page”: “test.html”,
“open_in_tab” : true
}
}

test.html

<!DOCTYPE html>
<html>
<head></head>
	<body>
		<button id="button1">Test</button>
		<script type="text/javascript" src="script.js"></script>
	</body>
</html>

script.js

function downloadTextFile(arr) {
	var txt = "";
	arr.forEach(function(row) {
		txt += row;
		txt += "\n";
	});


	var hiddenElement = document.createElement('a');
	hiddenElement.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(txt);
	hiddenElement.target = '_target';
	hiddenElement.download = 'URLS.txt';
	document.body.appendChild(hiddenElement);
	hiddenElement.click();
	document.body.removeChild(hiddenElement);
}
var array = ["test1", "test2","test3"];

document.getElementById("button1").addEventListener("click", function() {
	downloadTextFile(array);
});

You get different behaviors if you load test.html normally vs. loading the WebExtension temporarily and opening the preference page.

I never have been developed a Web Extensions, but I think you need permissions to “use” downloads resource.
Check this: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/downloads

  1. The target = '_target' seems strange. What are you trying to dowith that? (http://www.w3schools.com/TAgs/att_a_target.asp)
  2. Have you tried to use a Blob objectURL (with correct mime type) instead of the data: URL?

If that doesn’t help you could zip your text file. That way Firefox woun’t be able to open it inline and will offer to save it.

  1. That is a typo. It’s suppose to be target = '_blank', but it doesn’t matter though since Firefox displays the text file anyway in the same tab.

  2. Using something like FileSaver.js, the file could not download under WebExtensions, while normally it works.

I have a feeling that it might be a bug in the WebExtension sandbox since the protocol for the options menu is moz-extension://{extension ID here}/settings.html. I’ll try out the zip file later but my workaround so far is to create a link tag saying “Right click to save as”. It’s not ideal but at least it won’t be confusing to the user.

Calling this function directly from a click handler works for me:

/**
 * Invokes a save dialog for a Blob or an Url object or strings target.
 * @param  {Blob|Url|string}  content  The Blob or url to save.
 * @param  {string}           name     The suggested file name.
 */
function saveAs(content, name) {
	const isBlob = typeof content.type === 'string';

	const link = Object.assign(window.document.createElement('a'), {
		download: name,
		target: '_blank', // fallback
		href: isBlob ? window.URL.createObjectURL(content) : content,
	});
	clickElement.call(window, link);
	isBlob && global.setTimeout(function() { window.URL.revokeObjectURL(link.href); }, 1000);
};

function clickElement(element) {
	const evt = window.document.createEvent('MouseEvents');
	evt.initEvent('click', true, true);
	element.dispatchEvent(evt);
	return element;
}

I call it with saveAs(new Blob([ string, ], { type: 'application/json', }), 'data.json').

You can download a MPL licensed commonJS module containing this function from GitHub.

For me, it gets stuck loading and doesn’t display anything. Did you open the page directly or open the preference page from the test extension? It should have the prefix “moz-extension://” in the URL bar.

I’m using Firefox 51 and Chrome 55 on Windows 10.
It works from the inline "options_ui", a tab and in Chrome the browserAction panel.

Finally I replicate your code with the @NilkasG’s options and it doesn’t work, like you said “it gets stuck loading…” I don’t know, probably WebExtension has a bug

I am having the same issue: https://github.com/sniklaus/youtube-watchmarker/issues/1

In my case, I am using FileSaver.js (https://github.com/eligrey/FileSaver.js/) within a page that has been opened through a browser action.

I have actually noticed this behavior months ago when I developed this extension. It did however only happen on one of my machines and none of the others, which made it difficult to debug. Over time, more and more of my machines have been experiencing this behavior though.

Filed a bug:

https://bugzilla.mozilla.org/show_bug.cgi?id=1338981