Files

275 lines
7.9 KiB
JavaScript

///https://wicg.github.io/file-system-access/#api-filesystemfilehandle-getfile
export class Files {
//-----------------------------
// FILE TYPE
//-----------------------------
static autoTypes( type ) {
let t = []
switch( type ){
case 'svg':
t = [ { accept: { 'image/svg+xml': '.svg'} }, ]
break;
case 'wav':
t = [ { accept: { 'audio/wav': '.wav'} }, ]
break;
case 'mp3':
t = [ { accept: { 'audio/mpeg': '.mp3'} }, ]
break;
case 'mp4':
t = [ { accept: { 'video/mp4': '.mp4'} }, ]
break;
case 'bin': case 'hex':
t = [ { description: 'Binary Files', accept: { 'application/octet-stream': ['.bin', '.hex'] } }, ]
break;
case 'text':
t = [ { description: 'Text Files', accept: { 'text/plain': ['.txt', '.text'], 'text/html': ['.html', '.htm'] } }, ]
break;
case 'json':
t = [ { description: 'JSON Files', accept: { 'application/json': ['.json'] } }, ]//text/plain
break;
case 'js':
t = [ { description: 'JavaScript Files', accept: { 'text/javascript': ['.js'] } }, ]
break;
case 'image':
t = [ { description: 'Images', accept: { 'image/*': ['.png', '.gif', '.jpeg', '.jpg'] } }, ]
break;
case 'gif':
t = [ { description: 'Images', accept: { 'image/*': ['.gif'] } }, ]
break;
case 'png':
t = [ { description: 'Images', accept: { 'image/*': ['.png'] } }, ]
break;
case 'jpg':
t = [ { description: 'Images', accept: { 'image/*': ['.jpg', '.jpeg'] } }, ]
break;
case 'icon':
t = [ { description: 'Icons', accept: { 'image/x-ico': ['.ico'] } }, ]
break;
case 'lut':
t = [ { description: 'Lut', accept: { 'text/plain': ['.cube', '.3dl'] } }, ]
break;
case 'glb': case 'gltf': case 'fbx': case 'obj': case 'stl':
t = [ { description: 'Model', accept: { 'model/*': ['.glb', '.gltf', '.fbx', '.obj', '.stl'] } }, ]
break;
}
return t
}
//-----------------------------
// LOAD
//-----------------------------
static async load( o = {} ) {
if (typeof window.showOpenFilePicker !== 'function') {
window.showOpenFilePicker = Files.showOpenFilePickerPolyfill
}
try {
let type = o.type || ''
const options = {
excludeAcceptAllOption: type ? true : false,
multiple: false,
//startIn:'./assets'
};
options.types = Files.autoTypes( type )
if( o.path ) options.startIn = o.path;
// create a new handle
const handle = await window.showOpenFilePicker( options )
const file = await handle[0].getFile()
//let content = await file.text()
if( !file ) return null
let fname = file.name;
let ftype = fname.substring( fname.lastIndexOf('.')+1, fname.length );
const dataUrl = [ 'png', 'jpg', 'jpeg', 'mp4', 'webm', 'ogg', 'mp3' ];
const dataBuf = [ 'sea', 'z', 'hex', 'bvh', 'BVH', 'glb', 'gltf', 'exr', 'fbx', 'stl' ];
const reader = new FileReader();
if( dataUrl.indexOf( ftype ) !== -1 ) reader.readAsDataURL( file );
else if( dataBuf.indexOf( ftype ) !== -1 ) reader.readAsArrayBuffer( file );
else reader.readAsText( file );
reader.onload = function(e) {
let content = e.target.result;
//console.log('>>>>', type, ftype)
switch(ftype){
case 'image':
let img = new Image();
img.onload = function() {
img.width =img.width;
img.height =img.height;
if( o.callback ) o.callback( img, fname, ftype, [img.width, img.height] )
}
img.src = content
break;
case 'json':
if( o.callback ) o.callback( JSON.parse( content ), fname, ftype )
break;
default:
if( o.callback ) o.callback( content, fname, ftype )
break;
}
}
} catch(e) {
console.log(e)
if( o.always && o.callback ) o.callback( null )
}
}
static showOpenFilePickerPolyfill( options ) {
return new Promise((resolve) => {
const input = document.createElement("input");
input.type = "file";
input.multiple = options.multiple;
input.accept = options.types
.map((type) => type.accept)
.flatMap((inst) => Object.keys(inst).flatMap((key) => inst[key]))
.join(",");
input.addEventListener("change", () => {
resolve(
[...input.files].map((file) => {
return {
getFile: async () =>
new Promise((resolve) => {
resolve(file);
}),
};
})
);
});
input.click();
})
}
//-----------------------------
// SAVE
//-----------------------------
static async save( o = {} ) {
let usePoly = false;
if (typeof window.showSaveFilePicker !== 'function') {
window.showSaveFilePicker = Files.showSaveFilePickerPolyfill
usePoly = true;
}
try {
let type = o.type || ''
const options = {
suggestedName: o.name || 'hello',
data: o.data || ''
};
options.types = Files.autoTypes( type )
options.finalType = Object.keys( options.types[0].accept )[0]
options.suggestedName += options.types[0].accept[options.finalType][0]
// create a new handle
const handle = await window.showSaveFilePicker( options );
if( usePoly ) return
// create a FileSystemWritableFileStream to write to
const file = await handle.createWritable();
let blob = new Blob([ options.data ], { type: options.finalType });
// write our file
await file.write(blob);
// close the file and write the contents to disk.
await file.close();
} catch(e) {
console.log(e);
}
}
static showSaveFilePickerPolyfill( options ) {
return new Promise((resolve) => {
const a = document.createElement("a");
a.download = options.suggestedName || "my-file.txt"
let blob = new Blob([ options.data ], { type:options.finalType });
a.href = URL.createObjectURL( blob )
a.addEventListener("click", () => {
resolve(
setTimeout( () => URL.revokeObjectURL(a.href), 1000 )
)
})
a.click()
})
}
//-----------------------------
// FOLDER not possible in poly
//-----------------------------
static async getFolder() {
try {
const handle = await window.showDirectoryPicker();
const files = [];
for await (const entry of handle.values()) {
const file = await entry.getFile();
files.push(file);
}
console.log(files)
return files;
} catch(e) {
console.log(e);
}
}
}