File size: 5,920 Bytes
ea35075 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
import {
fileOpen,
fileSave,
FileWithHandle,
FirstFileOpenOptions,
} from 'browser-fs-access'
export function download(href: string, title: string) {
const a = document.createElement('a')
a.setAttribute('href', href)
a.setAttribute('download', title)
a.click()
}
export function downloadJson(data: string, fileName: string) {
const blob = new Blob([data], { type: 'text/json' })
const href = window.URL.createObjectURL(blob)
download(href, fileName)
URL.revokeObjectURL(href)
}
async function fileOpenLegacy<M extends boolean | undefined = false>(
_options: FirstFileOpenOptions<M> = {}
): Promise<FileWithHandle | FileWithHandle[]> {
let options: FirstFileOpenOptions<M>[]
if (!Array.isArray(_options)) {
options = [_options]
} else options = _options
return new Promise((resolve, reject) => {
const input = document.createElement('input') as HTMLInputElement
input.type = 'file'
const accept = [
...options.map((option) => option.mimeTypes || []),
...options.map((option) => option.extensions || []),
].join()
input.multiple = options[0].multiple || false
// Empty string allows everything.
input.accept = accept || ''
// Append to the DOM, else Safari on iOS won't fire the `change` event
// reliably.
input.style.display = 'none'
document.body.append(input)
const _reject = () => cleanupListenersAndMaybeReject?.(reject)
const _resolve = (value: FileWithHandle | FileWithHandle[]) => {
if (typeof cleanupListenersAndMaybeReject === 'function') {
cleanupListenersAndMaybeReject()
}
resolve(value)
}
// ToDo: Remove this workaround once
// https://github.com/whatwg/html/issues/6376 is specified and supported.
const cleanupListenersAndMaybeReject =
options[0].legacySetup &&
options[0].legacySetup(_resolve, _reject, input)
const cancelDetector = () => {
window.removeEventListener('focus', cancelDetector)
input.remove()
}
input.addEventListener('click', () => {
window.addEventListener('focus', cancelDetector)
})
input.addEventListener('change', () => {
window.removeEventListener('focus', cancelDetector)
input.remove()
if (input.files)
_resolve(
input.multiple ? Array.from(input.files) : input.files[0]
)
else {
_reject()
}
})
if ('showPicker' in HTMLInputElement.prototype) {
input.showPicker()
} else {
input.click()
}
})
}
export async function uploadJson() {
try {
const file = await fileOpenLegacy({
mimeTypes: ['application/json'],
legacySetup: (_, rejectionHandler) => {
const timeoutId = setTimeout(rejectionHandler, 10_000)
return (reject) => {
clearTimeout(timeoutId)
if (reject) {
console.error('reject')
reject('Failed to Open file')
}
}
},
})
return await new Promise<string>((resolve, reject) => {
const reader = new FileReader()
reader.onload = function () {
resolve(reader.result as string)
}
reader.onerror = function () {
reject(reader.error)
}
if (Array.isArray(file) == false)
reader.readAsText(file as FileWithHandle)
else reject("Don't select multiple files")
})
} catch (error) {
console.log(error)
return null
}
}
export async function uploadImage() {
try {
const file = await fileOpenLegacy({
mimeTypes: ['image/*'],
legacySetup: (_, rejectionHandler) => {
const timeoutId = setTimeout(rejectionHandler, 10_000)
return (reject) => {
clearTimeout(timeoutId)
console.log('reject')
if (reject) {
reject('Open file timeout')
}
}
},
})
return await new Promise<string>((resolve, reject) => {
const reader = new FileReader()
reader.onload = function () {
resolve(reader.result as string)
}
reader.onerror = function () {
reject(reader.error)
}
if (Array.isArray(file) == false)
reader.readAsDataURL(file as FileWithHandle)
else reject("Don't select multiple files")
})
} catch (error) {
console.log(error)
return null
}
}
export async function CopyTextToClipboard(text: string) {
try {
await navigator.clipboard.writeText(text)
} catch (error) {
// https://github.com/sudodoki/copy-to-clipboard/blob/main/index.js
const input = document.createElement('input') as HTMLInputElement
input.type = 'text'
input.style.display = 'none'
input.value = text
input.ariaHidden = 'true'
// reset user styles for span element
input.style.all = 'unset'
// prevents scrolling to the end of the page
input.style.position = 'fixed'
input.style.top = '0'
input.style.clip = 'rect(0, 0, 0, 0)'
document.body.append(input)
input.select()
const successful = document.execCommand('copy')
input.remove()
if (!successful) {
throw new Error('copy command was unsuccessful')
}
}
}
|