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

Commit cf48f77

Browse files
niveditcfacebook-github-bot
authored andcommitted
Tree Data - Fix for backspace at the start of a nested block
Summary: On backspace (with collapsed selection) at the beginning of the first child (C) of a parent node (P), we want the behavior to be: * The parent node P is deleted. * All the children (siblings of C) become siblings of P's previous sibling. Pair programmed with flarnie :) Reviewed By: mitermayer Differential Revision: D9129672 fbshipit-source-id: af577be995a4c1029352cd83dd71357f8f045ff8
1 parent f3d3490 commit cf48f77

File tree

1 file changed

+76
-12
lines changed

1 file changed

+76
-12
lines changed

src/model/transaction/removeRangeFromContentState.js

+76-12
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ import type ContentState from 'ContentState';
1818
import type SelectionState from 'SelectionState';
1919

2020
const ContentBlockNode = require('ContentBlockNode');
21-
const Immutable = require('immutable');
2221

2322
const getNextDelimiterBlockKey = require('getNextDelimiterBlockKey');
23+
const Immutable = require('immutable');
2424

2525
const {List, Map} = Immutable;
2626

@@ -225,6 +225,61 @@ const updateBlockMapLinks = (
225225
}),
226226
),
227227
);
228+
229+
// if parent (startBlock) was deleted
230+
if (
231+
blockMap.get(startBlock.getKey()) == null &&
232+
blockMap.get(endBlock.getKey()) != null &&
233+
endBlock.getParentKey() === startBlock.getKey() &&
234+
endBlock.getPrevSiblingKey() == null
235+
) {
236+
const prevSiblingKey = startBlock.getPrevSiblingKey();
237+
// endBlock becomes next sibling of parent's prevSibling
238+
transformBlock(endBlock.getKey(), blocks, block =>
239+
block.merge({
240+
prevSibling: prevSiblingKey,
241+
}),
242+
);
243+
transformBlock(prevSiblingKey, blocks, block =>
244+
block.merge({
245+
nextSibling: endBlock.getKey(),
246+
}),
247+
);
248+
249+
// Update parent for previous parent's children, and children for that parent
250+
const prevSibling = prevSiblingKey ? blockMap.get(prevSiblingKey) : null;
251+
const newParentKey = prevSibling ? prevSibling.getParentKey() : null;
252+
startBlock.getChildKeys().forEach(childKey => {
253+
transformBlock(childKey, blocks, block =>
254+
block.merge({
255+
parent: newParentKey, // set to null if there is no parent
256+
}),
257+
);
258+
});
259+
if (newParentKey != null) {
260+
const newParent = blockMap.get(newParentKey);
261+
transformBlock(newParentKey, blocks, block =>
262+
block.merge({
263+
children: newParent
264+
.getChildKeys()
265+
.concat(startBlock.getChildKeys()),
266+
}),
267+
);
268+
}
269+
270+
// last child of deleted parent should point to next sibling
271+
transformBlock(
272+
startBlock.getChildKeys().find(key => {
273+
const block = (blockMap.get(key): ContentBlockNode);
274+
return block.getNextSiblingKey() === null;
275+
}),
276+
blocks,
277+
block =>
278+
block.merge({
279+
nextSibling: startBlock.getNextSiblingKey(),
280+
}),
281+
);
282+
}
228283
});
229284
};
230285

@@ -255,7 +310,7 @@ const removeRangeFromContentState = (
255310
const endBlockchildrenKeys = endBlock.getChildKeys();
256311
const endBlockAncestors = getAncestorsKeys(endKey, blockMap);
257312

258-
// endBlock has unselected sibblings so we can not remove its ancestors parents
313+
// endBlock has unselected siblings so we can not remove its ancestors parents
259314
if (endBlock.getNextSiblingKey()) {
260315
parentAncestors = parentAncestors.concat(endBlockAncestors);
261316
}
@@ -295,16 +350,25 @@ const removeRangeFromContentState = (
295350
characterList,
296351
});
297352

298-
const newBlocks = blockMap
299-
.toSeq()
300-
.skipUntil((_, k) => k === startKey)
301-
.takeUntil((_, k) => k === endKey)
302-
.filter((_, k) => parentAncestors.indexOf(k) === -1)
303-
.concat(Map([[endKey, null]]))
304-
.map((_, k) => {
305-
return k === startKey ? modifiedStart : null;
306-
});
307-
353+
// If cursor (collapsed) is at the start of the first child, delete parent
354+
// instead of child
355+
const shouldDeleteParent =
356+
isExperimentalTreeBlock &&
357+
startOffset === 0 &&
358+
endOffset === 0 &&
359+
endBlock.getParentKey() === startKey &&
360+
endBlock.getPrevSiblingKey() == null;
361+
const newBlocks = shouldDeleteParent
362+
? Map([[startKey, null]])
363+
: blockMap
364+
.toSeq()
365+
.skipUntil((_, k) => k === startKey)
366+
.takeUntil((_, k) => k === endKey)
367+
.filter((_, k) => parentAncestors.indexOf(k) === -1)
368+
.concat(Map([[endKey, null]]))
369+
.map((_, k) => {
370+
return k === startKey ? modifiedStart : null;
371+
});
308372
let updatedBlockMap = blockMap.merge(newBlocks).filter(block => !!block);
309373

310374
// Only update tree block pointers if the range is across blocks

0 commit comments

Comments
 (0)