Forráskód Böngészése

feat: format the selected text to url if available (#3245)

Lucas.Xu 1 éve
szülő
commit
724fc895e1

+ 35 - 2
frontend/appflowy_flutter/integration_test/document/document_copy_and_paste_test.dart

@@ -195,11 +195,43 @@ void main() {
     //   expect(node.attributes[ImageBlockKeys.url], isNotNull);
     // });
   });
+
+  testWidgets(
+    'format the selected text to href when pasting url if available',
+    (tester) async {
+      const text = 'appflowy';
+      const url = 'https://appflowy.io';
+      await tester.pasteContent(
+        plainText: url,
+        beforeTest: (editorState) async {
+          await tester.ime.insertText(text);
+          await tester.editor.updateSelection(
+            Selection.single(
+              path: [0],
+              startOffset: 0,
+              endOffset: text.length,
+            ),
+          );
+        },
+        (editorState) {
+          final node = editorState.getNodeAtPath([0])!;
+          expect(node.type, ParagraphBlockKeys.type);
+          expect(node.delta!.toJson(), [
+            {
+              'insert': text,
+              'attributes': {'href': url}
+            }
+          ]);
+        },
+      );
+    },
+  );
 }
 
 extension on WidgetTester {
   Future<void> pasteContent(
     void Function(EditorState editorState) test, {
+    Future<void> Function(EditorState editorState)? beforeTest,
     String? plainText,
     String? html,
     (String, Uint8List?)? image,
@@ -210,6 +242,8 @@ extension on WidgetTester {
     // create a new document
     await createNewPageWithName();
 
+    await beforeTest?.call(editor.getCurrentEditorState());
+
     // mock the clipboard
     getIt<ClipboardService>().setData(
       ClipboardServiceData(
@@ -227,7 +261,6 @@ extension on WidgetTester {
     );
     await pumpAndSettle();
 
-    final editorState = editor.getCurrentEditorState();
-    test(editorState);
+    test(editor.getCurrentEditorState());
   }
 }

+ 0 - 1
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/copy_and_paste/custom_paste_command.dart

@@ -53,7 +53,6 @@ CommandShortcutEventHandler _pasteCommandHandler = (editorState) {
       await editorState.deleteSelectionIfNeeded();
       await editorState.pasteImage(image.$1, image.$2!);
     } else if (plainText != null && plainText.isNotEmpty) {
-      await editorState.deleteSelectionIfNeeded();
       await editorState.pastePlainText(plainText);
     }
   }();

+ 28 - 0
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/copy_and_paste/paste_from_plain_text.dart

@@ -7,6 +7,12 @@ RegExp _hrefRegex = RegExp(
 
 extension PasteFromPlainText on EditorState {
   Future<void> pastePlainText(String plainText) async {
+    if (await pasteHtmlIfAvailable(plainText)) {
+      return;
+    }
+
+    await deleteSelectionIfNeeded();
+
     final nodes = plainText
         .split('\n')
         .map(
@@ -33,4 +39,26 @@ extension PasteFromPlainText on EditorState {
       await pasteMultiLineNodes(nodes.toList());
     }
   }
+
+  Future<bool> pasteHtmlIfAvailable(String plainText) async {
+    final selection = this.selection;
+    if (selection == null ||
+        !selection.isSingle ||
+        selection.isCollapsed ||
+        !_hrefRegex.hasMatch(plainText)) {
+      return false;
+    }
+
+    final node = getNodeAtPath(selection.start.path);
+    if (node == null) {
+      return false;
+    }
+
+    final transaction = this.transaction;
+    transaction.formatText(node, selection.startIndex, selection.length, {
+      AppFlowyRichTextKeys.href: plainText,
+    });
+    await apply(transaction);
+    return true;
+  }
 }