Browse Source

feat: implement text delete

Lucas.Xu 2 years ago
parent
commit
b245841ec3

+ 5 - 1
frontend/app_flowy/packages/flowy_editor/example/assets/example.json

@@ -162,7 +162,11 @@
         "type": "text",
         "delta": [
           {
-            "insert": "Hello world"
+            "insert": "Hello "
+          },
+          {
+            "insert": "world",
+            "attributes": { "bold": true }
           }
         ],
         "attributes": {

+ 2 - 0
frontend/app_flowy/packages/flowy_editor/lib/service/editor_service.dart

@@ -1,3 +1,4 @@
+import 'package:flowy_editor/service/internal_key_event_handlers/delele_text_handler.dart';
 import 'package:flutter/material.dart';
 
 import 'package:flowy_editor/editor_state.dart';
@@ -30,6 +31,7 @@ NodeWidgetBuilders defaultBuilders = {
 };
 
 List<FlowyKeyEventHandler> defaultKeyEventHandler = [
+  deleteTextHandler,
   slashShortcutHandler,
   flowyDeleteNodesHandler,
   arrowKeysHandler,

+ 83 - 0
frontend/app_flowy/packages/flowy_editor/lib/service/internal_key_event_handlers/delele_text_handler.dart

@@ -0,0 +1,83 @@
+import 'package:flowy_editor/flowy_editor.dart';
+import 'package:flowy_editor/service/keyboard_service.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+
+// Handle delete text.
+FlowyKeyEventHandler deleteTextHandler = (editorState, event) {
+  if (event.logicalKey != LogicalKeyboardKey.backspace) {
+    return KeyEventResult.ignored;
+  }
+
+  final selection = editorState.service.selectionService.currentSelection;
+  if (selection == null) {
+    return KeyEventResult.ignored;
+  }
+
+  final nodes = editorState.service.selectionService.currentSelectedNodes.value;
+  // make sure all nodes is [TextNode].
+  final textNodes = nodes.whereType<TextNode>().toList();
+  if (textNodes.length != nodes.length) {
+    return KeyEventResult.ignored;
+  }
+
+  TransactionBuilder transactionBuilder = TransactionBuilder(editorState);
+  if (textNodes.length == 1) {
+    final textNode = textNodes.first;
+    final index = selection.start.offset - 1;
+    if (index < 0) {
+      // 1. style
+      if (textNode.subtype != null) {
+        transactionBuilder.updateNode(textNode, {
+          'subtype': null,
+        });
+      } else {
+        // 2. non-style
+        // find previous text node.
+        while (textNode.previous != null) {
+          if (textNode.previous is TextNode) {
+            final previous = textNode.previous as TextNode;
+            transactionBuilder
+              ..deleteNode(textNode)
+              ..insertText(
+                previous,
+                previous.toRawString().length,
+                textNode.toRawString(),
+              );
+            // FIXME: keep the attributes.
+            break;
+          }
+        }
+      }
+    } else {
+      transactionBuilder.deleteText(
+        textNode,
+        selection.start.offset - 1,
+        1,
+      );
+    }
+  } else {
+    for (var i = 0; i < textNodes.length; i++) {
+      final textNode = textNodes[i];
+      if (i == 0) {
+        transactionBuilder.deleteText(
+          textNode,
+          selection.start.offset,
+          textNode.toRawString().length - selection.start.offset,
+        );
+      } else if (i == textNodes.length - 1) {
+        transactionBuilder.deleteText(
+          textNode,
+          0,
+          selection.end.offset,
+        );
+      } else {
+        transactionBuilder.deleteNode(textNode);
+      }
+    }
+  }
+
+  transactionBuilder.commit();
+
+  return KeyEventResult.handled;
+};