1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-12 17:26:17 +00:00

Merge pull request #2394 from daiyam/fence-attrs

add attributes to fence blocks
This commit is contained in:
Junyoung Choi (Sai)
2018-11-06 17:48:29 +09:00
committed by GitHub
9 changed files with 242 additions and 108 deletions

View File

@@ -737,7 +737,6 @@ export default class MarkdownPreview extends React.Component {
el.addEventListener('click', this.linkClickHandler)
})
} catch (e) {
console.error(e)
el.className = 'flowchart-error'
el.innerHTML = 'Flowchart parse error: ' + e.message
}
@@ -758,7 +757,6 @@ export default class MarkdownPreview extends React.Component {
el.addEventListener('click', this.linkClickHandler)
})
} catch (e) {
console.error(e)
el.className = 'sequence-error'
el.innerHTML = 'Sequence diagram parse error: ' + e.message
}
@@ -771,12 +769,18 @@ export default class MarkdownPreview extends React.Component {
try {
const chartConfig = JSON.parse(el.innerHTML)
el.innerHTML = ''
var canvas = document.createElement('canvas')
const canvas = document.createElement('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) {
console.error(e)
el.className = 'chart-error'
el.innerHTML = 'chartjs diagram parse error: ' + e.message
}

View File

@@ -209,41 +209,39 @@ code
text-decoration none
margin-right 2px
pre
padding 0.5em !important
padding 0.5rem !important
border solid 1px #D1D1D1
border-radius 5px
overflow-x auto
margin 0 0 1em
margin 0 0 1rem
display flex
line-height 1.4em
&.flowchart, &.sequence, &.chart
display flex
justify-content center
background-color white
&.CodeMirror
height initial
flex-wrap wrap
&>code
flex 1
overflow-x auto
code
background-color inherit
margin 0
padding 0
border none
border-radius 0
&.CodeMirror
height initial
flex-wrap wrap
&>code
flex 1
overflow-x auto
&.mermaid svg
max-width 100% !important
&>span.filename
width 100%
border-radius: 5px 0px 0px 0px
margin -8px 100% 8px -8px
padding 0px 6px
margin -0.5rem 100% 0.5rem -0.5rem
padding 0.125rem 0.375rem
background-color #777;
color white
&:empty
display none
&>span.lineNumber
display none
font-size 1em
padding 0.5em 0
margin -0.5em 0.5em -0.5em -0.5em
padding 0.5rem 0
margin -0.5rem 0.5rem -0.5rem -0.5rem
border-right 1px solid
text-align right
border-top-left-radius 4px
@@ -375,6 +373,19 @@ for name, val in admonition_types
color: val[color]
content: val[icon]
pre.fence
flex-wrap wrap
.chart, .flowchart, .mermaid, .sequence
display flex
justify-content center
background-color white
max-width 100%
flex-grow 1
canvas, svg
max-width 100% !important
themeDarkBackground = darken(#21252B, 10%)
themeDarkText = #f9f9f9
themeDarkBorder = lighten(themeDarkBackground, 20%)

View File

@@ -11,9 +11,9 @@ function getRandomInt (min, max) {
}
function getId () {
var pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
var id = 'm-'
for (var i = 0; i < 7; i++) {
const pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
let id = 'm-'
for (let i = 0; i < 7; i++) {
id += pool[getRandomInt(0, 16)]
}
return id
@@ -21,16 +21,20 @@ function getId () {
function render (element, content, theme) {
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' || theme === 'dracula'
mermaidAPI.initialize({
theme: isDarkTheme ? 'dark' : 'default',
themeCSS: isDarkTheme ? darkThemeStyling : ''
themeCSS: isDarkTheme ? darkThemeStyling : '',
useMaxWidth: false
})
mermaidAPI.render(getId(), content, (svgGraph) => {
element.innerHTML = svgGraph
})
} catch (e) {
console.error(e)
element.className = 'mermaid-error'
element.innerHTML = 'mermaid diagram parse error: ' + e.message
}

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 = 1
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 (const 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

@@ -15,7 +15,7 @@ module.exports = function sanitizePlugin (md, options) {
options
)
}
if (state.tokens[tokenIdx].type === 'fence') {
if (state.tokens[tokenIdx].type === '_fence') {
// escapeHtmlCharacters has better performance
state.tokens[tokenIdx].content = escapeHtmlCharacters(
state.tokens[tokenIdx].content,

View File

@@ -28,32 +28,6 @@ class Markdown {
html: true,
xhtmlOut: true,
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">${str}</pre>`
}
return '<pre class="code CodeMirror">' +
'<span class="filename">' + fileName + '</span>' +
createGutter(str, firstLineNumber) +
'<code class="' + langType + '">' +
str +
'</code></pre>'
},
sanitize: 'STRICT'
}
@@ -157,6 +131,39 @@ class Markdown {
this.md.use(require('markdown-it-admonition'), {types: ['note', 'hint', 'attention', 'caution', 'danger', 'error']})
this.md.use(require('./markdown-it-frontmatter'))
this.md.use(require('./markdown-it-fence'), {
chart: token => {
return `<pre class="fence" data-line="${token.map[0]}">
<span class="filename">${token.fileName}</span>
<div class="chart" data-height="${token.parameters.height}">${token.content}</div>
</pre>`
},
flowchart: token => {
return `<pre class="fence" data-line="${token.map[0]}">
<span class="filename">${token.fileName}</span>
<div class="flowchart" data-height="${token.parameters.height}">${token.content}</div>
</pre>`
},
mermaid: token => {
return `<pre class="fence" data-line="${token.map[0]}">
<span class="filename">${token.fileName}</span>
<div class="mermaid" data-height="${token.parameters.height}">${token.content}</div>
</pre>`
},
sequence: token => {
return `<pre class="fence" data-line="${token.map[0]}">
<span class="filename">${token.fileName}</span>
<div class="sequence" data-height="${token.parameters.height}">${token.content}</div>
</pre>`
}
}, token => {
return `<pre class="code CodeMirror" data-line="${token.map[0]}">
<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')
this.md.use(require('markdown-it-plantuml'), '', {
generateSource: function (umlCode) {

View File

@@ -47,9 +47,12 @@ Generated by [AVA](https://ava.li).
> Snapshot 1
`<pre class="code CodeMirror"><span class="filename">filename.js</span><span class="lineNumber CodeMirror-gutters"><span class="CodeMirror-linenumber">2</span></span><code class="js">var project = 'boostnote';
</code></pre>␊
`
`<pre class="code CodeMirror" data-line="1">
<span class="filename">filename.js</span>␊
<span class="lineNumber CodeMirror-gutters"><span class="CodeMirror-linenumber">2</span></span>␊
<code class="js">var project = 'boostnote';␊
</code>␊
</pre>`
## Markdown.render() should renders markdown correctly

View File

@@ -2826,20 +2826,6 @@ electron-config@^1.0.0:
dependencies:
conf "^1.0.0"
electron-download@^3.0.1:
version "3.3.0"
resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-3.3.0.tgz#2cfd54d6966c019c4d49ad65fbe65cc9cdef68c8"
dependencies:
debug "^2.2.0"
fs-extra "^0.30.0"
home-path "^1.0.1"
minimist "^1.2.0"
nugget "^2.0.0"
path-exists "^2.1.0"
rc "^1.1.2"
semver "^5.3.0"
sumchecker "^1.2.0"
electron-download@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-4.1.0.tgz#bf932c746f2f87ffcc09d1dd472f2ff6b9187845"
@@ -2854,7 +2840,21 @@ electron-download@^4.0.0:
semver "^5.3.0"
sumchecker "^2.0.1"
electron-gh-releases@^2.0.2:
electron-download@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-4.1.1.tgz#02e69556705cc456e520f9e035556ed5a015ebe8"
dependencies:
debug "^3.0.0"
env-paths "^1.0.0"
fs-extra "^4.0.1"
minimist "^1.2.0"
nugget "^2.0.1"
path-exists "^3.0.0"
rc "^1.2.1"
semver "^5.4.1"
sumchecker "^2.0.2"
electron-gh-releases@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/electron-gh-releases/-/electron-gh-releases-2.0.4.tgz#198c07a0970fb8e80fcc67bd0b4198a010923dc3"
dependencies:
@@ -2938,12 +2938,12 @@ electron-winstaller@^2.2.0:
lodash.template "^4.2.2"
temp "^0.8.3"
electron@2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/electron/-/electron-2.0.7.tgz#f7ce410433298e319032ce31f0e6ffd709ff052c"
electron@3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/electron/-/electron-3.0.3.tgz#2857ed8d37c1b46e0a75a72684800252255f3243"
dependencies:
"@types/node" "^8.0.24"
electron-download "^3.0.1"
electron-download "^4.1.0"
extract-zip "^1.0.3"
emojis-list@^2.0.0:
@@ -3058,10 +3058,6 @@ es6-promise@^3.1.2:
version "3.3.1"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613"
es6-promise@^4.0.5:
version "4.2.4"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29"
es6-set@~0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1"
@@ -3782,16 +3778,6 @@ fs-extra@0.26.7, fs-extra@^0.26.0, fs-extra@^0.26.7:
path-is-absolute "^1.0.0"
rimraf "^2.2.8"
fs-extra@^0.30.0:
version "0.30.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0"
dependencies:
graceful-fs "^4.1.2"
jsonfile "^2.1.0"
klaw "^1.0.0"
path-is-absolute "^1.0.0"
rimraf "^2.2.8"
fs-extra@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950"
@@ -3807,7 +3793,7 @@ fs-extra@^2.0.0:
graceful-fs "^4.1.2"
jsonfile "^2.1.0"
fs-extra@^4.0.0:
fs-extra@^4.0.0, fs-extra@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94"
dependencies:
@@ -4350,10 +4336,6 @@ home-or-tmp@^2.0.0:
os-homedir "^1.0.0"
os-tmpdir "^1.0.1"
home-path@^1.0.1:
version "1.0.6"
resolved "https://registry.yarnpkg.com/home-path/-/home-path-1.0.6.tgz#d549dc2465388a7f8667242c5b31588d29af29fc"
hooker@~0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/hooker/-/hooker-0.2.3.tgz#b834f723cc4a242aa65963459df6d984c5d3d959"
@@ -6480,7 +6462,7 @@ npmlog@^4.0.2:
gauge "~2.7.3"
set-blocking "~2.0.0"
nugget@^2.0.0:
nugget@^2.0.0, nugget@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/nugget/-/nugget-2.0.1.tgz#201095a487e1ad36081b3432fa3cada4f8d071b0"
dependencies:
@@ -6782,7 +6764,7 @@ path-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
path-exists@^2.0.0, path-exists@^2.1.0:
path-exists@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
dependencies:
@@ -7353,7 +7335,7 @@ raw-body@2.3.2:
iconv-lite "0.4.19"
unpipe "1.0.0"
rc@^1.0.1, rc@^1.1.2, rc@^1.1.6, rc@^1.1.7:
rc@^1.0.1, rc@^1.1.2, rc@^1.1.6, rc@^1.1.7, rc@^1.2.1:
version "1.2.8"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
dependencies:
@@ -8584,14 +8566,7 @@ stylus@^0.52.4:
sax "0.5.x"
source-map "0.1.x"
sumchecker@^1.2.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-1.3.1.tgz#79bb3b4456dd04f18ebdbc0d703a1d1daec5105d"
dependencies:
debug "^2.2.0"
es6-promise "^4.0.5"
sumchecker@^2.0.1:
sumchecker@^2.0.1, sumchecker@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-2.0.2.tgz#0f42c10e5d05da5d42eea3e56c3399a37d6c5b3e"
dependencies: