1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 01:36:22 +00:00

add attributes to fence blocks

This commit is contained in:
Baptiste Augrain
2018-09-13 11:07:19 +02:00
parent e2957192d0
commit 189b245b1d
5 changed files with 207 additions and 45 deletions

View File

@@ -738,10 +738,17 @@ export default class MarkdownPreview extends React.Component {
try { try {
const chartConfig = JSON.parse(el.innerHTML) const chartConfig = JSON.parse(el.innerHTML)
el.innerHTML = '' el.innerHTML = ''
var canvas = document.createElement('canvas')
const canvas = document.createElement('canvas')
el.appendChild(canvas) el.appendChild(canvas)
/* eslint-disable no-new */
new Chart(canvas, chartConfig) const height = el.attributes.getNamedItem('data-height')
if (height && height.value !== 'undefined') {
el.style.height = height.value + 'vh'
canvas.height = height.value + 'vh'
}
const chart = new Chart(canvas, chartConfig)
} catch (e) { } catch (e) {
console.error(e) console.error(e)
el.className = 'chart-error' el.className = 'chart-error'

View File

@@ -213,10 +213,12 @@ pre
margin 0 0 1em margin 0 0 1em
display flex display flex
line-height 1.4em line-height 1.4em
&.flowchart, &.sequence, &.chart code
display flex background-color inherit
justify-content center margin 0
background-color white padding 0
border none
border-radius 0
&.CodeMirror &.CodeMirror
height initial height initial
flex-wrap wrap flex-wrap wrap
@@ -230,12 +232,12 @@ pre
border none border none
border-radius 0 border-radius 0
&>span.filename &>span.filename
width 100% margin -8px -7px 8px -8px
border-radius: 5px 0px 0px 0px padding 2px 6px
margin -8px 100% 8px -8px
padding 0px 6px
background-color #777; background-color #777;
color white color white
&:empty
display none
&>span.lineNumber &>span.lineNumber
display none display none
font-size 1em font-size 1em
@@ -372,6 +374,18 @@ for name, val in admonition_types
color: val[color] color: val[color]
content: val[icon] content: val[icon]
pre.fence
flex-direction column
.chart, .flowchart, .mermaid, .sequence
display flex
justify-content center
background-color white
max-width 100%
canvas, svg
max-width 100% !important
themeDarkBackground = darken(#21252B, 10%) themeDarkBackground = darken(#21252B, 10%)
themeDarkText = #f9f9f9 themeDarkText = #f9f9f9
themeDarkBorder = lighten(themeDarkBackground, 20%) themeDarkBorder = lighten(themeDarkBackground, 20%)

View File

@@ -11,9 +11,9 @@ function getRandomInt (min, max) {
} }
function getId () { function getId () {
var pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' const pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
var id = 'm-' let id = 'm-'
for (var i = 0; i < 7; i++) { for (let i = 0; i < 7; i++) {
id += pool[getRandomInt(0, 16)] id += pool[getRandomInt(0, 16)]
} }
return id return id
@@ -21,14 +21,18 @@ function getId () {
function render (element, content, theme) { function render (element, content, theme) {
try { try {
const height = element.attributes.getNamedItem('data-height')
if (height && height.value !== 'undefined') {
element.style.height = height.value + 'vh'
}
let isDarkTheme = theme === 'dark' || theme === 'solarized-dark' || theme === 'monokai' let isDarkTheme = theme === 'dark' || theme === 'solarized-dark' || theme === 'monokai'
mermaidAPI.initialize({ mermaidAPI.initialize({
theme: isDarkTheme ? 'dark' : 'default', theme: isDarkTheme ? 'dark' : 'default',
themeCSS: isDarkTheme ? darkThemeStyling : '' themeCSS: isDarkTheme ? darkThemeStyling : '',
useMaxWidth: false
}) })
mermaidAPI.render(getId(), content, (svgGraph) => { mermaidAPI.render(getId(), content, (svgGraph) => {
element.innerHTML = svgGraph element.innerHTML = svgGraph
element.style.height = element.attributes.getNamedItem('data-height').value + 'vh'
}) })
} catch (e) { } catch (e) {
console.error(e) console.error(e)

View File

@@ -0,0 +1,130 @@
'use strict'
module.exports = function (md, renderers, defaultRenderer) {
function fence (state, startLine, endLine) {
let pos = state.bMarks[startLine] + state.tShift[startLine]
let max = state.eMarks[startLine]
if (state.sCount[startLine] - state.blkIndent >= 4 || pos + 3 > max) {
return false
}
const marker = state.src.charCodeAt(pos)
if (!(marker === 96 || marker === 126)) {
return false
}
let mem = pos
pos = state.skipChars(pos, marker)
let len = pos - mem
if (len < 3) {
return false
}
const markup = state.src.slice(mem, pos)
const params = state.src.slice(pos, max)
let nextLine = startLine
let haveEndMarker = false
while (true) {
nextLine++
if (nextLine >= endLine) {
break
}
pos = mem = state.bMarks[nextLine] + state.tShift[nextLine]
max = state.eMarks[nextLine]
if (pos < max && state.sCount[nextLine] < state.blkIndent) {
break
}
if (state.src.charCodeAt(pos) !== marker || state.sCount[nextLine] - state.blkIndent >= 4) {
continue
}
pos = state.skipChars(pos, marker)
if (pos - mem < len) {
continue
}
pos = state.skipSpaces(pos)
if (pos >= max) {
haveEndMarker = true
break
}
}
len = state.sCount[startLine]
state.line = nextLine + (haveEndMarker ? 1 : 0)
const parameters = {}
let langType = ''
let fileName = ''
let firstLineNumber = 0
let match = /^(\w[-\w]*)?(?:\(((?:\s*\w[-\w]*(?:=(?:'(?:.*?[^\\])?'|"(?:.*?[^\\])?"|(?:[^'"][^\s]*)))?)*)\))?(?::([^:]*)(?::(\d+))?)?\s*$/.exec(params)
if (match) {
if (match[1]) {
langType = match[1]
}
if (match[3]) {
fileName = match[3]
}
if (match[4]) {
firstLineNumber = parseInt(match[4], 10)
}
if (match[2]) {
const params = match[2]
const regex = /(\w[-\w]*)(?:=(?:'(.*?[^\\])?'|"(.*?[^\\])?"|([^'"][^\s]*)))?/g
let name, value
while ((match = regex.exec(params))) {
name = match[1]
value = match[2] || match[3] || match[4] || null
const height = /^(\d+)h$/.exec(name)
if (height && !value) {
parameters.height = height[1]
} else {
parameters[name] = value
}
}
}
}
let token
if (renderers[langType]) {
token = state.push(`${langType}_fence`, 'div', 0)
} else {
token = state.push('_fence', 'code', 0)
}
token.langType = langType
token.fileName = fileName
token.firstLineNumber = firstLineNumber
token.parameters = parameters
token.content = state.getLines(startLine + 1, nextLine, len, true)
token.markup = markup
token.map = [startLine, state.line]
return true
}
md.block.ruler.before('fence', '_fence', fence, {
alt: ['paragraph', 'reference', 'blockquote', 'list']
})
for (let name in renderers) {
md.renderer.rules[`${name}_fence`] = (tokens, index) => renderers[name](tokens[index])
}
if (defaultRenderer) {
md.renderer.rules['_fence'] = (tokens, index) => defaultRenderer(tokens[index])
}
}

View File

@@ -27,32 +27,6 @@ class Markdown {
html: true, html: true,
xhtmlOut: true, xhtmlOut: true,
breaks: config.preview.breaks, breaks: config.preview.breaks,
highlight: function (str, lang) {
const delimiter = ':'
const langInfo = lang.split(delimiter)
const langType = langInfo[0]
const fileName = langInfo[1] || ''
const firstLineNumber = parseInt(langInfo[2], 10)
if (langType === 'flowchart') {
return `<pre class="flowchart">${str}</pre>`
}
if (langType === 'sequence') {
return `<pre class="sequence">${str}</pre>`
}
if (langType === 'chart') {
return `<pre class="chart">${str}</pre>`
}
if (langType === 'mermaid') {
return `<pre class="mermaid" data-height="${fileName}">${str}</pre>`
}
return '<pre class="code CodeMirror">' +
'<span class="filename">' + fileName + '</span>' +
createGutter(str, firstLineNumber) +
'<code class="' + langType + '">' +
str +
'</code></pre>'
},
sanitize: 'STRICT' sanitize: 'STRICT'
} }
@@ -150,6 +124,39 @@ class Markdown {
this.md.use(require('markdown-it-kbd')) this.md.use(require('markdown-it-kbd'))
this.md.use(require('markdown-it-admonition')) this.md.use(require('markdown-it-admonition'))
this.md.use(require('./markdown-it-fence'), {
chart: token => {
return `<pre class="fence">
<span class="filename">${token.fileName}</span>
<div class="chart" data-height="${token.parameters.height}">${token.content}</div>
</pre>`
},
flowchart: token => {
return `<pre class="fence">
<span class="filename">${token.fileName}</span>
<div class="flowchart" data-height="${token.parameters.height}">${token.content}</div>
</pre>`
},
mermaid: token => {
return `<pre class="fence">
<span class="filename">${token.fileName}</span>
<div class="mermaid" data-height="${token.parameters.height}">${token.content}</div>
</pre>`
},
sequence: token => {
return `<pre class="fence">
<span class="filename">${token.fileName}</span>
<div class="sequence" data-height="${token.parameters.height}">${token.content}</div>
</pre>`
}
}, token => {
return `<pre class="code CodeMirror">
<span class="filename">${token.fileName}</span>
${createGutter(token.content, token.firstLineNumber)}
<code class="${token.langType}">${token.content}</code>
</pre>`
})
const deflate = require('markdown-it-plantuml/lib/deflate') const deflate = require('markdown-it-plantuml/lib/deflate')
this.md.use(require('markdown-it-plantuml'), '', { this.md.use(require('markdown-it-plantuml'), '', {
generateSource: function (umlCode) { generateSource: function (umlCode) {