Last active
January 29, 2020 23:50
-
-
Save mjfusa/5d60f80e26717116df777d66a12528d8 to your computer and use it in GitHub Desktop.
EdgeHTML PWA Save to File
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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