floppydrive.neocities.org/src/components/DiskReader.vue

87 lines
1.8 KiB
Vue

<script lang="ts" setup>
import { useTemplateRef } from 'vue'
const emit = defineEmits<{
start: [name: string]
progress: [read: number, total: number]
success: [data: ArrayBuffer]
error: [message: string]
}>()
const MAX_FILE_SIZE = 1440 * 1024
const fileInput = useTemplateRef('file-input')
async function onOpenClick() {
fileInput.value?.click()
}
async function onFileChange(event: Event) {
const files = (event.target as HTMLInputElement).files
if (!files?.length) {
return
}
try {
const data = await readFile(files[0])
emit('success', data)
} catch (e) {
let error
if (!(e instanceof Error)) {
error = new Error('' + e)
} else {
error = e
}
emit('error', error.message)
}
}
function readFile(file: File): Promise<ArrayBuffer> {
return new Promise((resolve, reject) => {
if (file.size > MAX_FILE_SIZE) {
reject(new Error('Maximum file size exceeded'))
return
}
const reader = new FileReader()
reader.onloadstart = (event: ProgressEvent) => {
emit('progress', event.loaded, event.total)
}
reader.onprogress = (event: ProgressEvent) => {
emit('progress', event.loaded, event.total)
}
reader.onload = (event: ProgressEvent) => {
emit('progress', event.loaded, event.total)
const result = (event.target as FileReader).result as ArrayBuffer
resolve(result)
}
reader.onerror = () => {
reject(`read error`)
}
reader.onabort = () => {
reject('read aborted')
}
reader.readAsArrayBuffer(file)
emit('start', file.name)
})
}
</script>
<template>
<div>
<input id="disk-file" ref="file-input" type="file" @change="onFileChange" />
<button type="button" @click="onOpenClick">Open a disk image...</button>
</div>
</template>
<style scoped>
input[type='file'] {
display: none;
}
</style>