mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 01:36:22 +00:00
CommonMark
This commit is contained in:
@@ -1,16 +1,34 @@
|
||||
var React = require('react')
|
||||
var { PropTypes } = React
|
||||
import React, { PropTypes } from 'react'
|
||||
import markdown from '../lib/markdown'
|
||||
var ReactDOM = require('react-dom')
|
||||
import ReactDOM from 'react-dom'
|
||||
import sanitizeHtml from '@rokt33r/sanitize-html'
|
||||
import hljs from 'highlight.js'
|
||||
|
||||
const electron = require('electron')
|
||||
const shell = electron.shell
|
||||
|
||||
const katex = window.katex
|
||||
|
||||
const sanitizeOpts = {
|
||||
allowedTags: [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol',
|
||||
'nl', 'li', 'b', 'i', 'strong', 'em', 'strike', 'code', 'hr', 'br', 'div',
|
||||
'table', 'thead', 'caption', 'tbody', 'tr', 'th', 'td', 'pre', 'img', 'span', 'cite', 'del', 'u' ],
|
||||
allowedClasses: {
|
||||
'a': ['lineAnchor'],
|
||||
'div': ['math'],
|
||||
'span': ['math', 'hljs-*'],
|
||||
'code': ['language-*']
|
||||
},
|
||||
allowedAttributes: {
|
||||
a: ['href', 'data-key'],
|
||||
img: [ 'src' ]
|
||||
}
|
||||
}
|
||||
|
||||
function handleAnchorClick (e) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
console.log(e.target.href)
|
||||
shell.openExternal(e.target.href)
|
||||
}
|
||||
|
||||
@@ -34,11 +52,13 @@ function math2Katex (display) {
|
||||
export default class MarkdownPreview extends React.Component {
|
||||
componentDidMount () {
|
||||
this.addListener()
|
||||
// this.renderCode()
|
||||
this.renderMath()
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
this.addListener()
|
||||
// this.renderCode()
|
||||
this.renderMath()
|
||||
}
|
||||
|
||||
@@ -50,6 +70,20 @@ export default class MarkdownPreview extends React.Component {
|
||||
this.removeListener()
|
||||
}
|
||||
|
||||
renderCode () {
|
||||
let codes = ReactDOM.findDOMNode(this).querySelectorAll('code:not(.rendered)')
|
||||
Array.prototype.forEach.call(codes, el => {
|
||||
let matched = el.className.match(/language-(.+)/)
|
||||
let lang = matched ? matched[1] : null
|
||||
try {
|
||||
let result = hljs.highlight(lang, el.innerHTML)
|
||||
el.innerHTML = result.value
|
||||
el.className += ' rendered'
|
||||
} catch (e) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
renderMath () {
|
||||
let inline = ReactDOM.findDOMNode(this).querySelectorAll('span.math')
|
||||
Array.prototype.forEach.call(inline, math2Katex(false))
|
||||
@@ -112,6 +146,9 @@ export default class MarkdownPreview extends React.Component {
|
||||
let content = isEmpty
|
||||
? '(Empty content)'
|
||||
: this.props.content
|
||||
content = markdown(content)
|
||||
content = sanitizeHtml(content, sanitizeOpts)
|
||||
|
||||
return (
|
||||
<div
|
||||
className={'MarkdownPreview' + (this.props.className != null ? ' ' + this.props.className : '') + (isEmpty ? ' empty' : '')}
|
||||
@@ -120,7 +157,7 @@ export default class MarkdownPreview extends React.Component {
|
||||
onMouseDown={e => this.handleMouseDown(e)}
|
||||
onMouseMove={e => this.handleMouseMove(e)}
|
||||
onMouseUp={e => this.handleMouseUp(e)}
|
||||
dangerouslySetInnerHTML={{__html: ' ' + markdown(content)}}
|
||||
dangerouslySetInnerHTML={{__html: ' ' + content}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
import markdownit from 'markdown-it'
|
||||
import hljs from 'highlight.js'
|
||||
import emoji from 'markdown-it-emoji'
|
||||
import math from 'markdown-it-math'
|
||||
import hljs from 'highlight.js'
|
||||
|
||||
var md = markdownit({
|
||||
typographer: true,
|
||||
linkify: true,
|
||||
html: true,
|
||||
xhtmlOut: true,
|
||||
highlight: function (str, lang) {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return hljs.highlight(lang, str).value
|
||||
} catch (__) {}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
try {
|
||||
return hljs.highlightAuto(str).value
|
||||
} catch (__) {}
|
||||
|
||||
return ''
|
||||
return str
|
||||
}
|
||||
})
|
||||
md.use(emoji)
|
||||
@@ -33,6 +30,7 @@ md.use(math, {
|
||||
let originalRenderToken = md.renderer.renderToken
|
||||
md.renderer.renderToken = function renderToken (tokens, idx, options) {
|
||||
let token = tokens[idx]
|
||||
|
||||
let result = originalRenderToken.call(md.renderer, tokens, idx, options)
|
||||
if (token.map != null) {
|
||||
return result + '<a class=\'lineAnchor\' data-key=\'' + token.map[0] + '\'></a>'
|
||||
|
||||
@@ -56,7 +56,8 @@ export default class ArticleEditor extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
if (this.props.mode === 'markdown' && this.state.status === PREVIEW_MODE) {
|
||||
let showPreview = this.props.mode === 'markdown' && this.state.status === PREVIEW_MODE
|
||||
if (showPreview) {
|
||||
return (
|
||||
<div className='ArticleEditor'>
|
||||
<MarkdownPreview
|
||||
|
||||
@@ -138,7 +138,9 @@ export default class ArticleNavigator extends React.Component {
|
||||
<div key={modifiedArticle.key} onClick={e => this.handleUnsavedItemClick(combinedArticle)(e)} className={className}>
|
||||
<div className='ArticleNavigator-unsaved-list-item-label'>
|
||||
<ModeIcon mode={combinedArticle.mode}/>
|
||||
{combinedArticle.title}
|
||||
{combinedArticle.title.trim().length > 0
|
||||
? combinedArticle.title
|
||||
: <span className='ArticleNavigator-unsaved-list-item-label-untitled'>(Untitled)</span>}
|
||||
</div>
|
||||
<button onClick={e => this.handleUncacheButtonClick(combinedArticle)(e)} className='ArticleNavigator-unsaved-list-item-discard-button'><i className='fa fa-times'/></button>
|
||||
</div>
|
||||
|
||||
@@ -144,9 +144,8 @@ function remap (state) {
|
||||
|
||||
articles.sort((a, b) => {
|
||||
let match = new Date(b.updatedAt) - new Date(a.updatedAt)
|
||||
if (match === 0) match = new Date(b.createdAt) - new Date(a.createdAt)
|
||||
if (match === 0) match = b.title.compare(a.title)
|
||||
if (match === 0) match = b.key.compare(a.key)
|
||||
if (match === 0) match = b.title.localeCompare(a.title)
|
||||
if (match === 0) match = b.key.localeCompare(a.key)
|
||||
return match
|
||||
})
|
||||
let allArticles = articles.slice()
|
||||
|
||||
@@ -26,6 +26,7 @@ marked()
|
||||
padding 0
|
||||
margin 0
|
||||
display inline
|
||||
font-size 0
|
||||
hr
|
||||
border-top none
|
||||
border-bottom solid 1px borderColor
|
||||
@@ -33,7 +34,7 @@ marked()
|
||||
h1, h2, h3, h4, h5, h6
|
||||
margin 0 0 15px
|
||||
font-weight 600
|
||||
* + h1, * + h2, * + h3, * + h4, * + h5, * + h6
|
||||
*:not(a.lineAnchor) + h1, *:not(a.lineAnchor) + h2, *:not(a.lineAnchor) + h3, *:not(a.lineAnchor) + h4, *:not(a.lineAnchor) + h5, *:not(a.lineAnchor) + h6
|
||||
margin-top 25px
|
||||
h1
|
||||
font-size 2em
|
||||
@@ -55,26 +56,28 @@ marked()
|
||||
font-size 0.8em
|
||||
line-height 1em
|
||||
|
||||
* + p, * + blockquote, * + ul, * + ol, * + pre
|
||||
*:not(a.lineAnchor) + p, *:not(a.lineAnchor) + blockquote, *:not(a.lineAnchor) + ul, *:not(a.lineAnchor) + ol, *:not(a.lineAnchor) + pre
|
||||
margin-top 15px
|
||||
p
|
||||
line-height 1.9em
|
||||
margin 0 0 15px
|
||||
img
|
||||
max-width 100%
|
||||
strong
|
||||
strong, b
|
||||
font-weight bold
|
||||
em
|
||||
em, i
|
||||
font-style italic
|
||||
s
|
||||
text-decoration line-through
|
||||
u
|
||||
text-decoration underline
|
||||
blockquote
|
||||
border-left solid 4px brandBorderColor
|
||||
margin 0 0 15px
|
||||
padding 0 25px
|
||||
ul
|
||||
list-style-type disc
|
||||
padding-left 35px
|
||||
padding-left 25px
|
||||
margin-bottom 15px
|
||||
li
|
||||
display list-item
|
||||
@@ -87,7 +90,7 @@ marked()
|
||||
list-style-type square
|
||||
ol
|
||||
list-style-type decimal
|
||||
padding-left 35px
|
||||
padding-left 25px
|
||||
margin-bottom 15px
|
||||
li
|
||||
display list-item
|
||||
@@ -97,18 +100,18 @@ marked()
|
||||
code
|
||||
font-family Monaco, Menlo, 'Ubuntu Mono', Consolas, source-code-pro, monospace
|
||||
padding 2px 4px
|
||||
border solid 1px borderColor
|
||||
border solid 1px alpha(borderColor, 0.3)
|
||||
border-radius 4px
|
||||
font-size 0.9em
|
||||
color black
|
||||
text-decoration none
|
||||
background-color #F6F6F6
|
||||
margin-right 2px
|
||||
* + code
|
||||
*:not(a.lineAnchor) + code
|
||||
margin-left 2px
|
||||
pre
|
||||
padding 5px
|
||||
border solid 1px borderColor
|
||||
border solid 1px alpha(borderColor, 0.3)
|
||||
border-radius 5px
|
||||
overflow-x auto
|
||||
margin 0 0 15px
|
||||
|
||||
Reference in New Issue
Block a user