Fix deleting highlights from the PDF notebook modal

This commit is contained in:
Jackson Harper 2023-02-02 11:49:12 +08:00
parent a3396997b2
commit 23615db32a
4 changed files with 86 additions and 15 deletions

View file

@ -29,6 +29,7 @@ export function HighlightView(props: HighlightViewProps): JSX.Element {
return (
<VStack css={{ width: '100%', boxSizing: 'border-box' }}>
{props.highlight.highlightPositionPercent}%
<StyledQuote
onClick={() => {
if (props.scrollToHighlight) {

View file

@ -2,7 +2,13 @@ import { ArticleAttributes } from '../../../lib/networking/queries/useGetArticle
import { Box } from '../../elements/LayoutPrimitives'
import { v4 as uuidv4 } from 'uuid'
import { nanoid } from 'nanoid'
import { useState, useEffect, useCallback, useRef } from 'react'
import {
useState,
useEffect,
useCallback,
useRef,
ReactComponentElement,
} from 'react'
import { isDarkTheme } from '../../../lib/themeUpdater'
import PSPDFKit from 'pspdfkit'
import { Instance, HighlightAnnotation, List, Annotation, Rect } from 'pspdfkit'
@ -17,6 +23,7 @@ import { webBaseURL } from '../../../lib/appConfig'
import { pspdfKitKey } from '../../../lib/appConfig'
import { NotebookModal } from './NotebookModal'
import { HighlightNoteModal } from './HighlightNoteModal'
import { showErrorToast } from '../../../lib/toastHelpers'
export type PdfArticleContainerProps = {
viewerUsername: string
@ -32,11 +39,11 @@ export default function PdfArticleContainer(
const [shareTarget, setShareTarget] = useState<Highlight | undefined>(
undefined
)
const [notebookKey, setNotebookKey] = useState<string>(uuidv4())
const [noteTarget, setNoteTarget] = useState<Highlight | undefined>(undefined)
const [noteTargetPageIndex, setNoteTargetPageIndex] = useState<
number | undefined
>(undefined)
const highlightsRef = useRef<Highlight[]>([])
const canShareNative = useCanShareNative()
@ -84,6 +91,18 @@ export default function PdfArticleContainer(
(i) => ALLOWED_TOOLBAR_ITEM_TYPES.indexOf(i.type) !== -1
)
const positionPercentForAnnotation = (annotation: Annotation) => {
let totalSize = 0
let sizeBefore = 0
for (let idx = 0; idx < annotation.pageIndex; idx++) {
sizeBefore += instance.pageInfoForIndex(idx)?.height ?? 0
}
for (let idx = 0; idx < instance.totalPageCount; idx++) {
totalSize += instance.pageInfoForIndex(idx)?.height ?? 0
}
return (sizeBefore + annotation.boundingBox.top) / totalSize
}
const annotationTooltipCallback = (annotation: Annotation) => {
const highlightAnnotation = annotation as HighlightAnnotation
const copy = {
@ -105,17 +124,22 @@ export default function PdfArticleContainer(
id: 'tooltip-remove-annotation',
className: 'TooltipItem-Remove',
onPress: () => {
instance.delete(annotation).then(() => {
if (
annotation.customData &&
annotation.customData.omnivoreHighlight &&
(annotation.customData.omnivoreHighlight as Highlight).id
) {
const data = annotation.customData
.omnivoreHighlight as Highlight
deleteHighlightMutation(data.id)
}
})
instance
.delete(annotation)
.then(() => {
if (
annotation.customData &&
annotation.customData.omnivoreHighlight &&
(annotation.customData.omnivoreHighlight as Highlight).id
) {
const data = annotation.customData
.omnivoreHighlight as Highlight
return deleteHighlightMutation(data.id)
}
})
.catch((err) => {
showErrorToast('Error deleting highlight: ' + err)
})
},
}
const note = {
@ -185,7 +209,7 @@ export default function PdfArticleContainer(
}),
})
instance.addEventListener('annotations.willChange', (event) => {
instance.addEventListener('annotations.willChange', async (event) => {
const annotation = event.annotations.get(0)
if (event.reason !== PSPDFKit.AnnotationsWillChangeReason.DELETE_END) {
return
@ -197,7 +221,7 @@ export default function PdfArticleContainer(
(annotation.customData.omnivoreHighlight as Highlight).id
) {
const data = annotation.customData.omnivoreHighlight as Highlight
deleteHighlightMutation(data.id)
await deleteHighlightMutation(data.id)
}
})
@ -302,6 +326,7 @@ export default function PdfArticleContainer(
PSPDFKit.Annotations.toSerializableObject(annotation)
if (overlapping.size === 0) {
const positionPercent = positionPercentForAnnotation(annotation)
const result = await createHighlightMutation({
id: id,
shortId: shortId,
@ -310,6 +335,8 @@ export default function PdfArticleContainer(
prefix: surroundingText.prefix,
suffix: surroundingText.suffix,
patch: JSON.stringify(serialized),
highlightPositionPercent: positionPercent * 100,
highlightPositionAnchorIndex: annotation.pageIndex,
})
if (result) {
highlightsRef.current.push(result)
@ -344,6 +371,7 @@ export default function PdfArticleContainer(
const mergedIds = overlapping.map(
(ha) => (ha.customData?.omnivoreHighlight as Highlight).id
)
const positionPercent = positionPercentForAnnotation(annotation)
const result = await mergeHighlightMutation({
quote,
id,
@ -353,6 +381,8 @@ export default function PdfArticleContainer(
suffix: surroundingText.suffix,
articleId: props.article.id,
overlapHighlightIdList: mergedIds.toArray(),
highlightPositionPercent: positionPercent * 100,
highlightPositionAnchorIndex: annotation.pageIndex,
})
if (result) {
highlightsRef.current.push(result)
@ -380,6 +410,35 @@ export default function PdfArticleContainer(
)
})()
document.addEventListener('deleteHighlightbyId', async (event) => {
const annotationId = (event as CustomEvent).detail as string
for (let pageIdx = 0; pageIdx < instance.totalPageCount; pageIdx++) {
const annotations = await instance.getAnnotations(pageIdx)
for (let annIdx = 0; annIdx < annotations.size; annIdx++) {
const annotation = annotations.get(annIdx)
if (
annotation &&
annotation.customData &&
annotation.customData.omnivoreHighlight &&
(annotation.customData.omnivoreHighlight as Highlight).id ==
annotationId
) {
await instance.delete(annotation)
await deleteHighlightMutation(annotationId)
const highlightIdx = highlightsRef.current.findIndex((value) => {
return value.id == annotationId
})
if (highlightIdx > -1) {
highlightsRef.current.splice(highlightIdx, 1)
}
// This is needed to force the notebook to reload the highlights
setNotebookKey(uuidv4())
}
}
}
})
return () => {
PSPDFKit && container && PSPDFKit.unload(container)
}
@ -426,10 +485,17 @@ export default function PdfArticleContainer(
)}
{props.showHighlightsModal && (
<NotebookModal
key={notebookKey}
highlights={highlightsRef.current}
onOpenChange={() => props.setShowHighlightsModal(false)}
/* eslint-disable @typescript-eslint/no-empty-function */
updateHighlight={() => {}}
deleteHighlightAction={(highlightId: string) => {
const event = new CustomEvent('deleteHighlightbyId', {
detail: highlightId,
})
document.dispatchEvent(event)
}}
/>
)}
</Box>

View file

@ -10,6 +10,8 @@ export type CreateHighlightInput = {
shortId: string
patch: string
articleId: string
highlightPositionPercent?: number
highlightPositionAnchorIndex?: number
}
type CreateHighlightOutput = {

View file

@ -12,6 +12,8 @@ export type MergeHighlightInput = {
suffix?: string
annotation?: string
overlapHighlightIdList: string[]
highlightPositionPercent?: number
highlightPositionAnchorIndex?: number
}
export type MergeHighlightOutput = {