Просмотр исходного кода

feat: implement heading, quote, bulleted_list in toolbar service

Lucas.Xu 2 лет назад
Родитель
Сommit
9b6afcc5c9

+ 1 - 1
frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart

@@ -21,7 +21,7 @@ class CheckboxNodeWidgetBuilder extends NodeWidgetBuilder<TextNode> {
 
   @override
   NodeValidator<Node> get nodeValidator => ((node) {
-        return node.attributes.containsKey(StyleKey.check);
+        return node.attributes.containsKey(StyleKey.checkbox);
       });
 }
 

+ 36 - 28
frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/rich_text_style.dart

@@ -25,26 +25,48 @@ class StyleKey {
   static String font = 'font';
   static String href = 'href';
 
+  static String subtype = 'subtype';
+  static String heading = 'heading';
+  static String h1 = 'h1';
+  static String h2 = 'h2';
+  static String h3 = 'h3';
+  static String h4 = 'h4';
+  static String h5 = 'h5';
+  static String h6 = 'h6';
+
+  static String bulletedList = 'bulleted-list';
+  static String numberList = 'number-list';
+
   static String quote = 'quote';
-  static String list = 'list';
-  static String number = 'number';
-  static String todo = 'todo';
+  static String checkbox = 'checkbox';
   static String code = 'code';
+  static String number = 'number';
 
-  static String subtype = 'subtype';
-  static String check = 'checkbox';
-  static String heading = 'heading';
+  static List<String> partialStyleKeys = [
+    StyleKey.bold,
+    StyleKey.italic,
+    StyleKey.underline,
+    StyleKey.strikethrough,
+  ];
+
+  static List<String> globalStyleKeys = [
+    StyleKey.heading,
+    StyleKey.bulletedList,
+    StyleKey.numberList,
+    StyleKey.quote,
+    StyleKey.code,
+  ];
 }
 
 double baseFontSize = 16.0;
 // TODO: customize.
 Map<String, double> headingToFontSize = {
-  'h1': baseFontSize + 15,
-  'h2': baseFontSize + 12,
-  'h3': baseFontSize + 9,
-  'h4': baseFontSize + 6,
-  'h5': baseFontSize + 3,
-  'h6': baseFontSize,
+  StyleKey.h1: baseFontSize + 15,
+  StyleKey.h2: baseFontSize + 12,
+  StyleKey.h3: baseFontSize + 9,
+  StyleKey.h4: baseFontSize + 6,
+  StyleKey.h5: baseFontSize + 3,
+  StyleKey.h6: baseFontSize,
 };
 
 extension NodeAttributesExtensions on Attributes {
@@ -73,13 +95,6 @@ extension NodeAttributesExtensions on Attributes {
     return null;
   }
 
-  String? get list {
-    if (containsKey(StyleKey.list) && this[StyleKey.list] is String) {
-      return this[StyleKey.list];
-    }
-    return null;
-  }
-
   int? get number {
     if (containsKey(StyleKey.number) && this[StyleKey.number] is int) {
       return this[StyleKey.number];
@@ -87,13 +102,6 @@ extension NodeAttributesExtensions on Attributes {
     return null;
   }
 
-  bool get todo {
-    if (containsKey(StyleKey.todo) && this[StyleKey.todo] is bool) {
-      return this[StyleKey.todo];
-    }
-    return false;
-  }
-
   bool get code {
     if (containsKey(StyleKey.code) && this[StyleKey.code] == true) {
       return this[StyleKey.code];
@@ -102,8 +110,8 @@ extension NodeAttributesExtensions on Attributes {
   }
 
   bool get check {
-    if (containsKey(StyleKey.check) && this[StyleKey.check] is bool) {
-      return this[StyleKey.check];
+    if (containsKey(StyleKey.checkbox) && this[StyleKey.checkbox] is bool) {
+      return this[StyleKey.checkbox];
     }
     return false;
   }

+ 11 - 7
frontend/app_flowy/packages/flowy_editor/lib/render/selection/toolbar_widget.dart

@@ -1,8 +1,9 @@
+import 'package:flowy_editor/render/rich_text/rich_text_style.dart';
+import 'package:flutter/material.dart';
+
 import 'package:flowy_editor/editor_state.dart';
 import 'package:flowy_editor/infra/flowy_svg.dart';
-import 'package:flowy_editor/render/rich_text/rich_text_style.dart';
 import 'package:flowy_editor/service/default_text_operations/format_rich_text_style.dart';
-import 'package:flutter/material.dart';
 
 typedef ToolbarEventHandler = void Function(EditorState editorState);
 
@@ -13,17 +14,20 @@ ToolbarEventHandlers defaultToolbarEventHandlers = {
   'italic': (editorState) => formatItalic(editorState),
   'strikethrough': (editorState) => formatStrikethrough(editorState),
   'underline': (editorState) => formatUnderline(editorState),
-  'quote': ((editorState) {}),
-  'number_list': ((editorState) {}),
-  'bulleted_list': ((editorState) {}),
+  'quote': (editorState) => formatQuote(editorState),
+  'number_list': (editorState) {},
+  'bulleted_list': (editorState) => formatBulletedList(editorState),
+  'H1': (editorState) => formatHeading(editorState, StyleKey.h1),
+  'H2': (editorState) => formatHeading(editorState, StyleKey.h2),
+  'H3': (editorState) => formatHeading(editorState, StyleKey.h3),
 };
 
 List<String> defaultListToolbarEventNames = [
   'H1',
   'H2',
   'H3',
-  'B-List',
-  'N-List',
+  // 'B-List',
+  // 'N-List',
 ];
 
 class ToolbarWidget extends StatefulWidget {

+ 56 - 6
frontend/app_flowy/packages/flowy_editor/lib/service/default_text_operations/format_rich_text_style.dart

@@ -1,27 +1,77 @@
 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/extensions/text_node_extensions.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';
+
+void formatHeading(EditorState editorState, String heading) {
+  formatTextNodes(editorState, {
+    StyleKey.subtype: StyleKey.heading,
+    StyleKey.heading: heading,
+  });
+}
+
+void formatQuote(EditorState editorState) {
+  formatTextNodes(editorState, {
+    StyleKey.subtype: StyleKey.quote,
+  });
+}
+
+void formatCheckbox(EditorState editorState) {
+  formatTextNodes(editorState, {
+    StyleKey.subtype: StyleKey.checkbox,
+    StyleKey.checkbox: false,
+  });
+}
+
+void formatBulletedList(EditorState editorState) {
+  formatTextNodes(editorState, {
+    StyleKey.subtype: StyleKey.bulletedList,
+  });
+}
+
+bool formatTextNodes(EditorState editorState, Attributes attributes) {
+  final nodes = editorState.service.selectionService.currentSelectedNodes.value;
+  final textNodes = nodes.whereType<TextNode>().toList();
+
+  if (textNodes.isEmpty) {
+    return false;
+  }
+
+  final builder = TransactionBuilder(editorState);
+
+  for (final textNode in textNodes) {
+    builder.updateNode(
+      textNode,
+      Attributes.fromIterable(
+        StyleKey.globalStyleKeys,
+        value: (_) => null,
+      )..addAll(attributes),
+    );
+  }
+
+  builder.commit();
+  return true;
+}
 
 bool formatBold(EditorState editorState) {
-  return formatRichText(editorState, StyleKey.bold);
+  return formatRichTextPartialStyle(editorState, StyleKey.bold);
 }
 
 bool formatItalic(EditorState editorState) {
-  return formatRichText(editorState, StyleKey.italic);
+  return formatRichTextPartialStyle(editorState, StyleKey.italic);
 }
 
 bool formatUnderline(EditorState editorState) {
-  return formatRichText(editorState, StyleKey.underline);
+  return formatRichTextPartialStyle(editorState, StyleKey.underline);
 }
 
 bool formatStrikethrough(EditorState editorState) {
-  return formatRichText(editorState, StyleKey.strikethrough);
+  return formatRichTextPartialStyle(editorState, StyleKey.strikethrough);
 }
 
-bool formatRichText(EditorState editorState, String styleKey) {
+bool formatRichTextPartialStyle(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);