diff --git a/public/js/extra.js b/public/js/extra.js
index 99233c09..dfc206b0 100644
--- a/public/js/extra.js
+++ b/public/js/extra.js
@@ -15,6 +15,7 @@ import { stripTags } from '../../utils/string'
import getUIElements from './lib/editor/ui-elements'
import { emojifyImageDir } from './lib/editor/constants'
+import { parseFenceCodeParams, serializeParamToAttribute } from './lib/markdown/utils'
import markdownit from 'markdown-it'
import markdownitContainer from 'markdown-it-container'
@@ -1028,24 +1029,30 @@ export function scrollToHash () {
location.hash = hash
}
+const fenceCodeAlias = {
+ sequence: 'sequence-diagram',
+ flow: 'flow-chart',
+ graphviz: 'graphviz',
+ mermaid: 'mermaid',
+ abc: 'abc',
+ vega: 'vega',
+ geo: 'geo'
+}
+
function highlightRender (code, lang) {
if (!lang || /no(-?)highlight|plain|text/.test(lang)) { return }
+
+ const params = parseFenceCodeParams(lang)
+ const attr = serializeParamToAttribute(params)
+ lang = lang.split(/\s+/g)[0]
+
code = escapeHTML(code)
- if (lang === 'sequence') {
- return `
${code}
`
- } else if (lang === 'flow') {
- return `${code}
`
- } else if (lang === 'graphviz') {
- return `${code}
`
- } else if (lang === 'mermaid') {
- return `${code}
`
- } else if (lang === 'abc') {
- return `${code}
`
- } else if (lang === 'vega') {
- return `${code}
`
- } else if (lang === 'geo') {
- return `${code}
`
+
+ const langAlias = fenceCodeAlias[lang]
+ if (langAlias) {
+ return `${code}
`
}
+
const result = {
value: code
}
@@ -1167,7 +1174,7 @@ md.renderer.rules.fence = (tokens, idx, options, env, self) => {
}
if (options.highlight) {
- highlighted = options.highlight(token.content, langName) || md.utils.escapeHtml(token.content)
+ highlighted = options.highlight(token.content, info) || md.utils.escapeHtml(token.content)
} else {
highlighted = md.utils.escapeHtml(token.content)
}
diff --git a/public/js/lib/markdown/utils.js b/public/js/lib/markdown/utils.js
new file mode 100644
index 00000000..3aeb646c
--- /dev/null
+++ b/public/js/lib/markdown/utils.js
@@ -0,0 +1,53 @@
+export function parseFenceCodeParams (lang) {
+ const attrMatch = lang.match(/{(.*)}/)
+ const params = {}
+ if (attrMatch && attrMatch.length >= 2) {
+ const attrs = attrMatch[1]
+ const paraMatch = attrs.match(/([#.](\S+?)\s)|((\S+?)\s*=\s*("(.+?)"|'(.+?)'|\[[^\]]*\]|\{[}]*\}|(\S+)))/g)
+ paraMatch && paraMatch.forEach(param => {
+ param = param.trim()
+ if (param[0] === '#') {
+ params['id'] = param.slice(1)
+ } else if (param[0] === '.') {
+ if (params['class']) params['class'] = []
+ params['class'] = params['class'].concat(param.slice(1))
+ } else {
+ const offset = param.indexOf('=')
+ const id = param.substring(0, offset).trim().toLowerCase()
+ let val = param.substring(offset + 1).trim()
+ const valStart = val[0]
+ const valEnd = val[val.length - 1]
+ if (['"', "'"].indexOf(valStart) !== -1 && ['"', "'"].indexOf(valEnd) !== -1 && valStart === valEnd) {
+ val = val.substring(1, val.length - 1)
+ }
+ if (id === 'class') {
+ if (params['class']) params['class'] = []
+ params['class'] = params['class'].concat(val)
+ } else {
+ params[id] = val
+ }
+ }
+ })
+ }
+ return params
+}
+
+export function serializeParamToAttribute (params) {
+ if (Object.getOwnPropertyNames(params).length === 0) {
+ return ''
+ } else {
+ return ` data-params="${escape(JSON.stringify(params))}"`
+ }
+}
+
+/**
+ * @param {HTMLElement} elem
+ */
+export function deserializeParamAttributeFromElement (elem) {
+ const params = elem.getAttribute('data-params')
+ if (params) {
+ return JSON.parse(unescape(params))
+ } else {
+ return {}
+ }
+}
diff --git a/public/js/lib/syncscroll.js b/public/js/lib/syncscroll.js
index 5bf209bc..9daf327c 100644
--- a/public/js/lib/syncscroll.js
+++ b/public/js/lib/syncscroll.js
@@ -73,7 +73,7 @@ md.renderer.rules.fence = (tokens, idx, options, env, self) => {
}
if (options.highlight) {
- highlighted = options.highlight(token.content, langName) || md.utils.escapeHtml(token.content)
+ highlighted = options.highlight(token.content, info) || md.utils.escapeHtml(token.content)
} else {
highlighted = md.utils.escapeHtml(token.content)
}