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:
@@ -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'
|
||||||
|
|||||||
@@ -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%)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
130
browser/lib/markdown-it-fence.js
Normal file
130
browser/lib/markdown-it-fence.js
Normal 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])
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user