87 lines
1.8 KiB
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>
|