I have an application where I want to save files of browser generated data to be saved on local disk. Sometimes i might want to edit this data before storing it, therefore i display it in a text-area on a popup window.
To store the data the same method is called, but when it is called from the popup it fails, while when called from the main browser window it saves the file successfully.
The method is the following
async function storeText(text = "...", win = null){
if (win == null)
win = window;
const options = {
types: [
{
description: 'Text files',
accept: {
'text/plain': ['.txt'],
},
},
],
suggestedName: "LoremIpsumFile.txt",
};
return win.showSaveFilePicker(options).then((fileHandle) =>{
console.log("got a file handle");
fileHandle.createWritable().then((writable) =>{
console.log("Got a writeable object");
console.log("Text is:\n "+ text);
writable.write(text).then(()=>{
console.log("Successfully written, now close");
writable.close();
}, (rejectWrite) => {
console.log("Could not write: " + rejectWrite);
});
}, (rejectWritable) =>{
console.log("Got no writable: " + rejectWritable);
});
}, (rejectHandle) =>{
console.log("Got no handle: " + rejectHandle);
});
}
If I call the function from a click-event on the main window, the String is correctly stored to file.
If the function is called from a button on the popup-window, the code executes until "got a file handle" but the returns leaving no trace of success or failure. A File with the given name and zero bytes size is then written to disk.
The full working example can be tested with this js Fiddle
Note 1: while the popup behaviour remains the same in the fiddle, the code for direct storage will not work, because of cross origin subframe
Note 2: The Window-Parameter must be passed to the function to make sure that the showSaveFilePicker() method is called on the same Window where the click event has happened. Otherwise - if simply window.showSaveFilePicker(options)
is called - a security error is thrown when invoked from the popup (Must be handling a user gesture to show a file picker)
My questions are:
Thanks to @Raymond Chen's comment, I figured out that what I wanted was impossible to achieve the way I wanted it. The possible solutions are:
div
on top of whatever is being displayed in the main window. With simple CSS z-index:100; position:absolute; left:0; top:0;
the div
is on top of the other content and should not interfere with the layout. The disadvantage of this option is that - unlike a popup-window - while it is visible you cannot look at the other content of the main window, sometimes this could be useful.Because of simplicity of the implementation, I chose the 2nd option. I might switch to the first one in future, if I see that the disadvantage it has becomes too annoying.