mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-14 15:14:56 -04:00
fix(component replacer): Use symbol for DO_NOT_REPLACE instead of undefined
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
22cf68d10c
commit
7a9951e351
16 changed files with 114 additions and 116 deletions
|
@ -22,22 +22,20 @@ import { Optional } from '@mrdrogdrog/optional'
|
||||||
*/
|
*/
|
||||||
export class BlockquoteColorExtraTagReplacer extends ComponentReplacer {
|
export class BlockquoteColorExtraTagReplacer extends ComponentReplacer {
|
||||||
replace(element: Element): NodeReplacement {
|
replace(element: Element): NodeReplacement {
|
||||||
if (
|
return Optional.of(element)
|
||||||
element.tagName === BlockquoteExtraTagMarkdownExtension.tagName &&
|
.filter(
|
||||||
element.attribs?.['data-label'] === 'color' &&
|
(element) =>
|
||||||
element.children !== undefined
|
element.tagName === BlockquoteExtraTagMarkdownExtension.tagName && element.attribs?.['data-label'] === 'color'
|
||||||
) {
|
)
|
||||||
let index = 0
|
.map((element) => element.children[0])
|
||||||
return Optional.ofNullable(element.children[0])
|
|
||||||
.filter(isText)
|
.filter(isText)
|
||||||
.map((child) => (child as Text).data)
|
.map((child) => (child as Text).data)
|
||||||
.filter((content) => cssColor.test(content))
|
.filter((content) => cssColor.test(content))
|
||||||
.map((color) => (
|
.map((color) => (
|
||||||
<span className={'blockquote-extra'} key={(index += 1)} style={{ color: color }}>
|
<span className={'blockquote-extra'} key={1} style={{ color: color }}>
|
||||||
<ForkAwesomeIcon key='icon' className={'mx-1'} icon={'tag'} />
|
<ForkAwesomeIcon key='icon' className={'mx-1'} icon={'tag'} />
|
||||||
</span>
|
</span>
|
||||||
))
|
))
|
||||||
.orElse(DO_NOT_REPLACE)
|
.orElse(DO_NOT_REPLACE)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,16 +23,17 @@ import { BlockquoteExtraTagMarkdownExtension } from './blockquote-extra-tag-mark
|
||||||
*/
|
*/
|
||||||
export class BlockquoteExtraTagReplacer extends ComponentReplacer {
|
export class BlockquoteExtraTagReplacer extends ComponentReplacer {
|
||||||
replace(element: Element, subNodeTransform: SubNodeTransform): NodeReplacement {
|
replace(element: Element, subNodeTransform: SubNodeTransform): NodeReplacement {
|
||||||
if (element.tagName !== BlockquoteExtraTagMarkdownExtension.tagName || !element.attribs) {
|
return Optional.of(element)
|
||||||
return DO_NOT_REPLACE
|
.filter(
|
||||||
}
|
(element) => element.tagName === BlockquoteExtraTagMarkdownExtension.tagName && element.attribs !== undefined
|
||||||
|
)
|
||||||
return (
|
.map((element) => (
|
||||||
<span className={'blockquote-extra'}>
|
<span className={'blockquote-extra'} key={1}>
|
||||||
{this.buildIconElement(element)}
|
{this.buildIconElement(element)}
|
||||||
{BlockquoteExtraTagReplacer.transformChildren(element, subNodeTransform)}
|
{BlockquoteExtraTagReplacer.transformChildren(element, subNodeTransform)}
|
||||||
</span>
|
</span>
|
||||||
)
|
))
|
||||||
|
.orElse(DO_NOT_REPLACE)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Element } from 'domhandler'
|
import type { Element } from 'domhandler'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { ComponentReplacer } from '../../replace-components/component-replacer'
|
import type { NodeReplacement } from '../../replace-components/component-replacer'
|
||||||
|
import { ComponentReplacer, DO_NOT_REPLACE } from '../../replace-components/component-replacer'
|
||||||
import { CsvTable } from './csv-table'
|
import { CsvTable } from './csv-table'
|
||||||
import { CodeBlockComponentReplacer } from '../../replace-components/code-block-component-replacer'
|
import { CodeBlockComponentReplacer } from '../../replace-components/code-block-component-replacer'
|
||||||
|
|
||||||
|
@ -14,10 +15,10 @@ import { CodeBlockComponentReplacer } from '../../replace-components/code-block-
|
||||||
* Detects code blocks with "csv" as language and renders them as table.
|
* Detects code blocks with "csv" as language and renders them as table.
|
||||||
*/
|
*/
|
||||||
export class CsvReplacer extends ComponentReplacer {
|
export class CsvReplacer extends ComponentReplacer {
|
||||||
public replace(codeNode: Element): React.ReactElement | undefined {
|
public replace(codeNode: Element): NodeReplacement {
|
||||||
const code = CodeBlockComponentReplacer.extractTextFromCodeNode(codeNode, 'csv')
|
const code = CodeBlockComponentReplacer.extractTextFromCodeNode(codeNode, 'csv')
|
||||||
if (!code) {
|
if (!code) {
|
||||||
return
|
return DO_NOT_REPLACE
|
||||||
}
|
}
|
||||||
|
|
||||||
const extraData = codeNode.attribs['data-extra']
|
const extraData = codeNode.attribs['data-extra']
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Element } from 'domhandler'
|
import type { Element } from 'domhandler'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { ComponentReplacer } from '../../replace-components/component-replacer'
|
import type { NodeReplacement } from '../../replace-components/component-replacer'
|
||||||
|
import { ComponentReplacer, DO_NOT_REPLACE } from '../../replace-components/component-replacer'
|
||||||
import { HighlightedCode } from './highlighted-code'
|
import { HighlightedCode } from './highlighted-code'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,10 +22,10 @@ export class HighlightedCodeReplacer extends ComponentReplacer {
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
public replace(codeNode: Element): React.ReactElement | undefined {
|
public replace(codeNode: Element): NodeReplacement {
|
||||||
const code = HighlightedCodeReplacer.extractCode(codeNode)
|
const code = HighlightedCodeReplacer.extractCode(codeNode)
|
||||||
if (!code) {
|
if (!code) {
|
||||||
return
|
return DO_NOT_REPLACE
|
||||||
}
|
}
|
||||||
|
|
||||||
const language = codeNode.attribs['data-highlight-language']
|
const language = codeNode.attribs['data-highlight-language']
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
@ -16,8 +16,9 @@ import { ClickShield } from '../../replace-components/click-shield/click-shield'
|
||||||
*/
|
*/
|
||||||
export class IframeCapsuleReplacer extends ComponentReplacer {
|
export class IframeCapsuleReplacer extends ComponentReplacer {
|
||||||
replace(node: Element, subNodeTransform: SubNodeTransform, nativeRenderer: NativeRenderer): NodeReplacement {
|
replace(node: Element, subNodeTransform: SubNodeTransform, nativeRenderer: NativeRenderer): NodeReplacement {
|
||||||
if (node.name === 'iframe') {
|
return node.name !== 'iframe' ? (
|
||||||
return (
|
DO_NOT_REPLACE
|
||||||
|
) : (
|
||||||
<ClickShield
|
<ClickShield
|
||||||
hoverIcon={'globe'}
|
hoverIcon={'globe'}
|
||||||
targetDescription={node.attribs.src}
|
targetDescription={node.attribs.src}
|
||||||
|
@ -25,8 +26,5 @@ export class IframeCapsuleReplacer extends ComponentReplacer {
|
||||||
{nativeRenderer()}
|
{nativeRenderer()}
|
||||||
</ClickShield>
|
</ClickShield>
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
return DO_NOT_REPLACE
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Element } from 'domhandler'
|
import type { Element } from 'domhandler'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { ComponentReplacer } from '../../replace-components/component-replacer'
|
import type { NodeReplacement } from '../../replace-components/component-replacer'
|
||||||
|
import { ComponentReplacer, DO_NOT_REPLACE } from '../../replace-components/component-replacer'
|
||||||
import { ProxyImageFrame } from './proxy-image-frame'
|
import { ProxyImageFrame } from './proxy-image-frame'
|
||||||
|
|
||||||
export type ImageClickHandler = (event: React.MouseEvent<HTMLImageElement, MouseEvent>) => void
|
export type ImageClickHandler = (event: React.MouseEvent<HTMLImageElement, MouseEvent>) => void
|
||||||
|
@ -22,9 +23,10 @@ export class ProxyImageReplacer extends ComponentReplacer {
|
||||||
this.clickHandler = clickHandler
|
this.clickHandler = clickHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
public replace(node: Element): React.ReactElement | undefined {
|
public replace(node: Element): NodeReplacement {
|
||||||
if (node.name === 'img') {
|
return node.name !== 'img' ? (
|
||||||
return (
|
DO_NOT_REPLACE
|
||||||
|
) : (
|
||||||
<ProxyImageFrame
|
<ProxyImageFrame
|
||||||
id={node.attribs.id}
|
id={node.attribs.id}
|
||||||
className={`${node.attribs.class} cursor-zoom-in`}
|
className={`${node.attribs.class} cursor-zoom-in`}
|
||||||
|
@ -37,5 +39,4 @@ export class ProxyImageReplacer extends ComponentReplacer {
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
import type { Element } from 'domhandler'
|
import type { Element } from 'domhandler'
|
||||||
import { isTag } from 'domhandler'
|
import { isTag } from 'domhandler'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import type { NodeReplacement } from '../../replace-components/component-replacer'
|
||||||
import { ComponentReplacer, DO_NOT_REPLACE } from '../../replace-components/component-replacer'
|
import { ComponentReplacer, DO_NOT_REPLACE } from '../../replace-components/component-replacer'
|
||||||
import { KatexMarkdownExtension } from './katex-markdown-extension'
|
import { KatexMarkdownExtension } from './katex-markdown-extension'
|
||||||
import { Optional } from '@mrdrogdrog/optional'
|
import { Optional } from '@mrdrogdrog/optional'
|
||||||
|
@ -17,7 +18,7 @@ const KaTeX = React.lazy(() => import(/* webpackChunkName: "katex" */ './katex-f
|
||||||
* Detects LaTeX syntax and renders it with KaTeX.
|
* Detects LaTeX syntax and renders it with KaTeX.
|
||||||
*/
|
*/
|
||||||
export class KatexReplacer extends ComponentReplacer {
|
export class KatexReplacer extends ComponentReplacer {
|
||||||
public replace(node: Element): React.ReactElement | undefined {
|
public replace(node: Element): NodeReplacement {
|
||||||
return this.extractKatexContent(node)
|
return this.extractKatexContent(node)
|
||||||
.map((latexContent) => {
|
.map((latexContent) => {
|
||||||
const isInline = !!node.attribs?.['data-inline']
|
const isInline = !!node.attribs?.['data-inline']
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Element } from 'domhandler'
|
import type { Element } from 'domhandler'
|
||||||
import { ComponentReplacer } from '../../replace-components/component-replacer'
|
import type { NodeReplacement } from '../../replace-components/component-replacer'
|
||||||
|
import { ComponentReplacer, DO_NOT_REPLACE } from '../../replace-components/component-replacer'
|
||||||
import { LinemarkerMarkdownExtension } from './linemarker-markdown-extension'
|
import { LinemarkerMarkdownExtension } from './linemarker-markdown-extension'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detects line markers and suppresses them in the resulting DOM.
|
* Detects line markers and suppresses them in the resulting DOM.
|
||||||
*/
|
*/
|
||||||
export class LinemarkerReplacer extends ComponentReplacer {
|
export class LinemarkerReplacer extends ComponentReplacer {
|
||||||
public replace(codeNode: Element): null | undefined {
|
public replace(codeNode: Element): NodeReplacement {
|
||||||
return codeNode.name === LinemarkerMarkdownExtension.tagName ? null : undefined
|
return codeNode.name === LinemarkerMarkdownExtension.tagName ? null : DO_NOT_REPLACE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
@ -22,10 +22,10 @@ export class JumpAnchorReplacer extends ComponentReplacer {
|
||||||
const jumpId = node.attribs['data-jump-target-id']
|
const jumpId = node.attribs['data-jump-target-id']
|
||||||
delete node.attribs['data-jump-target-id']
|
delete node.attribs['data-jump-target-id']
|
||||||
const replacement = nativeRenderer()
|
const replacement = nativeRenderer()
|
||||||
if (replacement === null || typeof replacement === 'string') {
|
return replacement === null || typeof replacement === 'string' ? (
|
||||||
return replacement
|
replacement
|
||||||
} else {
|
) : (
|
||||||
return <JumpAnchor {...(replacement.props as AllHTMLAttributes<HTMLAnchorElement>)} jumpTargetId={jumpId} />
|
<JumpAnchor {...(replacement.props as AllHTMLAttributes<HTMLAnchorElement>)} jumpTargetId={jumpId} />
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Element } from 'domhandler'
|
import type { Element } from 'domhandler'
|
||||||
import type { ReactElement } from 'react'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { ComponentReplacer } from '../../replace-components/component-replacer'
|
import type { NodeReplacement } from '../../replace-components/component-replacer'
|
||||||
|
import { ComponentReplacer, DO_NOT_REPLACE } from '../../replace-components/component-replacer'
|
||||||
import { TaskListCheckbox } from './task-list-checkbox'
|
import { TaskListCheckbox } from './task-list-checkbox'
|
||||||
|
|
||||||
export type TaskCheckedChangeHandler = (lineInMarkdown: number, checked: boolean) => void
|
export type TaskCheckedChangeHandler = (lineInMarkdown: number, checked: boolean) => void
|
||||||
|
@ -20,23 +20,17 @@ export class TaskListReplacer extends ComponentReplacer {
|
||||||
|
|
||||||
constructor(onTaskCheckedChange?: TaskCheckedChangeHandler) {
|
constructor(onTaskCheckedChange?: TaskCheckedChangeHandler) {
|
||||||
super()
|
super()
|
||||||
this.onTaskCheckedChange = (lineInMarkdown, checked) => {
|
this.onTaskCheckedChange = (lineInMarkdown, checked) => onTaskCheckedChange?.(lineInMarkdown, checked)
|
||||||
if (onTaskCheckedChange === undefined) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
onTaskCheckedChange(lineInMarkdown, checked)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public replace(node: Element): ReactElement | undefined {
|
public replace(node: Element): NodeReplacement {
|
||||||
if (node.attribs?.class !== 'task-list-item-checkbox') {
|
if (node.attribs?.class !== 'task-list-item-checkbox') {
|
||||||
return
|
return DO_NOT_REPLACE
|
||||||
}
|
}
|
||||||
const lineInMarkdown = Number(node.attribs['data-line'])
|
const lineInMarkdown = Number(node.attribs['data-line'])
|
||||||
if (isNaN(lineInMarkdown)) {
|
return isNaN(lineInMarkdown) ? (
|
||||||
return undefined
|
DO_NOT_REPLACE
|
||||||
}
|
) : (
|
||||||
return (
|
|
||||||
<TaskListCheckbox
|
<TaskListCheckbox
|
||||||
onTaskCheckedChange={this.onTaskCheckedChange}
|
onTaskCheckedChange={this.onTaskCheckedChange}
|
||||||
checked={node.attribs.checked !== undefined}
|
checked={node.attribs.checked !== undefined}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { NodeReplacement } from '../../replace-components/component-replacer'
|
import type { NodeReplacement } from '../../replace-components/component-replacer'
|
||||||
import { ComponentReplacer } from '../../replace-components/component-replacer'
|
import { ComponentReplacer, DO_NOT_REPLACE } from '../../replace-components/component-replacer'
|
||||||
import type { Element } from 'domhandler'
|
import type { Element } from 'domhandler'
|
||||||
import { UploadIndicatingFrame } from './upload-indicating-frame'
|
import { UploadIndicatingFrame } from './upload-indicating-frame'
|
||||||
|
|
||||||
|
@ -16,8 +16,10 @@ const uploadIdRegex = /^upload-(.+)$/
|
||||||
*/
|
*/
|
||||||
export class UploadIndicatingImageFrameReplacer extends ComponentReplacer {
|
export class UploadIndicatingImageFrameReplacer extends ComponentReplacer {
|
||||||
replace(node: Element): NodeReplacement {
|
replace(node: Element): NodeReplacement {
|
||||||
if (node.name === 'img' && uploadIdRegex.test(node.attribs.src)) {
|
return node.name !== 'img' || !uploadIdRegex.test(node.attribs.src) ? (
|
||||||
return <UploadIndicatingFrame width={node.attribs.width} height={node.attribs.height} />
|
DO_NOT_REPLACE
|
||||||
}
|
) : (
|
||||||
|
<UploadIndicatingFrame width={node.attribs.width} height={node.attribs.height} />
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { ValidReactDomElement } from './component-replacer'
|
import type { NodeReplacement } from './component-replacer'
|
||||||
import { ComponentReplacer } from './component-replacer'
|
import { ComponentReplacer, DO_NOT_REPLACE } from './component-replacer'
|
||||||
import type { FunctionComponent } from 'react'
|
import type { FunctionComponent } from 'react'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import type { Element } from 'domhandler'
|
import type { Element } from 'domhandler'
|
||||||
|
@ -22,9 +22,9 @@ export class CodeBlockComponentReplacer extends ComponentReplacer {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
replace(node: Element): ValidReactDomElement | undefined {
|
replace(node: Element): NodeReplacement {
|
||||||
const code = CodeBlockComponentReplacer.extractTextFromCodeNode(node, this.language)
|
const code = CodeBlockComponentReplacer.extractTextFromCodeNode(node, this.language)
|
||||||
return code ? React.createElement(this.component, { code: code }) : undefined
|
return code ? React.createElement(this.component, { code: code }) : DO_NOT_REPLACE
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,13 +10,13 @@ import type { ReactElement } from 'react'
|
||||||
|
|
||||||
export type ValidReactDomElement = ReactElement | string | null
|
export type ValidReactDomElement = ReactElement | string | null
|
||||||
|
|
||||||
export type SubNodeTransform = (node: Node, subKey: number | string) => NodeReplacement
|
export type SubNodeTransform = (node: Node, subKey: number | string) => ValidReactDomElement
|
||||||
|
|
||||||
export type NativeRenderer = () => ValidReactDomElement
|
export type NativeRenderer = () => ValidReactDomElement
|
||||||
|
|
||||||
export const REPLACE_WITH_NOTHING = null
|
export const DO_NOT_REPLACE = Symbol()
|
||||||
export const DO_NOT_REPLACE = undefined
|
|
||||||
export type NodeReplacement = ValidReactDomElement | typeof REPLACE_WITH_NOTHING | typeof DO_NOT_REPLACE
|
export type NodeReplacement = ValidReactDomElement | typeof DO_NOT_REPLACE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for all component replacers.
|
* Base class for all component replacers.
|
||||||
|
@ -42,7 +42,7 @@ export abstract class ComponentReplacer {
|
||||||
* @param subNodeTransform The transformer that should be used.
|
* @param subNodeTransform The transformer that should be used.
|
||||||
* @return The children as react elements.
|
* @return The children as react elements.
|
||||||
*/
|
*/
|
||||||
protected static transformChildren(node: Element, subNodeTransform: SubNodeTransform): NodeReplacement[] {
|
protected static transformChildren(node: Element, subNodeTransform: SubNodeTransform): ValidReactDomElement[] {
|
||||||
return node.children.map((value, index) => subNodeTransform(value, index))
|
return node.children.map((value, index) => subNodeTransform(value, index))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { NodeReplacement } from './component-replacer'
|
import type { NodeReplacement } from './component-replacer'
|
||||||
import { ComponentReplacer } from './component-replacer'
|
import { ComponentReplacer, DO_NOT_REPLACE } from './component-replacer'
|
||||||
import type { FunctionComponent } from 'react'
|
import type { FunctionComponent } from 'react'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import type { Element } from 'domhandler'
|
import type { Element } from 'domhandler'
|
||||||
|
@ -24,7 +24,7 @@ export class CustomTagWithIdComponentReplacer extends ComponentReplacer {
|
||||||
|
|
||||||
public replace(node: Element): NodeReplacement {
|
public replace(node: Element): NodeReplacement {
|
||||||
const id = this.extractId(node)
|
const id = this.extractId(node)
|
||||||
return id ? React.createElement(this.component, { id: id }) : undefined
|
return id ? React.createElement(this.component, { id: id }) : DO_NOT_REPLACE
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { NodeToReactTransformer } from './node-to-react-transformer'
|
||||||
import { Element } from 'domhandler'
|
import { Element } from 'domhandler'
|
||||||
import type { ReactElement, ReactHTMLElement } from 'react'
|
import type { ReactElement, ReactHTMLElement } from 'react'
|
||||||
import type { NodeReplacement } from '../replace-components/component-replacer'
|
import type { NodeReplacement } from '../replace-components/component-replacer'
|
||||||
import { ComponentReplacer, DO_NOT_REPLACE, REPLACE_WITH_NOTHING } from '../replace-components/component-replacer'
|
import { ComponentReplacer, DO_NOT_REPLACE } from '../replace-components/component-replacer'
|
||||||
|
|
||||||
describe('node to react transformer', () => {
|
describe('node to react transformer', () => {
|
||||||
let nodeToReactTransformer: NodeToReactTransformer
|
let nodeToReactTransformer: NodeToReactTransformer
|
||||||
|
@ -30,7 +30,7 @@ describe('node to react transformer', () => {
|
||||||
nodeToReactTransformer.setReplacers([
|
nodeToReactTransformer.setReplacers([
|
||||||
new (class extends ComponentReplacer {
|
new (class extends ComponentReplacer {
|
||||||
replace(): NodeReplacement {
|
replace(): NodeReplacement {
|
||||||
return REPLACE_WITH_NOTHING
|
return null
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
])
|
])
|
||||||
|
|
|
@ -8,7 +8,7 @@ import type { Element, Node } from 'domhandler'
|
||||||
import { isTag } from 'domhandler'
|
import { isTag } from 'domhandler'
|
||||||
import { convertNodeToReactElement } from '@hedgedoc/html-to-react/dist/convertNodeToReactElement'
|
import { convertNodeToReactElement } from '@hedgedoc/html-to-react/dist/convertNodeToReactElement'
|
||||||
import type { ComponentReplacer, NodeReplacement, ValidReactDomElement } from '../replace-components/component-replacer'
|
import type { ComponentReplacer, NodeReplacement, ValidReactDomElement } from '../replace-components/component-replacer'
|
||||||
import { DO_NOT_REPLACE, REPLACE_WITH_NOTHING } from '../replace-components/component-replacer'
|
import { DO_NOT_REPLACE } from '../replace-components/component-replacer'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import type { LineWithId } from '../markdown-extension/linemarker/types'
|
import type { LineWithId } from '../markdown-extension/linemarker/types'
|
||||||
import { Optional } from '@mrdrogdrog/optional'
|
import { Optional } from '@mrdrogdrog/optional'
|
||||||
|
@ -45,7 +45,7 @@ export class NodeToReactTransformer {
|
||||||
* @param index The index of the node within its parents child list.
|
* @param index The index of the node within its parents child list.
|
||||||
* @return the created react element
|
* @return the created react element
|
||||||
*/
|
*/
|
||||||
public translateNodeToReactElement(node: Node, index: number | string): ValidReactDomElement | undefined {
|
public translateNodeToReactElement(node: Node, index: number | string): ValidReactDomElement {
|
||||||
return isTag(node)
|
return isTag(node)
|
||||||
? this.translateElementToReactElement(node, index)
|
? this.translateElementToReactElement(node, index)
|
||||||
: convertNodeToReactElement(node, index, this.translateNodeToReactElement.bind(this))
|
: convertNodeToReactElement(node, index, this.translateNodeToReactElement.bind(this))
|
||||||
|
@ -58,10 +58,10 @@ export class NodeToReactTransformer {
|
||||||
* @param index The index of the element within its parents child list.
|
* @param index The index of the element within its parents child list.
|
||||||
* @return the created react element
|
* @return the created react element
|
||||||
*/
|
*/
|
||||||
private translateElementToReactElement(element: Element, index: number | string): ValidReactDomElement | undefined {
|
private translateElementToReactElement(element: Element, index: number | string): ValidReactDomElement {
|
||||||
const elementKey = this.calculateUniqueKey(element).orElseGet(() => (-index).toString())
|
const elementKey = this.calculateUniqueKey(element).orElseGet(() => (-index).toString())
|
||||||
const replacement = this.findElementReplacement(element, elementKey)
|
const replacement = this.findElementReplacement(element, elementKey)
|
||||||
if (replacement === REPLACE_WITH_NOTHING) {
|
if (replacement === null) {
|
||||||
return null
|
return null
|
||||||
} else if (replacement === DO_NOT_REPLACE) {
|
} else if (replacement === DO_NOT_REPLACE) {
|
||||||
return this.renderNativeNode(element, elementKey)
|
return this.renderNativeNode(element, elementKey)
|
||||||
|
@ -101,7 +101,7 @@ export class NodeToReactTransformer {
|
||||||
*
|
*
|
||||||
* @param element The {@link Element} that should be checked.
|
* @param element The {@link Element} that should be checked.
|
||||||
* @param elementKey The unique key for the element
|
* @param elementKey The unique key for the element
|
||||||
* @return The replacement or {@link DO_NOT_REPLACE} if the element shouldn't be replaced or {@link REPLACE_WITH_NOTHING} if the node shouldn't be rendered at all.
|
* @return The replacement or {@link DO_NOT_REPLACE} if the element shouldn't be replaced with a custom component.
|
||||||
*/
|
*/
|
||||||
private findElementReplacement(element: Element, elementKey: string): NodeReplacement {
|
private findElementReplacement(element: Element, elementKey: string): NodeReplacement {
|
||||||
const transformer = this.translateNodeToReactElement.bind(this)
|
const transformer = this.translateNodeToReactElement.bind(this)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue