chore: cleanup multiple uses of FileReader (#3110)

from
https://discord.com/channels/859816885297741824/1006133967642177556/1213038401465618433

### Change Type

- [x] `patch` — Bug fix
This commit is contained in:
Mime Čuvalo 2024-03-12 09:10:18 +00:00 committed by GitHub
parent 60cc0dcce3
commit dba6d4c414
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 14 additions and 52 deletions

View file

@ -1,6 +1,7 @@
/* eslint-disable react-hooks/rules-of-hooks */ /* eslint-disable react-hooks/rules-of-hooks */
import { import {
BaseBoxShapeUtil, BaseBoxShapeUtil,
FileHelpers,
HTMLContainer, HTMLContainer,
TLImageShape, TLImageShape,
TLOnDoubleClickHandler, TLOnDoubleClickHandler,
@ -19,12 +20,7 @@ import { usePrefersReducedMotion } from '../shared/usePrefersReducedMotion'
async function getDataURIFromURL(url: string): Promise<string> { async function getDataURIFromURL(url: string): Promise<string> {
const response = await fetch(url) const response = await fetch(url)
const blob = await response.blob() const blob = await response.blob()
return new Promise((resolve, reject) => { return FileHelpers.fileToBase64(blob)
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result as string)
reader.onerror = reject
reader.readAsDataURL(blob)
})
} }
/** @public */ /** @public */

View file

@ -2,6 +2,7 @@ import {
DefaultColorThemePalette, DefaultColorThemePalette,
DefaultFontFamilies, DefaultFontFamilies,
DefaultFontStyle, DefaultFontStyle,
FileHelpers,
HASH_PATTERN_ZOOM_NAMES, HASH_PATTERN_ZOOM_NAMES,
MAX_ZOOM, MAX_ZOOM,
SvgExportDef, SvgExportDef,
@ -27,12 +28,7 @@ export function getFontDefForExport(fontStyle: TLDefaultFontStyle): SvgExportDef
if (!url || !fontFaceRule) return null if (!url || !fontFaceRule) return null
const fontFile = await (await fetch(url)).blob() const fontFile = await (await fetch(url)).blob()
const base64FontFile = await new Promise<string>((resolve, reject) => { const base64FontFile = FileHelpers.fileToBase64(fontFile)
const reader = new FileReader()
reader.onload = () => resolve(reader.result as string)
reader.onerror = reject
reader.readAsDataURL(fontFile)
})
const newFontFaceRule = fontFaceRule.replace(url, base64FontFile) const newFontFaceRule = fontFaceRule.replace(url, base64FontFile)
const style = document.createElementNS('http://www.w3.org/2000/svg', 'style') const style = document.createElementNS('http://www.w3.org/2000/svg', 'style')

View file

@ -1,5 +1,6 @@
import { import {
Editor, Editor,
FileHelpers,
TLArrowShape, TLArrowShape,
TLBookmarkShape, TLBookmarkShape,
TLEmbedShape, TLEmbedShape,
@ -81,26 +82,6 @@ function disallowClipboardEvents(editor: Editor) {
) )
} }
/**
* Get a blob as a string.
*
* @param blob - The blob to get as a string.
* @internal
*/
async function blobAsString(blob: Blob) {
return new Promise<string>((resolve, reject) => {
const reader = new FileReader()
reader.addEventListener('loadend', () => {
const text = reader.result
resolve(text as string)
})
reader.addEventListener('error', () => {
reject(reader.error)
})
reader.readAsText(blob)
})
}
/** /**
* Whether a ClipboardItem is a file. * Whether a ClipboardItem is a file.
* @param item - The ClipboardItem to check. * @param item - The ClipboardItem to check.
@ -270,7 +251,7 @@ const handlePasteFromClipboardApi = async (
things.push({ things.push({
type: 'html', type: 'html',
source: new Promise<string>((r) => source: new Promise<string>((r) =>
item.getType('text/html').then((blob) => blobAsString(blob).then(r)) item.getType('text/html').then((blob) => FileHelpers.fileToBase64(blob).then(r))
), ),
}) })
} }
@ -279,7 +260,7 @@ const handlePasteFromClipboardApi = async (
things.push({ things.push({
type: 'url', type: 'url',
source: new Promise<string>((r) => source: new Promise<string>((r) =>
item.getType('text/uri-list').then((blob) => blobAsString(blob).then(r)) item.getType('text/uri-list').then((blob) => FileHelpers.fileToBase64(blob).then(r))
), ),
}) })
} }
@ -288,7 +269,7 @@ const handlePasteFromClipboardApi = async (
things.push({ things.push({
type: 'text', type: 'text',
source: new Promise<string>((r) => source: new Promise<string>((r) =>
item.getType('text/plain').then((blob) => blobAsString(blob).then(r)) item.getType('text/plain').then((blob) => FileHelpers.fileToBase64(blob).then(r))
), ),
}) })
} }

View file

@ -1,5 +1,6 @@
import { import {
Editor, Editor,
FileHelpers,
PngHelpers, PngHelpers,
TLShapeId, TLShapeId,
TLSvgOptions, TLSvgOptions,
@ -98,7 +99,6 @@ export async function getSvgAsString(svg: SVGElement) {
svg.setAttribute('width', +svg.getAttribute('width')! + '') svg.setAttribute('width', +svg.getAttribute('width')! + '')
svg.setAttribute('height', +svg.getAttribute('height')! + '') svg.setAttribute('height', +svg.getAttribute('height')! + '')
const fileReader = new FileReader()
const imgs = Array.from(clone.querySelectorAll('image')) as SVGImageElement[] const imgs = Array.from(clone.querySelectorAll('image')) as SVGImageElement[]
for (const img of imgs) { for (const img of imgs) {
@ -106,11 +106,7 @@ export async function getSvgAsString(svg: SVGElement) {
if (src) { if (src) {
if (!src.startsWith('data:')) { if (!src.startsWith('data:')) {
const blob = await (await fetch(src)).blob() const blob = await (await fetch(src)).blob()
const base64 = await new Promise<string>((resolve, reject) => { const base64 = await FileHelpers.fileToBase64(blob)
fileReader.onload = () => resolve(fileReader.result as string)
fileReader.onerror = () => reject(fileReader.error)
fileReader.readAsDataURL(blob)
})
img.setAttribute('xlink:href', base64) img.setAttribute('xlink:href', base64)
} }
} }

View file

@ -32,10 +32,10 @@ export class FileHelpers {
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {
if (file) { if (file) {
const reader = new FileReader() const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => resolve(reader.result as string) reader.onload = () => resolve(reader.result as string)
reader.onerror = (error) => reject(error) reader.onerror = (error) => reject(error)
reader.onabort = (error) => reject(error) reader.onabort = (error) => reject(error)
reader.readAsDataURL(file)
} }
}) })
} }

View file

@ -1,3 +1,4 @@
import { FileHelpers } from './file'
import { PngHelpers } from './png' import { PngHelpers } from './png'
/** /**
@ -44,16 +45,8 @@ export class MediaHelpers {
* Read a blob into a data url * Read a blob into a data url
* @public * @public
*/ */
static blobToDataUrl(blob: Blob): Promise<string> { static blobToDataUrl(blob: Blob) {
return new Promise((resolve, reject) => { return FileHelpers.fileToBase64(blob)
const reader = new FileReader()
reader.onload = () => resolve(reader.result as string)
reader.onerror = (e) => {
console.error(e)
reject(new Error('Could not read blob'))
}
reader.readAsDataURL(blob)
})
} }
/** /**