diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/document/selection.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/document/selection.dart index 68aecba8fc..641a985577 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/src/document/selection.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/document/selection.dart @@ -46,6 +46,8 @@ class Selection { (start.path <= end.path && !pathEquals(start.path, end.path)) || (isSingle && start.offset < end.offset); + Selection get reversed => copyWith(start: end, end: start); + Selection collapse({bool atStart = false}) { if (atStart) { return Selection(start: start, end: start); diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/extensions/text_node_extensions.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/extensions/text_node_extensions.dart index 131255ab63..3408546c42 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/src/extensions/text_node_extensions.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/extensions/text_node_extensions.dart @@ -20,14 +20,17 @@ extension TextNodeExtension on TextNode { bool allSatisfyInSelection(String styleKey, Selection selection) { final ops = delta.whereType(); + final startOffset = + selection.isBackward ? selection.start.offset : selection.end.offset; + final endOffset = + selection.isBackward ? selection.end.offset : selection.start.offset; var start = 0; for (final op in ops) { - if (start >= selection.end.offset) { + if (start >= endOffset) { break; } final length = op.length; - if (start < selection.end.offset && - start + length > selection.start.offset) { + if (start < endOffset && start + length > startOffset) { if (op.attributes == null || !op.attributes!.containsKey(styleKey) || op.attributes![styleKey] == false) { diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/service/default_text_operations/format_rich_text_style.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/service/default_text_operations/format_rich_text_style.dart index 6830dd62e4..64cd4f332e 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/src/service/default_text_operations/format_rich_text_style.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/service/default_text_operations/format_rich_text_style.dart @@ -43,7 +43,7 @@ bool insertTextNodeAfterSelection( } final node = nodes.first; - if (node is TextNode && node.delta.length == 0) { + if (node is TextNode && node.delta.isEmpty) { formatTextNodes(editorState, attributes); } else { final next = selection.end.path.next; @@ -157,11 +157,18 @@ bool formatRichTextPartialStyle(EditorState editorState, String styleKey) { } bool formatRichTextStyle(EditorState editorState, Attributes attributes) { - final selection = editorState.service.selectionService.currentSelection.value; - final nodes = editorState.service.selectionService.currentSelectedNodes; - final textNodes = nodes.whereType().toList(); + var selection = editorState.service.selectionService.currentSelection.value; + var nodes = editorState.service.selectionService.currentSelectedNodes; - if (selection == null || textNodes.isEmpty) { + if (selection == null) { + return false; + } + + nodes = selection.isBackward ? nodes : nodes.reversed.toList(growable: false); + selection = selection.isBackward ? selection : selection.reversed; + + var textNodes = nodes.whereType().toList(); + if (textNodes.isEmpty) { return false; } @@ -180,28 +187,20 @@ bool formatRichTextStyle(EditorState editorState, Attributes attributes) { } else { for (var i = 0; i < textNodes.length; i++) { final textNode = textNodes[i]; + var index = 0; + var length = textNode.toRawString().length; if (i == 0 && textNode == nodes.first) { - builder.formatText( - textNode, - selection.start.offset, - textNode.toRawString().length - selection.start.offset, - attributes, - ); + index = selection.start.offset; + length = textNode.toRawString().length - selection.start.offset; } else if (i == textNodes.length - 1 && textNode == nodes.last) { - builder.formatText( - textNode, - 0, - selection.end.offset, - attributes, - ); - } else { - builder.formatText( - textNode, - 0, - textNode.toRawString().length, - attributes, - ); + length = selection.end.offset; } + builder.formatText( + textNode, + index, + length, + attributes, + ); } } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/service/selection_service.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/service/selection_service.dart index 552e9eaf69..ecf013d0a4 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/src/service/selection_service.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/service/selection_service.dart @@ -487,6 +487,7 @@ class _FlowySelectionState extends State max = mid - 1; } } + min = min.clamp(start, end); final node = sortedNodes[min]; if (node.children.isNotEmpty && node.children.first.rect.top <= offset.dy) { final children = node.children.toList(growable: false);