Get base64 in good old IE11 (Not using promises) - javascript

I have already implemented a method to get a base64 from a file using promises. Which runs fine in edge, chrome and firefox.
Problem is that I also have to make it work in internet explorer 11. Which does not like promises I found out. Problem is that IE11 is using ES5 and Promises came in ES6. (Please correct me if i'm wrong)
So I have 3 options as I see it.
Try to rewrite the code using callbacks so that IE11 knows the syntax.
Using babel (Which I haven't tried but read it was an option)
Using bluebirdjs (Which also I haven't tried but read it was an option)
Which is the best option for me?
Here are my code I need to change:
$('#fileselected').change(function (e) {
var fileList = document.getElementById('fileselected').files;
var file = fileList[0]; // User can only choose one file at a time
getBase64(file).then(
data => {
var fileObj = { name: file.name, base64: data };
postFilesToUpload.push(fileObj); // Collecting the files, if user wants to add multiple
}
);
$("#postfilesadded").append("<li><h5>" + file.name + "</h5></li>"); // Show the user which files he have selected to upload
});
This method is using another method which I need to change:
function getBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}

Related

How to create file in the local fs using modern FileApi?

I have this code:
document.querySelector('#myfile').onchange = function(e) {
var files = this.files;
window.requestFileSystem(window.TEMPORARY, 1024 * 1024, function(fs) {
let file = files[0];
let nem_file_name = file.name + '_copy';
fs.root.getFile(nem_file_name, {
create: true,
exclusive: true
}, function(fileEntry) {
fileEntry.createWriter(fileWriter => {
fileWriter.write(file);
}, () => alert('error 1'));
}, err => alert('error 2 ' + err));
}, () => alert('error 3'));
};
<input type="file" id="myfile" ref="myfile" multiple />
I want to create a copy of my file when I select it with the input control. What's wrong with my code? I got no errors and nothing happens
The "modern" API is called File System Access, it is still only a proposal, but is expected to supersede the previous and deprecated File System API, and is already available in Chromium browsers.
To write a file using this API, you first request a FileHandle using the showSaveFilePicker() method, then you can create a writer from that handle and append data using that writer:
onclick = async (e) => { // needs to be initiated by an user gesture
const handle = await showSaveFilePicker(); // prompt "Save As"
const writer = await handle.createWritable(); // request writable stream
await writer.write( new Blob( [ "some data" ] ) ); // write the Blob directly
writer.close(); // end writing
};
But this API is still overprotected, so it unfortunately can't be ran in cross-origin iframes like the ones used here by StackSnippet or most popular fiddling services. So in order to make a live demo, I had to make a plunker, that you must run in windowed mode.
And if you need to set the name of the file yourself, you need to request for a directory access using showDirectoryPicker() and then to get a FileHandle from that directory handle using its getFileHandle() method. plnkr
The documentation states that this method is non-standard, only in Chrome and already deprecated:
Even compared to the rest of the File and Directory Entries API,
requestFileSystem() is especially non-standard; only Chrome implements
it, and all other browser makers have decided that they will not
implement it. It has even been removed from the proposed
specification. Do not use this method!
You should not use this.

Stream File Download in Safari and Firefox

Currently, as a requirement, if a user wishes to download a large zip file, the download is a streamed.
This is done by fetching an endpoint, then using Streamsaver.js to stream the download to their browser as shown below.
function download(id, fileName) {
const endpoint = `.../extract/downloads/zip_download/?id=${id}`;
return fetch(endpoint, requestOptions.get()).then(res => {
const downloadSize = res.headers.get("content-length");
const fileStream = createWriteStream(fileName, { size: downloadSize });
const writer = fileStream.getWriter();
if (res.body.pipeTo) {
writer.releaseLock();
return res.body.pipeTo(fileStream);
}
const reader = res.body.getReader();
const pump = () =>
reader
.read()
.then(({ value, done }) =>
done ? writer.close() : writer.write(value).then(pump)
);
return pump();
});
}
This works fine in Chrome, however I'm running into issues with Firefox and Safari. The issue I get is:
TypeError: undefined is not a constructor (evaluating 'new streamSaver.WritableStream')
What other methods are there of approaching this? Surely there must be a universal way to stream a download of a large that I'm missing?
I ran into the same issue and included the web-streams-polyfill package in my project to fix it. Currently, some non-chromium browsers appear to not support WritableStream.
For myself, I simply included this script tag in my index.html
<script src="https://unpkg.com/web-streams-polyfill/dist/polyfill.min.js"></script>

How to read file in Java Script line by line from hardcoded path and name of the file?

I would like to read file in Java Script.
The best it would be to read line by line, but there is also possibility to read the whole file at once.
Generally on the web there is quite a lot of implementations, but I would like to read a file in very simple way by entering, hardcoded path and file name in the Java Script code, not but any buttons or something like this. The pseudo code below:
<!DOCTYPE html>
<html>
<body>
<script type="text/javascript">
var file = FileReader("home/test.txt");//hardcoded path and name of the file
var listOfLines = [];
var line = file.readLine();
while(line != eof) {
listOfLines.push(file.readLine());
file.readLine();
}
</script>
</body>
</html>
Is there such possibility to do something like this.
Thank you.
That would be a pretty big security hole, if your browser could simply read arbityry files from your filesystem. Think, every banner on the web could read configuation files of your OS, and stuff like that.
also check this question/answer: How to set a value to a file input in HTML?
slightly different question, same problem.
But if the client gives your app the file you should process, that's something different.
//use fetch() to get the file content
function fetchFile(file){
const {name, lastModified, size, type} = file;
return fetch(URL.createObjectURL(file))
.then(response => response.text())
.then(text => ({name, lastModified, size, type, text}));
}
//use a FileReader to get the content
function readFile(file){
const {name, lastModified, size, type} = file;
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsText(file);
})
.then(text => ({name, lastModified, size, type, text}));
}
let input = document.querySelector('input');
input.onchange = function(){
const promises = [...input.files].map(fetchFile); //fetch
//const promises = [...input.files].map(readFile); //FileReader
Promise.all(promises)
.then(files => {
console.log(files);
})
}
<input type="file" />
This is just a quick snippet. You'd have to check wether there are further security measures/obstacles due to the fact that a web page is accessing local files; but since this snippet is working, I'm confident that you're good.
FileReader is working well and it is well supported, see:
https://caniuse.com/#search=FileReader
even IE has a partial support.
But it can read ONLY file returned from the user. You cannot read any file with an hardcoded path from the developer. Of course that is for security reasons, the javascript engine in the browser runs in a sandbox.
PS
Also, to read big csv files from javascript, I suggest this library, that I used many times with success:
https://www.papaparse.com/
reference:
https://www.w3.org/TR/FileAPI/
https://www.w3.org/TR/FileAPI/#dfn-filereader
https://developer.mozilla.org/it/docs/Web/API/FileReader

