Skip to content

Instantly share code, notes, and snippets.

@mjfusa
Last active January 29, 2020 23:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mjfusa/5d60f80e26717116df777d66a12528d8 to your computer and use it in GitHub Desktop.
Save mjfusa/5d60f80e26717116df777d66a12528d8 to your computer and use it in GitHub Desktop.
EdgeHTML PWA Save to File
<script>
/**
In EdgeHTML / PWA downloading content by creating a download link on the fly and calling Click (traditional method) does not work.
TL;DR: See below for an implementation of the file download for EdgeHTML / PWA.
Longer explanation:
When running with the Spartan WebView as a HWA (Hosted Web App) or PWA MS Store, you’re running inside a UWP container with the associated security restriction. This has 2 implications:
• msSaveOrOpenBlob is not defined in this execution context for security reasons
• you can’t download directly a file on the file system using the a.download + a.click approach
You have to use the WinRT / UWP APIs to manipulate files: https://docs.microsoft.com/en-us/windows/uwp/files/quickstart-reading-and-writing-files
The solution is then to feature detect the execution context testing if window.Windows is defined and calling the appropriate UWP APIs.
To let the user writing to a specific place on the disk, you have to use the FileSavePicker API: https://docs.microsoft.com/en-us/windows/uwp/files/quickstart-save-a-file-with-a-picker
This has been implemented in the code below:
**/
async function SaveAs(blob, fileName) {
// Test if we're running ing the Spartan (Edge) UWP / PWA Context
if (window.Windows) {
var buff = await (new Response(blob)).arrayBuffer();
let view = new Uint8Array(buff);
// Create the picker object and set options
var savePicker = new Windows.Storage.Pickers.FileSavePicker();
savePicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.downloads;
// Dropdown of file types the user can save the file as
savePicker.fileTypeChoices.insert("PNG Image", [".png"]);
// Default file name if the user does not type one in or select a file to replace
savePicker.suggestedFileName = fileName;
savePicker.pickSaveFileAsync().then(function (file) {
if (file) {
// Prevent updates to the remote version of the file until we finish making changes and call CompleteUpdatesAsync.
Windows.Storage.CachedFileManager.deferUpdates(file);
// write to file
Windows.Storage.FileIO.writeBytesAsync(file, view).then(function () {
// Let Windows know that we're finished changing the file so the other app can update the remote version of the file.
// Completing updates may require Windows to ask for user input.
return Windows.Storage.CachedFileManager.completeUpdatesAsync(file);
}).done(function (updateStatus) {
if (updateStatus === Windows.Storage.Provider.FileUpdateStatus.complete) {
console.log("File " + file.name + " was saved.", "sample", "status");
} else {
console.log("File " + file.name + " couldn't be saved.", "sample", "status");
}
});
} else {
console.log("Operation cancelled.", "sample", "status");
}
});
} else {
saveBlob(blob, fileName);
}
}
function saveBlob (blob, fileName) {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
var url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
function dataURItoBlob(dataURI) {
var binary = atob(dataURI.split(',')[1]);
var array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {'type': 'image/png'});
}
function dl(imageSrc) {
var c = document.createElement('canvas');
var img = document.getElementById(imageSrc);
c.height = img.naturalHeight;
c.width = img.naturalWidth;
var ctx = c.getContext('2d');
ctx.drawImage(img, 0, 0, c.width, c.height);
var base64String = c.toDataURL();
var blobObject = dataURItoBlob(base64String);
SaveAs(blobObject, 'test.png');
}
</script>
<img id="myimage" width="200" width="200" src="a.png"/> <!-- You'll need to provide this on your server -->
<p></p>
<button type="button" onclick="dl('myimage')">Click</button>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment