Skip to content

Commit

Permalink
add parseHtml
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexErrant committed Jan 28, 2025
1 parent 5698721 commit ede99bc
Show file tree
Hide file tree
Showing 14 changed files with 46 additions and 51 deletions.
3 changes: 2 additions & 1 deletion app-ugc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"app": "workspace:*",
"comlink": "^4.4.1",
"micromorph": "^0.4.5",
"shared": "workspace:*"
"shared": "workspace:*",
"shared-dom": "workspace:*"
}
}
5 changes: 2 additions & 3 deletions app-ugc/src/setBody.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
import { resizeIframe } from './registerServiceWorker'
import diff from 'micromorph'
import '@iframe-resizer/child'
import { parseHtml } from 'shared-dom/utility'

self.onmessage = async (event) => {
const data = event.data as unknown
Expand All @@ -21,10 +22,8 @@ self.onmessage = async (event) => {
}
}

const domParser = new DOMParser()

export async function setBody({ body, css }: RawRenderBodyInput) {
await diff(document, domParser.parseFromString(body, 'text/html'))
await diff(document, parseHtml(body))
if (css != null) {
const style = document.createElement('style')
style.textContent = css
Expand Down
4 changes: 2 additions & 2 deletions app/src/components/addNote.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { assertNever, objEntries, objValues } from 'shared/utility'
import { CardsRemote } from './cardsRemote'
import { createMutation } from '@tanstack/solid-query'
import { useTableCountContext } from './tableCountContext'
import { parseHtml } from 'shared-dom/utility'

function toView(template: Template): NoteCardView {
const now = C.getDate()
Expand Down Expand Up @@ -95,11 +96,10 @@ export const AddNote: VoidComponent<{
const noteCard = wip.noteCard!
if (noteCard.cards.length === 0)
C.toastFatal('There must be at least 1 card')
const dp = new DOMParser()
await tx(async () => {
const fieldValues = await Promise.all(
objEntries(noteCard.note.fieldValues).map(async ([f, v]) => {
const doc = dp.parseFromString(v, 'text/html')
const doc = parseHtml(v)
await Promise.all(
Array.from(doc.images).map(async (i) => {
await mutate(i)
Expand Down
4 changes: 2 additions & 2 deletions app/src/components/fieldEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { type NoteCardView } from '../uiLogic/cards'
import { toOneLine } from 'shared/htmlToText'
import { type NoteId, type MediaId } from 'shared/brand'
import { C } from '../topLevelAwait'
import { parseHtml } from 'shared-dom/utility'
// import "prosemirror-image-plugin/src/styles/sideResize.css"

// cf. https://gitlab.com/emergence-engineering/prosemirror-image-plugin/-/blob/master/src/updateImageNode.ts
Expand Down Expand Up @@ -131,7 +132,6 @@ const mySchema = makeSchema('editor')
const mySchemaSerializer = makeSchema('serializer')

const domSerializer = DOMSerializer.fromSchema(mySchemaSerializer)
const domParser = new DOMParser()
const proseMirrorDOMParser = ProseMirrorDOMParser.fromSchema(mySchema)

export const FieldEditor: VoidComponent<{
Expand Down Expand Up @@ -220,7 +220,7 @@ async function updateImgSrc(img: HTMLImageElement) {
}

async function createEditorState(value: string) {
const doc = domParser.parseFromString(value, 'text/html')
const doc = parseHtml(value)
await Promise.all(Array.from(doc.images).map(updateImgSrc))
return EditorState.create({
doc: proseMirrorDOMParser.parse(doc),
Expand Down
5 changes: 2 additions & 3 deletions app/src/components/noteSync.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { type NoteRemote, type Note } from 'shared/domain/note'
import { UploadEntry } from './uploadEntry'
import { uploadNotes } from '../domain/sync'
import { C } from '../topLevelAwait'
import { parseHtml } from 'shared-dom/utility'

const NoteSync: VoidComponent<{ template: Template; note: Note }> = (props) => (
<>
Expand Down Expand Up @@ -64,8 +65,6 @@ export const NoteNookSync: VoidComponent<{
)
}

const dp = new DOMParser()

const NoteNookSyncActual: VoidComponent<{
note: Note
template: Template
Expand All @@ -84,7 +83,7 @@ const NoteNookSyncActual: VoidComponent<{
}
if (remoteNote != null) {
for (const [field, value] of objEntries(remoteNote.fieldValues)) {
const doc = dp.parseFromString(value, 'text/html')
const doc = parseHtml(value)
await Promise.all(
Array.from(doc.images).map(async (imgEl) => {
const rmId = imgEl
Expand Down
17 changes: 8 additions & 9 deletions app/src/hubMessenger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { type Template } from 'shared/domain/template'
import { type Note } from 'shared/domain/note'
import { type Card } from 'shared/domain/card'
import { objEntries } from 'shared/utility'
import { parseHtml } from 'shared-dom/utility'

export const appExpose = {
ping: () => {},
Expand All @@ -32,11 +33,10 @@ export const appExpose = {
[rt.nook]: { remoteTemplateId: rt.id, uploadDate: now },
},
} satisfies Template
const dp = new DOMParser()
if (template.templateType.tag === 'standard') {
await Promise.all(
template.templateType.templates.map(async (t) => {
const { imgSrcs, front, back } = getTemplateImages(t, dp)
const { imgSrcs, front, back } = getTemplateImages(t)
t.front = serializer.serializeToString(front)
t.back = serializer.serializeToString(back)
return await downloadImages(imgSrcs)
Expand All @@ -45,7 +45,6 @@ export const appExpose = {
} else {
const { imgSrcs, front, back } = getTemplateImages(
template.templateType.template,
dp,
)
await downloadImages(imgSrcs)
template.templateType.template.front =
Expand Down Expand Up @@ -73,7 +72,7 @@ export const appExpose = {
[nook, { remoteNoteId: rn.id, uploadDate: now }],
]),
} satisfies Note
await downloadImages(getNoteImages(n.fieldValues, new DOMParser()))
await downloadImages(getNoteImages(n.fieldValues))
await C.db.upsertNote(n)
const ords = noteOrds.bind(C)(n, template)
const cards = ords.map((i) => {
Expand All @@ -100,10 +99,10 @@ export const appExpose = {
// highTODO needs security on the origin
Comlink.expose(appExpose, Comlink.windowEndpoint(self.parent))

function getNoteImages(fieldValues: Record<string, string>, dp: DOMParser) {
function getNoteImages(fieldValues: Record<string, string>) {
const imgSrcs = new Map<MediaId, string>()
for (const [f, v] of objEntries(fieldValues)) {
const doc = dp.parseFromString(v, 'text/html')
const doc = parseHtml(v)
Array.from(doc.images).forEach((i) => {
mutate(i, imgSrcs)
})
Expand All @@ -128,10 +127,10 @@ function mutate(img: HTMLImageElement, imgSrcs: Map<MediaId, string>) {
}
}

function getTemplateImages(ct: ChildTemplate, dp: DOMParser) {
function getTemplateImages(ct: ChildTemplate) {
const imgSrcs = new Map<MediaId, string>()
const front = dp.parseFromString(ct.front, 'text/html')
const back = dp.parseFromString(ct.back, 'text/html')
const front = parseHtml(ct.front)
const back = parseHtml(ct.back)
Array.from(front.images).forEach((i) => {
mutate(i, imgSrcs)
})
Expand Down
4 changes: 1 addition & 3 deletions app/src/sqlite/crsqlite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@ import { SQLITE_DETERMINISTIC, SQLITE_UTF8 } from '@vlcn.io/wa-sqlite'
import initSql from 'shared/sql.json'
import { ftsNormalize } from 'shared/htmlToText'

// const dp = new DOMParser()

function getMediaIds(fvs: string) {
// highTODO uncomment and fix by adding the mediaId table back
// const values = parseMap<string, string>(fvs).values()
// return Array.from(values)
// .flatMap((v) => dp.parseFromString(v, 'text/html'))
// .flatMap((v) => parseHtml(v))
// .flatMap((d) => Array.from(d.images))
// .map((i) => i.getAttribute('src'))
// .join(unitSeparator)
Expand Down
13 changes: 3 additions & 10 deletions app/src/sqlite/note.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,6 @@ JOIN noteFieldValue ON noteFieldValue.noteId = x.noteId AND noteFieldValue.field
)
},
getNewNotesToUpload: async function (noteId?: NoteId, nook?: NookId) {
const dp = new DOMParser()
const remoteTemplates = await ky
.selectFrom('remoteTemplate')
.selectAll()
Expand All @@ -285,7 +284,7 @@ JOIN noteFieldValue ON noteFieldValue.noteId = x.noteId AND noteFieldValue.field
.filter(notEmpty)
return domainToCreateRemote(note, remoteIds)
})
.map(async (n) => await remotifyNote(dp, n).then((x) => x.note)),
.map(async (n) => await remotifyNote(n).then((x) => x.note)),
)
},
getNewNotesToUploadDom: async function (noteId?: NoteId) {
Expand Down Expand Up @@ -318,7 +317,6 @@ JOIN noteFieldValue ON noteFieldValue.noteId = x.noteId AND noteFieldValue.field
)
},
getEditedNotesToUpload: async function (noteId?: NoteId, nook?: NookId) {
const dp = new DOMParser()
const remoteTemplates = await ky
.selectFrom('remoteTemplate')
.selectAll()
Expand Down Expand Up @@ -360,7 +358,7 @@ JOIN noteFieldValue ON noteFieldValue.noteId = x.noteId AND noteFieldValue.field
)
return domainToEditRemote(note, remotes)
})
.map(async (n) => await remotifyNote(dp, n).then((x) => x.note)),
.map(async (n) => await remotifyNote(n).then((x) => x.note)),
)
},
getEditedNotesToUploadDom: async function (noteId?: NoteId) {
Expand Down Expand Up @@ -402,7 +400,6 @@ JOIN noteFieldValue ON noteFieldValue.noteId = x.noteId AND noteFieldValue.field
> & { note: Note },
) {
const { hashByLocal } = await remotifyNote(
new DOMParser(),
domainToCreateRemote(remoteNote.note, [
/* this doesn't need any real values */
]),
Expand Down Expand Up @@ -479,14 +476,10 @@ JOIN noteFieldValue ON noteFieldValue.noteId = x.noteId AND noteFieldValue.field
}

async function remotifyNote<T extends CreateRemoteNote | EditRemoteNote>(
dp: DOMParser,
note: T,
) {
const fieldValues: Record<string, string> = {} satisfies T['fieldValues']
const { docs, hashByLocal } = await remotifyDoms(
dp,
objValues(note.fieldValues),
)
const { docs, hashByLocal } = await remotifyDoms(objValues(note.fieldValues))
let i = 0
for (const field of objKeys(note.fieldValues)) {
fieldValues[field] = docs[i]!.body.innerHTML
Expand Down
17 changes: 5 additions & 12 deletions app/src/sqlite/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,11 @@ export const templateCollectionMethods = {
templateId?: TemplateId,
nook?: NookId,
) {
const dp = new DOMParser()
const templatesAndStuff = await this.getNewTemplatesToUploadDom(templateId)
return await Promise.all(
templatesAndStuff
.map((n) => domainToCreateRemote(n, nook))
.map(
async (n) => await remotifyTemplate(dp, n).then((x) => x.template),
),
.map(async (n) => await remotifyTemplate(n).then((x) => x.template)),
)
},
getNewTemplatesToUploadDom: async function (templateId?: TemplateId) {
Expand All @@ -246,15 +243,12 @@ export const templateCollectionMethods = {
templateId?: TemplateId,
nook?: NookId,
) {
const dp = new DOMParser()
const templatesAndStuff =
await this.getEditedTemplatesToUploadDom(templateId)
return await Promise.all(
templatesAndStuff
.map((n) => domainToEditRemote(n, nook))
.map(
async (n) => await remotifyTemplate(dp, n).then((x) => x.template),
),
.map(async (n) => await remotifyTemplate(n).then((x) => x.template)),
)
},
getEditedTemplatesToUploadDom: async function (templateId?: TemplateId) {
Expand Down Expand Up @@ -293,7 +287,6 @@ export const templateCollectionMethods = {
.where('id', '=', templateDbId)
.executeTakeFirstOrThrow()
const { hashByLocal } = await remotifyTemplate(
new DOMParser(),
domainToCreateRemote(toTemplate([{ ...template, ...remoteTemplate }])!),
)
const srcs = new Set(hashByLocal.keys())
Expand Down Expand Up @@ -392,7 +385,7 @@ function toTemplate(allTemplates: TemplateRow[]) {

async function remotifyTemplate<
T extends CreateRemoteTemplate | EditRemoteTemplate,
>(dp: DOMParser, template: T) {
>(template: T) {
const serializer = new XMLSerializer()
const serialize = (doc: Document) => {
const s = serializer.serializeToString(doc)
Expand All @@ -407,7 +400,7 @@ async function remotifyTemplate<
t.front,
t.back,
])
const { docs, hashByLocal } = await remotifyDoms(dp, rawDoms)
const { docs, hashByLocal } = await remotifyDoms(rawDoms)
let i = 0
for (const t of template.templateType.templates) {
t.front = serialize(docs[i]!)
Expand All @@ -420,7 +413,7 @@ async function remotifyTemplate<
hashByLocal,
}
} else {
const { docs, hashByLocal } = await remotifyDoms(dp, [
const { docs, hashByLocal } = await remotifyDoms([
template.templateType.template.front,
template.templateType.template.back,
])
Expand Down
5 changes: 3 additions & 2 deletions app/src/sqlite/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@ import { jsonArrayFrom } from 'kysely/helpers/sqlite'
import { sql, type AliasedRawBuilder, type ExpressionBuilder } from 'kysely'
import { arrayToBase64, base64ToArray } from 'shared/binary'
import { nullNook } from 'shared-edge'
import { parseHtml } from 'shared-dom/utility'

export function parseTags(rawTags: string) {
return parseSet<string>(rawTags)
}

export async function remotifyDoms(dp: DOMParser, rawDoms: string[]) {
const docs = rawDoms.map((rawDom) => dp.parseFromString(rawDom, 'text/html'))
export async function remotifyDoms(rawDoms: string[]) {
const docs = rawDoms.map(parseHtml)
const imgSrcs = new Set(
docs
.flatMap((pd) => Array.from(pd.images))
Expand Down
3 changes: 2 additions & 1 deletion hub-ugc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"comlink": "^4.4.1",
"hub": "workspace:*",
"micromorph": "^0.4.5",
"shared": "workspace:*"
"shared": "workspace:*",
"shared-dom": "workspace:*"
}
}
5 changes: 2 additions & 3 deletions hub-ugc/src/setBody.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
import { resizeIframe } from './registerServiceWorker'
import diff from 'micromorph'
import '@iframe-resizer/child'
import { parseHtml } from 'shared-dom/utility'

self.onmessage = async (event) => {
const data = event.data as unknown
Expand All @@ -21,10 +22,8 @@ self.onmessage = async (event) => {
}
}

const domParser = new DOMParser()

export async function setBody({ body, css }: RawRenderBodyInput) {
await diff(document, domParser.parseFromString(body, 'text/html'))
await diff(document, parseHtml(body))
if (css != null) {
const style = document.createElement('style')
style.textContent = css
Expand Down
6 changes: 6 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions shared-dom/src/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ export function disposeObserver(ro: ResizeObserver | undefined, ref: Element) {
ro.disconnect()
}
}

let domParser: DOMParser
export function parseHtml(html: string) {
if (domParser == null) domParser = new DOMParser()
return domParser.parseFromString(html, 'text/html')
}

0 comments on commit ede99bc

Please sign in to comment.