Files
RomhackPlaza/resources/js/uploader.js
2026-05-20 18:25:15 +02:00

105 lines
3.8 KiB
JavaScript

import {createIcons, icons} from "lucide";
export const CHUNK_SIZE = 8192;
export function FSUploader(){
return {
files: [],
rawFiles: [],
section: document.querySelector("meta[name='fs-section']")?.content ?? '',
init( oldFiles ){
this.$watch('files', () =>{
this.$nextTick(() => window.refreshIcons(this.$el) )
})
},
get isUploading(){
return this.files.some(f => !f.done && !f.error);
},
get hasErrors(){
return this.files.some(f => f.error);
},
get allUploaded(){
return this.files.length === 0 || this.files.every(f => f.done);
},
async submitFile(e){
const selected = Array.from(e.target.files);
e.target.value = '';
for( const raw of selected ){
const totalChunks = Math.ceil(raw.size / CHUNK_SIZE );
const index = this.files.length;
this.files.push({
name: raw.name,
progress: 0,
currentChunk: 0,
totalChunks: totalChunks,
done: false,
error: null,
uuid: crypto.randomUUID()
});
this.rawFiles.push(raw);
this.uploadChunks(raw,index);
}
},
async uploadChunks(rawFile, index){
const file = this.files[index];
const url = `/api/fs/upload-chunk/${this.section}`;
const csrf = document.querySelector('meta[name=csrf-token]')?.content ?? '';
for( let i = 0; i < file.totalChunks; i++ ){
if( file.error )
return;
const start = i * CHUNK_SIZE;
const end = Math.min(start + CHUNK_SIZE, rawFile.size);
const chunk = rawFile.slice(start, end);
const formData = new FormData();
formData.append('file', chunk);
formData.append('file_uuid', file.uuid);
formData.append('current_chunk', i);
formData.append('total_chunks', file.totalChunks);
formData.append( 'filename', rawFile.name );
formData.append('_token', csrf );
try {
const response = await fetch(url, { method: 'POST', body: formData });
if(!response.ok)
throw new Error(`${response.status} ${response.statusText}`);
const data = await response.json();
if( data.success !== true || data.uploaded !== true )
throw new Error(`${data.error}`);
file.currentChunk = i + 1;
file.progress = Math.round((( i + 1) / file.totalChunks ) * 100);
if( data.finished === true ){
file.done = true;
}
} catch(err){
file.error = 'Error on chunk ' + ( i + 1 ) + '. ' + err.message;
file.progress = 0;
return;
}
}
},
retry(index){
const rawFile = this.rawFiles[index];
const totalChunks = Math.ceil(rawFile.size / CHUNK_SIZE );
this.files[index] = {
name: rawFile.name,
progress: 0,
currentChunk: 0,
totalChunks: totalChunks,
done: false,
error: null,
uuid: crypto.randomUUID()
};
this.uploadChunks(raw,index);
},
remove(index){
this.files.splice(index, 1);
this.rawFiles.splice(index, 1);
}
}
}