Created
May 29, 2019 12:29
-
-
Save Alhadis/e58ed916df460fc213f54037dfbc75b1 to your computer and use it in GitHub Desktop.
select-file.js
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
<!DOCTYPE html> | |
<html lang="en-AU"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> | |
<meta name="viewport" content="initial-scale=1, minimum-scale=1" /> | |
<title>Cross-browser/Electron file selection</title> | |
</head> | |
<body> | |
<button value="1">Select one file, any type</button> | |
<button value="2">Select multiple files, any type</button> | |
<button value="3">Select one image</button> | |
<button value="4">Select multiple images</button> | |
<script src="select-file.js"></script> | |
<script> | |
"use strict"; | |
document.body.onclick = e => { | |
const fn = results => console.log(results); | |
switch(+e.target.value){ | |
case 1: selectFile(false).then(fn); break; | |
case 2: selectFile(true).then(fn); break; | |
case 3: selectFile(false, "jpg, jpeg, png, gif").then(fn); break; | |
case 4: selectFile(true, "jpg, jpeg, png, gif").then(fn); break; | |
} | |
}; | |
</script> | |
</body> | |
</html> |
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
"use strict"; | |
const isNode = | |
!!("object" === typeof process | |
&& "object" === typeof global | |
&& "object" === typeof process.versions | |
&& "string" === typeof process.versions.node); | |
const isElectron = !!(isNode && process.versions.electron); | |
const readFile = async (path, raw = false) => { | |
// Node.js/Electron | |
if(isNode){ | |
const {readFile} = require("fs"); | |
return new Promise((resolve, reject) => { | |
readFile(path, raw ? null : "utf8", (error, data) => | |
error ? reject(error) : resolve(data)); | |
}); | |
} | |
// Modern browser | |
else if("function" === typeof window.fetch) | |
return (await fetch(path))[raw ? "arrayBuffer" : "text"](); | |
// Ancient browser, probably running transpiled ES5 source | |
else return new Promise((resolve, reject) => { | |
const xhr = new XMLHttpRequest(); | |
xhr.open("GET", path); | |
xhr.responseType = raw ? "arraybuffer" : "text"; | |
xhr.onreadystatechange = () => { | |
if(4 !== xhr.readyState) return; | |
xhr.status < 400 | |
? resolve(raw && "string" === typeof xhr.response | |
? xhr.response.split("") | |
: xhr.response) | |
: reject(new Error(`HTTP 1.1/${xhr.status} ${xhr.statusText}`)); | |
}; | |
xhr.onerror = reject; | |
xhr.send(); | |
}); | |
}; | |
async function selectFile(multiple = false, fileExts = null){ | |
fileExts = fileExts && ("string" === typeof fileExts | |
? fileExts.trim().split(/\s+/) | |
: [...fileExts]).map(e => e.replace(/^\*?\.|,/g, "")); | |
// Electron | |
if(isElectron){ | |
const {dialog, remote} = require("electron"); | |
const options = {properties: ["openFile", "showHiddenFiles"]}; | |
if(multiple) options.properties.push("multiSelections"); | |
if(fileExts) options.filters = fileExts.map(e => ({extensions: [e]})); | |
return Promise.all(((dialog || remote.dialog).showOpenDialog(options) || []) | |
.map(path => readFile(path, true).then(data => [path, data]))); | |
} | |
// Browsers | |
else{ | |
if(!fileInput){ | |
fileInput = document.createElement("input"); | |
fileInput.type = "file"; | |
} | |
fileInput.multiple = !!multiple; | |
fileInput.accept = fileExts ? fileExts.map(e => "." + e).join(",") : ""; | |
const files = await new Promise(resolve => { | |
fileInput.onchange = () => resolve([...fileInput.files]); | |
fileInput.click(); | |
}); | |
fileInput.onchange = null; | |
fileInput.value = ""; | |
return Promise.all(files.map(file => new Promise((resolve, reject) => { | |
const reader = new FileReader(); | |
reader.onabort = () => resolve(); | |
reader.onerror = () => reject(reader.error); | |
reader.onload = () => resolve([file.name, reader.result]); | |
reader.readAsArrayBuffer(file); | |
}))); | |
} | |
} | |
let fileInput = null; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment