Merge basic and full markdown renderer (#1040)

The original idea of the basic-markdown-renderer and the full-markdown-renderer was to reduce the complexity. The basic markdown renderer should just render markdown code and the full markdown renderer should implement all the special hedgedoc stuff like the embeddings.
While developing other aspects of the software I noticed, that it makes more sense to split the markdown-renderer by the view and not by the features. E.g.: The slide markdown renderer must translate <hr> into <sections> for the slides and the document markdown renderer must provide precise scroll positions. But both need e.g. the ability to show a youtube video.

Signed-off-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
This commit is contained in:
Tilman Vatteroth 2021-02-17 22:58:21 +01:00 committed by GitHub
parent 364aec1318
commit d9292e4db0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 777 additions and 979 deletions

View file

@ -1,7 +1,7 @@
/*
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
SPDX-License-Identifier: AGPL-3.0-only
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import React, { useEffect, useRef, useState } from 'react'
@ -25,26 +25,25 @@ export const FlowChart: React.FC<FlowChartProps> = ({ code }) => {
return
}
const currentDiagramRef = diagramRef.current
import(/* webpackChunkName: "flowchart.js" */ 'flowchart.js').then((imp) => {
const parserOutput = imp.parse(code)
try {
parserOutput.drawSVG(currentDiagramRef, {
'line-width': 2,
fill: 'none',
'font-size': 16,
'line-color': darkModeActivated ? '#ffffff' : '#000000',
'element-color': darkModeActivated ? '#ffffff' : '#000000',
'font-color': darkModeActivated ? '#ffffff' : '#000000',
'font-family': 'Source Sans Pro, "Twemoji Mozilla", monospace'
})
setError(false)
} catch (error) {
setError(true)
}
})
.catch(() => {
console.error('error while loading flowchart.js')
})
import(/* webpackChunkName: "flowchart.js" */ 'flowchart.js')
.then((imp) => {
const parserOutput = imp.parse(code)
try {
parserOutput.drawSVG(currentDiagramRef, {
'line-width': 2,
fill: 'none',
'font-size': 16,
'line-color': darkModeActivated ? '#ffffff' : '#000000',
'element-color': darkModeActivated ? '#ffffff' : '#000000',
'font-color': darkModeActivated ? '#ffffff' : '#000000',
'font-family': 'Source Sans Pro, "Twemoji Mozilla", monospace'
})
setError(false)
} catch (error) {
setError(true)
}
})
.catch(() => console.error('error while loading flowchart.js'))
return () => {
Array.from(currentDiagramRef.children)

View file

@ -1,7 +1,7 @@
/*
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
SPDX-License-Identifier: AGPL-3.0-only
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react'
@ -32,7 +32,7 @@ export const GraphvizFrame: React.FC<GraphvizFrameProps> = ({ code }) => {
}
const actualContainer = container.current
import('@hpcc-js/wasm')
import(/* webpackChunkName: "d3-graphviz" */'@hpcc-js/wasm')
.then((wasmPlugin) => {
wasmPlugin.wasmFolder('/static/js')
})

View file

