mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: recognize number
This commit is contained in:
@ -1,14 +1,9 @@
|
|||||||
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
import 'package:appflowy_editor/src/document/attributes.dart';
|
|
||||||
import 'package:appflowy_editor/src/document/node.dart';
|
|
||||||
import 'package:appflowy_editor/src/document/position.dart';
|
|
||||||
import 'package:appflowy_editor/src/document/selection.dart';
|
|
||||||
import 'package:appflowy_editor/src/extensions/path_extensions.dart';
|
import 'package:appflowy_editor/src/extensions/path_extensions.dart';
|
||||||
import 'package:appflowy_editor/src/operation/transaction_builder.dart';
|
|
||||||
import 'package:appflowy_editor/src/render/rich_text/rich_text_style.dart';
|
import 'package:appflowy_editor/src/render/rich_text/rich_text_style.dart';
|
||||||
import 'package:appflowy_editor/src/service/shortcut_event/shortcut_event_handler.dart';
|
|
||||||
|
|
||||||
/// Handle some cases where enter is pressed and shift is not pressed.
|
/// Handle some cases where enter is pressed and shift is not pressed.
|
||||||
///
|
///
|
||||||
@ -104,19 +99,12 @@ ShortcutEventHandler enterWithoutShiftInTextNodesHandler =
|
|||||||
|
|
||||||
// Otherwise,
|
// Otherwise,
|
||||||
// split the node into two nodes with style
|
// split the node into two nodes with style
|
||||||
final needCopyAttributes = StyleKey.globalStyleKeys
|
Attributes attributes = _attributesFromPreviousLine(textNode);
|
||||||
.where((key) => key != StyleKey.heading)
|
|
||||||
.contains(textNode.subtype);
|
|
||||||
Attributes attributes = {};
|
|
||||||
if (needCopyAttributes) {
|
|
||||||
attributes = Attributes.from(textNode.attributes);
|
|
||||||
if (attributes.check) {
|
|
||||||
attributes[StyleKey.checkbox] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final afterSelection = Selection.collapsed(
|
final afterSelection = Selection.collapsed(
|
||||||
Position(path: textNode.path.next, offset: 0),
|
Position(path: textNode.path.next, offset: 0),
|
||||||
);
|
);
|
||||||
|
|
||||||
TransactionBuilder(editorState)
|
TransactionBuilder(editorState)
|
||||||
..insertNode(
|
..insertNode(
|
||||||
textNode.path.next,
|
textNode.path.next,
|
||||||
@ -132,5 +120,44 @@ ShortcutEventHandler enterWithoutShiftInTextNodesHandler =
|
|||||||
)
|
)
|
||||||
..afterSelection = afterSelection
|
..afterSelection = afterSelection
|
||||||
..commit();
|
..commit();
|
||||||
|
|
||||||
|
// If the new type of a text node is number list,
|
||||||
|
// the numbers of the following nodes should be incremental.
|
||||||
|
if (textNode.subtype == StyleKey.numberList) {
|
||||||
|
_makeFollowingNodeIncremental(editorState, textNode);
|
||||||
|
}
|
||||||
|
|
||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Attributes _attributesFromPreviousLine(TextNode textNode) {
|
||||||
|
final prevAttributes = textNode.attributes;
|
||||||
|
final subType = textNode.subtype;
|
||||||
|
if (subType == null || subType == StyleKey.heading) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
final copy = Attributes.from(prevAttributes);
|
||||||
|
if (subType == StyleKey.numberList) {
|
||||||
|
return _nextNumberAttributesFromPreviousLine(copy, textNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subType == StyleKey.checkbox) {
|
||||||
|
copy[StyleKey.checkbox] = false;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
Attributes _nextNumberAttributesFromPreviousLine(
|
||||||
|
Attributes copy, TextNode textNode) {
|
||||||
|
final prevNum = textNode.attributes[StyleKey.number] as int?;
|
||||||
|
copy[StyleKey.number] = prevNum == null ? 1 : prevNum + 1;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _makeFollowingNodeIncremental(EditorState editorState, TextNode textNode) {
|
||||||
|
debugPrint("following nodes");
|
||||||
|
TransactionBuilder(editorState).commit();
|
||||||
|
}
|
||||||
|
@ -20,6 +20,8 @@ const _bulletedListSymbols = ['*', '-'];
|
|||||||
const _checkboxListSymbols = ['[x]', '-[x]'];
|
const _checkboxListSymbols = ['[x]', '-[x]'];
|
||||||
const _unCheckboxListSymbols = ['[]', '-[]'];
|
const _unCheckboxListSymbols = ['[]', '-[]'];
|
||||||
|
|
||||||
|
final _numberRegex = RegExp(r'^(\d+)\.');
|
||||||
|
|
||||||
ShortcutEventHandler whiteSpaceHandler = (editorState, event) {
|
ShortcutEventHandler whiteSpaceHandler = (editorState, event) {
|
||||||
if (event.logicalKey != LogicalKeyboardKey.space) {
|
if (event.logicalKey != LogicalKeyboardKey.space) {
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
@ -42,6 +44,16 @@ ShortcutEventHandler whiteSpaceHandler = (editorState, event) {
|
|||||||
|
|
||||||
final textNode = textNodes.first;
|
final textNode = textNodes.first;
|
||||||
final text = textNode.toRawString();
|
final text = textNode.toRawString();
|
||||||
|
|
||||||
|
final numberMatch = _numberRegex.firstMatch(text);
|
||||||
|
if (numberMatch != null) {
|
||||||
|
final matchText = numberMatch.group(0);
|
||||||
|
final numText = numberMatch.group(1);
|
||||||
|
if (matchText != null && numText != null) {
|
||||||
|
return _toNumberList(editorState, textNode, matchText, numText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((_checkboxListSymbols + _unCheckboxListSymbols).any(text.startsWith)) {
|
if ((_checkboxListSymbols + _unCheckboxListSymbols).any(text.startsWith)) {
|
||||||
return _toCheckboxList(editorState, textNode);
|
return _toCheckboxList(editorState, textNode);
|
||||||
} else if (_bulletedListSymbols.any(text.startsWith)) {
|
} else if (_bulletedListSymbols.any(text.startsWith)) {
|
||||||
@ -53,6 +65,31 @@ ShortcutEventHandler whiteSpaceHandler = (editorState, event) {
|
|||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
KeyEventResult _toNumberList(EditorState editorState, TextNode textNode,
|
||||||
|
String matchText, String numText) {
|
||||||
|
if (textNode.subtype == StyleKey.bulletedList) {
|
||||||
|
return KeyEventResult.ignored;
|
||||||
|
}
|
||||||
|
|
||||||
|
final numValue = int.tryParse(numText);
|
||||||
|
if (numValue == null) {
|
||||||
|
return KeyEventResult.ignored;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionBuilder(editorState)
|
||||||
|
..deleteText(textNode, 0, matchText.length)
|
||||||
|
..updateNode(textNode,
|
||||||
|
{StyleKey.subtype: StyleKey.numberList, StyleKey.number: numValue})
|
||||||
|
..afterSelection = Selection.collapsed(
|
||||||
|
Position(
|
||||||
|
path: textNode.path,
|
||||||
|
offset: 0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
..commit();
|
||||||
|
return KeyEventResult.handled;
|
||||||
|
}
|
||||||
|
|
||||||
KeyEventResult _toBulletedList(EditorState editorState, TextNode textNode) {
|
KeyEventResult _toBulletedList(EditorState editorState, TextNode textNode) {
|
||||||
if (textNode.subtype == StyleKey.bulletedList) {
|
if (textNode.subtype == StyleKey.bulletedList) {
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
|
Reference in New Issue
Block a user