mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-14 07:04:45 -04:00

* Add function for test attribute Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de> * Adjust components Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de> * Fix naming of attribute Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de> * Rename method Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de> * Rename method, interface, attribute and use interface Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de> * Lint and format fix Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
80 lines
2.6 KiB
TypeScript
80 lines
2.6 KiB
TypeScript
/*
|
|
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
*/
|
|
|
|
import type { ReactElement } from 'react'
|
|
import React, { Fragment, useEffect, useState } from 'react'
|
|
import convertHtmlToReact from '@hedgedoc/html-to-react'
|
|
import { CopyToClipboardButton } from '../../../../common/copyable/copy-to-clipboard-button/copy-to-clipboard-button'
|
|
import '../../../utils/button-inside.scss'
|
|
import './highlighted-code.scss'
|
|
import { Logger } from '../../../../../utils/logger'
|
|
import { cypressId } from '../../../../../utils/cypress-attribute'
|
|
|
|
const log = new Logger('HighlightedCode')
|
|
|
|
export interface HighlightedCodeProps {
|
|
code: string
|
|
language?: string
|
|
startLineNumber?: number
|
|
wrapLines: boolean
|
|
}
|
|
|
|
/*
|
|
TODO: Test method or rewrite code so this is not necessary anymore
|
|
*/
|
|
const escapeHtml = (unsafe: string): string => {
|
|
return unsafe
|
|
.replaceAll(/&/g, '&')
|
|
.replaceAll(/</g, '<')
|
|
.replaceAll(/>/g, '>')
|
|
.replaceAll(/"/g, '"')
|
|
.replaceAll(/'/g, ''')
|
|
}
|
|
|
|
const replaceCode = (code: string): (ReactElement | null | string)[][] => {
|
|
return code
|
|
.split('\n')
|
|
.filter((line) => !!line)
|
|
.map((line) => convertHtmlToReact(line, {}))
|
|
}
|
|
|
|
export const HighlightedCode: React.FC<HighlightedCodeProps> = ({ code, language, startLineNumber, wrapLines }) => {
|
|
const [dom, setDom] = useState<ReactElement[]>()
|
|
|
|
useEffect(() => {
|
|
import(/* webpackChunkName: "highlight.js" */ '../../../../common/hljs/hljs')
|
|
.then((hljs) => {
|
|
const languageSupported = (lang: string) => hljs.default.listLanguages().includes(lang)
|
|
const unreplacedCode =
|
|
!!language && languageSupported(language)
|
|
? hljs.default.highlight(code, { language }).value
|
|
: escapeHtml(code)
|
|
const replacedDom = replaceCode(unreplacedCode).map((line, index) => (
|
|
<Fragment key={index}>
|
|
<span className={'linenumber'}>{(startLineNumber || 1) + index}</span>
|
|
<div className={'codeline'}>{line}</div>
|
|
</Fragment>
|
|
))
|
|
setDom(replacedDom)
|
|
})
|
|
.catch((error: Error) => {
|
|
log.error('Error while loading highlight.js', error)
|
|
})
|
|
}, [code, language, startLineNumber])
|
|
|
|
return (
|
|
<div className={'code-highlighter'}>
|
|
<code className={`hljs ${startLineNumber !== undefined ? 'showGutter' : ''} ${wrapLines ? 'wrapLines' : ''}`}>
|
|
{dom}
|
|
</code>
|
|
<div className={'text-right button-inside'}>
|
|
<CopyToClipboardButton content={code} {...cypressId('copy-code-button')} />
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default HighlightedCode
|