Skip to content

Commit

Permalink
feat: add mathjax renderer (#385)
Browse files Browse the repository at this point in the history
* fix #376
* fix #384 

---------

Co-authored-by: yanglbme <[email protected]>
  • Loading branch information
YangFong and yanglbme authored Sep 7, 2024
1 parent feafd04 commit e93895e
Show file tree
Hide file tree
Showing 7 changed files with 298 additions and 273 deletions.
14 changes: 7 additions & 7 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,6 @@
crossorigin="anonymous"
/>
<style>
/**
解决公众号复制字体问题
*/
.katex .mathnormal {
font-family: 'Times New Roman' !important;
}

.loading {
position: fixed;
top: 0;
Expand Down Expand Up @@ -98,6 +91,13 @@
document.querySelector('.loading').classList.add('dark')
}
</script>
<script>
MathJax = {
svg: { fontCache: 'none' },
tex: { tags: 'ams' },
}
</script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
<script type="module" src="/src/main.js"></script>
</body>
<script src="https://cdn-doocs.oss-cn-shenzhen.aliyuncs.com/gh/wechatsync/article-syncjs@latest/dist/main.js"></script>
Expand Down
437 changes: 188 additions & 249 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,8 @@
"form-data": "4.0.0",
"highlight.js": "^11.10.0",
"juice": "^8.0.0",
"katex": "^0.16.11",
"lucide-vue-next": "^0.428.0",
"marked": "^14.1.1",
"marked-katex-extension": "^5.1.2",
"mermaid": "^11.1.0",
"minio": "7.1.3",
"node-fetch": "^3.3.2",
Expand Down
6 changes: 0 additions & 6 deletions src/components/CodemirrorEditor/EditorHeader/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,7 @@ function copy() {
const clipboardDiv = document.getElementById(`output`)
clipboardDiv.innerHTML = mergeCss(clipboardDiv.innerHTML)
clipboardDiv.innerHTML = modifyHtmlStructure(clipboardDiv.innerHTML)
// 调整 katex 公式元素为行内标签,目的是兼容微信公众号渲染
clipboardDiv.innerHTML = clipboardDiv.innerHTML
.replace(
/class="base"( style="display: inline")*/g,
`class="base" style="display: inline"`,
)
// 公众号不支持 position, 转换为等价的 translateY
.replace(/top:(.*?)em/g, `transform: translateY($1em)`)
// 适配主题中的颜色变量
Expand Down
7 changes: 7 additions & 0 deletions src/utils/MDKatex.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { MarkedExtension } from 'marked'

export interface MarkedKatexOptions {
nonStandard?: boolean
}

export function MDKatex(options?: MarkedKatexOptions): MarkedExtension
93 changes: 93 additions & 0 deletions src/utils/MDKatex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
const inlineRule = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n$]))\1(?=[\s?!.,:]|$)/
const inlineRuleNonStandard = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n$]))\1/ // Non-standard, even if there are no spaces before and after $ or $$, try to parse

const blockRule = /^(\${1,2})\n((?:\\[\s\S]|[^\\])+?)\n\1(?:\n|$)/

function createRenderer(display) {
return (token) => {
window.MathJax.texReset()
const mjxContainer = window.MathJax.tex2svg(token.text, { display })
const svg = mjxContainer.firstChild
const width = svg.style[`min-width`] || svg.getAttribute(`width`)
svg.removeAttribute(`width`)
svg.style = `max-width: 300vw !important;`
svg.style.width = width
svg.style.display = `initial`
if (display) {
return `<section style="text-align: center; overflow: auto;">${svg.outerHTML}</section>`
}
else {
return `<span style="display: inline-block; vertical-align: middle; line-height: 1;">${svg.outerHTML}</span>`
}
}
}

function inlineKatex(options, renderer) {
const nonStandard = options && options.nonStandard
const ruleReg = nonStandard ? inlineRuleNonStandard : inlineRule
return {
name: `inlineKatex`,
level: `inline`,
start(src) {
let index
let indexSrc = src

while (indexSrc) {
index = indexSrc.indexOf(`$`)
if (index === -1) {
return
}
const f = nonStandard ? index > -1 : index === 0 || indexSrc.charAt(index - 1) === ` `
if (f) {
const possibleKatex = indexSrc.substring(index)

if (possibleKatex.match(ruleReg)) {
return index
}
}

indexSrc = indexSrc.substring(index + 1).replace(/^\$+/, ``)
}
},
tokenizer(src) {
const match = src.match(ruleReg)
if (match) {
return {
type: `inlineKatex`,
raw: match[0],
text: match[2].trim(),
displayMode: match[1].length === 2,
}
}
},
renderer,
}
}

function blockKatex(options, renderer) {
return {
name: `blockKatex`,
level: `block`,
tokenizer(src) {
const match = src.match(blockRule)
if (match) {
return {
type: `blockKatex`,
raw: match[0],
text: match[2].trim(),
displayMode: match[1].length === 2,
}
}
},
renderer,
}
}

export function MDKatex(options = {}) {
return {
extensions: [
inlineKatex(options, createRenderer(false)),
blockKatex(options, createRenderer(true)),
],
}
}
12 changes: 3 additions & 9 deletions src/utils/renderer.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import type { Renderer, RendererObject, Tokens } from 'marked'
import { marked } from 'marked'
import hljs from 'highlight.js'
import markedKatex from 'marked-katex-extension'
import mermaid from 'mermaid'
import { toMerged } from 'es-toolkit'

import type { PropertiesHyphen } from 'csstype'
import { MDKatex } from './MDKatex'
import type { ExtendedProperties, IOpts, ThemeStyles } from '@/types'

marked.use(
markedKatex({
throwOnError: false,
output: `html`,
nonStandard: true,
}),
)
marked.use(MDKatex({ nonStandard: true }))

function buildTheme({ theme, fonts, size }: IOpts): ThemeStyles {
const base = toMerged(theme.base, {
Expand Down Expand Up @@ -151,7 +145,7 @@ export function initRenderer(opts: IOpts) {

blockquote({ tokens }: Tokens.Blockquote): string {
let text = this.parser.parse(tokens)
text = text.replace(/<p.*?>/g, `<p ${styles(`blockquote_p`)}>`)
text = text.replace(/<p .*?>/g, `<p ${styles(`blockquote_p`)}>`)
return styledContent(`blockquote`, text)
},

Expand Down

0 comments on commit e93895e

Please sign in to comment.