mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-14 15:14:56 -04:00

* Add application state hook Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de> * Add docs Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
128 lines
4.6 KiB
TypeScript
128 lines
4.6 KiB
TypeScript
/*
|
|
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
*/
|
|
import equal from 'fast-deep-equal'
|
|
import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react'
|
|
import { useApplicationState } from '../../../hooks/common/use-application-state'
|
|
import { useIsDarkModeActivated } from '../../../hooks/common/use-is-dark-mode-activated'
|
|
import { isTestMode } from '../../../utils/test-modes'
|
|
import { RendererProps } from '../../render-page/markdown-document'
|
|
import { ImageDetails, RendererType } from '../../render-page/rendering-message'
|
|
import { useContextOrStandaloneIframeCommunicator } from '../render-context/iframe-communicator-context-provider'
|
|
import { ScrollState } from '../synced-scroll/scroll-props'
|
|
import { useOnIframeLoad } from './hooks/use-on-iframe-load'
|
|
import { ShowOnPropChangeImageLightbox } from './show-on-prop-change-image-lightbox'
|
|
|
|
export interface RenderIframeProps extends RendererProps {
|
|
onRendererReadyChange?: (rendererReady: boolean) => void
|
|
rendererType: RendererType
|
|
forcedDarkMode?: boolean
|
|
frameClasses?: string
|
|
}
|
|
|
|
export const RenderIframe: React.FC<RenderIframeProps> = ({
|
|
markdownContent,
|
|
onTaskCheckedChange,
|
|
onFrontmatterChange,
|
|
scrollState,
|
|
onFirstHeadingChange,
|
|
onScroll,
|
|
onMakeScrollSource,
|
|
frameClasses,
|
|
onRendererReadyChange,
|
|
rendererType,
|
|
forcedDarkMode
|
|
}) => {
|
|
const savedDarkMode = useIsDarkModeActivated()
|
|
const darkMode = forcedDarkMode ?? savedDarkMode
|
|
const [rendererReady, setRendererReady] = useState<boolean>(false)
|
|
const [lightboxDetails, setLightboxDetails] = useState<ImageDetails | undefined>(undefined)
|
|
|
|
const frameReference = useRef<HTMLIFrameElement>(null)
|
|
const rendererOrigin = useApplicationState((state) => state.config.iframeCommunication.rendererOrigin)
|
|
const renderPageUrl = `${rendererOrigin}render`
|
|
const resetRendererReady = useCallback(() => setRendererReady(false), [])
|
|
const iframeCommunicator = useContextOrStandaloneIframeCommunicator()
|
|
const onIframeLoad = useOnIframeLoad(
|
|
frameReference,
|
|
iframeCommunicator,
|
|
rendererOrigin,
|
|
renderPageUrl,
|
|
resetRendererReady
|
|
)
|
|
const [frameHeight, setFrameHeight] = useState<number>(0)
|
|
|
|
useEffect(() => {
|
|
onRendererReadyChange?.(rendererReady)
|
|
}, [onRendererReadyChange, rendererReady])
|
|
|
|
useEffect(() => () => iframeCommunicator.unregisterEventListener(), [iframeCommunicator])
|
|
useEffect(
|
|
() => iframeCommunicator.onFirstHeadingChange(onFirstHeadingChange),
|
|
[iframeCommunicator, onFirstHeadingChange]
|
|
)
|
|
useEffect(
|
|
() => iframeCommunicator.onFrontmatterChange(onFrontmatterChange),
|
|
[iframeCommunicator, onFrontmatterChange]
|
|
)
|
|
useEffect(() => iframeCommunicator.onSetScrollState(onScroll), [iframeCommunicator, onScroll])
|
|
useEffect(
|
|
() => iframeCommunicator.onSetScrollSourceToRenderer(onMakeScrollSource),
|
|
[iframeCommunicator, onMakeScrollSource]
|
|
)
|
|
useEffect(
|
|
() => iframeCommunicator.onTaskCheckboxChange(onTaskCheckedChange),
|
|
[iframeCommunicator, onTaskCheckedChange]
|
|
)
|
|
useEffect(() => iframeCommunicator.onImageClicked(setLightboxDetails), [iframeCommunicator])
|
|
useEffect(
|
|
() =>
|
|
iframeCommunicator.onRendererReady(() => {
|
|
iframeCommunicator.sendSetBaseConfiguration({
|
|
baseUrl: window.location.toString(),
|
|
rendererType
|
|
})
|
|
setRendererReady(true)
|
|
}),
|
|
[darkMode, rendererType, iframeCommunicator, rendererReady, scrollState]
|
|
)
|
|
useEffect(() => iframeCommunicator.onHeightChange(setFrameHeight), [iframeCommunicator])
|
|
|
|
useEffect(() => {
|
|
if (rendererReady) {
|
|
iframeCommunicator.sendSetDarkmode(darkMode)
|
|
}
|
|
}, [darkMode, iframeCommunicator, rendererReady])
|
|
|
|
const oldScrollState = useRef<ScrollState | undefined>(undefined)
|
|
useEffect(() => {
|
|
if (rendererReady && !equal(scrollState, oldScrollState.current)) {
|
|
oldScrollState.current = scrollState
|
|
iframeCommunicator.sendScrollState(scrollState)
|
|
}
|
|
}, [iframeCommunicator, rendererReady, scrollState])
|
|
|
|
useEffect(() => {
|
|
if (rendererReady) {
|
|
iframeCommunicator.sendSetMarkdownContent(markdownContent)
|
|
}
|
|
}, [iframeCommunicator, markdownContent, rendererReady])
|
|
|
|
return (
|
|
<Fragment>
|
|
<ShowOnPropChangeImageLightbox details={lightboxDetails} />
|
|
<iframe
|
|
style={{ height: `${frameHeight}px` }}
|
|
data-cy={'documentIframe'}
|
|
onLoad={onIframeLoad}
|
|
title='render'
|
|
src={renderPageUrl}
|
|
{...(isTestMode() ? {} : { sandbox: 'allow-downloads allow-same-origin allow-scripts allow-popups' })}
|
|
ref={frameReference}
|
|
className={`border-0 ${frameClasses ?? ''}`}
|
|
/>
|
|
</Fragment>
|
|
)
|
|
}
|