|
@@ -1,4 +1,5 @@
|
|
|
import 'dart:async';
|
|
|
+import 'package:appflowy_editor/src/core/document/node.dart';
|
|
|
import 'package:appflowy_editor/src/infra/log.dart';
|
|
|
import 'package:appflowy_editor/src/render/selection_menu/selection_menu_widget.dart';
|
|
|
import 'package:appflowy_editor/src/render/style/editor_style.dart';
|
|
@@ -119,8 +120,11 @@ class EditorState {
|
|
|
///
|
|
|
/// The options can be used to determine whether the editor
|
|
|
/// should record the transaction in undo/redo stack.
|
|
|
- apply(Transaction transaction,
|
|
|
- [ApplyOptions options = const ApplyOptions(recordUndo: true)]) {
|
|
|
+ void apply(
|
|
|
+ Transaction transaction, {
|
|
|
+ ApplyOptions options = const ApplyOptions(recordUndo: true),
|
|
|
+ ruleCount = 0,
|
|
|
+ }) {
|
|
|
if (!editable) {
|
|
|
return;
|
|
|
}
|
|
@@ -132,6 +136,7 @@ class EditorState {
|
|
|
_observer.add(transaction);
|
|
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
|
+ _applyRules(ruleCount);
|
|
|
updateCursorSelection(transaction.afterSelection);
|
|
|
});
|
|
|
|
|
@@ -153,7 +158,7 @@ class EditorState {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- _debouncedSealHistoryItem() {
|
|
|
+ void _debouncedSealHistoryItem() {
|
|
|
if (disableSealTimer) {
|
|
|
return;
|
|
|
}
|
|
@@ -168,7 +173,7 @@ class EditorState {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- _applyOperation(Operation op) {
|
|
|
+ void _applyOperation(Operation op) {
|
|
|
if (op is InsertOperation) {
|
|
|
document.insert(op.path, op.nodes);
|
|
|
} else if (op is UpdateOperation) {
|
|
@@ -179,4 +184,27 @@ class EditorState {
|
|
|
document.updateText(op.path, op.delta);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ void _applyRules(int ruleCount) {
|
|
|
+ // Set a maximum count to prevent a dead loop.
|
|
|
+ if (ruleCount >= 5) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ final tr = transaction;
|
|
|
+
|
|
|
+ // Rules
|
|
|
+ _insureLastNodeEditable(tr);
|
|
|
+
|
|
|
+ if (tr.operations.isNotEmpty) {
|
|
|
+ apply(tr, ruleCount: ruleCount + 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void _insureLastNodeEditable(Transaction tr) {
|
|
|
+ if (document.root.children.isEmpty ||
|
|
|
+ document.root.children.last.id != 'text') {
|
|
|
+ tr.insertNode([document.root.children.length], TextNode.empty());
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|