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

fix: link text is only displayed if all selected text satisfy linked style

Lucas.Xu 2 éve
szülő
commit
60a7557520

+ 24 - 10
frontend/app_flowy/packages/appflowy_editor/lib/src/extensions/text_node_extensions.dart

@@ -29,24 +29,34 @@ extension TextNodeExtension on TextNode {
   }
 
   bool allSatisfyLinkInSelection(Selection selection) =>
-      allSatisfyInSelection(StyleKey.href, null, selection);
+      allSatisfyInSelection(StyleKey.href, selection, (value) {
+        return value != null;
+      });
 
   bool allSatisfyBoldInSelection(Selection selection) =>
-      allSatisfyInSelection(StyleKey.bold, true, selection);
+      allSatisfyInSelection(StyleKey.bold, selection, (value) {
+        return value == true;
+      });
 
   bool allSatisfyItalicInSelection(Selection selection) =>
-      allSatisfyInSelection(StyleKey.italic, true, selection);
+      allSatisfyInSelection(StyleKey.italic, selection, (value) {
+        return value == true;
+      });
 
   bool allSatisfyUnderlineInSelection(Selection selection) =>
-      allSatisfyInSelection(StyleKey.underline, true, selection);
+      allSatisfyInSelection(StyleKey.underline, selection, (value) {
+        return value == true;
+      });
 
   bool allSatisfyStrikethroughInSelection(Selection selection) =>
