diff --git a/src/components/editor-page/render-context/iframe-editor-to-renderer-communicator-context-provider.tsx b/src/components/editor-page/render-context/iframe-editor-to-renderer-communicator-context-provider.tsx index ee17f65bf..ab6255363 100644 --- a/src/components/editor-page/render-context/iframe-editor-to-renderer-communicator-context-provider.tsx +++ b/src/components/editor-page/render-context/iframe-editor-to-renderer-communicator-context-provider.tsx @@ -4,15 +4,26 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import React, { useContext, useMemo } from 'react' +import React, { createContext, useContext, useMemo } from 'react' import { IframeEditorToRendererCommunicator } from '../../render-page/iframe-editor-to-renderer-communicator' -const IFrameEditorToRendererCommunicatorContext = React.createContext( +const IFrameEditorToRendererCommunicatorContext = createContext( undefined ) -export const useIFrameEditorToRendererCommunicator: () => IframeEditorToRendererCommunicator | undefined = () => - useContext(IFrameEditorToRendererCommunicatorContext) +/** + * Provides the {@link IframeEditorToRendererCommunicator editor to renderer iframe communicator} that is set by a {@link IframeEditorToRendererCommunicatorContextProvider context provider}. + * + * @return the received communicator + * @throws Error if no communicator was received + */ +export const useIFrameEditorToRendererCommunicator: () => IframeEditorToRendererCommunicator = () => { + const communicatorFromContext = useContext(IFrameEditorToRendererCommunicatorContext) + if (!communicatorFromContext) { + throw new Error('No editor-to-renderer-iframe-communicator received. Did you forget to use the provider component?') + } + return communicatorFromContext +} export const IframeEditorToRendererCommunicatorContextProvider: React.FC = ({ children }) => { const currentIFrameCommunicator = useMemo( diff --git a/src/components/editor-page/render-context/iframe-renderer-to-editor-communicator-context-provider.tsx b/src/components/editor-page/render-context/iframe-renderer-to-editor-communicator-context-provider.tsx index 5da2ecaee..0033ab55e 100644 --- a/src/components/editor-page/render-context/iframe-renderer-to-editor-communicator-context-provider.tsx +++ b/src/components/editor-page/render-context/iframe-renderer-to-editor-communicator-context-provider.tsx @@ -13,8 +13,19 @@ const IFrameRendererToEditorCommunicatorContext = createContext IframeRendererToEditorCommunicator | undefined = () => - useContext(IFrameRendererToEditorCommunicatorContext) +/** + * Provides the {@link IframeRendererToEditorCommunicator renderer to editor iframe communicator} that is set by a {@link IframeRendererToEditorCommunicatorContextProvider context provider}. + * + * @return the received communicator + * @throws Error if no communicator was received + */ +export const useIFrameRendererToEditorCommunicator: () => IframeRendererToEditorCommunicator = () => { + const communicatorFromContext = useContext(IFrameRendererToEditorCommunicatorContext) + if (!communicatorFromContext) { + throw new Error('No renderer-to-editor-iframe-communicator received. Did you forget to use the provider component?') + } + return communicatorFromContext +} export const IframeRendererToEditorCommunicatorContextProvider: React.FC = ({ children }) => { const editorOrigin = useSelector((state: ApplicationState) => state.config.iframeCommunication.editorOrigin) diff --git a/src/components/editor-page/renderer-pane/hooks/use-on-iframe-load.ts b/src/components/editor-page/renderer-pane/hooks/use-on-iframe-load.ts index 0db6cc404..2af724262 100644 --- a/src/components/editor-page/renderer-pane/hooks/use-on-iframe-load.ts +++ b/src/components/editor-page/renderer-pane/hooks/use-on-iframe-load.ts @@ -9,7 +9,7 @@ import { IframeEditorToRendererCommunicator } from '../../../render-page/iframe- export const useOnIframeLoad = ( frameReference: RefObject, - iframeCommunicator: IframeEditorToRendererCommunicator | undefined, + iframeCommunicator: IframeEditorToRendererCommunicator, rendererOrigin: string, renderPageUrl: string, onNavigateAway: () => void @@ -19,12 +19,12 @@ export const useOnIframeLoad = ( return useCallback(() => { const frame = frameReference.current if (!frame || !frame.contentWindow) { - iframeCommunicator?.unsetOtherSide() + iframeCommunicator.unsetOtherSide() return } if (sendToRenderPage.current) { - iframeCommunicator?.setOtherSide(frame.contentWindow, rendererOrigin) + iframeCommunicator.setOtherSide(frame.contentWindow, rendererOrigin) sendToRenderPage.current = false return } else { diff --git a/src/components/editor-page/renderer-pane/render-iframe.tsx b/src/components/editor-page/renderer-pane/render-iframe.tsx index 079339a08..d1dd5da3a 100644 --- a/src/components/editor-page/renderer-pane/render-iframe.tsx +++ b/src/components/editor-page/renderer-pane/render-iframe.tsx @@ -58,39 +58,39 @@ export const RenderIframe: React.FC = ({ onRendererReadyChange?.(rendererReady) }, [onRendererReadyChange, rendererReady]) - useEffect(() => () => iframeCommunicator?.unregisterEventListener(), [iframeCommunicator]) + useEffect(() => () => iframeCommunicator.unregisterEventListener(), [iframeCommunicator]) useEffect( - () => iframeCommunicator?.onFirstHeadingChange(onFirstHeadingChange), + () => iframeCommunicator.onFirstHeadingChange(onFirstHeadingChange), [iframeCommunicator, onFirstHeadingChange] ) useEffect( - () => iframeCommunicator?.onFrontmatterChange(onFrontmatterChange), + () => iframeCommunicator.onFrontmatterChange(onFrontmatterChange), [iframeCommunicator, onFrontmatterChange] ) - useEffect(() => iframeCommunicator?.onSetScrollState(onScroll), [iframeCommunicator, onScroll]) + useEffect(() => iframeCommunicator.onSetScrollState(onScroll), [iframeCommunicator, onScroll]) useEffect( - () => iframeCommunicator?.onSetScrollSourceToRenderer(onMakeScrollSource), + () => iframeCommunicator.onSetScrollSourceToRenderer(onMakeScrollSource), [iframeCommunicator, onMakeScrollSource] ) useEffect( - () => iframeCommunicator?.onTaskCheckboxChange(onTaskCheckedChange), + () => iframeCommunicator.onTaskCheckboxChange(onTaskCheckedChange), [iframeCommunicator, onTaskCheckedChange] ) - useEffect(() => iframeCommunicator?.onImageClicked(setLightboxDetails), [iframeCommunicator]) + useEffect(() => iframeCommunicator.onImageClicked(setLightboxDetails), [iframeCommunicator]) useEffect(() => { - iframeCommunicator?.onRendererReady(() => { - iframeCommunicator?.sendSetBaseConfiguration({ + iframeCommunicator.onRendererReady(() => { + iframeCommunicator.sendSetBaseConfiguration({ baseUrl: window.location.toString(), rendererType }) setRendererReady(true) }) }, [darkMode, rendererType, iframeCommunicator, rendererReady, scrollState]) - useEffect(() => iframeCommunicator?.onHeightChange(setFrameHeight), [iframeCommunicator]) + useEffect(() => iframeCommunicator.onHeightChange(setFrameHeight), [iframeCommunicator]) useEffect(() => { if (rendererReady) { - iframeCommunicator?.sendSetDarkmode(darkMode) + iframeCommunicator.sendSetDarkmode(darkMode) } }, [darkMode, iframeCommunicator, rendererReady]) @@ -98,13 +98,13 @@ export const RenderIframe: React.FC = ({ useEffect(() => { if (rendererReady && !equal(scrollState, oldScrollState.current)) { oldScrollState.current = scrollState - iframeCommunicator?.sendScrollState(scrollState) + iframeCommunicator.sendScrollState(scrollState) } }, [iframeCommunicator, rendererReady, scrollState]) useEffect(() => { if (rendererReady) { - iframeCommunicator?.sendSetMarkdownContent(markdownContent) + iframeCommunicator.sendSetMarkdownContent(markdownContent) } }, [iframeCommunicator, markdownContent, rendererReady]) diff --git a/src/components/render-page/hooks/use-image-click-handler.ts b/src/components/render-page/hooks/use-image-click-handler.ts index 7cbb0c243..fdc072dac 100644 --- a/src/components/render-page/hooks/use-image-click-handler.ts +++ b/src/components/render-page/hooks/use-image-click-handler.ts @@ -8,16 +8,14 @@ import React, { useCallback } from 'react' import { ImageClickHandler } from '../../markdown-renderer/replace-components/image/image-replacer' import { IframeRendererToEditorCommunicator } from '../iframe-renderer-to-editor-communicator' -export const useImageClickHandler = ( - iframeCommunicator: IframeRendererToEditorCommunicator | undefined -): ImageClickHandler => { +export const useImageClickHandler = (iframeCommunicator: IframeRendererToEditorCommunicator): ImageClickHandler => { return useCallback( (event: React.MouseEvent) => { const image = event.target as HTMLImageElement if (image.src === '') { return } - iframeCommunicator?.sendClickedImageUrl({ + iframeCommunicator.sendClickedImageUrl({ src: image.src, alt: image.alt, title: image.title diff --git a/src/components/render-page/iframe-markdown-renderer.tsx b/src/components/render-page/iframe-markdown-renderer.tsx index 4bf7d99ec..f51f38cc7 100644 --- a/src/components/render-page/iframe-markdown-renderer.tsx +++ b/src/components/render-page/iframe-markdown-renderer.tsx @@ -26,17 +26,17 @@ export const IframeMarkdownRenderer: React.FC = () => { const countWordsInRenderedDocument = useCallback(() => { const documentContainer = document.querySelector('.markdown-body') if (!documentContainer) { - iframeCommunicator?.sendWordCountCalculated(0) + iframeCommunicator.sendWordCountCalculated(0) return } const wordCount = countWords(documentContainer) - iframeCommunicator?.sendWordCountCalculated(wordCount) + iframeCommunicator.sendWordCountCalculated(wordCount) }, [iframeCommunicator]) - useEffect(() => iframeCommunicator?.onSetBaseConfiguration(setBaseConfiguration), [iframeCommunicator]) - useEffect(() => iframeCommunicator?.onSetMarkdownContent(setMarkdownContent), [iframeCommunicator]) - useEffect(() => iframeCommunicator?.onSetDarkMode(setDarkMode), [iframeCommunicator]) - useEffect(() => iframeCommunicator?.onSetScrollState(setScrollState), [iframeCommunicator, scrollState]) + useEffect(() => iframeCommunicator.onSetBaseConfiguration(setBaseConfiguration), [iframeCommunicator]) + useEffect(() => iframeCommunicator.onSetMarkdownContent(setMarkdownContent), [iframeCommunicator]) + useEffect(() => iframeCommunicator.onSetDarkMode(setDarkMode), [iframeCommunicator]) + useEffect(() => iframeCommunicator.onSetScrollState(setScrollState), [iframeCommunicator, scrollState]) useEffect( () => iframeCommunicator?.onGetWordCount(countWordsInRenderedDocument), [iframeCommunicator, countWordsInRenderedDocument] @@ -44,33 +44,33 @@ export const IframeMarkdownRenderer: React.FC = () => { const onTaskCheckedChange = useCallback( (lineInMarkdown: number, checked: boolean) => { - iframeCommunicator?.sendTaskCheckBoxChange(lineInMarkdown, checked) + iframeCommunicator.sendTaskCheckBoxChange(lineInMarkdown, checked) }, [iframeCommunicator] ) const onFirstHeadingChange = useCallback( (firstHeading?: string) => { - iframeCommunicator?.sendFirstHeadingChanged(firstHeading) + iframeCommunicator.sendFirstHeadingChanged(firstHeading) }, [iframeCommunicator] ) const onMakeScrollSource = useCallback(() => { - iframeCommunicator?.sendSetScrollSourceToRenderer() + iframeCommunicator.sendSetScrollSourceToRenderer() }, [iframeCommunicator]) const onFrontmatterChange = useCallback( (frontmatter?: NoteFrontmatter) => { setNoteFrontmatter(frontmatter) - iframeCommunicator?.sendSetFrontmatter(frontmatter) + iframeCommunicator.sendSetFrontmatter(frontmatter) }, [iframeCommunicator] ) const onScroll = useCallback( (scrollState: ScrollState) => { - iframeCommunicator?.sendSetScrollState(scrollState) + iframeCommunicator.sendSetScrollState(scrollState) }, [iframeCommunicator] ) @@ -79,7 +79,7 @@ export const IframeMarkdownRenderer: React.FC = () => { const onHeightChange = useCallback( (height: number) => { - iframeCommunicator?.sendHeightChange(height) + iframeCommunicator.sendHeightChange(height) }, [iframeCommunicator] )