mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: implement italic, strikethrough and underline in toolbar service
This commit is contained in:
parent
ba78f0073d
commit
b11a127432
@ -26,7 +26,7 @@ Attributes? composeAttributes(Attributes? a, Attributes? b) {
|
|||||||
a ??= {};
|
a ??= {};
|
||||||
b ??= {};
|
b ??= {};
|
||||||
final Attributes attributes = {};
|
final Attributes attributes = {};
|
||||||
attributes.addAll(b);
|
attributes.addAll(Map.from(b)..removeWhere((_, value) => value == null));
|
||||||
|
|
||||||
for (final entry in a.entries) {
|
for (final entry in a.entries) {
|
||||||
if (!b.containsKey(entry.key)) {
|
if (!b.containsKey(entry.key)) {
|
||||||
|
@ -89,8 +89,12 @@ class Node extends ChangeNotifier with LinkedListEntry<Node> {
|
|||||||
this.attributes['subtype'] != attributes['subtype'];
|
this.attributes['subtype'] != attributes['subtype'];
|
||||||
|
|
||||||
for (final attribute in attributes.entries) {
|
for (final attribute in attributes.entries) {
|
||||||
|
if (attribute.value == null) {
|
||||||
|
this.attributes.remove(attribute.key);
|
||||||
|
} else {
|
||||||
this.attributes[attribute.key] = attribute.value;
|
this.attributes[attribute.key] = attribute.value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Notify the new attributes
|
// Notify the new attributes
|
||||||
// if attributes contains 'subtype', should notify parent to rebuild node
|
// if attributes contains 'subtype', should notify parent to rebuild node
|
||||||
// else, just notify current node.
|
// else, just notify current node.
|
||||||
|
@ -9,12 +9,10 @@ typedef ToolbarEventHandler = void Function(EditorState editorState);
|
|||||||
typedef ToolbarEventHandlers = Map<String, ToolbarEventHandler>;
|
typedef ToolbarEventHandlers = Map<String, ToolbarEventHandler>;
|
||||||
|
|
||||||
ToolbarEventHandlers defaultToolbarEventHandlers = {
|
ToolbarEventHandlers defaultToolbarEventHandlers = {
|
||||||
'bold': ((editorState) {
|
'bold': (editorState) => formatBold(editorState),
|
||||||
formatRichTextStyle(editorState, {StyleKey.bold: true});
|
'italic': (editorState) => formatItalic(editorState),
|
||||||
}),
|
'strikethrough': (editorState) => formatStrikethrough(editorState),
|
||||||
'italic': ((editorState) {}),
|
'underline': (editorState) => formatUnderline(editorState),
|
||||||
'strikethrough': ((editorState) {}),
|
|
||||||
'underline': ((editorState) {}),
|
|
||||||
'quote': ((editorState) {}),
|
'quote': ((editorState) {}),
|
||||||
'number_list': ((editorState) {}),
|
'number_list': ((editorState) {}),
|
||||||
'bulleted_list': ((editorState) {}),
|
'bulleted_list': ((editorState) {}),
|
||||||
|
@ -1,9 +1,49 @@
|
|||||||
|
import 'package:flowy_editor/document/attributes.dart';
|
||||||
import 'package:flowy_editor/document/node.dart';
|
import 'package:flowy_editor/document/node.dart';
|
||||||
import 'package:flowy_editor/editor_state.dart';
|
import 'package:flowy_editor/editor_state.dart';
|
||||||
import 'package:flowy_editor/operation/transaction_builder.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(
|
bool formatBold(EditorState editorState) {
|
||||||
EditorState editorState, Map<String, dynamic> attributes) {
|
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 selection = editorState.service.selectionService.currentSelection;
|
||||||
final nodes = editorState.service.selectionService.currentSelectedNodes.value;
|
final nodes = editorState.service.selectionService.currentSelectedNodes.value;
|
||||||
final textNodes = nodes.whereType<TextNode>().toList();
|
final textNodes = nodes.whereType<TextNode>().toList();
|
||||||
|
@ -23,9 +23,7 @@ FlowyKeyEventHandler updateTextStyleByCommandXHandler = (editorState, event) {
|
|||||||
// bold
|
// bold
|
||||||
case 'B':
|
case 'B':
|
||||||
case 'b':
|
case 'b':
|
||||||
formatRichTextStyle(editorState, {
|
formatBold(editorState);
|
||||||
StyleKey.bold: !textNodes.allSatisfyBoldInSelection(selection),
|
|
||||||
});
|
|
||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user