Files
RomhackPlaza/resources/js/SubmissionsClass/FSUploader.js

163 lines
4.7 KiB
JavaScript

import { FSFileData, CHUNK_SIZE } from "./FSFileData.js";
/**
* File uploader on FileServer.
* @returns {{files: Array<FSFileData>, section: string, init(): void, readonly numberOfFiles: number, readonly isUploading: boolean, readonly hasErrors: boolean, readonly allFilesUploaded: boolean, totalChunksNumber(*): number, handleSubmitFile(Event): Promise<void>, handleRetryFile(number): Promise<void>, removeFile(number): void}|boolean|this is FSFileData[]|number|boolean}
* @constructor
*/
export function FSUploader(){
return {
/**
* Array of uploaded files.
* @type {Array<FSFileData>}
*/
files: [],
/**
* Section that files must be uploaded.
* @type {string}
*/
section: document.querySelector("meta[name='fs-section']")?.content ?? '',
/**
* Triggered in fs-upload.blade.php
* Refresh icons.
*
* @param {Array<FSFileData>} oldFilesArray
*/
init( oldFilesArray ){
this.$watch('files', () =>{
this.$nextTick(() => window.refreshIcons(this.$el) )
})
if( oldFilesArray !== undefined && oldFilesArray.length > 0)
this.files = oldFilesArray;
},
/**
* Shortcut to files.length.
* @returns {number}
*/
get numberOfFiles(){
return this.files.length
},
/**
* Look if some files are currently in upload.
* @returns {boolean}
*/
get isUploading(){
return this.files.some(
file => file.isUploading
);
},
/**
* Check if some files have an error or not.
* @returns {boolean}
*/
get hasErrors(){
return this.files.some(
file => file.error
);
},
/**
* Check if all files are uploaded.
* True if all files are uploaded or no one.
*
* @returns {boolean}
*/
get allFilesUploaded(){
return ( this.numberOfFiles === 0 || this.files.every(file => file.done) );
},
/**
* Get total chunks size of a raw file.
* @param rawFile
* @returns {number}
*/
totalChunksNumber( rawFile ){
return Math.ceil( rawFile.size / CHUNK_SIZE );
},
/**
* Handle file submission.
* You can submit multiple files at once.
*
* @param {Event} e
* @returns {Promise<void>}
*/
async handleSubmitFile( e ){
const RAW_FILES_FROM_EVENT = Array.from( e.target.files );
e.target.value = ''; // Default.
for( const RAW_FILE of RAW_FILES_FROM_EVENT ){
const TOTAL_CHUNKS = this.totalChunksNumber(RAW_FILE);
let fsData = FSFileData( RAW_FILE.name, TOTAL_CHUNKS, RAW_FILE );
this.files.push( fsData );
await this.files[this.files.length - 1].upload(this.section);
}
},
handleDownloadFile( index ){
let download_url = this.files[index].download_url;
window.location.href = download_url;
},
async handleFileExplorer( index ){
if( this.files[index].file_explorer_files !== null )
return;
let file_explorer_url = this.files[index].file_explorer;
let response = await fetch(file_explorer_url, { method: 'GET', headers: { 'Content-Type': 'application/json' } });
let json = await response.json();
if( !json.files ){
this.files[index].file_explorer_files = [ "An error occurred during request" ];
return;
}
this.files[index].file_explorer_files = json.files;
},
/**
* Retry file uploading.
*
* @param {number} index FSFileData index in this.files.
* @returns {Promise<void>}
*/
handleRetryFile( index ){
const OLDFSFILE = this.files[index];
let fsData = FSFileData(OLDFSFILE.name, this.totalChunksNumber(OLDFSFILE.rawFile), OLDFSFILE.rawFile );
this.files[index] = fsData;
this.files[index].upload(this.section);
},
/**
* Remove a file.
* @param {number} index FSFileData index in this.files.
*/
handleRemoveFile( index ){
if( this.files[index].state === 'archived')
return;
this.files.splice(index, 1);
},
changeFileState( index, newState ){
this.files[index].state = newState;
}
}
}