mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2026-08-07 07:14:49 +00:00
refactor(frameCommunication): align Editor- and Renderer Handler
Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
committed by
Philip Molares
parent
5b7fa9aaba
commit
17c7ca48d7
+1
-3
@@ -27,9 +27,7 @@ export const useForceRenderPageUrlOnIframeLoadCallback = (
|
||||
const forcedUrl = useMemo(() => {
|
||||
const renderUrl = new URL(rendererBaseUrl)
|
||||
renderUrl.pathname += 'render'
|
||||
if (iframeCommunicator !== undefined) {
|
||||
renderUrl.searchParams.set('uuid', iframeCommunicator.getUuid())
|
||||
}
|
||||
renderUrl.searchParams.set('uuid', iframeCommunicator.getUuid())
|
||||
return renderUrl.toString()
|
||||
}, [iframeCommunicator, rendererBaseUrl])
|
||||
const redirectionInProgress = useRef<boolean>(false)
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ export const useSendFragmentToRenderer = (rendererReady: boolean): void => {
|
||||
const iframeCommunicator = useEditorToRendererCommunicator()
|
||||
|
||||
useEffect(() => {
|
||||
if (!rendererReady || !iframeCommunicator) {
|
||||
if (!rendererReady) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -12,12 +12,7 @@ import type { ScrollProps } from '../../editor-page/synced-scroll/scroll-props'
|
||||
import { useExtensionEventEmitter } from '../../markdown-renderer/hooks/use-extension-event-emitter'
|
||||
import type { CommonMarkdownRendererProps } from '../../render-page/renderers/common-markdown-renderer-props'
|
||||
import { useEditorReceiveHandler } from '../../render-page/window-post-message-communicator/hooks/use-editor-receive-handler'
|
||||
import type {
|
||||
ExtensionEvent,
|
||||
OnHeightChangeMessage,
|
||||
RendererType,
|
||||
SetScrollStateMessage
|
||||
} from '../../render-page/window-post-message-communicator/rendering-message'
|
||||
import type { RendererType } from '../../render-page/window-post-message-communicator/rendering-message'
|
||||
import { CommunicationMessageType } from '../../render-page/window-post-message-communicator/rendering-message'
|
||||
import { WaitSpinner } from '../wait-spinner/wait-spinner'
|
||||
import { useEffectOnRenderTypeChange } from './hooks/use-effect-on-render-type-change'
|
||||
@@ -67,7 +62,7 @@ export const RendererIframe: React.FC<RendererIframeProps> = ({
|
||||
const [rendererReady, setRendererReady] = useState<boolean>(false)
|
||||
const frameReference = useRef<HTMLIFrameElement>(null)
|
||||
const iframeCommunicator = useEditorToRendererCommunicator()
|
||||
const log = useMemo(() => new Logger(`RendererIframe[${iframeCommunicator?.getUuid()}]`), [iframeCommunicator])
|
||||
const log = useMemo(() => new Logger(`RendererIframe[${iframeCommunicator.getUuid()}]`), [iframeCommunicator])
|
||||
|
||||
const resetRendererReady = useCallback(() => {
|
||||
log.debug('Reset render status')
|
||||
@@ -98,7 +93,7 @@ export const RendererIframe: React.FC<RendererIframeProps> = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (!rendererReady) {
|
||||
iframeCommunicator?.unsetMessageTarget()
|
||||
iframeCommunicator.unsetMessageTarget()
|
||||
}
|
||||
}, [iframeCommunicator, rendererReady])
|
||||
|
||||
@@ -111,22 +106,19 @@ export const RendererIframe: React.FC<RendererIframeProps> = ({
|
||||
useEditorReceiveHandler(
|
||||
CommunicationMessageType.EXTENSION_EVENT,
|
||||
useMemo(() => {
|
||||
return eventEmitter === undefined
|
||||
? null
|
||||
: (values: ExtensionEvent) => eventEmitter.emit(values.eventName, values.payload)
|
||||
return eventEmitter === undefined ? null : ({ eventName, payload }) => eventEmitter.emit(eventName, payload)
|
||||
}, [eventEmitter])
|
||||
)
|
||||
|
||||
useEditorReceiveHandler(
|
||||
CommunicationMessageType.ON_HEIGHT_CHANGE,
|
||||
useCallback(
|
||||
(values: OnHeightChangeMessage) => {
|
||||
useMemo(() => {
|
||||
return ({ height }) => {
|
||||
if (adaptFrameHeightToContent) {
|
||||
setFrameHeight?.(values.height)
|
||||
setFrameHeight?.(height)
|
||||
}
|
||||
},
|
||||
[adaptFrameHeightToContent]
|
||||
)
|
||||
}
|
||||
}, [adaptFrameHeightToContent])
|
||||
)
|
||||
|
||||
useEditorReceiveHandler(
|
||||
@@ -142,9 +134,9 @@ export const RendererIframe: React.FC<RendererIframeProps> = ({
|
||||
log.error('Load triggered without content window')
|
||||
return
|
||||
}
|
||||
iframeCommunicator?.setMessageTarget(otherWindow)
|
||||
iframeCommunicator?.enableCommunication()
|
||||
iframeCommunicator?.sendMessageToOtherSide({
|
||||
iframeCommunicator.setMessageTarget(otherWindow)
|
||||
iframeCommunicator.enableCommunication()
|
||||
iframeCommunicator.sendMessageToOtherSide({
|
||||
type: CommunicationMessageType.SET_BASE_CONFIGURATION,
|
||||
baseConfiguration: {
|
||||
baseUrl: window.location.toString(),
|
||||
@@ -163,12 +155,20 @@ export const RendererIframe: React.FC<RendererIframeProps> = ({
|
||||
useSendScrollState(scrollState ?? null, rendererReady)
|
||||
useEditorReceiveHandler(
|
||||
CommunicationMessageType.SET_SCROLL_STATE,
|
||||
useCallback((values: SetScrollStateMessage) => onScroll?.(values.scrollState), [onScroll])
|
||||
useMemo(() => {
|
||||
return ({ scrollState }) => onScroll?.(scrollState)
|
||||
}, [onScroll])
|
||||
)
|
||||
useEditorReceiveHandler(
|
||||
CommunicationMessageType.ENABLE_RENDERER_SCROLL_SOURCE,
|
||||
useCallback(() => onMakeScrollSource?.(), [onMakeScrollSource])
|
||||
)
|
||||
useEditorReceiveHandler(
|
||||
CommunicationMessageType.SET_URL_HASH,
|
||||
useMemo(() => {
|
||||
return ({ hash }) => (window.location.hash = hash)
|
||||
}, [])
|
||||
)
|
||||
|
||||
const frameClassNames = useMemo(
|
||||
() => concatCssClasses({ 'd-none': !rendererReady && showWaitSpinner }, 'border-0', styles.frame, frameClasses),
|
||||
|
||||
+2
-5
@@ -10,9 +10,7 @@ import { EditorToRendererCommunicator } from '../../render-page/window-post-mess
|
||||
import type { PropsWithChildren } from 'react'
|
||||
import React, { createContext, useContext, useEffect, useMemo } from 'react'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import { Logger } from '../../../utils/logger'
|
||||
|
||||
const logger = new Logger('EditorToRendererCommunicator')
|
||||
const EditorToRendererCommunicatorContext = createContext<EditorToRendererCommunicator | undefined>(undefined)
|
||||
|
||||
/**
|
||||
@@ -21,11 +19,10 @@ const EditorToRendererCommunicatorContext = createContext<EditorToRendererCommun
|
||||
* @return the received communicator
|
||||
* @throws {Error} if no communicator was received
|
||||
*/
|
||||
export const useEditorToRendererCommunicator = (): EditorToRendererCommunicator | undefined => {
|
||||
export const useEditorToRendererCommunicator = (): EditorToRendererCommunicator => {
|
||||
const communicatorFromContext = useContext(EditorToRendererCommunicatorContext)
|
||||
if (!communicatorFromContext) {
|
||||
logger.error('No editor-to-renderer-iframe-communicator received. Did you forget to use the provider component?')
|
||||
return undefined
|
||||
throw new Error('No editor-to-renderer-iframe-communicator received. Did you forget to use the provider component?')
|
||||
}
|
||||
return communicatorFromContext
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ const RendererToEditorCommunicatorContext = createContext<RendererToEditorCommun
|
||||
* @return the received communicator
|
||||
* @throws {Error} if no communicator was received
|
||||
*/
|
||||
export const useRendererToEditorCommunicator: () => RendererToEditorCommunicator = () => {
|
||||
export const useRendererToEditorCommunicator = (): RendererToEditorCommunicator => {
|
||||
const communicatorFromContext = useContext(RendererToEditorCommunicatorContext)
|
||||
if (!communicatorFromContext) {
|
||||
throw new Error('No renderer-to-editor-iframe-communicator received. Did you forget to use the provider component?')
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ export const NoteInfoLineWordCount: React.FC<NoteInfoLineWordCountProps> = ({ vi
|
||||
const rendererReady = useApplicationState((state) => state.rendererStatus.rendererReady)
|
||||
useEffect(() => {
|
||||
if (rendererReady && visible) {
|
||||
editorToRendererCommunicator?.sendMessageToOtherSide({ type: CommunicationMessageType.GET_WORD_COUNT })
|
||||
editorToRendererCommunicator.sendMessageToOtherSide({ type: CommunicationMessageType.GET_WORD_COUNT })
|
||||
}
|
||||
}, [editorToRendererCommunicator, rendererReady, visible])
|
||||
|
||||
|
||||
@@ -28,13 +28,13 @@ export const usePrintIframe = (): (() => void) => {
|
||||
if (!iframe || !iframe.contentWindow) {
|
||||
return
|
||||
}
|
||||
iframeCommunicator?.sendMessageToOtherSide({
|
||||
iframeCommunicator.sendMessageToOtherSide({
|
||||
type: CommunicationMessageType.SET_PRINT_MODE,
|
||||
printMode: true
|
||||
})
|
||||
setTimeout(() => {
|
||||
iframe.contentWindow?.print()
|
||||
iframeCommunicator?.sendMessageToOtherSide({
|
||||
iframeCommunicator.sendMessageToOtherSide({
|
||||
type: CommunicationMessageType.SET_PRINT_MODE,
|
||||
printMode: false
|
||||
})
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
import type { AllHTMLAttributes } from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useRendererToEditorCommunicator } from '../../../editor-page/render-context/renderer-to-editor-communicator-context-provider'
|
||||
import { CommunicationMessageType } from '../../../render-page/window-post-message-communicator/rendering-message'
|
||||
|
||||
export interface JumpAnchorProps extends AllHTMLAttributes<HTMLAnchorElement> {
|
||||
jumpTargetId: string
|
||||
@@ -18,8 +20,13 @@ export interface JumpAnchorProps extends AllHTMLAttributes<HTMLAnchorElement> {
|
||||
* @param props Additional props directly given to the link
|
||||
*/
|
||||
export const JumpAnchor: React.FC<JumpAnchorProps> = ({ jumpTargetId, children, ...props }) => {
|
||||
const iframeCommunicator = useRendererToEditorCommunicator()
|
||||
const jumpToTargetId = useCallback(
|
||||
(event: React.MouseEvent<HTMLElement, MouseEvent>): void => {
|
||||
iframeCommunicator.sendMessageToOtherSide({
|
||||
type: CommunicationMessageType.SET_URL_HASH,
|
||||
hash: jumpTargetId
|
||||
})
|
||||
const intoViewElement = document.getElementById(jumpTargetId)
|
||||
const scrollElement = document.querySelector('[data-scroll-element]')
|
||||
if (!intoViewElement || !scrollElement) {
|
||||
@@ -30,7 +37,7 @@ export const JumpAnchor: React.FC<JumpAnchorProps> = ({ jumpTargetId, children,
|
||||
scrollElement.scrollTo({ behavior: 'smooth', top: intoViewElement.offsetTop })
|
||||
event.preventDefault()
|
||||
},
|
||||
[jumpTargetId]
|
||||
[iframeCommunicator, jumpTargetId]
|
||||
)
|
||||
|
||||
return (
|
||||
|
||||
@@ -11,8 +11,12 @@ import { DocumentMarkdownRenderer } from './renderers/document/document-markdown
|
||||
import { SimpleMarkdownRenderer } from './renderers/simple/simple-markdown-renderer'
|
||||
import { SlideshowMarkdownRenderer } from './renderers/slideshow/slideshow-markdown-renderer'
|
||||
import { useRendererReceiveHandler } from './window-post-message-communicator/hooks/use-renderer-receive-handler'
|
||||
import type { BaseConfiguration } from './window-post-message-communicator/rendering-message'
|
||||
import { CommunicationMessageType, RendererType } from './window-post-message-communicator/rendering-message'
|
||||
import type {
|
||||
BaseConfiguration} from './window-post-message-communicator/rendering-message';
|
||||
import {
|
||||
CommunicationMessageType,
|
||||
RendererType
|
||||
} from './window-post-message-communicator/rendering-message'
|
||||
import { countWords } from './word-counter'
|
||||
import type { RevealOptions } from 'reveal.js'
|
||||
import { EventEmitter2 } from 'eventemitter2'
|
||||
|
||||
+11
-5
@@ -8,22 +8,28 @@ import type { CommunicationMessages, RendererToEditorMessageType } from '../rend
|
||||
import type { Handler } from '../window-post-message-communicator'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
type EditorMessageHandler<MESSAGE_TYPE extends RendererToEditorMessageType> = Handler<
|
||||
CommunicationMessages,
|
||||
MESSAGE_TYPE
|
||||
> | null
|
||||
|
||||
|
||||
/**
|
||||
* Sets the handler for the given message type in the current editor to renderer communicator.
|
||||
*
|
||||
* @param messageType The message type that should be used to listen to.
|
||||
* @param handler The handler that should be called if a message with the given message type was received.
|
||||
*/
|
||||
export const useEditorReceiveHandler = <R extends RendererToEditorMessageType>(
|
||||
messageType: R,
|
||||
handler: Handler<CommunicationMessages, R> | null
|
||||
export const useEditorReceiveHandler = <MESSAGE_TYPE extends RendererToEditorMessageType>(
|
||||
messageType: MESSAGE_TYPE,
|
||||
handler: EditorMessageHandler<MESSAGE_TYPE>,
|
||||
): void => {
|
||||
const editorToRendererCommunicator = useEditorToRendererCommunicator()
|
||||
useEffect(() => {
|
||||
if (!handler) {
|
||||
return
|
||||
}
|
||||
editorToRendererCommunicator?.on(messageType, handler)
|
||||
return () => editorToRendererCommunicator?.off(messageType, handler)
|
||||
editorToRendererCommunicator.on(messageType, handler)
|
||||
return () => editorToRendererCommunicator.off(messageType, handler)
|
||||
}, [editorToRendererCommunicator, handler, messageType])
|
||||
}
|
||||
|
||||
+9
-6
@@ -8,7 +8,7 @@ import type { CommunicationMessages, EditorToRendererMessageType } from '../rend
|
||||
import type { Handler } from '../window-post-message-communicator'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
export type CommunicationMessageHandler<MESSAGE_TYPE extends EditorToRendererMessageType> = Handler<
|
||||
type RendererMessageHandler<MESSAGE_TYPE extends EditorToRendererMessageType> = Handler<
|
||||
CommunicationMessages,
|
||||
MESSAGE_TYPE
|
||||
>
|
||||
@@ -21,11 +21,14 @@ export type CommunicationMessageHandler<MESSAGE_TYPE extends EditorToRendererMes
|
||||
*/
|
||||
export const useRendererReceiveHandler = <MESSAGE_TYPE extends EditorToRendererMessageType>(
|
||||
messageType: MESSAGE_TYPE,
|
||||
handler: CommunicationMessageHandler<MESSAGE_TYPE>
|
||||
handler: RendererMessageHandler<MESSAGE_TYPE>,
|
||||
): void => {
|
||||
const editorToRendererCommunicator = useRendererToEditorCommunicator()
|
||||
const rendererToEditorCommunicator = useRendererToEditorCommunicator()
|
||||
useEffect(() => {
|
||||
editorToRendererCommunicator.on(messageType, handler)
|
||||
return () => editorToRendererCommunicator.off(messageType, handler)
|
||||
}, [editorToRendererCommunicator, handler, messageType])
|
||||
if (!handler) {
|
||||
return
|
||||
}
|
||||
rendererToEditorCommunicator.on(messageType, handler)
|
||||
return () => rendererToEditorCommunicator.off(messageType, handler)
|
||||
}, [rendererToEditorCommunicator, handler, messageType])
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ export const useSendToRenderer = (
|
||||
|
||||
useEffect(() => {
|
||||
if (message && rendererReady) {
|
||||
iframeCommunicator?.sendMessageToOtherSide(message)
|
||||
iframeCommunicator.sendMessageToOtherSide(message)
|
||||
}
|
||||
}, [iframeCommunicator, message, rendererReady])
|
||||
}
|
||||
|
||||
+9
-1
@@ -22,7 +22,8 @@ export enum CommunicationMessageType {
|
||||
IMAGE_UPLOAD = 'IMAGE_UPLOAD',
|
||||
EXTENSION_EVENT = 'EXTENSION_EVENT',
|
||||
SET_PRINT_MODE = 'SET_PRINT_MODE',
|
||||
SCROLL_TO_ELEMENT = 'SCROLL_TO_ELEMENT'
|
||||
SCROLL_TO_ELEMENT = 'SCROLL_TO_ELEMENT',
|
||||
SET_URL_HASH = 'SET_URL_HASH'
|
||||
}
|
||||
|
||||
export interface NoPayloadMessage<TYPE extends CommunicationMessageType> {
|
||||
@@ -99,6 +100,11 @@ export interface ScrollToElementMessage {
|
||||
elementId: string
|
||||
}
|
||||
|
||||
export interface SetUrlHashMessage {
|
||||
type: CommunicationMessageType.SET_URL_HASH
|
||||
hash: string
|
||||
}
|
||||
|
||||
export type CommunicationMessages =
|
||||
| NoPayloadMessage<CommunicationMessageType.RENDERER_READY>
|
||||
| NoPayloadMessage<CommunicationMessageType.ENABLE_RENDERER_SCROLL_SOURCE>
|
||||
@@ -115,6 +121,7 @@ export type CommunicationMessages =
|
||||
| ExtensionEvent
|
||||
| SetPrintModeConfigurationMessage
|
||||
| ScrollToElementMessage
|
||||
| SetUrlHashMessage
|
||||
|
||||
export type EditorToRendererMessageType =
|
||||
| CommunicationMessageType.SET_MARKDOWN_CONTENT
|
||||
@@ -135,6 +142,7 @@ export type RendererToEditorMessageType =
|
||||
| CommunicationMessageType.ON_WORD_COUNT_CALCULATED
|
||||
| CommunicationMessageType.IMAGE_UPLOAD
|
||||
| CommunicationMessageType.EXTENSION_EVENT
|
||||
| CommunicationMessageType.SET_URL_HASH
|
||||
|
||||
export enum RendererType {
|
||||
DOCUMENT = 'document',
|
||||
|
||||
Reference in New Issue
Block a user