/* * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ import React, { useCallback, useRef, useState } from 'react' import type { ScrollState } from '../editor-page/synced-scroll/scroll-props' import type { BaseConfiguration } from './window-post-message-communicator/rendering-message' import { CommunicationMessageType, RendererType } from './window-post-message-communicator/rendering-message' import { setDarkMode } from '../../redux/dark-mode/methods' import type { ImageClickHandler } from '../markdown-renderer/markdown-extension/image/proxy-image-replacer' import { useImageClickHandler } from './hooks/use-image-click-handler' import { MarkdownDocument } from './markdown-document' import { countWords } from './word-counter' import { useRendererToEditorCommunicator } from '../editor-page/render-context/renderer-to-editor-communicator-context-provider' import { useRendererReceiveHandler } from './window-post-message-communicator/hooks/use-renderer-receive-handler' import { SlideshowMarkdownRenderer } from '../markdown-renderer/slideshow-markdown-renderer' import { initialState } from '../../redux/note-details/initial-state' import type { RendererFrontmatterInfo } from '../../redux/note-details/types/note-details' /** * Wraps the markdown rendering in an iframe. */ export const IframeMarkdownRenderer: React.FC = () => { const [markdownContentLines, setMarkdownContentLines] = useState([]) const [scrollState, setScrollState] = useState({ firstLineInView: 1, scrolledPercentage: 0 }) const [baseConfiguration, setBaseConfiguration] = useState(undefined) const [frontmatterInfo, setFrontmatterInfo] = useState(initialState.frontmatterRendererInfo) const communicator = useRendererToEditorCommunicator() const sendScrolling = useRef(false) useRendererReceiveHandler( CommunicationMessageType.DISABLE_RENDERER_SCROLL_SOURCE, useCallback(() => { sendScrolling.current = false }, []) ) useRendererReceiveHandler( CommunicationMessageType.SET_BASE_CONFIGURATION, useCallback((values) => setBaseConfiguration(values.baseConfiguration), []) ) useRendererReceiveHandler( CommunicationMessageType.SET_MARKDOWN_CONTENT, useCallback((values) => setMarkdownContentLines(values.content), []) ) useRendererReceiveHandler( CommunicationMessageType.SET_DARKMODE, useCallback((values) => setDarkMode(values.activated), []) ) useRendererReceiveHandler( CommunicationMessageType.SET_SCROLL_STATE, useCallback((values) => setScrollState(values.scrollState), []) ) useRendererReceiveHandler( CommunicationMessageType.SET_FRONTMATTER_INFO, useCallback((values) => setFrontmatterInfo(values.frontmatterInfo), []) ) useRendererReceiveHandler( CommunicationMessageType.GET_WORD_COUNT, useCallback(() => { const documentContainer = document.querySelector('[data-word-count-target]') communicator.sendMessageToOtherSide({ type: CommunicationMessageType.ON_WORD_COUNT_CALCULATED, words: documentContainer ? countWords(documentContainer) : 0 }) }, [communicator]) ) const onTaskCheckedChange = useCallback( (lineInMarkdown: number, checked: boolean) => { communicator.sendMessageToOtherSide({ type: CommunicationMessageType.ON_TASK_CHECKBOX_CHANGE, checked, lineInMarkdown }) }, [communicator] ) const onFirstHeadingChange = useCallback( (firstHeading?: string) => { communicator.sendMessageToOtherSide({ type: CommunicationMessageType.ON_FIRST_HEADING_CHANGE, firstHeading }) }, [communicator] ) const onMakeScrollSource = useCallback(() => { sendScrolling.current = true communicator.sendMessageToOtherSide({ type: CommunicationMessageType.ENABLE_RENDERER_SCROLL_SOURCE }) }, [communicator]) const onScroll = useCallback( (scrollState: ScrollState) => { if (!sendScrolling.current) { return } communicator.sendMessageToOtherSide({ type: CommunicationMessageType.SET_SCROLL_STATE, scrollState }) }, [communicator] ) const onImageClick: ImageClickHandler = useImageClickHandler(communicator) const onHeightChange = useCallback( (height: number) => { communicator.sendMessageToOtherSide({ type: CommunicationMessageType.ON_HEIGHT_CHANGE, height }) }, [communicator] ) if (!baseConfiguration) { return null } switch (baseConfiguration.rendererType) { case RendererType.DOCUMENT: return ( ) case RendererType.SLIDESHOW: return ( ) case RendererType.INTRO: return ( ) default: return null } }