fix(widget-markdown): Hitting Enter key in a list item doesn't create a new list item (#5550)
This commit is contained in:
parent
3bd36776d6
commit
ab3e8e1f5a
@ -35,7 +35,7 @@ describe('Markdown widget', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('creates nested list when selection is collapsed in non-first block of list item', () => {
|
||||
it('converts a list item to a paragraph block which is a sibling of the parent list', () => {
|
||||
cy.clickUnorderedListButton()
|
||||
.type('foo')
|
||||
.enter()
|
||||
@ -44,44 +44,20 @@ describe('Markdown widget', () => {
|
||||
<ul>
|
||||
<li>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p></p>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p></p>
|
||||
`)
|
||||
.type('bar')
|
||||
.enter()
|
||||
.clickUnorderedListButton()
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
<li>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>bar</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p></p>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
`);
|
||||
});
|
||||
|
||||
it('converts empty nested list item to empty block in parent list item', () => {
|
||||
it('converts empty nested list item to empty paragraph block in parent list item', () => {
|
||||
cy.clickUnorderedListButton()
|
||||
.type('foo')
|
||||
.enter()
|
||||
.clickUnorderedListButton()
|
||||
.tabkey()
|
||||
.type('bar')
|
||||
.enter()
|
||||
.clickUnorderedListButton()
|
||||
.tabkey()
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
<li>
|
||||
@ -129,10 +105,10 @@ describe('Markdown widget', () => {
|
||||
cy.clickUnorderedListButton()
|
||||
.type('foo')
|
||||
.enter()
|
||||
.clickUnorderedListButton()
|
||||
.tabkey()
|
||||
.type('bar')
|
||||
.enter()
|
||||
.clickUnorderedListButton()
|
||||
.tabkey()
|
||||
.type('baz')
|
||||
.clickUnorderedListButton()
|
||||
.confirmMarkdownEditorContent(`
|
||||
@ -228,7 +204,7 @@ describe('Markdown widget', () => {
|
||||
.up()
|
||||
.enter()
|
||||
.type('qux')
|
||||
.clickUnorderedListButton()
|
||||
.tabkey()
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
<li>
|
||||
@ -250,7 +226,6 @@ describe('Markdown widget', () => {
|
||||
.up()
|
||||
.enter()
|
||||
.type('quux')
|
||||
.clickUnorderedListButton()
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
<li>
|
||||
@ -307,9 +282,9 @@ describe('Markdown widget', () => {
|
||||
it('affects only selected list items', () => {
|
||||
cy.clickUnorderedListButton()
|
||||
.type('foo')
|
||||
.enter({ times: 2 })
|
||||
.enter()
|
||||
.type('bar')
|
||||
.enter({ times: 2 })
|
||||
.enter()
|
||||
.type('baz')
|
||||
.setSelection('bar')
|
||||
.clickUnorderedListButton()
|
||||
@ -352,14 +327,69 @@ describe('Markdown widget', () => {
|
||||
`)
|
||||
.setSelection('baz')
|
||||
.clickUnorderedListButton()
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
<li>
|
||||
<p>foo</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>bar</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>baz</p>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
`)
|
||||
.setCursorAfter('baz')
|
||||
.enter()
|
||||
.clickUnorderedListButton()
|
||||
.tabkey()
|
||||
.type('qux')
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
<li>
|
||||
<p>foo</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>bar</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>baz</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>qux</p>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
`)
|
||||
.setSelection('baz')
|
||||
.clickOrderedListButton()
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
<li>
|
||||
<p>foo</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>bar</p>
|
||||
<ol>
|
||||
<li>
|
||||
<p>baz</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>qux</p>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ul>
|
||||
`)
|
||||
.setCursorAfter('qux')
|
||||
.enter({ times: 4 })
|
||||
.enter({ times: 2 })
|
||||
.clickUnorderedListButton()
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
@ -398,7 +428,7 @@ describe('Markdown widget', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('creates a new paragraph in a non-empty paragraph within a list item', () => {
|
||||
it('creates a new list item in a non-empty list', () => {
|
||||
cy.clickUnorderedListButton()
|
||||
.type('foo')
|
||||
.enter()
|
||||
@ -406,6 +436,8 @@ describe('Markdown widget', () => {
|
||||
<ul>
|
||||
<li>
|
||||
<p>foo</p>
|
||||
</li>
|
||||
<li>
|
||||
<p></p>
|
||||
</li>
|
||||
</ul>
|
||||
@ -416,46 +448,21 @@ describe('Markdown widget', () => {
|
||||
<ul>
|
||||
<li>
|
||||
<p>foo</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>bar</p>
|
||||
</li>
|
||||
<li>
|
||||
<p></p>
|
||||
</li>
|
||||
</ul>
|
||||
`);
|
||||
});
|
||||
|
||||
it('creates a new list item in an empty paragraph within a non-empty list item', () => {
|
||||
it('creates a new default block below a list when hitting Enter twice on an empty list item of the list', () => {
|
||||
cy.clickUnorderedListButton()
|
||||
.type('foo')
|
||||
.enter({ times: 2 })
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
<li>
|
||||
<p>foo</p>
|
||||
</li>
|
||||
<li>
|
||||
<p></p>
|
||||
</li>
|
||||
</ul>
|
||||
`)
|
||||
.type('bar')
|
||||
.enter()
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
<li>
|
||||
<p>foo</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>bar</p>
|
||||
<p></p>
|
||||
</li>
|
||||
</ul>
|
||||
`);
|
||||
});
|
||||
|
||||
it('creates a new block below list', () => {
|
||||
cy.clickUnorderedListButton()
|
||||
.type('foo')
|
||||
.enter({ times: 3 })
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
<li>
|
||||
@ -476,24 +483,10 @@ describe('Markdown widget', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('removes empty block in non-empty list item', () => {
|
||||
cy.clickUnorderedListButton()
|
||||
.type('foo')
|
||||
.enter()
|
||||
.backspace()
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
<li>
|
||||
<p>foo</p>
|
||||
</li>
|
||||
</ul>
|
||||
`);
|
||||
});
|
||||
|
||||
it('removes the list item if list not empty', () => {
|
||||
cy.clickUnorderedListButton()
|
||||
.type('foo')
|
||||
.enter({ times: 2 })
|
||||
.enter()
|
||||
.backspace()
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
@ -544,7 +537,7 @@ describe('Markdown widget', () => {
|
||||
it('indents nested list items', () => {
|
||||
cy.clickUnorderedListButton()
|
||||
.type('foo')
|
||||
.enter({ times: 2 })
|
||||
.enter()
|
||||
.type('bar')
|
||||
.tabkey()
|
||||
.confirmMarkdownEditorContent(`
|
||||
@ -559,7 +552,7 @@ describe('Markdown widget', () => {
|
||||
</li>
|
||||
</ul>
|
||||
`)
|
||||
.enter({ times: 2 })
|
||||
.enter()
|
||||
.tabkey()
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
@ -583,8 +576,8 @@ describe('Markdown widget', () => {
|
||||
it('only nests up to one level down from the parent list', () => {
|
||||
cy.clickUnorderedListButton()
|
||||
.type('foo')
|
||||
.enter({ times: 2 })
|
||||
.tabkey({ times: 5 })
|
||||
.enter()
|
||||
.tabkey()
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
<li>
|
||||
@ -602,7 +595,7 @@ describe('Markdown widget', () => {
|
||||
it('unindents nested list items with shift', () => {
|
||||
cy.clickUnorderedListButton()
|
||||
.type('foo')
|
||||
.enter({ times: 2 })
|
||||
.enter()
|
||||
.tabkey()
|
||||
.tabkey({ shift: true })
|
||||
.confirmMarkdownEditorContent(`
|
||||
@ -620,10 +613,10 @@ describe('Markdown widget', () => {
|
||||
it('indents and unindents from one level below parent back to document root', () => {
|
||||
cy.clickUnorderedListButton()
|
||||
.type('foo')
|
||||
.enter({ times: 2 })
|
||||
.enter()
|
||||
.tabkey()
|
||||
.type('bar')
|
||||
.enter({ times: 2 })
|
||||
.enter()
|
||||
.tabkey()
|
||||
.type('baz')
|
||||
.confirmMarkdownEditorContent(`
|
||||
|
@ -59,8 +59,8 @@ describe('Markdown widget', () => {
|
||||
.clickUnorderedListButton()
|
||||
.clickHeadingOneButton()
|
||||
.type('foo')
|
||||
.enter({ times: 3 })
|
||||
.clickQuoteButton()
|
||||
.enter({ times: 2 }) // First Enter creates new list item. Second Enter turns that list item into a default block.
|
||||
.clickQuoteButton() // Unwrap the quote block.
|
||||
.confirmMarkdownEditorContent(`
|
||||
<ul>
|
||||
<li>
|
||||
@ -126,7 +126,7 @@ describe('Markdown widget', () => {
|
||||
cy.focused()
|
||||
.clickUnorderedListButton()
|
||||
.type('foo')
|
||||
.enter({ times: 2 })
|
||||
.enter()
|
||||
.type('bar')
|
||||
.setSelection('foo', 'bar')
|
||||
.clickQuoteButton()
|
||||
@ -154,7 +154,7 @@ describe('Markdown widget', () => {
|
||||
</ul>
|
||||
`)
|
||||
.setCursorAfter('bar')
|
||||
.enter({ times: 2 })
|
||||
.enter()
|
||||
.type('baz')
|
||||
.setSelection('bar', 'baz')
|
||||
.clickQuoteButton()
|
||||
@ -185,6 +185,38 @@ describe('Markdown widget', () => {
|
||||
.clickUnorderedListButton()
|
||||
.clickQuoteButton()
|
||||
.type('foo')
|
||||
// Content should contains 4 <blockquote> tags and 3 <ul> tags
|
||||
.confirmMarkdownEditorContent(`
|
||||
<blockquote>
|
||||
<ul>
|
||||
<li>
|
||||
<blockquote>
|
||||
<ul>
|
||||
<li>
|
||||
<blockquote>
|
||||
<ul>
|
||||
<li>
|
||||
<blockquote>
|
||||
<p>foo</p>
|
||||
</blockquote>
|
||||
</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
`)
|
||||
/*
|
||||
* First Enter creates new paragraph within the innermost block quote.
|
||||
* Second Enter moves that paragraph one level up to become sibling of the previous quote block and direct child of a list item.
|
||||
* Third Enter to turn that paragraph into a list item and move it one level up.
|
||||
* Repeat the circle for three more times to reach the second list item of the outermost list block.
|
||||
* Then Enter again to turn that list item into a paragraph and move it one level up to become sibling of the outermost list and
|
||||
* direct child of the outermost block quote.
|
||||
*/
|
||||
.enter({ times: 10 })
|
||||
.type('bar')
|
||||
.confirmMarkdownEditorContent(`
|
||||
@ -211,7 +243,16 @@ describe('Markdown widget', () => {
|
||||
<p>bar</p>
|
||||
</blockquote>
|
||||
`)
|
||||
.backspace({ times: 12 })
|
||||
/* The GOAL is to delete all the text content inside this deeply nested block quote and turn it into a default paragraph block on top level.
|
||||
* We need:
|
||||
* 3 Backspace to delete the word “bar”.
|
||||
* 1 Backspace to remove the paragraph that contains bar and bring cursor to the end of the unordered list which is direct child of the outermost block quote.
|
||||
* 3 Backspace to remove the word “foo”.
|
||||
* 1 Backspace to remove the current block quote that the cursor is on, 1 Backspace to remove the list that wraps the block quote. Repeat this step for three times for a total of 6 Backspace until the cursor is on the outermost block quote.
|
||||
* 1 Backspace to remove to toggle off the outermost block quote and turn it into a default paragraph.
|
||||
* Total Backspaces required: 3 + 1 + 3 + ((1 + 1) * 3) + 1 = 14
|
||||
*/
|
||||
.backspace({ times: 14 })
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -268,9 +268,42 @@ function ListPlugin({ defaultType, unorderedListType, orderedListType }) {
|
||||
|
||||
if (listOrListItem.type === 'list-item') {
|
||||
const listItem = listOrListItem;
|
||||
|
||||
const {
|
||||
value: { document },
|
||||
} = editor;
|
||||
// If focus is at start of list item, unwrap the entire list item.
|
||||
if (editor.atStartOf(listItem)) {
|
||||
/* If the list item in question has a grandparent list, this means it is a child of a nested list.
|
||||
* Hitting Enter key on an empty nested list item like this should move that list item out of the nested list
|
||||
* and into the grandparent list. The targeted list item becomes direct child of its grandparent list
|
||||
* Example
|
||||
* <ul> ----- GRANDPARENT LIST
|
||||
* <li> ------ GRANDPARENT LIST ITEM
|
||||
* <p>foo</p>
|
||||
* <ul> ----- PARENT LIST
|
||||
* <li>
|
||||
* <p>bar</p>
|
||||
* </li>
|
||||
* <li> ------ LIST ITEM
|
||||
* <p></p> ----- WHERE THE ENTER KEY HAPPENS
|
||||
* </li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
*/
|
||||
const parentList = document.getParent(listItem.key);
|
||||
const grandparentListItem = document.getParent(parentList.key);
|
||||
if (grandparentListItem.type === 'list-item') {
|
||||
const grandparentList = document.getParent(grandparentListItem.key);
|
||||
const indexOfGrandparentListItem = grandparentList.nodes.findIndex(
|
||||
node => node.key === grandparentListItem.key,
|
||||
);
|
||||
return editor.moveNodeByKey(
|
||||
listItem.key,
|
||||
grandparentList.key,
|
||||
indexOfGrandparentListItem + 1,
|
||||
);
|
||||
}
|
||||
return editor.unwrapListItem(listItem);
|
||||
}
|
||||
|
||||
@ -285,7 +318,23 @@ function ListPlugin({ defaultType, unorderedListType, orderedListType }) {
|
||||
editor.wrapBlockAtRange(range, newListItem).unwrapNodeByKey(newListItem.key);
|
||||
});
|
||||
}
|
||||
|
||||
const list = document.getParent(listItem.key);
|
||||
if (LIST_TYPES.includes(list.type)) {
|
||||
const newListItem = Block.create({
|
||||
type: 'list-item',
|
||||
nodes: [Block.create('paragraph')],
|
||||
});
|
||||
// Check if the targeted list item contains a nested list. If it does, insert a new list item in the beginning of that nested list.
|
||||
const nestedList = listItem.findDescendant(block => LIST_TYPES.includes(block.type));
|
||||
if (nestedList) {
|
||||
return editor.insertNodeByKey(nestedList.key, 0, newListItem).moveForward(1); // Each list item is separated by a \n character. We need to move the cursor past this character so that it'd be on new list item that has just been inserted
|
||||
}
|
||||
// Find index of the list item block that receives Enter key
|
||||
const previousListItemIndex = list.nodes.findIndex(block => block.key === listItem.key);
|
||||
return editor
|
||||
.insertNodeByKey(list.key, previousListItemIndex + 1, newListItem) // insert a new list item after the list item above
|
||||
.moveForward(1);
|
||||
}
|
||||
return next();
|
||||
} else {
|
||||
const list = listOrListItem;
|
||||
|
Loading…
x
Reference in New Issue
Block a user