mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 01:36:22 +00:00
GFM checkbox
This commit is contained in:
@@ -219,6 +219,12 @@ export default class CodeEditor extends React.Component {
|
||||
session.on('change', this.changeHandler)
|
||||
}
|
||||
|
||||
setValue (value) {
|
||||
let session = this.editor.getSession()
|
||||
session.setValue(value)
|
||||
this.value = value
|
||||
}
|
||||
|
||||
render () {
|
||||
let { className, fontFamily } = this.props
|
||||
fontFamily = _.isString(fontFamily) && fontFamily.length > 0
|
||||
|
||||
@@ -73,6 +73,29 @@ class MarkdownEditor extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleCheckboxClick (e) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
let idMatch = /checkbox-([0-9]+)/
|
||||
let checkedMatch = /\[x\]/i
|
||||
let uncheckedMatch = /\[ \]/
|
||||
if (idMatch.test(e.target.getAttribute('id'))) {
|
||||
let lineIndex = parseInt(e.target.getAttribute('id').match(idMatch)[1], 10) - 1
|
||||
let lines = this.refs.code.value
|
||||
.split('\n')
|
||||
|
||||
let targetLine = lines[lineIndex]
|
||||
|
||||
if (targetLine.match(checkedMatch)) {
|
||||
lines[lineIndex] = targetLine.replace(checkedMatch, '[ ]')
|
||||
}
|
||||
if (targetLine.match(uncheckedMatch)) {
|
||||
lines[lineIndex] = targetLine.replace(uncheckedMatch, '[x]')
|
||||
}
|
||||
this.refs.code.setValue(lines.join('\n'))
|
||||
}
|
||||
}
|
||||
|
||||
focus () {
|
||||
if (this.state.status === 'PREVIEW') {
|
||||
this.setState({
|
||||
@@ -135,6 +158,7 @@ class MarkdownEditor extends React.Component {
|
||||
value={value}
|
||||
onMouseUp={(e) => this.handlePreviewMouseUp(e)}
|
||||
onMouseDown={(e) => this.handlePreviewMouseDown(e)}
|
||||
onCheckboxClick={(e) => this.handleCheckboxClick(e)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -22,7 +22,8 @@ export default class MarkdownPreview extends React.Component {
|
||||
this.contextMenuHandler = (e) => this.handleContextMenu(e)
|
||||
this.mouseDownHandler = (e) => this.handleMouseDown(e)
|
||||
this.mouseUpHandler = (e) => this.handleMouseUp(e)
|
||||
this.goExternalHandler = (e) => this.handlePreviewAnchorClick(e)
|
||||
this.anchorClickHandler = (e) => this.handlePreviewAnchorClick(e)
|
||||
this.checkboxClickHandler = (e) => this.handleCheckboxClick(e)
|
||||
}
|
||||
|
||||
handlePreviewAnchorClick (e) {
|
||||
@@ -40,13 +41,21 @@ export default class MarkdownPreview extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleCheckboxClick (e) {
|
||||
this.props.onCheckboxClick(e)
|
||||
}
|
||||
|
||||
handleContextMenu (e) {
|
||||
this.props.onContextMenu(e)
|
||||
}
|
||||
|
||||
handleMouseDown (e) {
|
||||
if (e.target != null && e.target.tagName === 'A') {
|
||||
return null
|
||||
if (e.target != null) {
|
||||
switch (e.target.tagName) {
|
||||
case 'A':
|
||||
case 'INPUT':
|
||||
return null
|
||||
}
|
||||
}
|
||||
if (this.props.onMouseDown != null) this.props.onMouseDown(e)
|
||||
}
|
||||
@@ -85,7 +94,10 @@ export default class MarkdownPreview extends React.Component {
|
||||
|
||||
rewriteIframe () {
|
||||
Array.prototype.forEach.call(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
|
||||
el.removeEventListener('click', this.goExternalHandler)
|
||||
el.removeEventListener('click', this.anchorClickHandler)
|
||||
})
|
||||
Array.prototype.forEach.call(this.refs.root.contentWindow.document.querySelectorAll('input[type="checkbox"]'), (el) => {
|
||||
el.removeEventListener('click', this.checkboxClickHandler)
|
||||
})
|
||||
|
||||
let { value, fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme } = this.props
|
||||
@@ -128,7 +140,10 @@ export default class MarkdownPreview extends React.Component {
|
||||
this.refs.root.contentWindow.document.body.innerHTML = markdown(value)
|
||||
|
||||
Array.prototype.forEach.call(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
|
||||
el.addEventListener('click', this.goExternalHandler)
|
||||
el.addEventListener('click', this.anchorClickHandler)
|
||||
})
|
||||
Array.prototype.forEach.call(this.refs.root.contentWindow.document.querySelectorAll('input[type="checkbox"]'), (el) => {
|
||||
el.addEventListener('click', this.checkboxClickHandler)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -141,13 +156,13 @@ export default class MarkdownPreview extends React.Component {
|
||||
}
|
||||
|
||||
scrollTo (targetRow) {
|
||||
let lineAnchors = this.getWindow().document.querySelectorAll('[data-line]')
|
||||
let blocks = this.getWindow().document.querySelectorAll('body>[data-line]')
|
||||
|
||||
for (let index = 0; index < lineAnchors.length; index++) {
|
||||
let lineAnchor = lineAnchors[index]
|
||||
let row = parseInt(lineAnchor.getAttribute('data-line'))
|
||||
for (let index = 0; index < blocks.length; index++) {
|
||||
let block = blocks[index]
|
||||
let row = parseInt(block.getAttribute('data-line'))
|
||||
if (row > targetRow) {
|
||||
let targetAnchor = lineAnchors[index - 1]
|
||||
let targetAnchor = blocks[index - 1]
|
||||
targetAnchor != null && this.getWindow().scrollTo(0, targetAnchor.offsetTop)
|
||||
break
|
||||
}
|
||||
|
||||
@@ -68,6 +68,10 @@ body
|
||||
padding 5px
|
||||
margin -5px
|
||||
border-radius 5px
|
||||
li
|
||||
label.taskListItem
|
||||
margin-left -2em
|
||||
background-color white
|
||||
div.math-rendered
|
||||
text-align center
|
||||
.math-failed
|
||||
|
||||
@@ -61,7 +61,58 @@ md.use(math, {
|
||||
}
|
||||
})
|
||||
md.use(require('markdown-it-footnote'))
|
||||
// Override task item
|
||||
md.block.ruler.at('paragraph', function (state, startLine/*, endLine*/) {
|
||||
let content, terminate, i, l, token
|
||||
let nextLine = startLine + 1
|
||||
let terminatorRules = state.md.block.ruler.getRules('paragraph')
|
||||
let endLine = state.lineMax
|
||||
|
||||
// jump line-by-line until empty one or EOF
|
||||
for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
|
||||
// this would be a code block normally, but after paragraph
|
||||
// it's considered a lazy continuation regardless of what's there
|
||||
if (state.sCount[nextLine] - state.blkIndent > 3) { continue }
|
||||
|
||||
// quirk for blockquotes, this line should already be checked by that rule
|
||||
if (state.sCount[nextLine] < 0) { continue }
|
||||
|
||||
// Some tags can terminate paragraph without empty line.
|
||||
terminate = false
|
||||
for (i = 0, l = terminatorRules.length; i < l; i++) {
|
||||
if (terminatorRules[i](state, nextLine, endLine, true)) {
|
||||
terminate = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (terminate) { break }
|
||||
}
|
||||
|
||||
content = state.getLines(startLine, nextLine, state.blkIndent, false).trim()
|
||||
|
||||
state.line = nextLine
|
||||
|
||||
token = state.push('paragraph_open', 'p', 1)
|
||||
token.map = [ startLine, state.line ]
|
||||
|
||||
if (state.parentType === 'list') {
|
||||
let match = content.match(/\[( |x)\] ?(.+)/i)
|
||||
if (match) {
|
||||
content = `<label class='taskListItem' for='checkbox-${startLine + 1}'><input type='checkbox'${match[1] !== ' ' ? ' checked' : ''} id='checkbox-${startLine + 1}'/> ${match[2]}</label>`
|
||||
}
|
||||
}
|
||||
|
||||
token = state.push('inline', '', 0)
|
||||
token.content = content
|
||||
token.map = [ startLine, state.line ]
|
||||
token.children = []
|
||||
|
||||
token = state.push('paragraph_close', 'p', -1)
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
// Add line number attribute for scrolling
|
||||
let originalRender = md.renderer.render
|
||||
md.renderer.render = function render (tokens, options, env) {
|
||||
tokens.forEach((token) => {
|
||||
|
||||
Reference in New Issue
Block a user