Skip to content
This repository was archived by the owner on Feb 6, 2023. It is now read-only.

Commit 0cb3804

Browse files
niveditcfacebook-github-bot
authored andcommitted
Unnest the first non-leaf child
Summary: We don't want to leave behind doubly nested children if their preceding block is untabbed. Here we iterate to make sure that the next block is never left with a non-leaf first child. Diagram of this operation, also implemented in the test below: https://pxl.cl/hs20 Reviewed By: vdurmont Differential Revision: D9826012 fbshipit-source-id: 1c14c5091ce89ddee3e80b2a7e9eef9d4759c320
1 parent 77e6844 commit 0cb3804

File tree

3 files changed

+203
-0
lines changed

3 files changed

+203
-0
lines changed

src/model/modifier/exploration/NestedRichTextEditorUtil.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,27 @@ const NestedRichTextEditorUtil: RichTextUtils = {
419419
);
420420
blockMap = DraftTreeOperations.moveChildUp(blockMap, key);
421421
}
422+
423+
// on untab, we also want to unnest any sibling blocks that become two levels deep
424+
// ensure that block's old parent does not have a non-leaf as its first child.
425+
if (parentKey != null) {
426+
let parent = blockMap.get(parentKey);
427+
while (parent != null) {
428+
const children = parent.getChildKeys();
429+
const firstChildKey = children.first();
430+
invariant(
431+
firstChildKey != null,
432+
'parent must have at least one child',
433+
);
434+
const firstChild = blockMap.get(firstChildKey);
435+
if (firstChild.getChildKeys().count() === 0) {
436+
break;
437+
} else {
438+
blockMap = DraftTreeOperations.moveChildUp(blockMap, firstChildKey);
439+
parent = blockMap.get(parentKey);
440+
}
441+
}
442+
}
422443
}
423444
content = editorState.getCurrentContent().merge({
424445
blockMap: blockMap,

src/model/modifier/exploration/__tests__/NestedRichTextEditorUtil-test.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,66 @@ test('onTab (untab) on a middle child splits the block at that child', () => {
585585
);
586586
});
587587

588+
const contentBlockNodes4 = [
589+
new ContentBlockNode({
590+
key: 'A',
591+
parent: null,
592+
text: 'alpha',
593+
children: Immutable.List([]),
594+
prevSibling: null,
595+
nextSibling: 'X',
596+
type: 'ordered-list-item',
597+
}),
598+
new ContentBlockNode({
599+
key: 'X',
600+
parent: null,
601+
text: '',
602+
children: Immutable.List(['B', 'Y']),
603+
prevSibling: 'A',
604+
nextSibling: null,
605+
type: 'ordered-list-item',
606+
}),
607+
new ContentBlockNode({
608+
key: 'B',
609+
parent: 'X',
610+
text: 'beta',
611+
children: Immutable.List([]),
612+
prevSibling: null,
613+
nextSibling: 'Y',
614+
type: 'ordered-list-item',
615+
}),
616+
new ContentBlockNode({
617+
key: 'Y',
618+
parent: 'X',
619+
text: '',
620+
children: Immutable.List(['C']),
621+
prevSibling: 'B',
622+
nextSibling: null,
623+
type: 'ordered-list-item',
624+
}),
625+
new ContentBlockNode({
626+
key: 'C',
627+
parent: 'Y',
628+
text: 'charlie',
629+
children: Immutable.List([]),
630+
prevSibling: null,
631+
nextSibling: null,
632+
type: 'ordered-list-item',
633+
}),
634+
];
635+
636+
test('onTab (untab) unnests non-leaf next sibling', () => {
637+
assertNestedUtilOperation(
638+
editorState =>
639+
onTab({preventDefault: () => {}, shiftKey: true}, editorState, 2),
640+
{
641+
anchorKey: 'B',
642+
focusKey: 'B',
643+
},
644+
contentBlockNodes4,
645+
);
646+
});
647+
588648
// TODO (T32099101)
589649
test('onSplitParent must split a nested block retaining parent', () => {
590650
expect(true).toBe(true);

src/model/modifier/exploration/__tests__/__snapshots__/NestedRichTextEditorUtil-test.js.snap

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,6 +1903,128 @@ Object {
19031903
}
19041904
`;
19051905

1906+
exports[`onTab (untab) unnests non-leaf next sibling 1`] = `
1907+
Object {
1908+
"A": Object {
1909+
"characterList": Array [
1910+
Object {
1911+
"entity": null,
1912+
"style": Array [],
1913+
},
1914+
Object {
1915+
"entity": null,
1916+
"style": Array [],
1917+
},
1918+
Object {
1919+
"entity": null,
1920+
"style": Array [],
1921+
},
1922+
Object {
1923+
"entity": null,
1924+
"style": Array [],
1925+
},
1926+
Object {
1927+
"entity": null,
1928+
"style": Array [],
1929+
},
1930+
],
1931+
"children": Array [],
1932+
"data": Object {},
1933+
"depth": 0,
1934+
"key": "A",
1935+
"nextSibling": "B",
1936+
"parent": null,
1937+
"prevSibling": null,
1938+
"text": "alpha",
1939+
"type": "ordered-list-item",
1940+
},
1941+
"B": Object {
1942+
"characterList": Array [
1943+
Object {
1944+
"entity": null,
1945+
"style": Array [],
1946+
},
1947+
Object {
1948+
"entity": null,
1949+
"style": Array [],
1950+
},
1951+
Object {
1952+
"entity": null,
1953+
"style": Array [],
1954+
},
1955+
Object {
1956+
"entity": null,
1957+
"style": Array [],
1958+
},
1959+
],
1960+
"children": Array [],
1961+
"data": Object {},
1962+
"depth": 0,
1963+
"key": "B",
1964+
"nextSibling": "Y",
1965+
"parent": null,
1966+
"prevSibling": "A",
1967+
"text": "beta",
1968+
"type": "ordered-list-item",
1969+
},
1970+
"C": Object {
1971+
"characterList": Array [
1972+
Object {
1973+
"entity": null,
1974+
"style": Array [],
1975+
},
1976+
Object {
1977+
"entity": null,
1978+
"style": Array [],
1979+
},
1980+
Object {
1981+
"entity": null,
1982+
"style": Array [],
1983+
},
1984+
Object {
1985+
"entity": null,
1986+
"style": Array [],
1987+
},
1988+
Object {
1989+
"entity": null,
1990+
"style": Array [],
1991+
},
1992+
Object {
1993+
"entity": null,
1994+
"style": Array [],
1995+
},
1996+
Object {
1997+
"entity": null,
1998+
"style": Array [],
1999+
},
2000+
],
2001+
"children": Array [],
2002+
"data": Object {},
2003+
"depth": 0,
2004+
"key": "C",
2005+
"nextSibling": null,
2006+
"parent": "Y",
2007+
"prevSibling": null,
2008+
"text": "charlie",
2009+
"type": "ordered-list-item",
2010+
},
2011+
"Y": Object {
2012+
"characterList": Array [],
2013+
"children": Array [
2014+
"C",
2015+
],
2016+
"data": Object {},
2017+
"depth": 0,
2018+
"key": "Y",
2019+
"nextSibling": null,
2020+
"parent": null,
2021+
"prevSibling": "B",
2022+
"text": "",
2023+
"type": "ordered-list-item",
2024+
},
2025+
}
2026+
`;
2027+
19062028
exports[`onTab when siblings are at the same depth creates a new parent 1`] = `
19072029
Object {
19082030
"A": Object {

0 commit comments

Comments
 (0)