Browse Source

feat: implement italic, strikethrough and underline in toolbar service

Lucas.Xu 2 years ago
parent
commit
b11a127432

+ 1 - 1
frontend/app_flowy/packages/flowy_editor/lib/document/attributes.dart

@@ -26,7 +26,7 @@ Attributes? composeAttributes(Attributes? a, Attributes? b) {
   a ??= {};
   b ??= {};
   final Attributes attributes = {};
-  attributes.addAll(b);
+  attributes.addAll(Map.from(b)..removeWhere((_, value) => value == null));
 
   for (final entry in a.entries) {
     if (!b.containsKey(entry.key)) {

+ 5 - 1
frontend/app_flowy/packages/flowy_editor/lib/document/node.dart

@@ -89,7 +89,11 @@ class Node extends ChangeNotifier with LinkedListEntry<Node> {
         this.attributes['subtype'] != attributes['subtype'];
 
     for (final attribute in attributes.entries) {
-      this.attributes[attribute.key] = attribute.value;
+      if (attribute.value == null) {
+        this.attributes.remove(attribute.key);
+      } else {
+        this.attributes[attribute.key] = attribute.value;
+      }
     }
     // Notify the new attributes
     // if attributes contains 'subtype', should notify parent to rebuild node

+ 4 - 6
frontend/app_flowy/packages/flowy_editor/lib/render/selection/toolbar_widget.dart

@@ -9,12 +9,10 @@ typedef ToolbarEventHandler = void Function(EditorState editorState);
 typedef ToolbarEventHandlers = Map<String, ToolbarEventHandler>;
 
 ToolbarEventHandlers defaultToolbarEventHandlers = {
-  'bold': ((editorState) {
-    formatRichTextStyle(editorState, {StyleKey.bold: true});
-  }),
-  'italic': ((editorState) {}),
-  'strikethrough': ((editorState) {}),
-  'underline': ((editorState) {}),
+  'bold': (editorState) => formatBold(editorState),
+  'italic': (editorState) => formatItalic(editorState),
+  'strikethrough': (editorState) => formatStrikethrough(editorState),
+  'underline': (editorState) => formatUnderline(editorState),
   'quote': ((editorState) {}),
   'number_list': ((editorState) {}),
   'bulleted_list': ((editorState) {}),

+ 42 - 2
frontend/app_flowy/packages/flowy_editor/lib/service/default_text_operations/format_rich_text_style.dart

@@ -1,9 +1,49 @@
+import 'package:flowy_editor/document/attributes.dart';
 import 'package:flowy_editor/document/node.dart';
 import 'package:flowy_editor/editor_state.dart';
 import 'package:flowy_editor/operation/transaction_builder.dart';
+import 'package:flowy_editor/render/rich_text/rich_text_style.dart';
+import 'package:flowy_editor/extensions/text_node_extensions.dart';
 
-bool formatRichTextStyle(
-    EditorState editorState, Map<String, dynamic> attributes) {
+bool formatBold(EditorState editorState) {
+  return formatRichText(editorState, StyleKey.bold);
+}
+
+bool formatItalic(EditorState editorState) {
+  return formatRichText(editorState, StyleKey.italic);
+}
+
+bool formatUnderline(EditorState editorState) {
+  return formatRichText(editorState, StyleKey.underline);
+}
+
+bool formatStrikethrough(EditorState editorState) {
+  return formatRichText(editorState, StyleKey.strikethrough);
+}
+
+bool formatRichText(EditorState editorState, String styleKey) {
+  final selection = editorState.service.selectionService.currentSelection;
+  final nodes = editorState.service.selectionService.currentSelectedNodes.value;
+  final textNodes = nodes.whereType<TextNode>().toList(growable: false);
+
+  if (selection == null || textNodes.isEmpty) {
+    return false;
+  }
+
+  bool value = !textNodes.allSatisfyInSelection(styleKey, selection);
+  Attributes attributes = {
+    styleKey: value,
+  };
+  if (styleKey == StyleKey.underline && value) {
+    attributes[StyleKey.strikethrough] = null;
+  } else if (styleKey == StyleKey.strikethrough && value) {
+    attributes[StyleKey.underline] = null;
+  }
+
+  return formatRichTextStyle(editorState, attributes);
+}
+
+bool formatRichTextStyle(EditorState editorState, Attributes attributes) {
   final selection = editorState.service.selectionService.currentSelection;
   final nodes = editorState.service.selectionService.currentSelectedNodes.value;
   final textNodes = nodes.whereType<TextNode>().toList();

+ 1 - 3
frontend/app_flowy/packages/flowy_editor/lib/service/internal_key_event_handlers/update_text_style_by_command_x_handler.dart

@@ -23,9 +23,7 @@ FlowyKeyEventHandler updateTextStyleByCommandXHandler = (editorState, event) {
     // bold
     case 'B':
     case 'b':
-      formatRichTextStyle(editorState, {
-        StyleKey.bold: !textNodes.allSatisfyBoldInSelection(selection),
-      });
+      formatBold(editorState);
       return KeyEventResult.handled;
     default:
       break;