mirror of
https://github.com/marktext/marktext.git
synced 2025-05-17 01:10:41 +08:00
feat: finish task list
This commit is contained in:
parent
a4e973e5e0
commit
d6fb921e79
2
TODO.md
2
TODO.md
@ -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
|
||||||
|
|
||||||
**菜单**
|
**菜单**
|
||||||
|
|
||||||
|
@ -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'
|
||||||
|
@ -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)) {
|
||||||
/**
|
/**
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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':
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user