Kaynağa Gözat

fix: unable to parse html text which contains <mark> tag (#3529)

Lucas.Xu 1 yıl önce
ebeveyn
işleme
938953d7b3

+ 44 - 0
frontend/appflowy_flutter/integration_test/document/document_option_action_test.dart

@@ -0,0 +1,44 @@
+import 'package:flutter_test/flutter_test.dart';
+import 'package:integration_test/integration_test.dart';
+
+import '../util/util.dart';
+
+void main() {
+  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+
+  // +, ... button beside the block component.
+  group('document with option action button', () {
+    testWidgets(
+        'click + to add a block after current selection, and click + and option key to add a block before current selection',
+        (tester) async {
+      await tester.initializeAppFlowy();
+      await tester.tapGoButton();
+
+      var editorState = tester.editor.getCurrentEditorState();
+      expect(editorState.getNodeAtPath([1])?.delta?.toPlainText(), isNotEmpty);
+
+      // add a new block after the current selection
+      await tester.editor.hoverAndClickOptionAddButton([0], false);
+      // await tester.pumpAndSettle();
+      expect(editorState.getNodeAtPath([1])?.delta?.toPlainText(), isEmpty);
+
+      // cancel the selection menu
+      await tester.tapAt(Offset.zero);
+
+      await tester.editor.hoverAndClickOptionAddButton([0], true);
+      await tester.pumpAndSettle();
+      expect(editorState.getNodeAtPath([0])?.delta?.toPlainText(), isEmpty);
+      // cancel the selection menu
+      await tester.tapAt(Offset.zero);
+      await tester.tapAt(Offset.zero);
+
+      await tester.createNewPageWithName(name: 'test');
+      await tester.openPage(gettingStarted);
+
+      // check the status again
+      editorState = tester.editor.getCurrentEditorState();
+      expect(editorState.getNodeAtPath([0])?.delta?.toPlainText(), isEmpty);
+      expect(editorState.getNodeAtPath([2])?.delta?.toPlainText(), isEmpty);
+    });
+  });
+}

+ 2 - 0
frontend/appflowy_flutter/integration_test/document/document_test_runner.dart

@@ -5,6 +5,7 @@ import 'document_codeblock_paste_test.dart' as document_codeblock_paste_test;
 import 'document_copy_and_paste_test.dart' as document_copy_and_paste_test;
 import 'document_create_and_delete_test.dart'
     as document_create_and_delete_test;
+import 'document_option_action_test.dart' as document_option_action_test;
 import 'document_text_direction_test.dart' as document_text_direction_test;
 import 'document_with_cover_image_test.dart' as document_with_cover_image_test;
 import 'document_with_database_test.dart' as document_with_database_test;
@@ -31,4 +32,5 @@ void startTesting() {
   document_codeblock_paste_test.main();
   document_alignment_test.main();
   document_text_direction_test.main();
+  document_option_action_test.main();
 }

+ 31 - 0
frontend/appflowy_flutter/integration_test/util/editor_test_operations.dart

@@ -1,6 +1,7 @@
 import 'dart:ui';
 
 import 'package:appflowy/generated/locale_keys.g.dart';
+import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/block_action_add_button.dart';
 import 'package:appflowy/plugins/document/presentation/editor_plugins/header/cover_editor.dart';
 import 'package:appflowy/plugins/document/presentation/editor_plugins/header/custom_cover_picker.dart';
 import 'package:appflowy/plugins/document/presentation/editor_plugins/header/document_header_node_widget.dart';
@@ -174,4 +175,34 @@ class EditorOperations {
     );
     await tester.pumpAndSettle(const Duration(milliseconds: 200));
   }
+
+  /// hover and click on the + button beside the block component.
+  Future<void> hoverAndClickOptionAddButton(
+    Path path,
+    bool withModifiedKey, // alt on windows or linux, option on macos
+  ) async {
+    final optionAddButton = find.byWidgetPredicate(
+      (widget) =>
+          widget is BlockComponentActionWrapper &&
+          widget.node.path.equals(path),
+    );
+    await tester.hoverOnWidget(
+      optionAddButton,
+      onHover: () async {
+        if (withModifiedKey) {
+          await tester.sendKeyDownEvent(LogicalKeyboardKey.altLeft);
+        }
+        await tester.tapButton(
+          find.byWidgetPredicate(
+            (widget) =>
+                widget is BlockAddButton &&
+                widget.blockComponentContext.node.path.equals(path),
+          ),
+        );
+        if (withModifiedKey) {
+          await tester.sendKeyUpEvent(LogicalKeyboardKey.altLeft);
+        }
+      },
+    );
+  }
 }

