feat: implement heading, quote, bulleted_list in toolbar service

This commit is contained in:
Lucas.Xu 2022-08-02 11:42:16 +08:00
parent b11a127432
commit 9b6afcc5c9
4 changed files with 105 additions and 43 deletions

View File

@ -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);
});
}

View File

@ -25,26 +25,48 @@ class StyleKey {
static String font = 'font';
static String href = 'href';
static String quote = 'quote';
static String list = 'list';
static String number = 'number';
static String todo = 'todo';
static String code = 'code';
static String subtype = 'subtype';
static String check = 'checkbox';
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 checkbox = 'checkbox';
static String code = 'code';
static String number = 'number';
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;
}

View File

@ -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 {

View File

@ -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);