From 64e3513988f25da336d2cfc9a6b5d80e38d25629 Mon Sep 17 00:00:00 2001 From: Tilman Vatteroth Date: Fri, 7 Apr 2023 19:42:55 +0200 Subject: [PATCH] feat: move first heading title extraction into an app extension Signed-off-by: Tilman Vatteroth --- frontend/cypress/e2e/documentTitle.spec.ts | 2 +- .../document-read-only-page-content.tsx | 2 - .../editor-page/editor-page-content.tsx | 2 - .../renderer-pane/render-iframe.tsx | 11 --- .../common-markdown-renderer-props.ts | 1 - .../document-markdown-renderer.tsx | 10 +- .../extract-first-headline-app-extension.ts | 23 +++++ ...xtract-first-headline-editor-extension.tsx | 18 ++++ ...ract-first-headline-markdown-extension.tsx | 17 ++++ .../extract-first-headline-node-processor.ts | 61 +++++++++++++ .../hooks/use-extract-first-headline.ts | 91 ------------------- .../slideshow-markdown-renderer.tsx | 13 +-- .../render-page/iframe-markdown-renderer.tsx | 23 +---- .../render-page/markdown-document.tsx | 6 -- .../rendering-message.ts | 8 -- .../slide-show-page-content.tsx | 2 - .../optional-app-extensions.ts | 4 +- 17 files changed, 126 insertions(+), 168 deletions(-) create mode 100644 frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-app-extension.ts create mode 100644 frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-editor-extension.tsx create mode 100644 frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-markdown-extension.tsx create mode 100644 frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-node-processor.ts delete mode 100644 frontend/src/components/markdown-renderer/hooks/use-extract-first-headline.ts diff --git a/frontend/cypress/e2e/documentTitle.spec.ts b/frontend/cypress/e2e/documentTitle.spec.ts index dd8545c83..46ff816b5 100644 --- a/frontend/cypress/e2e/documentTitle.spec.ts +++ b/frontend/cypress/e2e/documentTitle.spec.ts @@ -74,7 +74,7 @@ describe('Document Title', () => { it('katex code looks right', () => { cy.setCodemirrorContent(`# $\\alpha$-foo`) cy.getIframeBody().find('h1').should('contain', 'α') - cy.title().should('eq', `α-foo - HedgeDoc @ ${branding.name}`) + cy.title().should('eq', `\\alpha-foo - HedgeDoc @ ${branding.name}`) }) }) }) diff --git a/frontend/src/components/document-read-only-page/document-read-only-page-content.tsx b/frontend/src/components/document-read-only-page/document-read-only-page-content.tsx index 29baf8a11..e6ade2a3c 100644 --- a/frontend/src/components/document-read-only-page/document-read-only-page-content.tsx +++ b/frontend/src/components/document-read-only-page/document-read-only-page-content.tsx @@ -4,7 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only */ import { useTrimmedNoteMarkdownContentWithoutFrontmatter } from '../../hooks/common/use-trimmed-note-markdown-content-without-frontmatter' -import { updateNoteTitleByFirstHeading } from '../../redux/note-details/methods' import { setRendererStatus } from '../../redux/renderer-status/methods' import { RenderIframe } from '../editor-page/renderer-pane/render-iframe' import { RendererType } from '../render-page/window-post-message-communicator/rendering-message' @@ -27,7 +26,6 @@ export const DocumentReadOnlyPageContent: React.FC = () => { diff --git a/frontend/src/components/editor-page/editor-page-content.tsx b/frontend/src/components/editor-page/editor-page-content.tsx index 0e1358b81..3a4ba0dc1 100644 --- a/frontend/src/components/editor-page/editor-page-content.tsx +++ b/frontend/src/components/editor-page/editor-page-content.tsx @@ -5,7 +5,6 @@ */ import { useApplicationState } from '../../hooks/common/use-application-state' import { useApplyDarkMode } from '../../hooks/common/use-apply-dark-mode' -import { updateNoteTitleByFirstHeading } from '../../redux/note-details/methods' import { Logger } from '../../utils/logger' import { MotdModal } from '../common/motd-modal/motd-modal' import { CommunicatorImageLightbox } from '../markdown-renderer/extensions/image/communicator-image-lightbox' @@ -112,7 +111,6 @@ export const EditorPageContent: React.FC = () => { diff --git a/frontend/src/components/editor-page/renderer-pane/render-iframe.tsx b/frontend/src/components/editor-page/renderer-pane/render-iframe.tsx index 3464c2c83..7a65e972d 100644 --- a/frontend/src/components/editor-page/renderer-pane/render-iframe.tsx +++ b/frontend/src/components/editor-page/renderer-pane/render-iframe.tsx @@ -13,7 +13,6 @@ import type { RendererProps } from '../../render-page/markdown-document' import { useEditorReceiveHandler } from '../../render-page/window-post-message-communicator/hooks/use-editor-receive-handler' import type { ExtensionEvent, - OnFirstHeadingChangeMessage, OnHeightChangeMessage, RendererType, SetScrollStateMessage @@ -45,7 +44,6 @@ const log = new Logger('RenderIframe') * @param markdownContentLines Array of lines of the markdown content * @param onTaskCheckedChange Callback that is fired when a task-list item in the iframe is checked * @param scrollState The current {@link ScrollState} - * @param onFirstHeadingChange Callback that is fired when the first heading of the note changes * @param onScroll Callback that is fired when the user scrolls in the iframe * @param onMakeScrollSource Callback that is fired when the renderer requests to be set as the current scroll source * @param frameClasses CSS classes that should be applied to the iframe @@ -57,7 +55,6 @@ const log = new Logger('RenderIframe') export const RenderIframe: React.FC = ({ markdownContentLines, scrollState, - onFirstHeadingChange, onScroll, onMakeScrollSource, frameClasses, @@ -92,14 +89,6 @@ export const RenderIframe: React.FC = ({ onRendererStatusChange?.(rendererReady) }, [onRendererStatusChange, rendererReady]) - useEditorReceiveHandler( - CommunicationMessageType.ON_FIRST_HEADING_CHANGE, - useCallback( - (values: OnFirstHeadingChangeMessage) => onFirstHeadingChange?.(values.firstHeading), - [onFirstHeadingChange] - ) - ) - useEditorReceiveHandler( CommunicationMessageType.ENABLE_RENDERER_SCROLL_SOURCE, useCallback(() => onMakeScrollSource?.(), [onMakeScrollSource]) diff --git a/frontend/src/components/markdown-renderer/common-markdown-renderer-props.ts b/frontend/src/components/markdown-renderer/common-markdown-renderer-props.ts index 8dbe707d2..46343fdef 100644 --- a/frontend/src/components/markdown-renderer/common-markdown-renderer-props.ts +++ b/frontend/src/components/markdown-renderer/common-markdown-renderer-props.ts @@ -6,7 +6,6 @@ import type { Ref } from 'react' export interface CommonMarkdownRendererProps { - onFirstHeadingChange?: (firstHeading: string | undefined) => void baseUrl: string outerContainerRef?: Ref newlinesAreBreaks?: boolean diff --git a/frontend/src/components/markdown-renderer/document-markdown-renderer.tsx b/frontend/src/components/markdown-renderer/document-markdown-renderer.tsx index b6e0ef3e0..51029f458 100644 --- a/frontend/src/components/markdown-renderer/document-markdown-renderer.tsx +++ b/frontend/src/components/markdown-renderer/document-markdown-renderer.tsx @@ -10,10 +10,9 @@ import type { LineMarkers } from './extensions/linemarker/add-line-marker-markdo import { LinemarkerMarkdownExtension } from './extensions/linemarker/linemarker-markdown-extension' import type { LineMarkerPosition } from './extensions/linemarker/types' import { useCalculateLineMarkerPosition } from './hooks/use-calculate-line-marker-positions' -import { useExtractFirstHeadline } from './hooks/use-extract-first-headline' import { useMarkdownExtensions } from './hooks/use-markdown-extensions' import { MarkdownToReact } from './markdown-to-react/markdown-to-react' -import React, { useEffect, useMemo, useRef } from 'react' +import React, { useMemo, useRef } from 'react' import { useTranslation } from 'react-i18next' export interface DocumentMarkdownRendererProps extends CommonMarkdownRendererProps { @@ -25,9 +24,7 @@ export interface DocumentMarkdownRendererProps extends CommonMarkdownRendererPro * * @param className Additional class names directly given to the div * @param markdownContentLines The markdown lines - * @param onFirstHeadingChange The callback to call if the first heading changes. * @param onLineMarkerPositionChanged The callback to call with changed {@link LineMarkers} - * @param onTaskCheckedChange The callback to call if a task is checked or unchecked. * @param baseUrl The base url of the renderer * @param outerContainerRef A reference for the outer container * @param newlinesAreBreaks If newlines are rendered as breaks or not @@ -35,7 +32,6 @@ export interface DocumentMarkdownRendererProps extends CommonMarkdownRendererPro export const DocumentMarkdownRenderer: React.FC = ({ className, markdownContentLines, - onFirstHeadingChange, onLineMarkerPositionChanged, baseUrl, outerContainerRef, @@ -57,10 +53,6 @@ export const DocumentMarkdownRenderer: React.FC = useTranslation() useCalculateLineMarkerPosition(markdownBodyRef, currentLineMarkers.current, onLineMarkerPositionChanged) - const extractFirstHeadline = useExtractFirstHeadline(markdownBodyRef, onFirstHeadingChange) - useEffect(() => { - extractFirstHeadline() - }, [extractFirstHeadline, markdownContentLines]) return (
diff --git a/frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-app-extension.ts b/frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-app-extension.ts new file mode 100644 index 000000000..9026c0638 --- /dev/null +++ b/frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-app-extension.ts @@ -0,0 +1,23 @@ +/* + * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) + * + * SPDX-License-Identifier: AGPL-3.0-only + */ +import type { MarkdownRendererExtensionOptions } from '../../../../extensions/base/app-extension' +import { AppExtension } from '../../../../extensions/base/app-extension' +import type { MarkdownRendererExtension } from '../base/markdown-renderer-extension' +import { ExtractFirstHeadlineEditorExtension } from './extract-first-headline-editor-extension' +import { ExtractFirstHeadlineMarkdownExtension } from './extract-first-headline-markdown-extension' + +/** + * Provides first headline extraction + */ +export class ExtractFirstHeadlineAppExtension extends AppExtension { + buildMarkdownRendererExtensions(options: MarkdownRendererExtensionOptions): MarkdownRendererExtension[] { + return [new ExtractFirstHeadlineMarkdownExtension(options.eventEmitter)] + } + + buildEditorExtensionComponent(): React.FC { + return ExtractFirstHeadlineEditorExtension + } +} diff --git a/frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-editor-extension.tsx b/frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-editor-extension.tsx new file mode 100644 index 000000000..8188cfbc0 --- /dev/null +++ b/frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-editor-extension.tsx @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) + * + * SPDX-License-Identifier: AGPL-3.0-only + */ +import { updateNoteTitleByFirstHeading } from '../../../../redux/note-details/methods' +import { useExtensionEventEmitterHandler } from '../../hooks/use-extension-event-emitter' +import { ExtractFirstHeadlineNodeProcessor } from './extract-first-headline-node-processor' +import type React from 'react' + +/** + * Receives the {@link ExtractFirstHeadlineNodeProcessor.EVENT_NAME first heading extraction event} + * and saves the title in the global application state. + */ +export const ExtractFirstHeadlineEditorExtension: React.FC = () => { + useExtensionEventEmitterHandler(ExtractFirstHeadlineNodeProcessor.EVENT_NAME, updateNoteTitleByFirstHeading) + return null +} diff --git a/frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-markdown-extension.tsx b/frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-markdown-extension.tsx new file mode 100644 index 000000000..400707f30 --- /dev/null +++ b/frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-markdown-extension.tsx @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) + * + * SPDX-License-Identifier: AGPL-3.0-only + */ +import type { NodeProcessor } from '../../node-preprocessors/node-processor' +import { EventMarkdownRendererExtension } from '../base/event-markdown-renderer-extension' +import { ExtractFirstHeadlineNodeProcessor } from './extract-first-headline-node-processor' + +/** + * Adds first heading extraction to the renderer + */ +export class ExtractFirstHeadlineMarkdownExtension extends EventMarkdownRendererExtension { + buildNodeProcessors(): NodeProcessor[] { + return [new ExtractFirstHeadlineNodeProcessor(this.eventEmitter)] + } +} diff --git a/frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-node-processor.ts b/frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-node-processor.ts new file mode 100644 index 000000000..00b5de6fe --- /dev/null +++ b/frontend/src/components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-node-processor.ts @@ -0,0 +1,61 @@ +/* + * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) + * + * SPDX-License-Identifier: AGPL-3.0-only + */ +import { NodeProcessor } from '../../node-preprocessors/node-processor' +import { Optional } from '@mrdrogdrog/optional' +import type { Document, Node, Element } from 'domhandler' +import { isTag, isText } from 'domhandler' +import type { EventEmitter2 } from 'eventemitter2' + +const headlineTagRegex = /^h[1-6]$/gi + +/** + * Searches for the first headline tag and extracts its plain text content. + */ +export class ExtractFirstHeadlineNodeProcessor extends NodeProcessor { + public static readonly EVENT_NAME = 'HeadlineExtracted' + + constructor(private eventEmitter: EventEmitter2) { + super() + } + + process(nodes: Document): Document { + Optional.ofNullable(this.checkNodesForHeadline(nodes.children)) + .map((foundHeadlineNode) => this.extractInnerTextFromNode(foundHeadlineNode).trim()) + .filter((text) => text !== '') + .ifPresent((text) => this.eventEmitter.emit(ExtractFirstHeadlineNodeProcessor.EVENT_NAME, text)) + return nodes + } + + private checkNodesForHeadline(nodes: Node[]): Node | undefined { + return nodes.find((node) => isTag(node) && node.name.match(headlineTagRegex)) + } + + private extractInnerTextFromNode(node: Node): string { + if (isText(node)) { + return node.nodeValue + } else if (isTag(node)) { + return this.extractInnerTextFromTag(node) + } else { + return '' + } + } + + private extractInnerTextFromTag(node: Element): string { + if (node.name === 'a' && this.findAttribute(node, 'class')?.value.includes('heading-anchor')) { + return '' + } else if (node.name === 'img') { + return this.findAttribute(node, 'alt')?.value ?? '' + } else { + return node.children.reduce((state, child) => { + return state + this.extractInnerTextFromNode(child) + }, '') + } + } + + private findAttribute(node: Element, attributeName: string) { + return node.attributes.find((attribute) => attribute.name === attributeName) + } +} diff --git a/frontend/src/components/markdown-renderer/hooks/use-extract-first-headline.ts b/frontend/src/components/markdown-renderer/hooks/use-extract-first-headline.ts deleted file mode 100644 index d0fa729b5..000000000 --- a/frontend/src/components/markdown-renderer/hooks/use-extract-first-headline.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) - * - * SPDX-License-Identifier: AGPL-3.0-only - */ -import { Optional } from '@mrdrogdrog/optional' -import type React from 'react' -import { useCallback, useEffect, useMemo, useRef } from 'react' - -/** - * Extracts the plain text content of a {@link ChildNode node}. - * - * @param node The node whose text content should be extracted. - * @return the plain text content - */ -const extractInnerText = (node: ChildNode | null): string => { - if (!node || isKatexMathMlElement(node) || isHeadlineLinkElement(node)) { - return '' - } else if (node.childNodes && node.childNodes.length > 0) { - return extractInnerTextFromChildren(node) - } else if (node.nodeName.toLowerCase() === 'img') { - return (node as HTMLImageElement).getAttribute('alt') ?? '' - } else { - return node.textContent ?? '' - } -} - -/** - * Determines if the given {@link ChildNode node} is the mathml part of a KaTeX rendering. - * @param node The node that might be a katex mathml element - */ -const isKatexMathMlElement = (node: ChildNode): boolean => (node as HTMLElement).classList?.contains('katex-mathml') - -/** - * Determines if the given {@link ChildNode node} is the link icon of a heading. - * @param node The node to check - */ -const isHeadlineLinkElement = (node: ChildNode): boolean => (node as HTMLElement).classList?.contains('heading-anchor') - -/** - * Extracts the text content of the children of the given {@link ChildNode node}. - * @param node The node whose children should be processed. The content of the node itself won't be included. - * @return the concatenated text content of the child nodes - */ -const extractInnerTextFromChildren = (node: ChildNode): string => - Array.from(node.childNodes).reduce((state, child) => { - return state + extractInnerText(child) - }, '') - -/** - * Extracts the plain text content of the first level 1 heading in the document. - * - * @param documentElement The root element of (sub)dom that should be inspected - * @param onFirstHeadingChange A callback that will be executed with the new level 1 heading - */ -export const useExtractFirstHeadline = ( - documentElement: React.RefObject, - onFirstHeadingChange?: (firstHeading: string | undefined) => void -): (() => void) => { - const lastFirstHeadingContent = useRef() - const currentFirstHeadingElement = useRef(null) - - const extractHeaderText = useCallback(() => { - if (!onFirstHeadingChange) { - return - } - const headingText = extractInnerText(currentFirstHeadingElement.current).trim() - if (headingText !== lastFirstHeadingContent.current) { - lastFirstHeadingContent.current = headingText - onFirstHeadingChange(headingText) - } - }, [onFirstHeadingChange]) - - const mutationObserver = useMemo(() => new MutationObserver(() => extractHeaderText()), [extractHeaderText]) - useEffect(() => () => mutationObserver.disconnect(), [mutationObserver]) - - return useCallback(() => { - const foundFirstHeading = Optional.ofNullable(documentElement.current) - .map((currentDocumentElement) => currentDocumentElement.getElementsByTagName('h1').item(0)) - .orElse(null) - if (foundFirstHeading === currentFirstHeadingElement.current) { - return - } - mutationObserver.disconnect() - currentFirstHeadingElement.current = foundFirstHeading - if (foundFirstHeading !== null) { - mutationObserver.observe(foundFirstHeading, { subtree: true, childList: true }) - } - extractHeaderText() - }, [documentElement, extractHeaderText, mutationObserver]) -} diff --git a/frontend/src/components/markdown-renderer/slideshow-markdown-renderer.tsx b/frontend/src/components/markdown-renderer/slideshow-markdown-renderer.tsx index 6f14a7204..4f63d6858 100644 --- a/frontend/src/components/markdown-renderer/slideshow-markdown-renderer.tsx +++ b/frontend/src/components/markdown-renderer/slideshow-markdown-renderer.tsx @@ -6,13 +6,12 @@ import type { ScrollProps } from '../editor-page/synced-scroll/scroll-props' import type { CommonMarkdownRendererProps } from './common-markdown-renderer-props' import { RevealMarkdownExtension } from './extensions/reveal/reveal-markdown-extension' -import { useExtractFirstHeadline } from './hooks/use-extract-first-headline' import { useMarkdownExtensions } from './hooks/use-markdown-extensions' import { REVEAL_STATUS, useReveal } from './hooks/use-reveal' import { LoadingSlide } from './loading-slide' import { MarkdownToReact } from './markdown-to-react/markdown-to-react' import type { SlideOptions } from '@hedgedoc/commons' -import React, { useEffect, useMemo, useRef } from 'react' +import React, { useMemo, useRef } from 'react' export interface SlideshowMarkdownRendererProps extends CommonMarkdownRendererProps { slideOptions?: SlideOptions @@ -23,8 +22,6 @@ export interface SlideshowMarkdownRendererProps extends CommonMarkdownRendererPr * * @param className Additional class names directly given to the div * @param markdownContentLines The markdown lines - * @param onFirstHeadingChange The callback to call if the first heading changes. - * @param onLineMarkerPositionChanged The callback to call with changed {@link LineMarkers} * @param baseUrl The base url of the renderer * @param newlinesAreBreaks If newlines are rendered as breaks or not * @param slideOptions The {@link SlideOptions} to use @@ -32,7 +29,6 @@ export interface SlideshowMarkdownRendererProps extends CommonMarkdownRendererPr export const SlideshowMarkdownRenderer: React.FC = ({ className, markdownContentLines, - onFirstHeadingChange, baseUrl, newlinesAreBreaks, slideOptions @@ -46,13 +42,6 @@ export const SlideshowMarkdownRenderer: React.FC { - if (revealStatus === REVEAL_STATUS.INITIALISED) { - extractFirstHeadline() - } - }, [extractFirstHeadline, markdownContentLines, revealStatus]) - const slideShowDOM = useMemo( () => revealStatus === REVEAL_STATUS.INITIALISED ? ( diff --git a/frontend/src/components/render-page/iframe-markdown-renderer.tsx b/frontend/src/components/render-page/iframe-markdown-renderer.tsx index e194c3a39..947bd349e 100644 --- a/frontend/src/components/render-page/iframe-markdown-renderer.tsx +++ b/frontend/src/components/render-page/iframe-markdown-renderer.tsx @@ -73,16 +73,6 @@ export const IframeMarkdownRenderer: React.FC = () => { }, [communicator]) ) - const onFirstHeadingChange = useCallback( - (firstHeading?: string) => { - communicator.sendMessageToOtherSide({ - type: CommunicationMessageType.ON_FIRST_HEADING_CHANGE, - firstHeading - }) - }, - [communicator] - ) - const onMakeScrollSource = useCallback(() => { sendScrolling.current = true communicator.sendMessageToOtherSide({ @@ -128,7 +118,6 @@ export const IframeMarkdownRenderer: React.FC = () => { { @@ -159,16 +147,7 @@ export const IframeMarkdownRenderer: React.FC = () => { default: return null } - }, [ - baseConfiguration, - markdownContentLines, - onFirstHeadingChange, - onHeightChange, - onMakeScrollSource, - onScroll, - scrollState, - slideOptions - ]) + }, [baseConfiguration, markdownContentLines, onHeightChange, onMakeScrollSource, onScroll, scrollState, slideOptions]) const extensionEventEmitter = useMemo(() => new EventEmitter2({ wildcard: true }), []) diff --git a/frontend/src/components/render-page/markdown-document.tsx b/frontend/src/components/render-page/markdown-document.tsx index d0eab827c..1a6505ce1 100644 --- a/frontend/src/components/render-page/markdown-document.tsx +++ b/frontend/src/components/render-page/markdown-document.tsx @@ -14,7 +14,6 @@ import type { MutableRefObject } from 'react' import React, { useEffect, useMemo, useRef, useState } from 'react' export interface RendererProps extends ScrollProps { - onFirstHeadingChange?: (firstHeading: string | undefined) => void documentRenderPaneRef?: MutableRefObject markdownContentLines: string[] onHeightChange?: (height: number) => void @@ -32,12 +31,9 @@ export interface MarkdownDocumentProps extends RendererProps { * * @param additionalOuterContainerClasses Additional classes given to the outer container directly * @param additionalRendererClasses Additional classes given {@link DocumentMarkdownRenderer} directly - * @param onFirstHeadingChange The callback to call when the first heading changes. * @param onMakeScrollSource The callback to call if a change of the scroll source is requested- - * @param onTaskCheckedChange The callback to call if a task get's checked or unchecked. * @param baseUrl The base url for the renderer * @param markdownContentLines The current content of the markdown document. - * @param onImageClick The callback to call if an image is clicked. * @param onScroll The callback to call if the renderer is scrolling. * @param scrollState The current {@link ScrollState} * @param onHeightChange The callback to call if the height of the document changes @@ -47,7 +43,6 @@ export interface MarkdownDocumentProps extends RendererProps { export const MarkdownDocument: React.FC = ({ additionalOuterContainerClasses, additionalRendererClasses, - onFirstHeadingChange, onMakeScrollSource, baseUrl, markdownContentLines, @@ -94,7 +89,6 @@ export const MarkdownDocument: React.FC = ({ outerContainerRef={rendererRef} className={`mb-3 ${additionalRendererClasses ?? ''}`} markdownContentLines={markdownContentLines} - onFirstHeadingChange={onFirstHeadingChange} onLineMarkerPositionChanged={recalculateLineMarkers} baseUrl={baseUrl} newlinesAreBreaks={newlinesAreBreaks} diff --git a/frontend/src/components/render-page/window-post-message-communicator/rendering-message.ts b/frontend/src/components/render-page/window-post-message-communicator/rendering-message.ts index 35cdfd7e1..75008e367 100644 --- a/frontend/src/components/render-page/window-post-message-communicator/rendering-message.ts +++ b/frontend/src/components/render-page/window-post-message-communicator/rendering-message.ts @@ -11,7 +11,6 @@ export enum CommunicationMessageType { SET_MARKDOWN_CONTENT = 'SET_MARKDOWN_CONTENT', RENDERER_READY = 'RENDERER_READY', SET_DARKMODE = 'SET_DARKMODE', - ON_FIRST_HEADING_CHANGE = 'ON_FIRST_HEADING_CHANGE', ENABLE_RENDERER_SCROLL_SOURCE = 'ENABLE_RENDERER_SCROLL_SOURCE', DISABLE_RENDERER_SCROLL_SOURCE = 'DISABLE_RENDERER_SCROLL_SOURCE', SET_SCROLL_STATE = 'SET_SCROLL_STATE', @@ -72,11 +71,6 @@ export interface SetScrollStateMessage { scrollState: ScrollState } -export interface OnFirstHeadingChangeMessage { - type: CommunicationMessageType.ON_FIRST_HEADING_CHANGE - firstHeading: string | undefined -} - export interface SetSlideOptionsMessage { type: CommunicationMessageType.SET_SLIDE_OPTIONS slideOptions: SlideOptions @@ -101,7 +95,6 @@ export type CommunicationMessages = | GetWordCountMessage | SetMarkdownContentMessage | SetScrollStateMessage - | OnFirstHeadingChangeMessage | SetSlideOptionsMessage | OnHeightChangeMessage | OnWordCountCalculatedMessage @@ -120,7 +113,6 @@ export type EditorToRendererMessageType = export type RendererToEditorMessageType = | CommunicationMessageType.RENDERER_READY | CommunicationMessageType.ENABLE_RENDERER_SCROLL_SOURCE - | CommunicationMessageType.ON_FIRST_HEADING_CHANGE | CommunicationMessageType.SET_SCROLL_STATE | CommunicationMessageType.ON_HEIGHT_CHANGE | CommunicationMessageType.ON_WORD_COUNT_CALCULATED diff --git a/frontend/src/components/slide-show-page/slide-show-page-content.tsx b/frontend/src/components/slide-show-page/slide-show-page-content.tsx index 2482572ea..0235f2c5d 100644 --- a/frontend/src/components/slide-show-page/slide-show-page-content.tsx +++ b/frontend/src/components/slide-show-page/slide-show-page-content.tsx @@ -5,7 +5,6 @@ */ import { useApplicationState } from '../../hooks/common/use-application-state' import { useTrimmedNoteMarkdownContentWithoutFrontmatter } from '../../hooks/common/use-trimmed-note-markdown-content-without-frontmatter' -import { updateNoteTitleByFirstHeading } from '../../redux/note-details/methods' import { setRendererStatus } from '../../redux/renderer-status/methods' import { RenderIframe } from '../editor-page/renderer-pane/render-iframe' import { useSendToRenderer } from '../render-page/window-post-message-communicator/hooks/use-send-to-renderer' @@ -42,7 +41,6 @@ export const SlideShowPageContent: React.FC = () => { frameClasses={'h-100 w-100'} markdownContentLines={markdownContentLines} rendererType={RendererType.SLIDESHOW} - onFirstHeadingChange={updateNoteTitleByFirstHeading} onRendererStatusChange={setRendererStatus} />
diff --git a/frontend/src/extensions/extra-integrations/optional-app-extensions.ts b/frontend/src/extensions/extra-integrations/optional-app-extensions.ts index 84fe7b538..e96b3eb20 100644 --- a/frontend/src/extensions/extra-integrations/optional-app-extensions.ts +++ b/frontend/src/extensions/extra-integrations/optional-app-extensions.ts @@ -6,6 +6,7 @@ import { BasicMarkdownSyntaxAppExtension } from '../../components/markdown-renderer/extensions/basic-markdown-syntax/basic-markdown-syntax-app-extension' import { BootstrapIconAppExtension } from '../../components/markdown-renderer/extensions/bootstrap-icons/bootstrap-icon-app-extension' import { EmojiAppExtension } from '../../components/markdown-renderer/extensions/emoji/emoji-app-extension' +import { ExtractFirstHeadlineAppExtension } from '../../components/markdown-renderer/extensions/extract-first-headline/extract-first-headline-app-extension' import { IframeCapsuleAppExtension } from '../../components/markdown-renderer/extensions/iframe-capsule/iframe-capsule-app-extension' import { ImagePlaceholderAppExtension } from '../../components/markdown-renderer/extensions/image-placeholder/image-placeholder-app-extension' import { TableOfContentsAppExtension } from '../../components/markdown-renderer/extensions/table-of-contents/table-of-contents-app-extension' @@ -60,5 +61,6 @@ export const optionalAppExtensions: AppExtension[] = [ new TableOfContentsAppExtension(), new ImagePlaceholderAppExtension(), new IframeCapsuleAppExtension(), - new BasicMarkdownSyntaxAppExtension() + new BasicMarkdownSyntaxAppExtension(), + new ExtractFirstHeadlineAppExtension() ]