+ 8 - 5
frontend/appflowy_flutter/lib/plugins/document/application/editor_transaction_adapter.dart

@@ -119,12 +119,15 @@ extension on InsertOperation {
       final parentId = node.parent?.id ??
           editorState.getNodeAtPath(currentPath.parent)?.id ??
           '';
-      var prevId = previousNode?.id ??
-          editorState.getNodeAtPath(currentPath.previous)?.id ??
-          '';
+      var prevId = previousNode?.id;
+      // if the node is the first child of the parent, then its prevId should be empty.
+      final isFirstChild = currentPath.previous.equals(currentPath);
+      if (!isFirstChild) {
+        prevId ??= editorState.getNodeAtPath(currentPath.previous)?.id ?? '';
+      }
+      prevId ??= '';
       assert(parentId.isNotEmpty);
-      if (currentPath.equals(currentPath.previous) &&
-          !currentPath.equals([0])) {
+      if (isFirstChild) {
         prevId = '';
       } else {
         assert(prevId.isNotEmpty && prevId != node.id);

+ 3 - 1
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart

@@ -177,12 +177,14 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
       focusedSelection: selection,
       // setup the theme
       editorStyle: styleCustomizer.style(),
-      // customize the block builder
+      // customize the block builders
       blockComponentBuilders: blockComponentBuilders,
       // customize the shortcuts
       characterShortcutEvents: characterShortcutEvents,
       commandShortcutEvents: commandShortcutEvents,
+      // customize the context menu items
       contextMenuItems: customContextMenuItems,
+      // customize the header and footer.
       header: widget.header,
       footer: const VSpace(200),
     );

+ 4 - 2
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/actions/option_action.dart

@@ -243,8 +243,10 @@ class ColorOptionAction extends PopoverActionCell {
         final bgColor =
             node.attributes[blockComponentBackgroundColor] as String?;
         final selectedColor = bgColor?.tryToColor();
-        // get default background color from themeExtension
-        final defaultColor = AFThemeExtension.of(context).calloutBGColor;
+        // get default background color for callout block from themeExtension
+        final defaultColor = node.type == CalloutBlockKeys.type
+            ? AFThemeExtension.of(context).calloutBGColor
+            : Colors.transparent;
         final colors = [
           // reset to default background color
           FlowyColorOption(

+ 11 - 3
frontend/appflowy_flutter/pubspec.lock

@@ -54,11 +54,11 @@ packages:
     dependency: "direct main"
     description:
       path: "."
-      ref: "8e618465258b3de0ce5253c4fa97bacb24884e8c"
-      resolved-ref: "8e618465258b3de0ce5253c4fa97bacb24884e8c"
+      ref: ce8aa6d
+      resolved-ref: ce8aa6d35decc0c2e770f8440413ca73ae4a578b
       url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
     source: git
-    version: "1.4.1"
+    version: "1.4.2"
   appflowy_popover:
     dependency: "direct main"
     description:
@@ -1575,6 +1575,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.3.2"
+  universal_html:
+    dependency: transitive
+    description:
+      name: universal_html
+      sha256: "56536254004e24d9d8cfdb7dbbf09b74cf8df96729f38a2f5c238163e3d58971"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.4"
   universal_io:
     dependency: transitive
     description:

+ 1 - 1
frontend/appflowy_flutter/pubspec.yaml

@@ -47,7 +47,7 @@ dependencies:
   appflowy_editor:
     git:
       url: https://github.com/AppFlowy-IO/appflowy-editor.git
-      ref: 8e618465258b3de0ce5253c4fa97bacb24884e8c
+      ref: ce8aa6d
   appflowy_popover:
     path: packages/appflowy_popover
 

+ 1 - 1
frontend/appflowy_flutter/test/unit_test/editor/transaction_adapter_test.dart

@@ -38,7 +38,7 @@ void main() {
       );
       expect(
         actions[0].blockActionPB.payload.prevId,
-        editorState.document.root.children.first.id,
+        '',
         reason: '0 - prev id',
       );
       expect(