feat: finish task list

This commit is contained in:
Jocs 2018-01-21 00:38:05 +08:00
parent a4e973e5e0
commit d6fb921e79
9 changed files with 154 additions and 56 deletions

View File

@ -6,7 +6,7 @@
- [ ] codeBlock 在 list item 中时list style 问题。 - [ ] codeBlock 在 list item 中时list style 问题。
- [ ] 在通过 Aganippe 打开文件时,无法通过右键选择 Aganippe。严重 bug - [ ] 在通过 Aganippe 打开文件时,无法通过右键选择 Aganippe。严重 bug
- [ ] 在通过 Aganippe 打开文件时,通过右键选择软件,但是打开无内容。(严重 bug - [ ] 在通过 Aganippe 打开文件时,通过右键选择软件,但是打开无内容。(严重 bug
- [ ] task item: (2)task item 只能和 task item 在一个 ul 中。所以需要优化 update 模块 - [ ] task item: 第一行为 list item 全选然后删除youbug
**菜单** **菜单**

View File

@ -71,6 +71,10 @@ export const CLASS_OR_ID = genUpper2LowerKeyHash([
'AG_REMOVE', 'AG_REMOVE',
'AG_EMOJI_MARKER', 'AG_EMOJI_MARKER',
'AG_NOTEXT_LINK', 'AG_NOTEXT_LINK',
'AG_ORDER_LIST',
'AG_ORDER_LIST_ITEM',
'AG_BULLET_LIST',
'AG_BULLET_LIST_ITEM',
'AG_TASK_LIST', 'AG_TASK_LIST',
'AG_TASK_LIST_ITEM', 'AG_TASK_LIST_ITEM',
'AG_TASK_LIST_ITEM_CHECKBOX' 'AG_TASK_LIST_ITEM_CHECKBOX'

View File

@ -17,7 +17,7 @@ const backspaceCtrl = ContentState => {
if ( if (
(parent && parent.type === 'li' && inLeft === 0 && this.isFirstChild(block)) || (parent && parent.type === 'li' && inLeft === 0 && this.isFirstChild(block)) ||
(parent && parent.type === 'li' && inLeft === 0 && parent.isTask && preBlock.type === 'input') // handle task item (parent && parent.type === 'li' && inLeft === 0 && parent.listItemType === 'task' && preBlock.type === 'input') // handle task item
) { ) {
if (this.isOnlyChild(parent)) { if (this.isOnlyChild(parent)) {
/** /**

View File

@ -27,7 +27,7 @@ const enterCtrl = ContentState => {
const paragraphInListItem = this.createBlock('p', text) const paragraphInListItem = this.createBlock('p', text)
const checkboxInListItem = this.createBlock('input') const checkboxInListItem = this.createBlock('input')
listItem.isTask = true listItem.listItemType = 'task'
checkboxInListItem.checked = checked checkboxInListItem.checked = checked
this.appendChild(listItem, checkboxInListItem) this.appendChild(listItem, checkboxInListItem)
this.appendChild(listItem, paragraphInListItem) this.appendChild(listItem, paragraphInListItem)
@ -96,7 +96,7 @@ const enterCtrl = ContentState => {
event.preventDefault() event.preventDefault()
if ( if (
(parent && parent.type === 'li' && this.isOnlyChild(block)) || (parent && parent.type === 'li' && this.isOnlyChild(block)) ||
(parent && parent.type === 'li' && parent.isTask && parent.children.length === 2) // one `input` and one `p` (parent && parent.type === 'li' && parent.listItemType === 'task' && parent.children.length === 2) // one `input` and one `p`
) { ) {
block = parent block = parent
parent = this.getParent(block) parent = this.getParent(block)
@ -106,6 +106,7 @@ const enterCtrl = ContentState => {
let type let type
let newBlock let newBlock
switch (true) { switch (true) {
case left !== 0 && right !== 0: // cursor in the middle case left !== 0 && right !== 0: // cursor in the middle
type = preType type = preType
@ -118,13 +119,14 @@ const enterCtrl = ContentState => {
if (type === 'li') { if (type === 'li') {
// handle task item // handle task item
if (block.isTask) { if (block.listItemType === 'task') {
const { checked } = block.children[0] // block.children[0] is input[type=checkbox] const { checked } = block.children[0] // block.children[0] is input[type=checkbox]
block.children[1].text = pre // block.children[1] is p block.children[1].text = pre // block.children[1] is p
newBlock = this.createTaskItemBlock(post, checked) newBlock = this.createTaskItemBlock(post, checked)
} else { } else {
block.children[0].text = pre block.children[0].text = pre
newBlock = this.createBlockLi(post) newBlock = this.createBlockLi(post)
newBlock.listItemType = block.listItemType
} }
} else { } else {
block.text = pre block.text = pre
@ -150,11 +152,12 @@ const enterCtrl = ContentState => {
this.removeBlock(block) this.removeBlock(block)
} else if (parent && parent.type === 'li') { } else if (parent && parent.type === 'li') {
if (parent.isTask) { if (parent.listItemType === 'task') {
const { checked } = parent.children[0] const { checked } = parent.children[0]
newBlock = this.createTaskItemBlock('', checked) newBlock = this.createTaskItemBlock('', checked)
} else { } else {
newBlock = this.createBlockLi() newBlock = this.createBlockLi()
newBlock.listItemType = parent.listItemType
} }
this.insertAfter(newBlock, parent) this.insertAfter(newBlock, parent)
const index = this.findIndex(parent.children, block) const index = this.findIndex(parent.children, block)
@ -176,11 +179,12 @@ const enterCtrl = ContentState => {
case left !== 0 && right === 0: // cursor at end of paragraph case left !== 0 && right === 0: // cursor at end of paragraph
case left === 0 && right !== 0: // cursor at begin of paragraph case left === 0 && right !== 0: // cursor at begin of paragraph
if (preType === 'li') { if (preType === 'li') {
if (block.isTask) { if (block.listItemType === 'task') {
const { checked } = block.children[0] const { checked } = block.children[0]
newBlock = this.createTaskItemBlock('', checked) newBlock = this.createTaskItemBlock('', checked)
} else { } else {
newBlock = this.createBlockLi() newBlock = this.createBlockLi()
newBlock.listItemType = block.listItemType
} }
} else { } else {
newBlock = this.createBlock('p') newBlock = this.createBlock('p')
@ -205,7 +209,7 @@ const enterCtrl = ContentState => {
const cursorBlock = blockNeedFocus ? block : newBlock const cursorBlock = blockNeedFocus ? block : newBlock
let key let key
if (cursorBlock.type === 'li') { if (cursorBlock.type === 'li') {
if (cursorBlock.isTask) { if (cursorBlock.listItemType === 'task') {
key = cursorBlock.children[1].key key = cursorBlock.children[1].key
} else { } else {
key = cursorBlock.children[0].key key = cursorBlock.children[0].key

View File

@ -31,7 +31,7 @@ const updateCtrl = ContentState => {
ContentState.prototype.checkInlineUpdate = function (block) { ContentState.prototype.checkInlineUpdate = function (block) {
const { text } = block const { text } = block
const parent = this.getParent(block) const parent = this.getParent(block)
const [match, disorder, tasklist, order, header, blockquote, hr] = text.match(INLINE_UPDATE_REG) || [] const [match, bullet, tasklist, order, header, blockquote, hr] = text.match(INLINE_UPDATE_REG) || []
let newType let newType
switch (true) { switch (true) {
@ -39,11 +39,11 @@ const updateCtrl = ContentState => {
this.updateHr(block, hr) this.updateHr(block, hr)
return true return true
case !!disorder: case !!bullet:
this.updateList(block, 'disorder', disorder) this.updateList(block, 'bullet', bullet)
return true return true
case !!tasklist && parent && parent.type === 'li': case !!tasklist && parent && parent.listItemType === 'bullet': // only `bullet` list item can be update to `task` list item
this.updateTaskListItem(block, 'tasklist', tasklist) this.updateTaskListItem(block, 'tasklist', tasklist)
return true return true
@ -78,13 +78,49 @@ const updateCtrl = ContentState => {
ContentState.prototype.updateTaskListItem = function (block, type, marker) { ContentState.prototype.updateTaskListItem = function (block, type, marker) {
const parent = this.getParent(block) const parent = this.getParent(block)
const grandpa = this.getParent(parent)
const checked = /\[x\]\s/i.test(marker) // use `i` flag to ignore upper case or lower case const checked = /\[x\]\s/i.test(marker) // use `i` flag to ignore upper case or lower case
const checkbox = this.createBlock('input') const checkbox = this.createBlock('input')
const { start, end } = this.cursor const { start, end } = this.cursor
checkbox.checked = checked checkbox.checked = checked
this.insertBefore(checkbox, block) this.insertBefore(checkbox, block)
block.text = block.text.substring(marker.length) block.text = block.text.substring(marker.length)
parent.isTask = true parent.listItemType = 'task'
let taskListWrapper
if (this.isOnlyChild(parent)) {
grandpa.listType = 'task'
} else if (this.isFirstChild(parent) || this.isLastChild(parent)) {
taskListWrapper = this.createBlock('ul')
taskListWrapper.listType = 'task'
this.isFirstChild(parent) ? this.insertBefore(taskListWrapper, grandpa) : this.insertAfter(taskListWrapper, grandpa)
this.removeBlock(parent)
this.appendChild(taskListWrapper, parent)
} else {
taskListWrapper = this.createBlock('ul')
taskListWrapper.listType = 'task'
const bulletListWrapper = this.createBlock('ul')
bulletListWrapper.listType = 'bullet'
let preSibling = this.getPreSibling(parent)
while (preSibling) {
this.removeBlock(preSibling)
if (bulletListWrapper.children.length) {
const firstChild = bulletListWrapper.children[0]
this.insertBefore(preSibling, firstChild)
} else {
this.appendChild(bulletListWrapper, preSibling)
}
preSibling = this.getPreSibling(preSibling)
}
this.removeBlock(parent)
this.appendChild(taskListWrapper, parent)
this.insertBefore(taskListWrapper, grandpa)
this.insertBefore(bulletListWrapper, taskListWrapper)
}
this.cursor = { this.cursor = {
start: { start: {
key: start.key, key: start.key,
@ -105,47 +141,43 @@ const updateCtrl = ContentState => {
} }
ContentState.prototype.updateList = function (block, type, marker) { ContentState.prototype.updateList = function (block, type, marker) {
console.log(type, marker)
const parent = this.getParent(block) const parent = this.getParent(block)
const preSibling = this.getPreSibling(block) const preSibling = this.getPreSibling(block)
const nextSibling = this.getNextSibling(block) const nextSibling = this.getNextSibling(block)
const wrapperTag = type === 'order' ? 'ol' : 'ul' const wrapperTag = type === 'order' ? 'ol' : 'ul' // `bullet` => `ul` and `order` => `ol`
const newText = block.text.substring(marker.length) const newText = block.text.substring(marker.length)
const { start, end } = this.cursor const { start, end } = this.cursor
const startOffset = start.offset const startOffset = start.offset
const endOffset = end.offset const endOffset = end.offset
let newBlock const newBlock = this.createBlockLi(newText)
newBlock.listItemType = type
if ((preSibling && preSibling.type === wrapperTag) && (nextSibling && nextSibling.type === wrapperTag)) { if (preSibling && preSibling.listType === type && nextSibling && nextSibling.listType === type) {
newBlock = this.createBlockLi(newText)
this.appendChild(preSibling, newBlock) this.appendChild(preSibling, newBlock)
const partChildren = nextSibling.children.splice(0) const partChildren = nextSibling.children.splice(0)
partChildren.forEach(b => this.appendChild(preSibling, b)) partChildren.forEach(b => this.appendChild(preSibling, b))
this.removeBlock(nextSibling) this.removeBlock(nextSibling)
this.removeBlock(block) this.removeBlock(block)
} else if (preSibling && preSibling.type === wrapperTag) { } else if (preSibling && preSibling.type === wrapperTag) {
newBlock = this.createBlockLi(newText)
this.appendChild(preSibling, newBlock) this.appendChild(preSibling, newBlock)
this.removeBlock(block) this.removeBlock(block)
} else if (nextSibling && nextSibling.type === wrapperTag) { } else if (nextSibling && nextSibling.listType === type) {
newBlock = this.createBlockLi(newText)
this.insertBefore(newBlock, nextSibling.children[0]) this.insertBefore(newBlock, nextSibling.children[0])
this.removeBlock(block) this.removeBlock(block)
} else if (parent && parent.type === wrapperTag) { } else if (parent && parent.listType === type) {
newBlock = this.createBlockLi(newText)
this.insertBefore(newBlock, block) this.insertBefore(newBlock, block)
this.removeBlock(block) this.removeBlock(block)
} else { } else {
block.type = wrapperTag block.type = wrapperTag
block.listType = type // `bullet` or `order`
block.text = '' block.text = ''
if (wrapperTag === 'ol') { if (wrapperTag === 'ol') {
const start = marker.split('.')[0] const start = marker.split('.')[0]
block.start = start block.start = start
} }
newBlock = this.createBlockLi(newText)
this.appendChild(block, newBlock) this.appendChild(block, newBlock)
} }

View File

@ -66,12 +66,40 @@ class StateRender {
} }
if (block.children.length) { if (block.children.length) {
if (/ul|ol/.test(block.type) && block.listType) {
switch (block.listType) {
case 'order':
blockSelector += `.${CLASS_OR_ID['AG_ORDER_LIST']}`
break
case 'bullet':
blockSelector += `.${CLASS_OR_ID['AG_BULLET_LIST']}`
break
case 'task':
blockSelector += `.${CLASS_OR_ID['AG_TASK_LIST']}`
break
default:
break
}
}
if (block.type === 'li' && block.listItemType) {
switch (block.listItemType) {
case 'order':
blockSelector += `.${CLASS_OR_ID['AG_ORDER_LIST_ITEM']}`
break
case 'bullet':
blockSelector += `.${CLASS_OR_ID['AG_BULLET_LIST_ITEM']}`
break
case 'task':
blockSelector += `.${CLASS_OR_ID['AG_TASK_LIST_ITEM']}`
break
default:
break
}
}
if (block.type === 'ol') { if (block.type === 'ol') {
Object.assign(data.attrs, { start: block.start }) Object.assign(data.attrs, { start: block.start })
} }
if (block.type === 'li' && block.isTask) {
blockSelector += `.${CLASS_OR_ID['AG_TASK_LIST_ITEM']}`
}
return h(blockSelector, data, block.children.map(child => renderBlock(child))) return h(blockSelector, data, block.children.map(child => renderBlock(child)))
} else { } else {
let children = block.text let children = block.text

View File

@ -17,7 +17,9 @@ var block = {
nptable: noop, nptable: noop,
lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/, lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/, blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, tasklist: /^( *)([*+-] \[(?:X|x|\s)\]) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1(?:[*+-] \[(?:X|x|\s)\]))\n*|\s*$)/,
orderlist: /^( *)(\d+\.) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1\d+\. )\n*|\s*$)/,
bulletlist: /^( *)([*+-]) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1[*+-] )\n*|\s*$)/,
html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/, html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
table: noop, table: noop,
@ -26,17 +28,18 @@ var block = {
}; };
block.checkbox = /^\[([ x])\] +/; block.checkbox = /^\[([ x])\] +/;
block.bullet = /(?:[*+-]|\d+\.)/; block.bullet = /(?:[*+-] \[(?:X|x|\s)\]|[*+-]|\d+\.)/;
block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/; block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
block.item = replace(block.item, 'gm') block.item = replace(block.item, 'gm')
(/bull/g, block.bullet) (/bull/g, block.bullet)
(); ();
block.list = replace(block.list) ['tasklist', 'orderlist', 'bulletlist'].forEach(list => {
(/bull/g, block.bullet) block[list] = replace(block[list])
('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))') ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
('def', '\\n+(?=' + block.def.source + ')') ('def', '\\n+(?=' + block.def.source + ')')
(); ();
});
block.blockquote = replace(block.blockquote) block.blockquote = replace(block.blockquote)
('def', block.def) ('def', block.def)
@ -79,10 +82,13 @@ block.gfm = merge({}, block.normal, {
heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/ heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
}); });
// fix me
block.gfm.paragraph = replace(block.paragraph) block.gfm.paragraph = replace(block.paragraph)
('(?!', '(?!' + ('(?!', '(?!' +
block.gfm.fences.source.replace('\\1', '\\2') + '|' + block.gfm.fences.source.replace('\\1', '\\2') + '|' +
block.list.source.replace('\\1', '\\3') + '|') block.tasklist.source.replace('\\1', '\\5') + '|' +
block.orderlist.source.replace('\\1', '\\7') + '|' +
block.bulletlist.source.replace('\\1', '\\9') + '|')
(); ();
/** /**
@ -168,7 +174,8 @@ Lexer.prototype.token = function(src, top, bq) {
this.tokens.push({ this.tokens.push({
type: 'code', type: 'code',
text: !this.options.pedantic ? text: !this.options.pedantic ?
cap.replace(/\n+$/, '') : cap cap.replace(/\n+$/, '') :
cap
}); });
continue; continue;
} }
@ -270,18 +277,18 @@ Lexer.prototype.token = function(src, top, bq) {
} }
// list // list
if (cap = this.rules.list.exec(src)) { if (cap = this.rules.tasklist.exec(src) || this.rules.orderlist.exec(src) || this.rules.bulletlist.exec(src)) {
src = src.substring(cap[0].length); src = src.substring(cap[0].length);
bull = cap[2]; bull = cap[2];
this.tokens.push({ this.tokens.push({
type: 'list_start', type: 'list_start',
ordered: bull.length > 1 ordered: bull.length > 1 && /\d/.test(bull),
listType: bull.length > 1 ? (/\d/.test(bull) ? 'order' : 'task') : 'bullet'
}); });
// Get each top-level item. // Get each top-level item.
cap = cap[0].match(this.rules.item); cap = cap[0].match(this.rules.item);
next = false; next = false;
l = cap.length; l = cap.length;
i = 0; i = 0;
@ -334,8 +341,10 @@ Lexer.prototype.token = function(src, top, bq) {
this.tokens.push({ this.tokens.push({
checked: checked, checked: checked,
listItemType: bull.length > 1 ? (/\d/.test(bull) ? 'order' : 'task') : 'bullet',
type: loose ? type: loose ?
'loose_item_start' : 'list_item_start' 'loose_item_start' :
'list_item_start'
}); });
// Recurse. // Recurse.
@ -358,7 +367,8 @@ Lexer.prototype.token = function(src, top, bq) {
src = src.substring(cap[0].length); src = src.substring(cap[0].length);
this.tokens.push({ this.tokens.push({
type: this.options.sanitize ? type: this.options.sanitize ?
'paragraph' : 'html', 'paragraph' :
'html',
pre: !this.options.sanitizer && pre: !this.options.sanitizer &&
(cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'), (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
text: cap[0] text: cap[0]
@ -412,11 +422,13 @@ Lexer.prototype.token = function(src, top, bq) {
// top-level paragraph // top-level paragraph
if (top && (cap = this.rules.paragraph.exec(src))) { if (top && (cap = this.rules.paragraph.exec(src))) {
console.log(cap)
src = src.substring(cap[0].length); src = src.substring(cap[0].length);
this.tokens.push({ this.tokens.push({
type: 'paragraph', type: 'paragraph',
text: cap[1].charAt(cap[1].length - 1) === '\n' ? text: cap[1].charAt(cap[1].length - 1) === '\n' ?
cap[1].slice(0, -1) : cap[1] cap[1].slice(0, -1) :
cap[1]
}); });
continue; continue;
} }
@ -812,16 +824,28 @@ Renderer.prototype.hr = function() {
Renderer.prototype.list = function(body, ordered, taskList) { Renderer.prototype.list = function(body, ordered, taskList) {
var type = ordered ? 'ol' : 'ul'; var type = ordered ? 'ol' : 'ul';
var classes = taskList ? ' class="task-list"' : ''; var classes = !ordered ? (taskList ? ' class="task-list"' : ' class="bullet-list"') : ' class="order-list"'
return '<' + type + classes + '>\n' + body + '</' + type + '>\n'; return '<' + type + classes + '>\n' + body + '</' + type + '>\n';
}; };
Renderer.prototype.listitem = function(text, checked) { Renderer.prototype.listitem = function(text, checked, listItemType) {
var classes
switch (listItemType) {
case 'order':
classes = ' class="order-list-item"'
break
case 'task':
classes = ' class="task-list-item"'
break
case 'bullet':
classes = ' class="bullet-list-item"'
break
}
if (checked === undefined) { if (checked === undefined) {
return '<li>' + text + '</li>\n'; return '<li ' + classes + '>' + text + '</li>\n';
} }
return '<li class="task-list-item">' + return '<li ' + classes + '>' +
'<input type="checkbox" class="task-list-item-checkbox"' + '<input type="checkbox" class="task-list-item-checkbox"' +
(checked ? ' checked' : '') + (checked ? ' checked' : '') +
'> ' + '> ' +
@ -1074,7 +1098,8 @@ Parser.prototype.tok = function() {
case 'list_item_start': case 'list_item_start':
{ {
var body = '', var body = '',
checked = this.token.checked; checked = this.token.checked,
listItemType = this.token.listItemType;
while (this.next().type !== 'list_item_end') { while (this.next().type !== 'list_item_end') {
body += this.token.type === 'text' ? body += this.token.type === 'text' ?
@ -1082,23 +1107,25 @@ Parser.prototype.tok = function() {
this.tok(); this.tok();
} }
return this.renderer.listitem(body, checked); return this.renderer.listitem(body, checked, listItemType);
} }
case 'loose_item_start': case 'loose_item_start':
{ {
var body = '', var body = '',
checked = this.token.checked; checked = this.token.checked,
listItemType = this.token.listItemType;
while (this.next().type !== 'list_item_end') { while (this.next().type !== 'list_item_end') {
body += this.tok(); body += this.tok();
} }
return this.renderer.listitem(body, checked); return this.renderer.listitem(body, checked, listItemType);
} }
case 'html': case 'html':
{ {
var html = !this.token.pre && !this.options.pedantic ? var html = !this.token.pre && !this.options.pedantic ?
this.inline.output(this.token.text) : this.token.text; this.inline.output(this.token.text) :
this.token.text;
return this.renderer.html(html); return this.renderer.html(html);
} }
case 'paragraph': case 'paragraph':

View File

@ -122,7 +122,7 @@ class ExportMarkdown {
if (listInfo.type === 'ul') { if (listInfo.type === 'ul') {
itemMarker = '- ' itemMarker = '- '
if (block.isTask) { if (block.listItemType === 'task') {
const firstChild = children[0] const firstChild = children[0]
itemMarker += firstChild.checked ? '[x] ' : '[ ] ' itemMarker += firstChild.checked ? '[x] ' : '[ ] '
children = children.slice(1) children = children.slice(1)

View File

@ -49,7 +49,6 @@ const importRegister = ContentState => {
} }
const htmlText = marked(markdown, { disableInline: true }) const htmlText = marked(markdown, { disableInline: true })
const domAst = parse5.parseFragment(htmlText) const domAst = parse5.parseFragment(htmlText)
const childNodes = domAst.childNodes const childNodes = domAst.childNodes
@ -100,7 +99,7 @@ const importRegister = ContentState => {
const checked = child.attrs.some(attr => attr.name === 'checked' && attr.value === '') const checked = child.attrs.some(attr => attr.name === 'checked' && attr.value === '')
if (isTaskListItemCheckbox) { if (isTaskListItemCheckbox) {
parent.isTask = true // double check parent.listItemType = 'task' // double check
block = this.createBlock('input') block = this.createBlock('input')
block.checked = checked block.checked = checked
this.appendChild(parent, block) this.appendChild(parent, block)
@ -110,19 +109,22 @@ const importRegister = ContentState => {
case 'li': case 'li':
const isTask = child.attrs.some(attr => attr.name === 'class' && attr.value === 'task-list-item') const isTask = child.attrs.some(attr => attr.name === 'class' && attr.value === 'task-list-item')
block = this.createBlock('li') block = this.createBlock('li')
block.isTask = isTask block.listItemType = parent.nodeName === 'ul' ? (isTask ? 'task' : 'bullet') : 'order'
this.appendChild(parent, block) this.appendChild(parent, block)
travel(block, child.childNodes) travel(block, child.childNodes)
break break
case 'ul': case 'ul':
const isTaskList = child.attrs.some(attr => attr.name === 'class' && attr.value === 'task-list')
block = this.createBlock('ul') block = this.createBlock('ul')
block.listType = isTaskList ? 'task' : 'bullet'
travel(block, child.childNodes) travel(block, child.childNodes)
this.appendChild(parent, block) this.appendChild(parent, block)
break break
case 'ol': case 'ol':
block = this.createBlock('ol') block = this.createBlock('ol')
block.listType = 'order'
child.attrs.forEach(attr => { child.attrs.forEach(attr => {
block[attr.name] = attr.value block[attr.name] = attr.value
}) })
@ -154,7 +156,8 @@ const importRegister = ContentState => {
case '#text': case '#text':
const { parentNode } = child const { parentNode } = child
value = child.value value = child.value
if (parentNode.nodeName === 'li' && value !== '\n') {
if (parentNode.nodeName === 'li' && /\S/.test(value)) {
block = this.createBlock('p', value) block = this.createBlock('p', value)
this.appendChild(parent, block) this.appendChild(parent, block)
} }