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

Commit fbd18ce

Browse files
niveditcfacebook-github-bot
authored andcommitted
Merge successive non-leaf blocks resulting from tab
Summary: When you tab a block & both its neighbors are non-leaves, we should merge the two blocks. https://pxl.cl/ht30 This is case 6 below, which I had postponed back in D9631917: {F137497472} Reviewed By: vdurmont Differential Revision: D9836483 fbshipit-source-id: 2c74a772e5c1d0b2751db10e760632ac75e77273
1 parent 36e588a commit fbd18ce

File tree

3 files changed

+293
-17
lines changed

3 files changed

+293
-17
lines changed

src/model/modifier/exploration/NestedRichTextEditorUtil.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -322,22 +322,22 @@ const NestedRichTextEditorUtil: RichTextUtils = {
322322
const prevSibling = blockMap.get(prevSiblingKey);
323323
const nextSibling =
324324
nextSiblingKey != null ? blockMap.get(nextSiblingKey) : null;
325-
if (
326-
prevSibling != null &&
327-
prevSibling.getText() === '' &&
328-
prevSibling.getChildKeys().count() > 0
329-
) {
325+
const prevSiblingNonLeaf =
326+
prevSibling != null && prevSibling.getChildKeys().count() > 0;
327+
const nextSiblingNonLeaf =
328+
nextSibling != null && nextSibling.getChildKeys().count() > 0;
329+
if (prevSiblingNonLeaf) {
330330
blockMap = DraftTreeOperations.updateAsSiblingsChild(
331331
blockMap,
332332
key,
333333
'previous',
334334
);
335-
// else, if next sibling is a non-leaf move node as child of next sibling
336-
} else if (
337-
nextSibling != null &&
338-
nextSibling.getText() === '' &&
339-
nextSibling.getChildKeys().count() > 0
340-
) {
335+
// if next sibling is also non-leaf, merge the previous & next siblings
336+
if (nextSiblingNonLeaf) {
337+
blockMap = DraftTreeOperations.mergeBlocks(blockMap, prevSiblingKey);
338+
}
339+
// else, if only next sibling is non-leaf move node as child of next sibling
340+
} else if (nextSiblingNonLeaf) {
341341
blockMap = DraftTreeOperations.updateAsSiblingsChild(
342342
blockMap,
343343
key,

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

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,83 @@ test('onTab when siblings are at the same depth creates a new parent', () => {
466466
);
467467
});
468468

469+
const contentBlockNodes3 = [
470+
new ContentBlockNode({
471+
key: 'A',
472+
parent: null,
473+
text: 'alpha',
474+
children: Immutable.List([]),
475+
prevSibling: null,
476+
nextSibling: 'X',
477+
type: 'ordered-list-item',
478+
}),
479+
new ContentBlockNode({
480+
key: 'X',
481+
parent: null,
482+
text: '',
483+
children: Immutable.List(['B']),
484+
prevSibling: 'A',
485+
nextSibling: 'C',
486+
type: 'ordered-list-item',
487+
}),
488+
new ContentBlockNode({
489+
key: 'B',
490+
parent: 'X',
491+
text: 'beta',
492+
children: Immutable.List([]),
493+
prevSibling: null,
494+
nextSibling: null,
495+
type: 'ordered-list-item',
496+
}),
497+
new ContentBlockNode({
498+
key: 'C',
499+
parent: null,
500+
text: 'charlie',
501+
children: Immutable.List([]),
502+
prevSibling: 'X',
503+
nextSibling: 'Y',
504+
type: 'ordered-list-item',
505+
}),
506+
new ContentBlockNode({
507+
key: 'Y',
508+
parent: null,
509+
text: '',
510+
children: Immutable.List(['D', 'E']),
511+
prevSibling: 'C',
512+
nextSibling: null,
513+
type: 'ordered-list-item',
514+
}),
515+
new ContentBlockNode({
516+
key: 'D',
517+
parent: 'Y',
518+
text: 'delta',
519+
children: Immutable.List([]),
520+
prevSibling: null,
521+
nextSibling: 'E',
522+
type: 'ordered-list-item',
523+
}),
524+
new ContentBlockNode({
525+
key: 'E',
526+
parent: 'Y',
527+
text: 'epsilon',
528+
children: Immutable.List([]),
529+
prevSibling: 'D',
530+
nextSibling: null,
531+
type: 'ordered-list-item',
532+
}),
533+
];
534+
535+
test('onTab when both siblings are non-leaf merges blocks', () => {
536+
assertNestedUtilOperation(
537+
editorState => onTab({preventDefault: () => {}}, editorState, 1),
538+
{
539+
anchorKey: 'C',
540+
focusKey: 'C',
541+
},
542+
contentBlockNodes3,
543+
);
544+
});
545+
469546
test('onTab (untab) on a block with no parent does nothing', () => {
470547
assertNestedUtilOperation(
471548
editorState =>
@@ -502,7 +579,7 @@ test('onTab (untab) on a last child moves block as next sibling of parent', () =
502579
);
503580
});
504581

505-
const contentBlockNodes3 = [
582+
const contentBlockNodes4 = [
506583
new ContentBlockNode({
507584
key: 'A',
508585
nextSibling: 'X',
@@ -581,11 +658,11 @@ test('onTab (untab) on a middle child splits the block at that child', () => {
581658
anchorKey: 'E',
582659
focusKey: 'E',
583660
},
584-
contentBlockNodes3,
661+
contentBlockNodes4,
585662
);
586663
});
587664

588-
const contentBlockNodes4 = [
665+
const contentBlockNodes5 = [
589666
new ContentBlockNode({
590667
key: 'A',
591668
parent: null,
@@ -641,11 +718,11 @@ test('onTab (untab) unnests non-leaf next sibling', () => {
641718
anchorKey: 'B',
642719
focusKey: 'B',
643720
},
644-
contentBlockNodes4,
721+
contentBlockNodes5,
645722
);
646723
});
647724

648-
const contentBlockNodes5 = [
725+
const contentBlockNodes6 = [
649726
new ContentBlockNode({
650727
key: 'A',
651728
parent: null,
@@ -719,7 +796,7 @@ test('onTab (untab) merges adjacent non-leaf blocks', () => {
719796
anchorKey: 'B',
720797
focusKey: 'B',
721798
},
722-
contentBlockNodes5,
799+
contentBlockNodes6,
723800
);
724801
});
725802

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

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2223,6 +2223,205 @@ Object {
22232223
}
22242224
`;
22252225

2226+
exports[`onTab when both siblings are non-leaf merges blocks 1`] = `
2227+
Object {
2228+
"A": Object {
2229+
"characterList": Array [
2230+
Object {
2231+
"entity": null,
2232+
"style": Array [],
2233+
},
2234+
Object {
2235+
"entity": null,
2236+
"style": Array [],
2237+
},
2238+
Object {
2239+
"entity": null,
2240+
"style": Array [],
2241+
},
2242+
Object {
2243+
"entity": null,
2244+
"style": Array [],
2245+
},
2246+
Object {
2247+
"entity": null,
2248+
"style": Array [],
2249+
},
2250+
],
2251+
"children": Array [],
2252+
"data": Object {},
2253+
"depth": 0,
2254+
"key": "A",
2255+
"nextSibling": "X",
2256+
"parent": null,
2257+
"prevSibling": null,
2258+
"text": "alpha",
2259+
"type": "ordered-list-item",
2260+
},
2261+
"B": Object {
2262+
"characterList": Array [
2263+
Object {
2264+
"entity": null,
2265+
"style": Array [],
2266+
},
2267+
Object {
2268+
"entity": null,
2269+
"style": Array [],
2270+
},
2271+
Object {
2272+
"entity": null,
2273+
"style": Array [],
2274+
},
2275+
Object {
2276+
"entity": null,
2277+
"style": Array [],
2278+
},
2279+
],
2280+
"children": Array [],
2281+
"data": Object {},
2282+
"depth": 0,
2283+
"key": "B",
2284+
"nextSibling": "C",
2285+
"parent": "X",
2286+
"prevSibling": null,
2287+
"text": "beta",
2288+
"type": "ordered-list-item",
2289+
},
2290+
"C": Object {
2291+
"characterList": Array [
2292+
Object {
2293+
"entity": null,
2294+
"style": Array [],
2295+
},
2296+
Object {
2297+
"entity": null,
2298+
"style": Array [],
2299+
},
2300+
Object {
2301+
"entity": null,
2302+
"style": Array [],
2303+
},
2304+
Object {
2305+
"entity": null,
2306+
"style": Array [],
2307+
},
2308+
Object {
2309+
"entity": null,
2310+
"style": Array [],
2311+
},
2312+
Object {
2313+
"entity": null,
2314+
"style": Array [],
2315+
},
2316+
Object {
2317+
"entity": null,
2318+
"style": Array [],
2319+
},
2320+
],
2321+
"children": Array [],
2322+
"data": Object {},
2323+
"depth": 1,
2324+
"key": "C",
2325+
"nextSibling": "D",
2326+
"parent": "X",
2327+
"prevSibling": "B",
2328+
"text": "charlie",
2329+
"type": "ordered-list-item",
2330+
},
2331+
"D": Object {
2332+
"characterList": Array [
2333+
Object {
2334+
"entity": null,
2335+
"style": Array [],
2336+
},
2337+
Object {
2338+
"entity": null,
2339+
"style": Array [],
2340+
},
2341+
Object {
2342+
"entity": null,
2343+
"style": Array [],
2344+
},
2345+
Object {
2346+
"entity": null,
2347+
"style": Array [],
2348+
},
2349+
Object {
2350+
"entity": null,
2351+
"style": Array [],
2352+
},
2353+
],
2354+
"children": Array [],
2355+
"data": Object {},
2356+
"depth": 0,
2357+
"key": "D",
2358+
"nextSibling": "E",
2359+
"parent": "X",
2360+
"prevSibling": "C",
2361+
"text": "delta",
2362+
"type": "ordered-list-item",
2363+
},
2364+
"E": Object {
2365+
"characterList": Array [
2366+
Object {
2367+
"entity": null,
2368+
"style": Array [],
2369+
},
2370+
Object {
2371+
"entity": null,
2372+
"style": Array [],
2373+
},
2374+
Object {
2375+
"entity": null,
2376+
"style": Array [],
2377+
},
2378+
Object {
2379+
"entity": null,
2380+
"style": Array [],
2381+
},
2382+
Object {
2383+
"entity": null,
2384+
"style": Array [],
2385+
},
2386+
Object {
2387+
"entity": null,
2388+
"style": Array [],
2389+
},
2390+
Object {
2391+
"entity": null,
2392+
"style": Array [],
2393+
},
2394+
],
2395+
"children": Array [],
2396+
"data": Object {},
2397+
"depth": 0,
2398+
"key": "E",
2399+
"nextSibling": null,
2400+
"parent": "X",
2401+
"prevSibling": "D",
2402+
"text": "epsilon",
2403+
"type": "ordered-list-item",
2404+
},
2405+
"X": Object {
2406+
"characterList": Array [],
2407+
"children": Array [
2408+
"B",
2409+
"C",
2410+
"D",
2411+
"E",
2412+
],
2413+
"data": Object {},
2414+
"depth": 0,
2415+
"key": "X",
2416+
"nextSibling": null,
2417+
"parent": null,
2418+
"prevSibling": "A",
2419+
"text": "",
2420+
"type": "ordered-list-item",
2421+
},
2422+
}
2423+
`;
2424+
22262425
exports[`onTab when siblings are at the same depth creates a new parent 1`] = `
22272426
Object {
22282427
"A": Object {

0 commit comments

Comments
 (0)