@ -1,13 +1,9 @@
/*
/*!
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
.markdown-body {
}
.markdown-body {
@import '../../../../../../node_modules/highlight.js/styles/github';

View file

@ -17,13 +17,16 @@ export interface HighlightedCodeProps {
wrapLines: boolean
}
export const escapeHtml = (unsafe: string): string => {
/*
TODO: Test method or rewrite code so this is not necessary anymore
*/
const escapeHtml = (unsafe: string): string => {
return unsafe
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;')
.replaceAll(/&/g, '&amp;')
.replaceAll(/</g, '&lt;')
.replaceAll(/>/g, '&gt;')
.replaceAll(/"/g, '&quot;')
.replaceAll(/'/g, '&#039;')
}
const replaceCode = (code: string): ReactElement[][] => {
@ -69,3 +72,5 @@ export const HighlightedCode: React.FC<HighlightedCodeProps> = ({ code, language
</div>
</Fragment>)
}
export default HighlightedCode

View file

@ -18,7 +18,7 @@ export type LineNumberMarkerOptions = (lineMarkers: LineMarkers[]) => void;
* This plugin adds markers to the dom, that are used to map line numbers to dom elements.
* It also provides a list of line numbers for the top level dom elements.
*/
export const lineNumberMarker: MarkdownIt.PluginWithOptions<LineNumberMarkerOptions> = (md: MarkdownIt, options) => {
export const lineNumberMarker: (options: LineNumberMarkerOptions) => MarkdownIt.PluginSimple = (options) => (md: MarkdownIt) => {
// add app_linemarker token before each opening or self-closing level-0 tag
md.core.ruler.push('line_number_marker', (state) => {
const lineMarkers: LineMarkers[] = []

View file

@ -1,7 +1,7 @@
/*
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
SPDX-License-Identifier: AGPL-3.0-only
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import React, { Fragment, useEffect, useRef, useState } from 'react'
@ -45,21 +45,22 @@ export const MarkmapFrame: React.FC<MarkmapFrameProps> = ({ code }) => {
return
}
const actualContainer = diagramContainer.current
import('./markmap-loader').then(({ markmapLoader }) => {
try {
const svg: SVGSVGElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
svg.setAttribute('width', '100%')
actualContainer.querySelectorAll('svg')
.forEach(child => child.remove())
actualContainer.appendChild(svg)
markmapLoader(svg, code)
} catch (error) {
console.error(error)
}
})
.catch(() => {
console.error('error while loading markmap')
})
import(/* webpackChunkName: "markmap" */'./markmap-loader')
.then(({ markmapLoader }) => {
try {
const svg: SVGSVGElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
svg.setAttribute('width', '100%')
actualContainer.querySelectorAll('svg')
.forEach(child => child.remove())
actualContainer.appendChild(svg)
markmapLoader(svg, code)
} catch (error) {
console.error(error)
}
})
.catch(() => {
console.error('error while loading markmap')
})
}, [code])
return (

View file

@ -1,7 +1,7 @@
/*
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
SPDX-License-Identifier: AGPL-3.0-only
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react'
@ -27,13 +27,14 @@ export const MermaidChart: React.FC<MermaidChartProps> = ({ code }) => {
useEffect(() => {
if (!mermaidInitialized) {
import('mermaid').then((mermaid) => {
mermaid.default.initialize({ startOnLoad: false })
mermaidInitialized = true
})
.catch(() => {
console.error('error while loading mermaid')
})
import(/* webpackChunkName: "mermaid" */'mermaid')
.then((mermaid) => {
mermaid.default.initialize({ startOnLoad: false })
mermaidInitialized = true
})
.catch(() => {
console.error('error while loading mermaid')
})
}
}, [])
@ -51,22 +52,23 @@ export const MermaidChart: React.FC<MermaidChartProps> = ({ code }) => {
if (!diagramContainer.current) {
return
}
import('mermaid').then((mermaid) => {
try {
if (!diagramContainer.current) {
return
import(/* webpackChunkName: "mermaid" */'mermaid')
.then((mermaid) => {
try {
if (!diagramContainer.current) {
return
}
mermaid.default.parse(code)
delete diagramContainer.current.dataset.processed
diagramContainer.current.textContent = code
mermaid.default.init(diagramContainer.current)
setError(undefined)
} catch (error) {
const message = (error as MermaidParseError).str
showError(message || t('renderer.mermaid.unknownError'))
}
mermaid.default.parse(code)
delete diagramContainer.current.dataset.processed
diagramContainer.current.textContent = code
mermaid.default.init(diagramContainer.current)
setError(undefined)
} catch (error) {
const message = (error as MermaidParseError).str
showError(message || t('renderer.mermaid.unknownError'))
}
})
.catch(() => showError('Error while loading mermaid'))
})
.catch(() => showError('Error while loading mermaid'))
}, [code, showError, t])
return <Fragment>

View file

@ -8,10 +8,12 @@ import { DomElement } from 'domhandler'
import React, { ReactElement } from 'react'
import { ComponentReplacer } from '../ComponentReplacer'
export type TaskCheckedChangeHandler = (lineInMarkdown: number, checked: boolean) => void
export class TaskListReplacer extends ComponentReplacer {
onTaskCheckedChange?: (lineInMarkdown: number, checked: boolean) => void
constructor(onTaskCheckedChange?: (lineInMarkdown: number, checked: boolean) => void) {
constructor(onTaskCheckedChange?: TaskCheckedChangeHandler) {
super()
this.onTaskCheckedChange = onTaskCheckedChange
}

View file

@ -1,7 +1,7 @@
/*
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
SPDX-License-Identifier: AGPL-3.0-only
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react'
@ -31,34 +31,35 @@ export const VegaChart: React.FC<VegaChartProps> = ({ code }) => {
if (!diagramContainer.current) {
return
}
import(/* webpackChunkName: "vega" */ 'vega-embed').then((embed) => {
try {
if (!diagramContainer.current) {
return
}
const spec = JSON.parse(code) as VisualizationSpec
embed.default(diagramContainer.current, spec, {
actions: {
export: true,
source: false,
compiled: false,
editor: false
},
i18n: {
PNG_ACTION: t('renderer.vega-lite.png'),
SVG_ACTION: t('renderer.vega-lite.svg')
import(/* webpackChunkName: "vega" */ 'vega-embed')
.then((embed) => {
try {
if (!diagramContainer.current) {
return
}
})
.then(() => setError(undefined))
.catch(err => showError(err))
} catch (err) {
showError(t('renderer.vega-lite.errorJson'))
}
})
.catch(() => {
console.error('error while loading vega-light')
})
const spec = JSON.parse(code) as VisualizationSpec
embed.default(diagramContainer.current, spec, {
actions: {
export: true,
source: false,
compiled: false,
editor: false
},
i18n: {
PNG_ACTION: t('renderer.vega-lite.png'),
SVG_ACTION: t('renderer.vega-lite.svg')
}
})
.then(() => setError(undefined))
.catch(err => showError(err))
} catch (err) {
showError(t('renderer.vega-lite.errorJson'))
}
})
.catch(() => {
console.error('error while loading vega-light')
})
}, [code, showError, t])
return <Fragment>