Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add attributes to fence blocks #2394

Merged
merged 15 commits into from
Nov 6, 2018
Merged
13 changes: 10 additions & 3 deletions browser/components/MarkdownPreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -738,10 +738,17 @@ 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'
Expand Down
37 changes: 23 additions & 14 deletions browser/components/markdown.styl
Original file line number Diff line number Diff line change
Expand Up @@ -213,29 +213,25 @@ pre
margin 0 0 1em
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
&>span.filename
width 100%
border-radius: 5px 0px 0px 0px
margin -8px 100% 8px -8px
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change to fix a small display bug:
z-index: 10
Before:
image
After:
image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ZeroX-DG I removed the errors for every diagram (chart, flowchart, mermaid and sequence).
I've also fixed a bug with the line number...

But I can't replicated the visual bug you are getting...
Here what I get:
screenshot

Here my preferences:
screenshot

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You preview font size is too small, you can set it to 24 and you will see the problem

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here my fix:
screenshot

padding 0px 6px
padding 2px 6px
background-color #777;
color white
&:empty
display none
&>span.lineNumber
display none
font-size 1em
Expand Down Expand Up @@ -361,7 +357,7 @@ for name, val in admonition_types
.admonition.{name}
@extend $admonition
border-left-color: val[color]

.admonition.{name}>.admonition-title
@extend $admonition-title
border-bottom-color: .1rem solid rgba(val[color], 0.2)
Expand All @@ -372,6 +368,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%)
Expand Down
17 changes: 11 additions & 6 deletions browser/components/render/MermaidRender.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,34 @@ import mermaidAPI from 'mermaid'

// fixes bad styling in the mermaid dark theme
const darkThemeStyling = `
.loopText tspan {
fill: white;
.loopText tspan {
fill: white;
}`

function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min)) + min
}

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
}

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'
mermaidAPI.initialize({
theme: isDarkTheme ? 'dark' : 'default',
themeCSS: isDarkTheme ? darkThemeStyling : ''
themeCSS: isDarkTheme ? darkThemeStyling : '',
useMaxWidth: false
})
mermaidAPI.render(getId(), content, (svgGraph) => {
element.innerHTML = svgGraph
Expand Down
130 changes: 130 additions & 0 deletions browser/lib/markdown-it-fence.js
Original file line number Diff line number Diff line change
@@ -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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use const instead of let

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ZeroX-DG thanks! I did learn something today The for-of loop

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, amazing right? I also discorvered the for-of loop a few months ago 😄 I realized that I've been in stone age for years 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did know the for-of loop but I didn't know I could use const for the iterator. (Since the loop do change the value/address of the variable)

md.renderer.rules[`${name}_fence`] = (tokens, index) => renderers[name](tokens[index])
}

if (defaultRenderer) {
md.renderer.rules['_fence'] = (tokens, index) => defaultRenderer(tokens[index])
}
}
59 changes: 33 additions & 26 deletions browser/lib/markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,32 +27,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'
}

Expand Down Expand Up @@ -150,6 +124,39 @@ class Markdown {
this.md.use(require('markdown-it-kbd'))
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')
this.md.use(require('markdown-it-plantuml'), '', {
generateSource: function (umlCode) {
Expand Down
6 changes: 5 additions & 1 deletion browser/styles/index.styl
Original file line number Diff line number Diff line change
Expand Up @@ -383,4 +383,8 @@ modalMonokai()
width 100%
background-color $ui-monokai-backgroundColor
overflow hidden
border-radius $modal-border-radius
border-radius $modal-border-radius

pre.mermaid svg {
max-width 100% !important
}
9 changes: 6 additions & 3 deletions tests/lib/snapshots/markdown-test.js.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,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">␊
<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

Expand Down
Binary file modified tests/lib/snapshots/markdown-test.js.snap
Binary file not shown.