executeHandleBackspace function
bool
executeHandleBackspace(
- FluentDocument document, {
- bool ctrl = false,
- bool lineStart = false,
Handles the Backspace key.
Supported behaviors:
- If there's an active selection: delete the selection
- If cursor is at the start of a ListItem: outdent (remove from list)
- If cursor is at the start of another node: merge with the previous node
- If cursor is on an image: remove the image
- If lineStart is pressed: delete to beginning of line
- If ctrl is pressed: delete the previous word
- Otherwise: delete the previous character in the fragment
Implementation
bool executeHandleBackspace(FluentDocument document, {bool ctrl = false, bool lineStart = false}) {
if (document.registry.dispatchBackspace(document, ctrl: ctrl, lineStart: lineStart)) {
return true;
}
final root = document.content;
final cursor = document.cursor;
if (deleteSelectionIfExists(document)) return true;
if (lineStart) {
return _handleDeleteToLineStart(document);
}
if (ctrl) {
return deleteWordHelper(document, forward: false);
}
final currentNode = document.nodeById(cursor.anchorId);
if (currentNode is HorizontalRule || currentNode is FluentImage) {
return removeNodeAndReposition(document, currentNode!);
}
final currentFrag = resolveFragmentFromCursor(currentNode, cursor.anchorOffset);
if (currentFrag == null) return false;
if (currentFrag is FluentImage) {
removeNode(root, currentFrag);
document.updateContent();
return true;
}
final container = document.findLogicalContainerCached(cursor.anchorId);
if (container == null) return false;
if (container is Paragraph && container.text.isEmpty &&
findAncestorCached<FluentCell>(document, container as FNode) == null) {
final prevStop = moveLeft(
root, CaretStop(cursor.anchorId, 0),
stops: document.caretStops,
cachedLines: document.logicalLines,
).position;
if (prevStop != null) {
removeNode(root, container as FNode);
cursor.moveTo(prevStop.fragmentId, prevStop.offset);
document.updateContent();
return true;
}
return false;
}
if (currentFrag is FluentImage) {
return removeNodeAndReposition(document, currentFrag);
}
if (findAncestorCached<FluentCell>(document, currentFrag) != null &&
currentFrag.text.isNotEmpty &&
currentFrag.text.replaceAll('\u200B', '').isEmpty) {
return true;
}
if (cursor.anchorOffset == 0) {
return _handleBackspaceAtStart(document, container, currentFrag);
}
int newOffset = FragmentOperations.getPreviousGraphemeOffsetSkippingZWS(currentFrag.text, cursor.anchorOffset);
final deleteCount = cursor.anchorOffset - newOffset;
final cellParent = findAncestorCached<FluentCell>(document, currentFrag);
FragmentOperations.deleteTextInFragment(currentFrag, newOffset, count: deleteCount);
if (cellParent != null && currentFrag.text.isEmpty) {
currentFrag.text = '\u200B';
cursor.moveTo(currentFrag.id, 0);
document.updateContent();
return true;
}
if (currentFrag.text.isEmpty) {
if (_removeEmptyFragmentAndReposition(document, container, currentFrag)) {
document.updateContent();
return true;
}
}
cursor.moveTo(currentFrag.id, newOffset);
notifyTextMutation(document, container, currentFrag.id, newOffset, -1);
document.updateContent();
return true;
}