|
@@ -1,114 +1,130 @@
|
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
|
import 'package:appflowy_editor/src/extensions/node_extensions.dart';
|
|
import 'package:appflowy_editor/src/extensions/node_extensions.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/material.dart';
|
|
-import 'package:flutter/services.dart';
|
|
|
|
|
|
|
|
-ShortcutEventHandler arrowKeysHandler = (editorState, event) {
|
|
|
|
- if (!_arrowKeys.contains(event.logicalKey)) {
|
|
|
|
|
|
+ShortcutEventHandler cursorLeftSelect = (editorState, event) {
|
|
|
|
+ final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
|
|
+ final selection = editorState.service.selectionService.currentSelection.value;
|
|
|
|
+ if (nodes.isEmpty || selection == null) {
|
|
return KeyEventResult.ignored;
|
|
return KeyEventResult.ignored;
|
|
}
|
|
}
|
|
-
|
|
|
|
- if (event.isMetaPressed && event.isShiftPressed) {
|
|
|
|
- return _arrowKeysWithMetaAndShift(editorState, event);
|
|
|
|
- } else if (event.isMetaPressed) {
|
|
|
|
- return _arrowKeysWithMeta(editorState, event);
|
|
|
|
- } else if (event.isShiftPressed) {
|
|
|
|
- return _arrowKeysWithShift(editorState, event);
|
|
|
|
- } else {
|
|
|
|
- return _arrowKeysOnly(editorState, event);
|
|
|
|
|
|
+ final end = selection.end.goLeft(editorState);
|
|
|
|
+ if (end == null) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
}
|
|
}
|
|
|
|
+ editorState.service.selectionService.updateSelection(
|
|
|
|
+ selection.copyWith(end: end),
|
|
|
|
+ );
|
|
|
|
+ return KeyEventResult.handled;
|
|
};
|
|
};
|
|
|
|
|
|
-final _arrowKeys = [
|
|
|
|
- LogicalKeyboardKey.arrowLeft,
|
|
|
|
- LogicalKeyboardKey.arrowRight,
|
|
|
|
- LogicalKeyboardKey.arrowUp,
|
|
|
|
- LogicalKeyboardKey.arrowDown
|
|
|
|
-];
|
|
|
|
|
|
+ShortcutEventHandler cursorRightSelect = (editorState, event) {
|
|
|
|
+ final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
|
|
+ final selection = editorState.service.selectionService.currentSelection.value;
|
|
|
|
+ if (nodes.isEmpty || selection == null) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+ final end = selection.end.goRight(editorState);
|
|
|
|
+ if (end == null) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+ editorState.service.selectionService.updateSelection(
|
|
|
|
+ selection.copyWith(end: end),
|
|
|
|
+ );
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+};
|
|
|
|
|
|
-KeyEventResult _arrowKeysWithMetaAndShift(
|
|
|
|
- EditorState editorState, RawKeyEvent event) {
|
|
|
|
- if (!event.isMetaPressed ||
|
|
|
|
- !event.isShiftPressed ||
|
|
|
|
- !_arrowKeys.contains(event.logicalKey)) {
|
|
|
|
- assert(false);
|
|
|
|
|
|
+ShortcutEventHandler cursorUpSelect = (editorState, event) {
|
|
|
|
+ final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
|
|
+ final selection = editorState.service.selectionService.currentSelection.value;
|
|
|
|
+ if (nodes.isEmpty || selection == null) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+ final end = _goUp(editorState);
|
|
|
|
+ if (end == null) {
|
|
return KeyEventResult.ignored;
|
|
return KeyEventResult.ignored;
|
|
}
|
|
}
|
|
|
|
+ editorState.service.selectionService.updateSelection(
|
|
|
|
+ selection.copyWith(end: end),
|
|
|
|
+ );
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+};
|
|
|
|
|
|
|
|
+ShortcutEventHandler cursorDownSelect = (editorState, event) {
|
|
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
final selection = editorState.service.selectionService.currentSelection.value;
|
|
final selection = editorState.service.selectionService.currentSelection.value;
|
|
if (nodes.isEmpty || selection == null) {
|
|
if (nodes.isEmpty || selection == null) {
|
|
return KeyEventResult.ignored;
|
|
return KeyEventResult.ignored;
|
|
}
|
|
}
|
|
|
|
+ final end = _goDown(editorState);
|
|
|
|
+ if (end == null) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+ editorState.service.selectionService.updateSelection(
|
|
|
|
+ selection.copyWith(end: end),
|
|
|
|
+ );
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+};
|
|
|
|
|
|
- var start = selection.start;
|
|
|
|
- var end = selection.end;
|
|
|
|
- if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
|
|
|
|
- final position = nodes.first.selectable?.start();
|
|
|
|
- if (position != null) {
|
|
|
|
- end = position;
|
|
|
|
- }
|
|
|
|
- } else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
|
|
|
|
- final position = nodes.first.selectable?.end();
|
|
|
|
- if (position != null) {
|
|
|
|
- end = position;
|
|
|
|
- }
|
|
|
|
- } else if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
|
|
|
|
- final position = editorState.document.root.children
|
|
|
|
- .whereType<TextNode>()
|
|
|
|
- .first
|
|
|
|
- .selectable
|
|
|
|
- ?.start();
|
|
|
|
- if (position != null) {
|
|
|
|
- end = position;
|
|
|
|
- }
|
|
|
|
- } else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
|
|
|
|
- final position = editorState.document.root.children
|
|
|
|
- .whereType<TextNode>()
|
|
|
|
- .last
|
|
|
|
- .selectable
|
|
|
|
- ?.end();
|
|
|
|
- if (position != null) {
|
|
|
|
- end = position;
|
|
|
|
- }
|
|
|
|
|
|
+ShortcutEventHandler cursorTop = (editorState, event) {
|
|
|
|
+ final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
|
|
+ if (nodes.isEmpty) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+ final position = editorState.document.root.children
|
|
|
|
+ .whereType<TextNode>()
|
|
|
|
+ .first
|
|
|
|
+ .selectable
|
|
|
|
+ ?.start();
|
|
|
|
+ if (position == null) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
}
|
|
}
|
|
editorState.service.selectionService.updateSelection(
|
|
editorState.service.selectionService.updateSelection(
|
|
- selection.copyWith(start: start, end: end),
|
|
|
|
|
|
+ Selection.collapsed(position),
|
|
);
|
|
);
|
|
return KeyEventResult.handled;
|
|
return KeyEventResult.handled;
|
|
-}
|
|
|
|
|
|
+};
|
|
|
|
|
|
-// Move the cursor to top, bottom, left and right of the document.
|
|
|
|
-KeyEventResult _arrowKeysWithMeta(EditorState editorState, RawKeyEvent event) {
|
|
|
|
- if (!event.isMetaPressed ||
|
|
|
|
- event.isShiftPressed ||
|
|
|
|
- !_arrowKeys.contains(event.logicalKey)) {
|
|
|
|
- assert(false);
|
|
|
|
|
|
+ShortcutEventHandler cursorBottom = (editorState, event) {
|
|
|
|
+ final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
|
|
+ if (nodes.isEmpty) {
|
|
return KeyEventResult.ignored;
|
|
return KeyEventResult.ignored;
|
|
}
|
|
}
|
|
|
|
+ final position = editorState.document.root.children
|
|
|
|
+ .whereType<TextNode>()
|
|
|
|
+ .last
|
|
|
|
+ .selectable
|
|
|
|
+ ?.end();
|
|
|
|
+ if (position == null) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+ editorState.service.selectionService.updateSelection(
|
|
|
|
+ Selection.collapsed(position),
|
|
|
|
+ );
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+};
|
|
|
|
|
|
|
|
+ShortcutEventHandler cursorBegin = (editorState, event) {
|
|
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
if (nodes.isEmpty) {
|
|
if (nodes.isEmpty) {
|
|
return KeyEventResult.ignored;
|
|
return KeyEventResult.ignored;
|
|
}
|
|
}
|
|
- Position? position;
|
|
|
|
- if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
|
|
|
|
- position = nodes.first.selectable?.start();
|
|
|
|
- } else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
|
|
|
|
- position = nodes.last.selectable?.end();
|
|
|
|
- } else if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
|
|
|
|
- position = editorState.document.root.children
|
|
|
|
- .whereType<TextNode>()
|
|
|
|
- .first
|
|
|
|
- .selectable
|
|
|
|
- ?.start();
|
|
|
|
- } else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
|
|
|
|
- position = editorState.document.root.children
|
|
|
|
- .whereType<TextNode>()
|
|
|
|
- .last
|
|
|
|
- .selectable
|
|
|
|
- ?.end();
|
|
|
|
|
|
+ final position = nodes.first.selectable?.start();
|
|
|
|
+ if (position == null) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+ editorState.service.selectionService.updateSelection(
|
|
|
|
+ Selection.collapsed(position),
|
|
|
|
+ );
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+ShortcutEventHandler cursorEnd = (editorState, event) {
|
|
|
|
+ final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
|
|
+ if (nodes.isEmpty) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
}
|
|
}
|
|
|
|
+ final position = nodes.first.selectable?.end();
|
|
if (position == null) {
|
|
if (position == null) {
|
|
return KeyEventResult.ignored;
|
|
return KeyEventResult.ignored;
|
|
}
|
|
}
|
|
@@ -116,95 +132,161 @@ KeyEventResult _arrowKeysWithMeta(EditorState editorState, RawKeyEvent event) {
|
|
Selection.collapsed(position),
|
|
Selection.collapsed(position),
|
|
);
|
|
);
|
|
return KeyEventResult.handled;
|
|
return KeyEventResult.handled;
|
|
-}
|
|
|
|
|
|
+};
|
|
|
|
|
|
-KeyEventResult _arrowKeysWithShift(EditorState editorState, RawKeyEvent event) {
|
|
|
|
- if (event.isMetaPressed ||
|
|
|
|
- !event.isShiftPressed ||
|
|
|
|
- !_arrowKeys.contains(event.logicalKey)) {
|
|
|
|
- assert(false);
|
|
|
|
|
|
+ShortcutEventHandler cursorTopSelect = (editorState, event) {
|
|
|
|
+ final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
|
|
+ final selection = editorState.service.selectionService.currentSelection.value;
|
|
|
|
+ if (nodes.isEmpty || selection == null) {
|
|
return KeyEventResult.ignored;
|
|
return KeyEventResult.ignored;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ var start = selection.start;
|
|
|
|
+ var end = selection.end;
|
|
|
|
+ final position = editorState.document.root.children
|
|
|
|
+ .whereType<TextNode>()
|
|
|
|
+ .first
|
|
|
|
+ .selectable
|
|
|
|
+ ?.start();
|
|
|
|
+ if (position != null) {
|
|
|
|
+ end = position;
|
|
|
|
+ }
|
|
|
|
+ editorState.service.selectionService.updateSelection(
|
|
|
|
+ selection.copyWith(start: start, end: end),
|
|
|
|
+ );
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+ShortcutEventHandler cursorBottomSelect = (editorState, event) {
|
|
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
final selection = editorState.service.selectionService.currentSelection.value;
|
|
final selection = editorState.service.selectionService.currentSelection.value;
|
|
if (nodes.isEmpty || selection == null) {
|
|
if (nodes.isEmpty || selection == null) {
|
|
return KeyEventResult.ignored;
|
|
return KeyEventResult.ignored;
|
|
}
|
|
}
|
|
- Position? end;
|
|
|
|
- if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
|
|
|
|
- end = selection.end.goLeft(editorState);
|
|
|
|
- } else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
|
|
|
|
- end = selection.end.goRight(editorState);
|
|
|
|
- } else if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
|
|
|
|
- end = _goUp(editorState);
|
|
|
|
- } else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
|
|
|
|
- end = _goDown(editorState);
|
|
|
|
|
|
+ var start = selection.start;
|
|
|
|
+ var end = selection.end;
|
|
|
|
+ final position = editorState.document.root.children
|
|
|
|
+ .whereType<TextNode>()
|
|
|
|
+ .last
|
|
|
|
+ .selectable
|
|
|
|
+ ?.end();
|
|
|
|
+ if (position != null) {
|
|
|
|
+ end = position;
|
|
}
|
|
}
|
|
- if (end == null) {
|
|
|
|
|
|
+ editorState.service.selectionService.updateSelection(
|
|
|
|
+ selection.copyWith(start: start, end: end),
|
|
|
|
+ );
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+ShortcutEventHandler cursorBeginSelect = (editorState, event) {
|
|
|
|
+ final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
|
|
+ final selection = editorState.service.selectionService.currentSelection.value;
|
|
|
|
+ if (nodes.isEmpty || selection == null) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var start = selection.start;
|
|
|
|
+ var end = selection.end;
|
|
|
|
+ final position = nodes.last.selectable?.start();
|
|
|
|
+ if (position != null) {
|
|
|
|
+ end = position;
|
|
|
|
+ }
|
|
|
|
+ editorState.service.selectionService.updateSelection(
|
|
|
|
+ selection.copyWith(start: start, end: end),
|
|
|
|
+ );
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+ShortcutEventHandler cursorEndSelect = (editorState, event) {
|
|
|
|
+ final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
|
|
+ final selection = editorState.service.selectionService.currentSelection.value;
|
|
|
|
+ if (nodes.isEmpty || selection == null) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var start = selection.start;
|
|
|
|
+ var end = selection.end;
|
|
|
|
+ final position = nodes.last.selectable?.end();
|
|
|
|
+ if (position != null) {
|
|
|
|
+ end = position;
|
|
|
|
+ }
|
|
|
|
+ editorState.service.selectionService.updateSelection(
|
|
|
|
+ selection.copyWith(start: start, end: end),
|
|
|
|
+ );
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+KeyEventResult cursorUp(EditorState editorState, RawKeyEvent event) {
|
|
|
|
+ final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
|
|
+ final selection =
|
|
|
|
+ editorState.service.selectionService.currentSelection.value?.normalize;
|
|
|
|
+ if (nodes.isEmpty || selection == null) {
|
|
return KeyEventResult.ignored;
|
|
return KeyEventResult.ignored;
|
|
}
|
|
}
|
|
- editorState.service.selectionService
|
|
|
|
- .updateSelection(selection.copyWith(end: end));
|
|
|
|
|
|
+ final upPosition = _goUp(editorState);
|
|
|
|
+ editorState.updateCursorSelection(
|
|
|
|
+ upPosition == null ? null : Selection.collapsed(upPosition),
|
|
|
|
+ );
|
|
return KeyEventResult.handled;
|
|
return KeyEventResult.handled;
|
|
}
|
|
}
|
|
|
|
|
|
-KeyEventResult _arrowKeysOnly(EditorState editorState, RawKeyEvent event) {
|
|
|
|
- if (event.isMetaPressed ||
|
|
|
|
- event.isShiftPressed ||
|
|
|
|
- !_arrowKeys.contains(event.logicalKey)) {
|
|
|
|
- assert(false);
|
|
|
|
|
|
+KeyEventResult cursorDown(EditorState editorState, RawKeyEvent event) {
|
|
|
|
+ final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
|
|
+ final selection =
|
|
|
|
+ editorState.service.selectionService.currentSelection.value?.normalize;
|
|
|
|
+ if (nodes.isEmpty || selection == null) {
|
|
return KeyEventResult.ignored;
|
|
return KeyEventResult.ignored;
|
|
}
|
|
}
|
|
|
|
+ final downPosition = _goDown(editorState);
|
|
|
|
+ editorState.updateCursorSelection(
|
|
|
|
+ downPosition == null ? null : Selection.collapsed(downPosition),
|
|
|
|
+ );
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+}
|
|
|
|
|
|
|
|
+KeyEventResult cursorLeft(EditorState editorState, RawKeyEvent event) {
|
|
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
final selection =
|
|
final selection =
|
|
editorState.service.selectionService.currentSelection.value?.normalize;
|
|
editorState.service.selectionService.currentSelection.value?.normalize;
|
|
if (nodes.isEmpty || selection == null) {
|
|
if (nodes.isEmpty || selection == null) {
|
|
return KeyEventResult.ignored;
|
|
return KeyEventResult.ignored;
|
|
}
|
|
}
|
|
- if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
|
|
|
|
- if (selection.isCollapsed) {
|
|
|
|
- final leftPosition = selection.start.goLeft(editorState);
|
|
|
|
- if (leftPosition != null) {
|
|
|
|
- editorState.service.selectionService.updateSelection(
|
|
|
|
- Selection.collapsed(leftPosition),
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
|
|
+ if (selection.isCollapsed) {
|
|
|
|
+ final leftPosition = selection.start.goLeft(editorState);
|
|
|
|
+ if (leftPosition != null) {
|
|
editorState.service.selectionService.updateSelection(
|
|
editorState.service.selectionService.updateSelection(
|
|
- Selection.collapsed(selection.start),
|
|
|
|
|
|
+ Selection.collapsed(leftPosition),
|
|
);
|
|
);
|
|
}
|
|
}
|
|
- return KeyEventResult.handled;
|
|
|
|
- } else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
|
|
|
|
- if (selection.isCollapsed) {
|
|
|
|
- final rightPosition = selection.start.goRight(editorState);
|
|
|
|
- if (rightPosition != null) {
|
|
|
|
- editorState.service.selectionService.updateSelection(
|
|
|
|
- Selection.collapsed(rightPosition),
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
|
|
+ } else {
|
|
|
|
+ editorState.service.selectionService.updateSelection(
|
|
|
|
+ Selection.collapsed(selection.start),
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ return KeyEventResult.handled;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+KeyEventResult cursorRight(EditorState editorState, RawKeyEvent event) {
|
|
|
|
+ final nodes = editorState.service.selectionService.currentSelectedNodes;
|
|
|
|
+ final selection =
|
|
|
|
+ editorState.service.selectionService.currentSelection.value?.normalize;
|
|
|
|
+ if (nodes.isEmpty || selection == null) {
|
|
|
|
+ return KeyEventResult.ignored;
|
|
|
|
+ }
|
|
|
|
+ if (selection.isCollapsed) {
|
|
|
|
+ final rightPosition = selection.start.goRight(editorState);
|
|
|
|
+ if (rightPosition != null) {
|
|
editorState.service.selectionService.updateSelection(
|
|
editorState.service.selectionService.updateSelection(
|
|
- Selection.collapsed(selection.end),
|
|
|
|
|
|
+ Selection.collapsed(rightPosition),
|
|
);
|
|
);
|
|
}
|
|
}
|
|
- return KeyEventResult.handled;
|
|
|
|
- } else if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
|
|
|
|
- final upPosition = _goUp(editorState);
|
|
|
|
- editorState.updateCursorSelection(
|
|
|
|
- upPosition == null ? null : Selection.collapsed(upPosition),
|
|
|
|
- );
|
|
|
|
- return KeyEventResult.handled;
|
|
|
|
- } else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
|
|
|
|
- final downPosition = _goDown(editorState);
|
|
|
|
- editorState.updateCursorSelection(
|
|
|
|
- downPosition == null ? null : Selection.collapsed(downPosition),
|
|
|
|
|
|
+ } else {
|
|
|
|
+ editorState.service.selectionService.updateSelection(
|
|
|
|
+ Selection.collapsed(selection.end),
|
|
);
|
|
);
|
|
- return KeyEventResult.handled;
|
|
|
|
}
|
|
}
|
|
- return KeyEventResult.ignored;
|
|
|
|
|
|
+ return KeyEventResult.handled;
|
|
}
|
|
}
|
|
|
|
|
|
extension on Position {
|
|
extension on Position {
|