-      allSatisfyInSelection(StyleKey.strikethrough, true, selection);
+      allSatisfyInSelection(StyleKey.strikethrough, selection, (value) {
+        return value == true;
+      });
 
   bool allSatisfyInSelection(
     String styleKey,
-    dynamic value,
     Selection selection,
+    bool Function(dynamic value) compare,
   ) {
     final ops = delta.whereType<TextInsert>();
     final startOffset =
@@ -62,7 +72,7 @@ extension TextNodeExtension on TextNode {
       if (start < endOffset && start + length > startOffset) {
         if (op.attributes == null ||
             !op.attributes!.containsKey(styleKey) ||
-            op.attributes![styleKey] != value) {
+            !compare(op.attributes![styleKey])) {
           return false;
         }
       }
@@ -116,13 +126,15 @@ extension TextNodesExtension on List<TextNode> {
   bool allSatisfyInSelection(
     String styleKey,
     Selection selection,
-    dynamic value,
+    dynamic matchValue,
   ) {
     if (isEmpty) {
       return false;
     }
     if (length == 1) {
-      return first.allSatisfyInSelection(styleKey, value, selection);
+      return first.allSatisfyInSelection(styleKey, selection, (value) {
+        return value == matchValue;
+      });
     } else {
       for (var i = 0; i < length; i++) {
         final node = this[i];
@@ -142,7 +154,9 @@ extension TextNodesExtension on List<TextNode> {
             end: Position(path: node.path, offset: node.toRawString().length),
           );
         }
-        if (!node.allSatisfyInSelection(styleKey, value, newSelection)) {
+        if (!node.allSatisfyInSelection(styleKey, newSelection, (value) {
+          return value == matchValue;
+        })) {
           return false;
         }
       }

+ 5 - 0
frontend/app_flowy/packages/appflowy_editor/lib/src/infra/log.dart

@@ -75,6 +75,11 @@ class Log {
   /// For example, uses the logger when processing scroll events.
   static Log scroll = Log._(name: 'scroll');
 
+  /// For logging message related to [AppFlowyToolbarService].
+  ///
+  /// For example, uses the logger when processing toolbar events.
+  static Log toolbar = Log._(name: 'toolbar');
+
   /// For logging message related to UI.
   ///
   /// For example, uses the logger when building the widget.

+ 6 - 1
frontend/app_flowy/packages/appflowy_editor/lib/src/render/toolbar/toolbar_item.dart

@@ -181,7 +181,12 @@ void _showLinkMenu(EditorState editorState, BuildContext context) {
   final length = (selection.start.offset - selection.end.offset).abs();
   final node = editorState.service.selectionService.currentSelectedNodes.first
       as TextNode;
-  final linkText = node.getAttributeInSelection(selection, StyleKey.href);
+  final String linkText;
+  if (node.allSatisfyLinkInSelection(selection)) {
+    linkText = node.getAttributeInSelection(selection, StyleKey.href);
+  } else {
+    linkText = '';
+  }
   _linkMenuOverlay = OverlayEntry(builder: (context) {
     return Positioned(
       top: matchRect.bottom + 5.0,

+ 3 - 3
frontend/app_flowy/packages/appflowy_editor/lib/src/service/service.dart

@@ -36,10 +36,10 @@ class FlowyService {
 
   // toolbar service
   final toolbarServiceKey = GlobalKey(debugLabel: 'flowy_toolbar_service');
-  FlowyToolbarService? get toolbarService {
+  AppFlowyToolbarService? get toolbarService {
     if (toolbarServiceKey.currentState != null &&
-        toolbarServiceKey.currentState is FlowyToolbarService) {
-      return toolbarServiceKey.currentState! as FlowyToolbarService;
+        toolbarServiceKey.currentState is AppFlowyToolbarService) {
+      return toolbarServiceKey.currentState! as AppFlowyToolbarService;
     }
     return null;
   }

+ 2 - 2
frontend/app_flowy/packages/appflowy_editor/lib/src/service/toolbar_service.dart

@@ -5,7 +5,7 @@ import 'package:appflowy_editor/appflowy_editor.dart';
 import 'package:appflowy_editor/src/render/toolbar/toolbar_widget.dart';
 import 'package:appflowy_editor/src/extensions/object_extensions.dart';
 
-abstract class FlowyToolbarService {
+abstract class AppFlowyToolbarService {
   /// Show the toolbar widget beside the offset.
   void showInOffset(Offset offset, LayerLink layerLink);
 
@@ -31,7 +31,7 @@ class FlowyToolbar extends StatefulWidget {
 }
 
 class _FlowyToolbarState extends State<FlowyToolbar>
-    implements FlowyToolbarService {
+    implements AppFlowyToolbarService {
   OverlayEntry? _toolbarOverlay;
   final _toolbarWidgetKey = GlobalKey(debugLabel: '_toolbar_widget');
 

+ 23 - 4
frontend/app_flowy/packages/appflowy_editor/test/service/internal_key_event_handlers/update_text_style_by_command_x_handler_test.dart

@@ -82,7 +82,14 @@ Future<void> _testUpdateTextStyleByCommandX(
   );
   var textNode = editor.nodeAtPath([1]) as TextNode;
   expect(
-      textNode.allSatisfyInSelection(matchStyle, matchValue, selection), true);
+      textNode.allSatisfyInSelection(
+        matchStyle,
+        selection,
+        (value) {
+          return value == matchValue;
+        },
+      ),
+      true);
 
   selection =
       Selection.single(path: [1], startOffset: 0, endOffset: text.length);
@@ -94,7 +101,14 @@ Future<void> _testUpdateTextStyleByCommandX(
   );
   textNode = editor.nodeAtPath([1]) as TextNode;
   expect(
-      textNode.allSatisfyInSelection(matchStyle, matchValue, selection), true);
+      textNode.allSatisfyInSelection(
+        matchStyle,
+        selection,
+        (value) {
+          return value == matchValue;
+        },
+      ),
+      true);
 
   await editor.updateSelection(selection);
   await editor.pressLogicKey(
@@ -123,9 +137,14 @@ Future<void> _testUpdateTextStyleByCommandX(
     expect(
       node.allSatisfyInSelection(
         matchStyle,
-        matchValue,
         Selection.single(
-            path: node.path, startOffset: 0, endOffset: text.length),
+          path: node.path,
+          startOffset: 0,
+          endOffset: text.length,
+        ),
+        (value) {
+          return value == matchValue;
+        },
       ),
       true,
     );