mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #18655 from overleaf/dp-pdf-viewer-typescript
Convert PdfJsViewer component to typescript GitOrigin-RevId: 1019b947f3e6869a99495d3de7cd14ebd5007587
This commit is contained in:
parent
d652717c5a
commit
656130b2ed
2 changed files with 32 additions and 23 deletions
|
@ -1,4 +1,3 @@
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import { memo, useCallback, useEffect, useRef, useState } from 'react'
|
import { memo, useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { debounce, throttle } from 'lodash'
|
import { debounce, throttle } from 'lodash'
|
||||||
import PdfViewerControls from './pdf-viewer-controls'
|
import PdfViewerControls from './pdf-viewer-controls'
|
||||||
|
@ -17,7 +16,12 @@ import { debugConsole } from '@/utils/debugging'
|
||||||
import { usePdfPreviewContext } from '@/features/pdf-preview/components/pdf-preview-provider'
|
import { usePdfPreviewContext } from '@/features/pdf-preview/components/pdf-preview-provider'
|
||||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||||
|
|
||||||
function PdfJsViewer({ url, pdfFile }) {
|
type PdfJsViewerProps = {
|
||||||
|
url: string
|
||||||
|
pdfFile: Record<string, any>
|
||||||
|
}
|
||||||
|
|
||||||
|
function PdfJsViewer({ url, pdfFile }: PdfJsViewerProps) {
|
||||||
const { _id: projectId } = useProjectContext()
|
const { _id: projectId } = useProjectContext()
|
||||||
|
|
||||||
const { setError, firstRenderDone, highlights, position, setPosition } =
|
const { setError, firstRenderDone, highlights, position, setPosition } =
|
||||||
|
@ -40,7 +44,7 @@ function PdfJsViewer({ url, pdfFile }) {
|
||||||
const [totalPages, setTotalPages] = useState(null)
|
const [totalPages, setTotalPages] = useState(null)
|
||||||
|
|
||||||
// local state values
|
// local state values
|
||||||
const [pdfJsWrapper, setPdfJsWrapper] = useState()
|
const [pdfJsWrapper, setPdfJsWrapper] = useState<PDFJSWrapper | null>()
|
||||||
const [initialised, setInitialised] = useState(false)
|
const [initialised, setInitialised] = useState(false)
|
||||||
|
|
||||||
const handlePageChange = useCallback(
|
const handlePageChange = useCallback(
|
||||||
|
@ -84,8 +88,8 @@ function PdfJsViewer({ url, pdfFile }) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!pdfJsWrapper || !firstRenderDone) return
|
if (!pdfJsWrapper || !firstRenderDone) return
|
||||||
|
|
||||||
let timePDFFetched
|
let timePDFFetched: number
|
||||||
let timePDFRendered
|
let timePDFRendered: number
|
||||||
const submitLatencies = () => {
|
const submitLatencies = () => {
|
||||||
if (!timePDFFetched) {
|
if (!timePDFFetched) {
|
||||||
// The pagerendered event was attached after pagesinit fired. :/
|
// The pagerendered event was attached after pagesinit fired. :/
|
||||||
|
@ -164,7 +168,7 @@ function PdfJsViewer({ url, pdfFile }) {
|
||||||
setStartFetch(performance.now())
|
setStartFetch(performance.now())
|
||||||
|
|
||||||
const abortController = new AbortController()
|
const abortController = new AbortController()
|
||||||
const handleFetchError = err => {
|
const handleFetchError = (err: Error) => {
|
||||||
if (abortController.signal.aborted) return
|
if (abortController.signal.aborted) return
|
||||||
// The error is already logged at the call-site with additional context.
|
// The error is already logged at the call-site with additional context.
|
||||||
if (err instanceof pdfJsWrapper.PDFJS.MissingPDFException) {
|
if (err instanceof pdfJsWrapper.PDFJS.MissingPDFException) {
|
||||||
|
@ -192,7 +196,7 @@ function PdfJsViewer({ url, pdfFile }) {
|
||||||
|
|
||||||
// listen for scroll events
|
// listen for scroll events
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let storePositionTimer
|
let storePositionTimer: number
|
||||||
|
|
||||||
if (initialised && pdfJsWrapper) {
|
if (initialised && pdfJsWrapper) {
|
||||||
if (!pdfJsWrapper.isVisible()) {
|
if (!pdfJsWrapper.isVisible()) {
|
||||||
|
@ -233,7 +237,7 @@ function PdfJsViewer({ url, pdfFile }) {
|
||||||
// listen for double-click events
|
// listen for double-click events
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (pdfJsWrapper) {
|
if (pdfJsWrapper) {
|
||||||
const handleTextlayerrendered = textLayer => {
|
const handleTextlayerrendered = (textLayer: any) => {
|
||||||
// handle both versions for backwards-compatibility
|
// handle both versions for backwards-compatibility
|
||||||
const textLayerDiv =
|
const textLayerDiv =
|
||||||
textLayer.source.textLayerDiv ?? textLayer.source.textLayer.div
|
textLayer.source.textLayerDiv ?? textLayer.source.textLayer.div
|
||||||
|
@ -243,7 +247,7 @@ function PdfJsViewer({ url, pdfFile }) {
|
||||||
if (!pageElement.dataset.listeningForDoubleClick) {
|
if (!pageElement.dataset.listeningForDoubleClick) {
|
||||||
pageElement.dataset.listeningForDoubleClick = true
|
pageElement.dataset.listeningForDoubleClick = true
|
||||||
|
|
||||||
const doubleClickListener = event => {
|
const doubleClickListener = (event: Event) => {
|
||||||
const clickPosition = pdfJsWrapper.clickPosition(
|
const clickPosition = pdfJsWrapper.clickPosition(
|
||||||
event,
|
event,
|
||||||
pageElement,
|
pageElement,
|
||||||
|
@ -291,6 +295,10 @@ function PdfJsViewer({ url, pdfFile }) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (positionRef.current) {
|
if (positionRef.current) {
|
||||||
|
// Typescript is incorrectly inferring the type of the scale argument to
|
||||||
|
// scrollToPosition from its default value. We can remove this ignore once
|
||||||
|
// pdfJsWrapper is converted to using tyepscript.
|
||||||
|
// @ts-ignore
|
||||||
pdfJsWrapper.scrollToPosition(positionRef.current, scaleRef.current)
|
pdfJsWrapper.scrollToPosition(positionRef.current, scaleRef.current)
|
||||||
} else {
|
} else {
|
||||||
pdfJsWrapper.viewer.currentScaleValue = scaleRef.current
|
pdfJsWrapper.viewer.currentScaleValue = scaleRef.current
|
||||||
|
@ -307,8 +315,8 @@ function PdfJsViewer({ url, pdfFile }) {
|
||||||
|
|
||||||
// when highlights are created, build the highlight elements
|
// when highlights are created, build the highlight elements
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const timers = []
|
const timers: number[] = []
|
||||||
let intersectionObserver
|
let intersectionObserver: IntersectionObserver
|
||||||
|
|
||||||
if (pdfJsWrapper && highlights?.length) {
|
if (pdfJsWrapper && highlights?.length) {
|
||||||
// watch for the highlight elements to scroll into view
|
// watch for the highlight elements to scroll into view
|
||||||
|
@ -318,12 +326,14 @@ function PdfJsViewer({ url, pdfFile }) {
|
||||||
if (entry.isIntersecting) {
|
if (entry.isIntersecting) {
|
||||||
intersectionObserver.unobserve(entry.target)
|
intersectionObserver.unobserve(entry.target)
|
||||||
|
|
||||||
|
const element = entry.target as HTMLElement
|
||||||
|
|
||||||
// fade the element in and out
|
// fade the element in and out
|
||||||
entry.target.style.opacity = '0.5'
|
element.style.opacity = '0.5'
|
||||||
|
|
||||||
timers.push(
|
timers.push(
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
entry.target.style.opacity = '0'
|
element.style.opacity = '0'
|
||||||
}, 1000)
|
}, 1000)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -334,7 +344,7 @@ function PdfJsViewer({ url, pdfFile }) {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const elements = []
|
const elements: HTMLDivElement[] = []
|
||||||
|
|
||||||
for (const highlight of highlights) {
|
for (const highlight of highlights) {
|
||||||
try {
|
try {
|
||||||
|
@ -384,13 +394,13 @@ function PdfJsViewer({ url, pdfFile }) {
|
||||||
break
|
break
|
||||||
case 'zoom-in':
|
case 'zoom-in':
|
||||||
if (pdfJsWrapper) {
|
if (pdfJsWrapper) {
|
||||||
setScale(pdfJsWrapper.viewer.currentScale * 1.25)
|
setScale(`${pdfJsWrapper.viewer.currentScale * 1.25}`)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'zoom-out':
|
case 'zoom-out':
|
||||||
if (pdfJsWrapper) {
|
if (pdfJsWrapper) {
|
||||||
setScale(pdfJsWrapper.viewer.currentScale * 0.75)
|
setScale(`${pdfJsWrapper.viewer.currentScale * 0.75}`)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -499,7 +509,7 @@ function PdfJsViewer({ url, pdfFile }) {
|
||||||
>
|
>
|
||||||
<div className="pdfViewer" />
|
<div className="pdfViewer" />
|
||||||
</div>
|
</div>
|
||||||
<div className="pdfjs-controls" tabIndex="0">
|
<div className="pdfjs-controls" tabIndex={0}>
|
||||||
{hasNewPdfToolbar ? (
|
{hasNewPdfToolbar ? (
|
||||||
toolbarInfoLoaded && (
|
toolbarInfoLoaded && (
|
||||||
<PdfViewerControlsToolbar
|
<PdfViewerControlsToolbar
|
||||||
|
@ -518,11 +528,6 @@ function PdfJsViewer({ url, pdfFile }) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
PdfJsViewer.propTypes = {
|
|
||||||
url: PropTypes.string.isRequired,
|
|
||||||
pdfFile: PropTypes.object,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withErrorBoundary(memo(PdfJsViewer), () => (
|
export default withErrorBoundary(memo(PdfJsViewer), () => (
|
||||||
<PdfPreviewErrorBoundaryFallback type="pdf" />
|
<PdfPreviewErrorBoundaryFallback type="pdf" />
|
||||||
))
|
))
|
|
@ -79,7 +79,11 @@ export type CompileContext = {
|
||||||
stoppedOnFirstError: boolean
|
stoppedOnFirstError: boolean
|
||||||
uncompiled?: boolean
|
uncompiled?: boolean
|
||||||
validationIssues?: Record<string, any>
|
validationIssues?: Record<string, any>
|
||||||
firstRenderDone: () => void
|
firstRenderDone: (metrics: {
|
||||||
|
latencyFetch: number
|
||||||
|
latencyRender: number | undefined
|
||||||
|
pdfCachingMetrics: { viewerId: string }
|
||||||
|
}) => void
|
||||||
cleanupCompileResult?: () => void
|
cleanupCompileResult?: () => void
|
||||||
animateCompileDropdownArrow: boolean
|
animateCompileDropdownArrow: boolean
|
||||||
editedSinceCompileStarted: boolean
|
editedSinceCompileStarted: boolean
|
||||||
|
|
Loading…
Reference in a new issue