Reorganize redux and hooks (1/4) (#985)

Signed-off-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
This commit is contained in:
Tilman Vatteroth 2021-02-01 22:55:49 +01:00 committed by GitHub
parent bdf8110676
commit 1b7abf9f27
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
61 changed files with 898 additions and 986 deletions

View file

@ -10,10 +10,10 @@ import { Alert } from 'react-bootstrap'
import { Trans, useTranslation } from 'react-i18next'
import { InternalLink } from '../common/links/internal-link'
import { ShowIf } from '../common/show-if/show-if'
import { RawYAMLMetadata, YAMLMetaData } from '../editor/yaml-metadata/yaml-metadata'
import { NoteFrontmatter, RawNoteFrontmatter } from '../editor/note-frontmatter/note-frontmatter'
import { BasicMarkdownRenderer } from './basic-markdown-renderer'
import { useExtractFirstHeadline } from './hooks/use-extract-first-headline'
import { usePostMetaDataOnChange } from './hooks/use-post-meta-data-on-change'
import { usePostFrontmatterOnChange } from './hooks/use-post-frontmatter-on-change'
import { usePostTocAstOnChange } from './hooks/use-post-toc-ast-on-change'
import { useReplacerInstanceListCreator } from './hooks/use-replacer-instance-list-creator'
import { FullMarkdownItConfigurator } from './markdown-it-configurator/FullMarkdownItConfigurator'
@ -25,7 +25,7 @@ import { useCalculateLineMarkerPosition } from './utils/calculate-line-marker-po
export interface FullMarkdownRendererProps {
onFirstHeadingChange?: (firstHeading: string | undefined) => void
onLineMarkerPositionChanged?: (lineMarkerPosition: LineMarkerPosition[]) => void
onMetaDataChange?: (yamlMetaData: YAMLMetaData | undefined) => void
onFrontmatterChange?: (frontmatter: NoteFrontmatter | undefined) => void
onTaskCheckedChange?: (lineInMarkdown: number, checked: boolean) => void
onTocChange?: (ast: TocAst) => void
rendererRef?: Ref<HTMLDivElement>
@ -37,7 +37,7 @@ export const FullMarkdownRenderer: React.FC<FullMarkdownRendererProps & Addition
{
onFirstHeadingChange,
onLineMarkerPositionChanged,
onMetaDataChange,
onFrontmatterChange,
onTaskCheckedChange,
onTocChange,
content,
@ -53,11 +53,11 @@ export const FullMarkdownRenderer: React.FC<FullMarkdownRendererProps & Addition
const [showYamlError, setShowYamlError] = useState(false)
const hasNewYamlError = useRef(false)
const rawMetaRef = useRef<RawYAMLMetadata>()
const rawMetaRef = useRef<RawNoteFrontmatter>()
const firstHeadingRef = useRef<string>()
const documentElement = useRef<HTMLDivElement>(null)
const currentLineMarkers = useRef<LineMarkers[]>()
usePostMetaDataOnChange(rawMetaRef.current, firstHeadingRef.current, onMetaDataChange, onFirstHeadingChange)
usePostFrontmatterOnChange(rawMetaRef.current, firstHeadingRef.current, onFrontmatterChange, onFirstHeadingChange)
useCalculateLineMarkerPosition(documentElement, currentLineMarkers.current, onLineMarkerPositionChanged, documentElement.current?.offsetTop ?? 0)
useExtractFirstHeadline(documentElement, content, onFirstHeadingChange)
@ -66,7 +66,7 @@ export const FullMarkdownRenderer: React.FC<FullMarkdownRendererProps & Addition
const markdownIt = useMemo(() => {
return (new FullMarkdownItConfigurator(
!!onMetaDataChange,
!!onFrontmatterChange,
errorState => hasNewYamlError.current = errorState,
rawMeta => {
rawMetaRef.current = rawMeta
@ -78,9 +78,9 @@ export const FullMarkdownRenderer: React.FC<FullMarkdownRendererProps & Addition
currentLineMarkers.current = lineMarkers
}
)).buildConfiguredMarkdownIt()
}, [onMetaDataChange])
}, [onFrontmatterChange])
const clearMetadata = useCallback(() => {
const clearFrontmatter = useCallback(() => {
hasNewYamlError.current = false
rawMetaRef.current = undefined
}, [])
@ -107,7 +107,7 @@ export const FullMarkdownRenderer: React.FC<FullMarkdownRendererProps & Addition
componentReplacers={allReplacers}
markdownIt={markdownIt}
documentReference={documentElement}
onBeforeRendering={clearMetadata}
onBeforeRendering={clearFrontmatter}
onAfterRendering={checkYamlErrorState}
/>
</div>

View file

@ -4,10 +4,14 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import React, { useCallback, useEffect } from 'react'
import React, { useCallback, useEffect, useRef } from 'react'
export const useExtractFirstHeadline = (documentElement: React.RefObject<HTMLDivElement>, content: string, onFirstHeadingChange?: (firstHeading: string | undefined) => void): void => {
const extractInnerText = useCallback((node: ChildNode): string => {
const extractInnerText = useCallback((node: ChildNode | null): string => {
if (!node) {
return ''
}
let innerText = ''
if ((node as HTMLElement).classList?.contains("katex-mathml")) {
@ -15,7 +19,9 @@ export const useExtractFirstHeadline = (documentElement: React.RefObject<HTMLDiv
}
if (node.childNodes && node.childNodes.length > 0) {
node.childNodes.forEach((child) => { innerText += extractInnerText(child) })
node.childNodes.forEach((child) => {
innerText += extractInnerText(child)
})
} else if (node.nodeName === 'IMG') {
innerText += (node as HTMLImageElement).getAttribute('alt')
} else {
@ -24,14 +30,17 @@ export const useExtractFirstHeadline = (documentElement: React.RefObject<HTMLDiv
return innerText
}, [])
const lastFirstHeading = useRef<string | undefined>()
useEffect(() => {
if (onFirstHeadingChange && documentElement.current) {
const firstHeading = documentElement.current.getElementsByTagName('h1').item(0)
if (firstHeading) {
onFirstHeadingChange(extractInnerText(firstHeading))
} else {
onFirstHeadingChange(undefined)
const headingText = extractInnerText(firstHeading)
if (headingText === lastFirstHeading.current) {
return
}
lastFirstHeading.current = headingText
onFirstHeadingChange(headingText)
}
}, [documentElement, extractInnerText, onFirstHeadingChange, content])
}

View file

@ -0,0 +1,35 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import equal from 'fast-deep-equal'
import { useEffect, useRef } from 'react'
import { NoteFrontmatter, RawNoteFrontmatter } from '../../editor/note-frontmatter/note-frontmatter'
export const usePostFrontmatterOnChange = (
rawFrontmatter: RawNoteFrontmatter | undefined,
firstHeadingRef: string | undefined,
onFrontmatterChange?: (frontmatter: NoteFrontmatter | undefined) => void,
onFirstHeadingChange?: (firstHeading: string | undefined) => void
): void => {
const oldMetaRef = useRef<RawNoteFrontmatter>()
const oldFirstHeadingRef = useRef<string>()
useEffect(() => {
if (onFrontmatterChange && !equal(oldMetaRef.current, rawFrontmatter)) {
if (rawFrontmatter) {
const newFrontmatter = new NoteFrontmatter(rawFrontmatter)
onFrontmatterChange(newFrontmatter)
} else {
onFrontmatterChange(undefined)
}
oldMetaRef.current = rawFrontmatter
}
if (onFirstHeadingChange && !equal(firstHeadingRef, oldFirstHeadingRef.current)) {
onFirstHeadingChange(firstHeadingRef || undefined)
oldFirstHeadingRef.current = firstHeadingRef
}
})
}

View file

@ -1,35 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import equal from 'fast-deep-equal'
import { useEffect, useRef } from 'react'
import { RawYAMLMetadata, YAMLMetaData } from '../../editor/yaml-metadata/yaml-metadata'
export const usePostMetaDataOnChange = (
rawMetaRef: RawYAMLMetadata|undefined,
firstHeadingRef: string|undefined,
onMetaDataChange?: (yamlMetaData: YAMLMetaData | undefined) => void,
onFirstHeadingChange?: (firstHeading: string | undefined) => void
): void => {
const oldMetaRef = useRef<RawYAMLMetadata>()
const oldFirstHeadingRef = useRef<string>()
useEffect(() => {
if (onMetaDataChange && !equal(oldMetaRef.current, rawMetaRef)) {
if (rawMetaRef) {
const newMetaData = new YAMLMetaData(rawMetaRef)
onMetaDataChange(newMetaData)
} else {
onMetaDataChange(undefined)
}
oldMetaRef.current = rawMetaRef
}
if (onFirstHeadingChange && !equal(firstHeadingRef, oldFirstHeadingRef.current)) {
onFirstHeadingChange(firstHeadingRef || undefined)
oldFirstHeadingRef.current = firstHeadingRef
}
})
}

View file

@ -6,7 +6,7 @@
import MarkdownIt from 'markdown-it'
import { TocAst } from 'markdown-it-toc-done-right'
import { RawYAMLMetadata } from '../../editor/yaml-metadata/yaml-metadata'
import { RawNoteFrontmatter } from '../../editor/note-frontmatter/note-frontmatter'
import { documentToc } from '../markdown-it-plugins/document-toc'
import { frontmatterExtract } from '../markdown-it-plugins/frontmatter'
import { headlineAnchors } from '../markdown-it-plugins/headline-anchors'
@ -28,7 +28,7 @@ export class FullMarkdownItConfigurator extends BasicMarkdownItConfigurator {
constructor (
private useFrontmatter: boolean,
private passYamlErrorState: (error: boolean) => void,
private onRawMeta: (rawMeta: RawYAMLMetadata) => void,
private onRawMeta: (rawMeta: RawNoteFrontmatter) => void,
private onToc: (toc: TocAst) => void,
private onLineMarkers: (lineMarkers: LineMarkers[]) => void
) {
@ -45,8 +45,8 @@ export class FullMarkdownItConfigurator extends BasicMarkdownItConfigurator {
!this.useFrontmatter
? undefined
: {
onYamlError: (hasError: boolean) => this.passYamlErrorState(hasError),
onRawMeta: (rawMeta: RawYAMLMetadata) => this.onRawMeta(rawMeta)
onParseError: (hasError: boolean) => this.passYamlErrorState(hasError),
onRawMeta: (rawMeta: RawNoteFrontmatter) => this.onRawMeta(rawMeta)
})
},
headlineAnchors,

View file

@ -7,11 +7,11 @@
import yaml from 'js-yaml'
import MarkdownIt from 'markdown-it'
import frontmatter from 'markdown-it-front-matter'
import { RawYAMLMetadata } from '../../editor/yaml-metadata/yaml-metadata'
import { RawNoteFrontmatter } from '../../editor/note-frontmatter/note-frontmatter'
interface FrontmatterPluginOptions {
onYamlError: (error: boolean) => void,
onRawMeta: (rawMeta: RawYAMLMetadata) => void,
onParseError: (error: boolean) => void,
onRawMeta: (rawMeta: RawNoteFrontmatter) => void,
}
export const frontmatterExtract: MarkdownIt.PluginWithOptions<FrontmatterPluginOptions> = (markdownIt: MarkdownIt, options) => {
@ -20,13 +20,13 @@ export const frontmatterExtract: MarkdownIt.PluginWithOptions<FrontmatterPluginO
}
frontmatter(markdownIt, (rawMeta: string) => {
try {
const meta: RawYAMLMetadata = yaml.load(rawMeta) as RawYAMLMetadata
options.onYamlError(false)
const meta: RawNoteFrontmatter = yaml.load(rawMeta) as RawNoteFrontmatter
options.onParseError(false)
options.onRawMeta(meta)
} catch (e) {
console.error(e)
options.onYamlError(true)
options.onRawMeta({} as RawYAMLMetadata)
options.onParseError(true)
options.onRawMeta({} as RawNoteFrontmatter)
}
})
}