|
@@ -4,10 +4,15 @@ import 'package:flutter/services.dart';
|
|
import 'package:flowy_editor/document/node.dart';
|
|
import 'package:flowy_editor/document/node.dart';
|
|
import 'package:flowy_editor/document/position.dart';
|
|
import 'package:flowy_editor/document/position.dart';
|
|
import 'package:flowy_editor/document/selection.dart';
|
|
import 'package:flowy_editor/document/selection.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/render/rich_text/rich_text_style.dart';
|
|
import 'package:flowy_editor/service/keyboard_service.dart';
|
|
import 'package:flowy_editor/service/keyboard_service.dart';
|
|
|
|
|
|
|
|
+const _bulletedListSymbols = ['*', '-'];
|
|
|
|
+const _checkboxListSymbols = ['[x]', '-[x]'];
|
|
|
|
+const _unCheckboxListSymbols = ['[]', '-[]'];
|
|
|
|
+
|
|
FlowyKeyEventHandler whiteSpaceHandler = (editorState, event) {
|
|
FlowyKeyEventHandler whiteSpaceHandler = (editorState, event) {
|
|
if (event.logicalKey != LogicalKeyboardKey.space) {
|
|
if (event.logicalKey != LogicalKeyboardKey.space) {
|
|
return KeyEventResult.ignored;
|
|
return KeyEventResult.ignored;
|
|
@@ -28,24 +33,99 @@ FlowyKeyEventHandler whiteSpaceHandler = (editorState, event) {
|
|
return KeyEventResult.ignored;
|
|
return KeyEventResult.ignored;
|
|
}
|
|
}
|
|
|
|
|
|
- final builder = TransactionBuilder(editorState);
|
|
|
|
final textNode = textNodes.first;
|
|
final textNode = textNodes.first;
|
|
final text = textNode.toRawString();
|
|
final text = textNode.toRawString();
|
|
- if (text == '*' || text == '-') {
|
|
|
|
- builder
|
|
|
|
- ..deleteText(textNode, 0, 1)
|
|
|
|
- ..updateNode(textNode, {
|
|
|
|
- StyleKey.subtype: StyleKey.bulletedList,
|
|
|
|
- })
|
|
|
|
- ..afterSelection = Selection.collapsed(
|
|
|
|
- Position(
|
|
|
|
- path: textNode.path,
|
|
|
|
- offset: 0,
|
|
|
|
- ),
|
|
|
|
- )
|
|
|
|
- ..commit();
|
|
|
|
- return KeyEventResult.handled;
|
|
|
|
|
|
+ if ((_checkboxListSymbols + _unCheckboxListSymbols).any(text.startsWith)) {
|
|
|
|
+ return _toCheckboxList(editorState, textNode);
|
|
|
|
+ } else if (_bulletedListSymbols.any(text.startsWith)) {
|
|
|
|
+ return _toBulletedList(editorState, textNode);
|
|
|
|
+ } else if (_countOfSign(text) != 0) {
|
|
|
|
+ return _toHeadingStyle(editorState, textNode);
|
|
}
|
|
}
|
|
|
|
|
|
return KeyEventResult.ignored;
|
|
return KeyEventResult.ignored;
|
|
};
|
|
};
|
|
|
|
+
|
|
|
|
+KeyEventResult _toBulletedList(EditorState editorState, TextNode textNode) {
|
|
|
|
+ if (textNode.subtype == StyleKey.bulletedList) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+ TransactionBuilder(editorState)
|
|
|
|
+ ..deleteText(textNode, 0, 1)
|
|
|
|
+ ..updateNode(textNode, {
|
|
|
|
+ StyleKey.subtype: StyleKey.bulletedList,
|
|
|
|
+ })
|
|
|
|
+ ..afterSelection = Selection.collapsed(
|
|
|
|
+ Position(
|
|
|
|
+ path: textNode.path,
|
|
|
|
+ offset: 0,
|
|
|
|
+ ),
|
|
|
|
+ )
|
|
|
|
+ ..commit();
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+KeyEventResult _toCheckboxList(EditorState editorState, TextNode textNode) {
|
|
|
|
+ if (textNode.subtype == StyleKey.checkbox) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+ final String symbol;
|
|
|
|
+ bool check = false;
|
|
|
|
+ final symbols = List<String>.from(_checkboxListSymbols)
|
|
|
|
+ ..retainWhere(textNode.toRawString().startsWith);
|
|
|
|
+ if (symbols.isNotEmpty) {
|
|
|
|
+ symbol = symbols.first;
|
|
|
|
+ check = true;
|
|
|
|
+ } else {
|
|
|
|
+ symbol = (List<String>.from(_unCheckboxListSymbols)
|
|
|
|
+ ..retainWhere(textNode.toRawString().startsWith))
|
|
|
|
+ .first;
|
|
|
|
+ check = false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ TransactionBuilder(editorState)
|
|
|
|
+ ..deleteText(textNode, 0, symbol.length)
|
|
|
|
+ ..updateNode(textNode, {
|
|
|
|
+ StyleKey.subtype: StyleKey.checkbox,
|
|
|
|
+ StyleKey.checkbox: check,
|
|
|
|
+ })
|
|
|
|
+ ..afterSelection = Selection.collapsed(
|
|
|
|
+ Position(
|
|
|
|
+ path: textNode.path,
|
|
|
|
+ offset: 0,
|
|
|
|
+ ),
|
|
|
|
+ )
|
|
|
|
+ ..commit();
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+KeyEventResult _toHeadingStyle(EditorState editorState, TextNode textNode) {
|
|
|
|
+ final x = _countOfSign(textNode.toRawString());
|
|
|
|
+ final hX = 'h$x';
|
|
|
|
+ if (textNode.attributes.heading == hX) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+ TransactionBuilder(editorState)
|
|
|
|
+ ..deleteText(textNode, 0, x)
|
|
|
|
+ ..updateNode(textNode, {
|
|
|
|
+ StyleKey.subtype: StyleKey.heading,
|
|
|
|
+ StyleKey.heading: hX,
|
|
|
|
+ })
|
|
|
|
+ ..afterSelection = Selection.collapsed(
|
|
|
|
+ Position(
|
|
|
|
+ path: textNode.path,
|
|
|
|
+ offset: 0,
|
|
|
|
+ ),
|
|
|
|
+ )
|
|
|
|
+ ..commit();
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int _countOfSign(String text) {
|
|
|
|
+ for (var i = 6; i >= 0; i--) {
|
|
|
|
+ if (text.startsWith('#' * i)) {
|
|
|
|
+ return i;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|