mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-23 19:47:03 -04:00
Restructure highlight code to enable line wrapping (#265)
* Restructure highlight code to enable line wrapping Signed-off-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
This commit is contained in:
parent
6bf214542e
commit
eb56da7871
7 changed files with 63 additions and 60 deletions
|
@ -27,6 +27,7 @@
|
|||
- A new table view for the history (besides the card view)
|
||||
- Better support for RTL-languages (and LTR-content in a RTL-page)
|
||||
- Users may now change their display name and password (only email accounts) on the new profile page
|
||||
- Highlighted code blocks can now use line wrapping and line numbers at once
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
@ -1,33 +1,42 @@
|
|||
.markdown-body pre code {
|
||||
.markdown-body {
|
||||
@import '../../../../node_modules/highlight.js/styles/github-gist';
|
||||
}
|
||||
|
||||
&.hljs {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.markdown-body pre code.hljs {
|
||||
|
||||
.linenumbers {
|
||||
text-align: right;
|
||||
position: relative;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
padding: 0 8px 0 0;
|
||||
min-width: 20px;
|
||||
box-sizing: content-box;
|
||||
color: #afafaf;
|
||||
border-right: 3px solid #6ce26c;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
padding: 16px;
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(0, 1fr);
|
||||
|
||||
& > span:before {
|
||||
content: attr(data-line-number);
|
||||
&.showGutter {
|
||||
.linenumber {
|
||||
position: relative;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
padding: 0 8px 0 0;
|
||||
min-width: 20px;
|
||||
box-sizing: content-box;
|
||||
color: #afafaf;
|
||||
border-right: 3px solid #6ce26c;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
|
||||
|
||||
&:before {
|
||||
content: attr(data-line-number);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.code {
|
||||
float: left;
|
||||
&.showGutter .line {
|
||||
margin: 0 0 0 16px;
|
||||
}
|
||||
&.wrapLines .line {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import hljs from 'highlight.js'
|
||||
import React, { useMemo } from 'react'
|
||||
import React, { Fragment, useMemo } from 'react'
|
||||
import ReactHtmlParser from 'react-html-parser'
|
||||
import { ShowIf } from '../show-if/show-if'
|
||||
import './highlighted-code.scss'
|
||||
|
||||
export interface HighlightedCodeProps {
|
||||
code: string,
|
||||
language?: string,
|
||||
showGutter: boolean
|
||||
wrapLines: boolean
|
||||
}
|
||||
|
||||
export const escapeHtml = (unsafe: string): string => {
|
||||
|
@ -19,11 +19,11 @@ export const escapeHtml = (unsafe: string): string => {
|
|||
.replace(/'/g, ''')
|
||||
}
|
||||
|
||||
const checkIfLanguageIsSupported = (language: string):boolean => {
|
||||
const checkIfLanguageIsSupported = (language: string): boolean => {
|
||||
return hljs.listLanguages().indexOf(language) > -1
|
||||
}
|
||||
|
||||
const correctLanguage = (language: string|undefined): string|undefined => {
|
||||
const correctLanguage = (language: string | undefined): string | undefined => {
|
||||
switch (language) {
|
||||
case 'html':
|
||||
return 'xml'
|
||||
|
@ -32,7 +32,7 @@ const correctLanguage = (language: string|undefined): string|undefined => {
|
|||
}
|
||||
}
|
||||
|
||||
export const HighlightedCode: React.FC<HighlightedCodeProps> = ({ code, language, showGutter }) => {
|
||||
export const HighlightedCode: React.FC<HighlightedCodeProps> = ({ code, language, showGutter, wrapLines }) => {
|
||||
const highlightedCode = useMemo(() => {
|
||||
const replacedLanguage = correctLanguage(language)
|
||||
return ((!!replacedLanguage && checkIfLanguageIsSupported(replacedLanguage)) ? hljs.highlight(replacedLanguage, code).value : escapeHtml(code))
|
||||
|
@ -42,25 +42,18 @@ export const HighlightedCode: React.FC<HighlightedCodeProps> = ({ code, language
|
|||
}, [code, language])
|
||||
|
||||
return (
|
||||
<code className={'hljs'}>
|
||||
<ShowIf condition={showGutter}>
|
||||
<span className={'linenumbers'}>
|
||||
{
|
||||
highlightedCode
|
||||
.map((line, index) => {
|
||||
return <span key={index} data-line-number={index + 1}/>
|
||||
})
|
||||
}
|
||||
</span>
|
||||
</ShowIf>
|
||||
<span className={'code'}>
|
||||
{
|
||||
highlightedCode
|
||||
.map((line, index) =>
|
||||
<div key={index} className={'line'}>
|
||||
<code className={`hljs ${showGutter ? 'showGutter' : ''} ${wrapLines ? 'wrapLines' : ''}`}>
|
||||
{
|
||||
highlightedCode
|
||||
.map((line, index) => {
|
||||
return <Fragment key={index}>
|
||||
<span className={'linenumber'} data-line-number={index + 1}/>
|
||||
<div className={'line'}>
|
||||
{line}
|
||||
</div>)
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</Fragment>
|
||||
})
|
||||
}
|
||||
|
||||
</code>)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import MarkdownIt from 'markdown-it/lib'
|
||||
|
||||
const highlightRegex = /^(\w*)(=?)$/
|
||||
const highlightRegex = /^(\w*)(=?)(!?)$/
|
||||
|
||||
export const highlightedCode: MarkdownIt.PluginSimple = (md: MarkdownIt) => {
|
||||
md.core.ruler.push('highlighted-code', (state) => {
|
||||
|
@ -16,6 +16,9 @@ export const highlightedCode: MarkdownIt.PluginSimple = (md: MarkdownIt) => {
|
|||
if (highlightInfos[2]) {
|
||||
token.attrJoin('data-show-gutter', '')
|
||||
}
|
||||
if (highlightInfos[3]) {
|
||||
token.attrJoin('data-wrap-lines', '')
|
||||
}
|
||||
}
|
||||
})
|
||||
return true
|
||||
|
|
|
@ -9,15 +9,15 @@ import footnote from 'markdown-it-footnote'
|
|||
import imsize from 'markdown-it-imsize'
|
||||
import inserted from 'markdown-it-ins'
|
||||
import marked from 'markdown-it-mark'
|
||||
import mathJax from 'markdown-it-mathjax'
|
||||
import markdownItRegex from 'markdown-it-regex'
|
||||
import subscript from 'markdown-it-sub'
|
||||
import superscript from 'markdown-it-sup'
|
||||
import toc from 'markdown-it-table-of-contents'
|
||||
import taskList from 'markdown-it-task-lists'
|
||||
import mathJax from 'markdown-it-mathjax'
|
||||
import React, { ReactElement, useMemo } from 'react'
|
||||
import MathJaxReact from 'react-mathjax'
|
||||
import ReactHtmlParser, { convertNodeToElement, Transform } from 'react-html-parser'
|
||||
import MathJaxReact from 'react-mathjax'
|
||||
import { createRenderContainer, validAlertLevels } from './container-plugins/alert'
|
||||
import { highlightedCode } from './markdown-it-plugins/highlighted-code'
|
||||
import { MarkdownItParserDebugger } from './markdown-it-plugins/parser-debugger'
|
||||
|
@ -35,12 +35,12 @@ import { replaceQuoteExtraTime } from './regex-plugins/replace-quote-extra-time'
|
|||
import { replaceVimeoLink } from './regex-plugins/replace-vimeo-link'
|
||||
import { replaceYouTubeLink } from './regex-plugins/replace-youtube-link'
|
||||
import { getGistReplacement } from './replace-components/gist/gist-frame'
|
||||
import { getHighlightedFence } from './replace-components/highlighted-fence/highlighted-fence'
|
||||
import { getMathJaxReplacement } from './replace-components/mathjax/mathjax-replacer'
|
||||
import { getHighlightedCodeBlock } from './replace-components/highlighted-code/highlighted-code'
|
||||
import { getPDFReplacement } from './replace-components/pdf/pdf-frame'
|
||||
import { getQuoteOptionsReplacement } from './replace-components/quote-options/quote-options'
|
||||
import { getTOCReplacement } from './replace-components/toc/toc-replacer'
|
||||
import { getVimeoReplacement } from './replace-components/vimeo/vimeo-frame'
|
||||
import { getQuoteOptionsReplacement } from './replace-components/quote-options/quote-options'
|
||||
import { getYouTubeReplacement } from './replace-components/youtube/youtube-frame'
|
||||
|
||||
export interface MarkdownPreviewProps {
|
||||
|
@ -51,7 +51,7 @@ export type SubNodeConverter = (node: DomElement, index: number) => ReactElement
|
|||
export type ComponentReplacer = (node: DomElement, index: number, counterMap: Map<string, number>, nodeConverter: SubNodeConverter) => (ReactElement | undefined);
|
||||
type ComponentReplacer2Identifier2CounterMap = Map<ComponentReplacer, Map<string, number>>
|
||||
|
||||
const allComponentReplacers: ComponentReplacer[] = [getYouTubeReplacement, getVimeoReplacement, getGistReplacement, getPDFReplacement, getTOCReplacement, getHighlightedCodeBlock, getQuoteOptionsReplacement, getMathJaxReplacement]
|
||||
const allComponentReplacers: ComponentReplacer[] = [getYouTubeReplacement, getVimeoReplacement, getGistReplacement, getPDFReplacement, getTOCReplacement, getHighlightedFence, getQuoteOptionsReplacement, getMathJaxReplacement]
|
||||
|
||||
const tryToReplaceNode = (node: DomElement, index:number, componentReplacer2Identifier2CounterMap: ComponentReplacer2Identifier2CounterMap, nodeConverter: SubNodeConverter) => {
|
||||
return allComponentReplacers
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
.markdown-body {
|
||||
@import '../../../../../../node_modules/highlight.js/styles/github-gist';
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
import { DomElement } from 'domhandler'
|
||||
import React, { ReactElement } from 'react'
|
||||
import { HighlightedCode } from '../../../../common/highlighted-code/highlighted-code'
|
||||
import './highlighted-code.scss'
|
||||
|
||||
const getElementReplacement = (codeNode: DomElement, index: number, counterMap: Map<string, number>): (ReactElement | undefined) => {
|
||||
if (codeNode.name !== 'code' || !codeNode.attribs || !codeNode.attribs['data-highlight-language'] || !codeNode.children || !codeNode.children[0]) {
|
||||
|
@ -10,7 +9,8 @@ const getElementReplacement = (codeNode: DomElement, index: number, counterMap:
|
|||
|
||||
const language = codeNode.attribs['data-highlight-language']
|
||||
const showGutter = codeNode.attribs['data-show-gutter'] !== undefined
|
||||
return <HighlightedCode key={index} language={language} showGutter={showGutter} code={codeNode.children[0].data as string}/>
|
||||
const wrapLines = codeNode.attribs['data-wrap-lines'] !== undefined
|
||||
return <HighlightedCode key={index} language={language} showGutter={showGutter} wrapLines={wrapLines} code={codeNode.children[0].data as string}/>
|
||||
}
|
||||
|
||||
export { getElementReplacement as getHighlightedCodeBlock }
|
||||
export { getElementReplacement as getHighlightedFence }
|
Loading…
Add table
Add a link
Reference in a new issue