Browse Source

feat: paste inside the TextNode

Vincent Chan 2 years ago
parent
commit
aba84a3ccd

+ 4 - 0
frontend/app_flowy/packages/flowy_editor/lib/operation/transaction_builder.dart

@@ -80,6 +80,10 @@ class TransactionBuilder {
     add(TextEditOperation(path, delta, inverted));
   }
 
+  setAfterSelection(Selection sel) {
+    afterSelection = sel;
+  }
+
   mergeText(TextNode firstNode, TextNode secondNode,
       {int? firstOffset, int secondOffset = 0}) {
     final firstLength = firstNode.delta.length;

+ 52 - 12
frontend/app_flowy/packages/flowy_editor/lib/service/internal_key_event_handlers/copy_paste_handler.dart

@@ -46,21 +46,61 @@ _handlePastePlainText(EditorState editorState, String plainText) {
     return;
   }
 
-  final path = [...selection.end.path];
-  if (path.isEmpty) {
+  final lines = plainText
+      .split("\n")
+      .map((e) => e.replaceAll(RegExp(r'\r'), ""))
+      .toList();
+
+  if (lines.isEmpty) {
     return;
-  }
-  path[path.length - 1]++;
+  } else if (lines.length == 1) {
+    final node =
+        editorState.document.nodeAtPath(selection.end.path)! as TextNode;
+    final beginOffset = selection.end.offset;
+    TransactionBuilder(editorState)
+      ..textEdit(node, () => Delta().retain(beginOffset).insert(lines[0]))
+      ..setAfterSelection(Selection.collapsed(Position(
+          path: selection.end.path, offset: beginOffset + lines[0].length)))
+      ..commit();
+  } else {
+    final firstLine = lines[0];
+    final beginOffset = selection.end.offset;
+    final remains = lines.sublist(1);
 
-  final lines =
-      plainText.split("\n").map((e) => e.replaceAll(RegExp(r'\r'), ""));
-  final nodes = lines
-      .map((e) => TextNode(type: "text", delta: Delta().insert(e)))
-      .toList();
+    final path = [...selection.end.path];
+    if (path.isEmpty) {
+      return;
+    }
 
-  final tb = TransactionBuilder(editorState);
-  tb.insertNodes(path, nodes);
-  tb.commit();
+    final node =
+        editorState.document.nodeAtPath(selection.end.path)! as TextNode;
+    final insertedLineSuffix = node.delta.slice(beginOffset);
+
+    path[path.length - 1]++;
+    var index = 0;
+    final tb = TransactionBuilder(editorState);
+    final nodes = remains.map((e) {
+      if (index++ == remains.length - 1) {
+        return TextNode(
+            type: "text",
+            delta: Delta().insert(e).addAll(insertedLineSuffix.operations));
+      }
+      return TextNode(type: "text", delta: Delta().insert(e));
+    }).toList();
+    // insert first line
+    tb.textEdit(
+        node,
+        () => Delta()
+            .retain(beginOffset)
+            .insert(firstLine)
+            .delete(node.delta.length - beginOffset));
+    // insert remains
+    tb.insertNodes(path, nodes);
+    tb.commit();
+
+    editorState.updateCursorSelection(Selection.collapsed(
+        Position(path: nodes.last.path, offset: lines.last.length)));
+  }
 }
 
 _handleCut() {