mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge pull request #824 from AppFlowy-IO/feat/handle-edit-keys
Feat: handle edit keys
This commit is contained in:
commit
c53df59b48
@ -1,5 +1,4 @@
|
|||||||
import 'package:flowy_editor/flowy_editor.dart';
|
import 'package:flowy_editor/flowy_editor.dart';
|
||||||
import 'package:flowy_editor/src/service/keyboard_service.dart';
|
|
||||||
import 'package:flowy_editor/src/infra/html_converter.dart';
|
import 'package:flowy_editor/src/infra/html_converter.dart';
|
||||||
import 'package:flowy_editor/src/document/node_iterator.dart';
|
import 'package:flowy_editor/src/document/node_iterator.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -7,6 +7,8 @@ import 'package:flowy_editor/src/service/internal_key_event_handlers/redo_undo_h
|
|||||||
import 'package:flowy_editor/src/service/internal_key_event_handlers/slash_handler.dart';
|
import 'package:flowy_editor/src/service/internal_key_event_handlers/slash_handler.dart';
|
||||||
import 'package:flowy_editor/src/service/internal_key_event_handlers/update_text_style_by_command_x_handler.dart';
|
import 'package:flowy_editor/src/service/internal_key_event_handlers/update_text_style_by_command_x_handler.dart';
|
||||||
import 'package:flowy_editor/src/service/internal_key_event_handlers/whitespace_handler.dart';
|
import 'package:flowy_editor/src/service/internal_key_event_handlers/whitespace_handler.dart';
|
||||||
|
import 'package:flowy_editor/src/service/internal_key_event_handlers/select_all_handler.dart';
|
||||||
|
import 'package:flowy_editor/src/service/internal_key_event_handlers/page_up_down_handler.dart';
|
||||||
import 'package:flowy_editor/src/service/keyboard_service.dart';
|
import 'package:flowy_editor/src/service/keyboard_service.dart';
|
||||||
|
|
||||||
List<FlowyKeyEventHandler> defaultKeyEventHandlers = [
|
List<FlowyKeyEventHandler> defaultKeyEventHandlers = [
|
||||||
@ -19,4 +21,6 @@ List<FlowyKeyEventHandler> defaultKeyEventHandlers = [
|
|||||||
enterWithoutShiftInTextNodesHandler,
|
enterWithoutShiftInTextNodesHandler,
|
||||||
updateTextStyleByCommandXHandler,
|
updateTextStyleByCommandXHandler,
|
||||||
whiteSpaceHandler,
|
whiteSpaceHandler,
|
||||||
|
selectAllHandler,
|
||||||
|
pageUpDownHandler,
|
||||||
];
|
];
|
||||||
|
@ -2,14 +2,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
import 'package:flowy_editor/flowy_editor.dart';
|
import 'package:flowy_editor/flowy_editor.dart';
|
||||||
import 'package:flowy_editor/src/service/keyboard_service.dart';
|
|
||||||
|
|
||||||
// Handle delete text.
|
|
||||||
FlowyKeyEventHandler deleteTextHandler = (editorState, event) {
|
|
||||||
if (event.logicalKey != LogicalKeyboardKey.backspace) {
|
|
||||||
return KeyEventResult.ignored;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
KeyEventResult _handleBackspace(EditorState editorState, RawKeyEvent event) {
|
||||||
final selection = editorState.service.selectionService.currentSelection.value;
|
final selection = editorState.service.selectionService.currentSelection.value;
|
||||||
if (selection == null) {
|
if (selection == null) {
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
@ -22,7 +16,7 @@ FlowyKeyEventHandler deleteTextHandler = (editorState, event) {
|
|||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionBuilder transactionBuilder = TransactionBuilder(editorState);
|
final transactionBuilder = TransactionBuilder(editorState);
|
||||||
if (textNodes.length == 1) {
|
if (textNodes.length == 1) {
|
||||||
final textNode = textNodes.first;
|
final textNode = textNodes.first;
|
||||||
final index = textNode.delta.prevRunePosition(selection.start.offset);
|
final index = textNode.delta.prevRunePosition(selection.start.offset);
|
||||||
@ -74,23 +68,90 @@ FlowyKeyEventHandler deleteTextHandler = (editorState, event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final first = textNodes.first;
|
_deleteNodes(transactionBuilder, textNodes, selection);
|
||||||
final last = textNodes.last;
|
|
||||||
var content = textNodes.last.toRawString();
|
|
||||||
content = content.substring(selection.end.offset, content.length);
|
|
||||||
// Merge the fist and the last text node content,
|
|
||||||
// and delete the all nodes expect for the first.
|
|
||||||
transactionBuilder
|
|
||||||
..deleteNodes(textNodes.sublist(1))
|
|
||||||
..mergeText(
|
|
||||||
first,
|
|
||||||
last,
|
|
||||||
firstOffset: selection.start.offset,
|
|
||||||
secondOffset: selection.end.offset,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
transactionBuilder.commit();
|
transactionBuilder.commit();
|
||||||
|
|
||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyEventResult _handleDelete(EditorState editorState, RawKeyEvent event) {
|
||||||
|
final selection = editorState.service.selectionService.currentSelection.value;
|
||||||
|
if (selection == null) {
|
||||||
|
return KeyEventResult.ignored;
|
||||||
|
}
|
||||||
|
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
||||||
|
// make sure all nodes is [TextNode].
|
||||||
|
final textNodes = nodes.whereType<TextNode>().toList();
|
||||||
|
if (textNodes.length != nodes.length) {
|
||||||
|
return KeyEventResult.ignored;
|
||||||
|
}
|
||||||
|
|
||||||
|
final transactionBuilder = TransactionBuilder(editorState);
|
||||||
|
if (textNodes.length == 1) {
|
||||||
|
final textNode = textNodes.first;
|
||||||
|
if (selection.start.offset >= textNode.delta.length) {
|
||||||
|
debugPrint("merge next line");
|
||||||
|
final nextNode = textNode.next;
|
||||||
|
if (nextNode == null) {
|
||||||
|
return KeyEventResult.ignored;
|
||||||
|
}
|
||||||
|
if (nextNode is TextNode) {
|
||||||
|
transactionBuilder.mergeText(textNode, nextNode);
|
||||||
|
}
|
||||||
|
transactionBuilder.deleteNode(nextNode);
|
||||||
|
} else {
|
||||||
|
final index = textNode.delta.nextRunePosition(selection.start.offset);
|
||||||
|
if (selection.isCollapsed) {
|
||||||
|
transactionBuilder.deleteText(
|
||||||
|
textNode,
|
||||||
|
selection.start.offset,
|
||||||
|
index - selection.start.offset,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
transactionBuilder.deleteText(
|
||||||
|
textNode,
|
||||||
|
selection.start.offset,
|
||||||
|
selection.end.offset - selection.start.offset,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_deleteNodes(transactionBuilder, textNodes, selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionBuilder.commit();
|
||||||
|
|
||||||
|
return KeyEventResult.handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _deleteNodes(TransactionBuilder transactionBuilder,
|
||||||
|
List<TextNode> textNodes, Selection selection) {
|
||||||
|
final first = textNodes.first;
|
||||||
|
final last = textNodes.last;
|
||||||
|
var content = textNodes.last.toRawString();
|
||||||
|
content = content.substring(selection.end.offset, content.length);
|
||||||
|
// Merge the fist and the last text node content,
|
||||||
|
// and delete the all nodes expect for the first.
|
||||||
|
transactionBuilder
|
||||||
|
..deleteNodes(textNodes.sublist(1))
|
||||||
|
..mergeText(
|
||||||
|
first,
|
||||||
|
last,
|
||||||
|
firstOffset: selection.start.offset,
|
||||||
|
secondOffset: selection.end.offset,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle delete text.
|
||||||
|
FlowyKeyEventHandler deleteTextHandler = (editorState, event) {
|
||||||
|
if (event.logicalKey == LogicalKeyboardKey.backspace) {
|
||||||
|
return _handleBackspace(editorState, event);
|
||||||
|
}
|
||||||
|
if (event.logicalKey == LogicalKeyboardKey.delete) {
|
||||||
|
return _handleDelete(editorState, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return KeyEventResult.ignored;
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
import 'package:flowy_editor/flowy_editor.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
double? getEditorHeight(EditorState editorState) {
|
||||||
|
final renderObj =
|
||||||
|
editorState.service.scrollServiceKey.currentContext?.findRenderObject();
|
||||||
|
if (renderObj is RenderBox) {
|
||||||
|
return renderObj.size.height;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
FlowyKeyEventHandler pageUpDownHandler = (editorState, event) {
|
||||||
|
if (event.logicalKey == LogicalKeyboardKey.pageUp) {
|
||||||
|
final scrollHeight = getEditorHeight(editorState);
|
||||||
|
final scrollService = editorState.service.scrollService;
|
||||||
|
if (scrollHeight != null && scrollService != null) {
|
||||||
|
scrollService.scrollTo(scrollService.dy - scrollHeight);
|
||||||
|
}
|
||||||
|
return KeyEventResult.handled;
|
||||||
|
} else if (event.logicalKey == LogicalKeyboardKey.pageDown) {
|
||||||
|
final scrollHeight = getEditorHeight(editorState);
|
||||||
|
final scrollService = editorState.service.scrollService;
|
||||||
|
if (scrollHeight != null && scrollService != null) {
|
||||||
|
scrollService.scrollTo(scrollService.dy + scrollHeight);
|
||||||
|
}
|
||||||
|
return KeyEventResult.handled;
|
||||||
|
}
|
||||||
|
return KeyEventResult.ignored;
|
||||||
|
};
|
@ -0,0 +1,26 @@
|
|||||||
|
import 'package:flowy_editor/flowy_editor.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
KeyEventResult _selectAll(EditorState editorState) {
|
||||||
|
if (editorState.document.root.children.isEmpty) {
|
||||||
|
return KeyEventResult.handled;
|
||||||
|
}
|
||||||
|
final firstNode = editorState.document.root.children.first;
|
||||||
|
final lastNode = editorState.document.root.children.last;
|
||||||
|
var offset = 0;
|
||||||
|
if (lastNode is TextNode) {
|
||||||
|
offset = lastNode.delta.length;
|
||||||
|
}
|
||||||
|
editorState.updateCursorSelection(Selection(
|
||||||
|
start: Position(path: firstNode.path, offset: 0),
|
||||||
|
end: Position(path: lastNode.path, offset: offset)));
|
||||||
|
return KeyEventResult.handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
FlowyKeyEventHandler selectAllHandler = (editorState, event) {
|
||||||
|
if (event.isMetaPressed && event.logicalKey == LogicalKeyboardKey.keyA) {
|
||||||
|
return _selectAll(editorState);
|
||||||
|
}
|
||||||
|
return KeyEventResult.ignored;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user