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

CommonMark

This commit is contained in:
Rokt33r
2016-01-06 04:41:19 +09:00
parent 15560a3bce
commit c8337c7287
11 changed files with 69 additions and 27 deletions

View File

@@ -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}}
/>
)
}

View File

@@ -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>'

View File

@@ -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

View File

@@ -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}/>&nbsp;
{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>

View File

@@ -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()

View File

@@ -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