added mathjax (#250)

added markdown-it-mathjax

Signed-off-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
Co-authored-by: Philip Molares <philip@mauricedoepke.de>
Co-authored-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
This commit is contained in:
Philip Molares 2020-06-23 00:38:06 +02:00 committed by GitHub
parent 9e6edb0aeb
commit 8133d565cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 107 additions and 2 deletions

View file

@ -19,6 +19,7 @@
"@types/react-bootstrap-typeahead": "3.4.6",
"@types/react-dom": "16.9.8",
"@types/react-html-parser": "2.0.1",
"@types/react-mathjax": "^1.0.0",
"@types/react-redux": "7.1.9",
"@types/react-router": "5.1.7",
"@types/react-router-bootstrap": "0.24.5",
@ -50,11 +51,13 @@
"markdown-it-footnote": "3.0.2",
"markdown-it-ins": "3.0.0",
"markdown-it-mark": "3.0.0",
"markdown-it-mathjax": "^2.0.0",
"markdown-it-regex": "0.2.0",
"markdown-it-sub": "1.0.0",
"markdown-it-sup": "1.0.0",
"markdown-it-table-of-contents": "0.4.4",
"markdown-it-task-lists": "2.1.1",
"mathjax": "^3.0.5",
"moment": "2.27.0",
"node-sass": "4.14.1",
"react": "16.13.1",
@ -64,6 +67,7 @@
"react-dom": "16.13.1",
"react-html-parser": "2.0.2",
"react-i18next": "11.7.0",
"react-mathjax": "^1.0.1",
"react-redux": "7.2.0",
"react-router": "5.2.0",
"react-router-bootstrap": "0.25.0",

View file

@ -15,6 +15,21 @@ const Editor: React.FC = () => {
const [markdownContent, setMarkdownContent] = useState(`# Embedding demo
[TOC]
## MathJax
You can render *LaTeX* mathematical expressions using **MathJax**, as on [math.stackexchange.com](https://math.stackexchange.com/):
The *Gamma function* satisfying $\\Gamma(n) = (n-1)!\\quad\\forall n\\in\\mathbb N$ is via the Euler integral
$$
x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.
$$
$$
\\Gamma(z) = \\int_0^\\infty t^{z-1}e^{-t}dt\\,.
$$
> More information about **LaTeX** mathematical expressions [here](https://meta.math.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference).
## Blockquote
> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.

View file

@ -13,7 +13,9 @@ 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 { createRenderContainer, validAlertLevels } from './container-plugins/alert'
import { highlightedCode } from './markdown-it-plugins/highlighted-code'
@ -32,6 +34,7 @@ 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 { 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 { getTOCReplacement } from './replace-components/toc/toc-replacer'
@ -47,7 +50,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]
const allComponentReplacers: ComponentReplacer[] = [getYouTubeReplacement, getVimeoReplacement, getGistReplacement, getPDFReplacement, getTOCReplacement, getHighlightedCodeBlock, getQuoteOptionsReplacement, getMathJaxReplacement]
const tryToReplaceNode = (node: DomElement, index:number, componentReplacer2Identifier2CounterMap: ComponentReplacer2Identifier2CounterMap, nodeConverter: SubNodeConverter) => {
return allComponentReplacers
@ -75,6 +78,7 @@ const MarkdownRenderer: React.FC<MarkdownPreviewProps> = ({ content }) => {
md.use(inserted)
md.use(marked)
md.use(footnote)
// noinspection CheckTagEmptyBody
md.use(anchor, {
permalink: true,
permalinkBefore: true,
@ -84,6 +88,14 @@ const MarkdownRenderer: React.FC<MarkdownPreviewProps> = ({ content }) => {
md.use(toc, {
markerPattern: /^\[TOC]$/i
})
md.use(mathJax({
beforeMath: '<codimd-mathjax>',
afterMath: '</codimd-mathjax>',
beforeInlineMath: '<codimd-mathjax inline>',
afterInlineMath: '</codimd-mathjax>',
beforeDisplayMath: '<codimd-mathjax>',
afterDisplayMath: '</codimd-mathjax>'
}))
md.use(markdownItRegex, replaceLegacyYoutubeShortCode)
md.use(markdownItRegex, replaceLegacyVimeoShortCode)
md.use(markdownItRegex, replaceLegacyGistShortCode)
@ -119,7 +131,11 @@ const MarkdownRenderer: React.FC<MarkdownPreviewProps> = ({ content }) => {
return (
<div className={'bg-light container-fluid flex-fill h-100 overflow-y-scroll pb-5'}>
<div className={'markdown-body container-fluid'}>{result}</div>
<div className={'markdown-body container-fluid'}>
<MathJaxReact.Provider>
{result}
</MathJaxReact.Provider>
</div>
</div>
)
}

View file

@ -0,0 +1,27 @@
import React from 'react'
import { DomElement } from 'domhandler'
import { ComponentReplacer } from '../../markdown-renderer'
import MathJax from 'react-mathjax'
const getNodeIfMathJaxBlock = (node: DomElement): (DomElement|undefined) => {
if (node.name !== 'p' || !node.children || node.children.length !== 1) {
return
}
const mathJaxNode = node.children[0]
return (mathJaxNode.name === 'codimd-mathjax' && mathJaxNode.attribs?.inline === undefined) ? mathJaxNode : undefined
}
const getNodeIfInlineMathJax = (node: DomElement): (DomElement|undefined) => {
return (node.name === 'codimd-mathjax' && node.attribs?.inline !== undefined) ? node : undefined
}
const getElementReplacement: ComponentReplacer = (node, index: number, counterMap) => {
const mathJax = getNodeIfMathJaxBlock(node) || getNodeIfInlineMathJax(node)
if (mathJax?.children && mathJax.children[0]) {
const mathJaxContent = mathJax.children[0]?.data as string
const isInline = (mathJax.attribs?.inline) !== undefined
return <MathJax.Node key={index} inline={isInline} formula={mathJaxContent}/>
}
}
export { getElementReplacement as getMathJaxReplacement }

View file

@ -0,0 +1,6 @@
declare module 'markdown-it-mathjax' {
import MarkdownIt from 'markdown-it/lib'
import { MathJaxOptions } from './interface'
const markdownItMathJax: (MathJaxOptions) => MarkdownIt.PluginSimple
export = markdownItMathJax
}

View file

@ -0,0 +1,8 @@
export interface MathJaxOptions {
beforeMath: string,
afterMath: string,
beforeInlineMath: string,
afterInlineMath: string,
beforeDisplayMath: string,
afterDisplayMath: string
}

View file

@ -1683,6 +1683,13 @@
"@types/htmlparser2" "*"
"@types/react" "*"
"@types/react-mathjax@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/react-mathjax/-/react-mathjax-1.0.0.tgz#5e337ddc0fbee4d01513d960f81f85963a9ee482"
integrity sha512-c3beW/LhRx/7LkwYGj7mIDphatRdih80Cpe4l2u3LFdyOgBloPaXq3H9QROC6GnhbGxVql7ByHLA70s+Q6ol1Q==
dependencies:
"@types/react" "*"
"@types/react-redux@7.1.9":
version "7.1.9"
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.9.tgz#280c13565c9f13ceb727ec21e767abe0e9b4aec3"
@ -7097,6 +7104,11 @@ load-json-file@^4.0.0:
pify "^3.0.0"
strip-bom "^3.0.0"
load-script@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/load-script/-/load-script-1.0.0.tgz#0491939e0bee5643ee494a7e3da3d2bac70c6ca4"
integrity sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ=
loader-fs-cache@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz#f08657646d607078be2f0a032f8bd69dd6f277d9"
@ -7334,6 +7346,11 @@ markdown-it-mark@3.0.0:
resolved "https://registry.yarnpkg.com/markdown-it-mark/-/markdown-it-mark-3.0.0.tgz#27c3e39ef3cc310b2dde5375082c9fa912983cda"
integrity sha512-HqMWeKfMMOu4zBO0emmxsoMWmbf2cPKZY1wP6FsTbKmicFfp5y4L3KXAsNeO1rM6NTJVOrNlLKMPjWzriBGspw==
markdown-it-mathjax@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/markdown-it-mathjax/-/markdown-it-mathjax-2.0.0.tgz#ae2b4f4c5c719a03f9e475c664f7b2685231d9e9"
integrity sha1-ritPTFxxmgP55HXGZPeyaFIx2ek=
markdown-it-regex@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/markdown-it-regex/-/markdown-it-regex-0.2.0.tgz#e09ad2d75209720d591d3949e1142c75c0fbecf6"
@ -7370,6 +7387,11 @@ markdown-it@11.0.0:
mdurl "^1.0.1"
uc.micro "^1.0.5"
mathjax@^3.0.5:
version "3.0.5"
resolved "https://registry.yarnpkg.com/mathjax/-/mathjax-3.0.5.tgz#707e703a9c1d95f0790bbd404b895566f459d514"
integrity sha512-9M7VulhltkD8sIebWutK/VfAD+m+6BIFqfpjDh9Pz/etoKUtjO6UMnOhUcDmNl6iApE8C9xrUmaMyNZkZAlrMw==
md5.js@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@ -9592,6 +9614,13 @@ react-lifecycles-compat@^3.0.4:
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
react-mathjax@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/react-mathjax/-/react-mathjax-1.0.1.tgz#a8c282e75d277a201632dfd07edf41edda372b4b"
integrity sha512-+mjFcciZY3GQoqiQm3aRTyDjgBKuoaXpY+SCONX00jScuPpTKwnASeFMS5+pbTIzDf5zPT2Y9ZZfQ9U/d4CKtQ==
dependencies:
load-script "^1.0.0"
react-overlays@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-2.1.1.tgz#ffe2090c4a10da6b8947a1c7b1a67d0457648a0d"