WebShims is not working in IE9 for FileReader

From the WebShims documents here at http://afarkas.github.io/webshim/demos/demos/filereader.html it is giving me an example of using FileReader with WebShims. Following it I have this code now
<input class="ws-filereader" id="userFiles" multiple type="file"/>
//Added Mordenizr and JQuery and WebShims library
$.webshims.polyfill();
$(function()
{
$('#userFiles').on('change', function (evt)
{
var reader, file;
reader = new FileReader();
reader.onload = function (evt)
{
var fileData = evt.target.result;
};
file = $(this).prop('files')[0];
reader.readAsDataURL(file);
});
});
When I run this in IE9, It enters the code on change of userFiles but when I call to get
console.log($(this).prop('files').length);
It gives 0. What's wrong with it?
When I turn on
$.webshims.setOptions('debug', true);
console gives me
Unable to get value of the property 'input': object is null or undefined.
There is a similar issue posted on its quesions https://github.com/Jahdrien/FileReader/issues/46 and it says that WebShims support IE9 for FileReader
The problem is that the files API was not introduced in IE until IE10:
http://msdn.microsoft.com/en-us/library/ie/hh673542%28v=vs.85%29.aspx
This list of polyfills might be of use finding a workaround:
https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills#wiki-file-api

When using plupload HOWTO duplicate file object when selected & submit it separately for a related server-side processing

I am using plupload to let users upload images. But I also want to generate thumbnails for preview before they finally decide to keep it. I understand currently "Image preview" feature is not present in plupload. So to work around this I decided to submit a new form containing just one file for each image added, & let the server process it & return a thumbnail.
Now my question is how do I get the handle on the file object from the plupload so that I can create an "input" file field dynamically.
Currently I iterate over uploader.files & set input.name but I dont know how to set the input.value field, since I cant seem to get the complete file path of the file added.
I am up for any suggestions (in addition to replacing this approach completely), I just need thumbnail of the file selected for upload.
Maybe my answer is a bit late, but I searched today for a similar solution and came up with the following approach. It will only work with the HTML5 Runtime.
As there is no way to get the file objects from plupload, I changed the onchange event of the dynamically created input field and store the file objects for myself. This is done by binding to the PostInit-Event.
After that I can show the image to the user by using the FileReader API introduced with HTML 5. So there is no need to send the image to the server. See my FilesAdded Listener below.
// Currently added File Objects
var nativeFiles = {};
var uploader = new plupload.Uploader({
runtimes : 'html5,html4',
// Your settings...
});
uploader.bind('PostInit', function(up, params) {
// Initialize Preview.
if(uploader.runtime == "html5") {
var inputFile = document.getElementById(uploader.id + '_html5');
var oldFunction = inputFile.onchange;
inputFile.onchange = function() {
nativeFiles = this.files;
oldFunction.call(inputFile);
}
}
});
uploader.bind('FilesAdded', function(up, files) {
for (var i in files) {
// Your code...
// Load Preview
if(uploader.runtime == "html5") {
var fileObject = uploader.getFile(files[i].id);
var reader = new FileReader();
reader.onload = (function(file, id) {
return function(e) {
var span = document.getElementById('thumb_'+id);
span.innerHTML = "<img src='"+e.target.result+"'/>";
};
})(nativeFiles[i], files[i].id);
reader.readAsDataURL(nativeFiles[i]);
}
}
});

Categories