javascriptpromisenative-file-system-api-js

FileSystem API fails to write file when called from popup window


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:


Solution

  • 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:

    1. Instead of opening a popup window locally, open it with reference to a PHP-Page on a https-context and pass the data that is to be edited as POST or GET parameter.
    2. Instead of opening a popup, simply put a 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 divis 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.