From 4794203e7448d8ca852af492da45c7b74e5e5372 Mon Sep 17 00:00:00 2001 From: Vincent Chan Date: Thu, 11 Aug 2022 16:09:45 +0800 Subject: [PATCH 1/3] feat: handle delete keys --- .../delete_text_handler.dart | 105 ++++++++++++++---- 1 file changed, 83 insertions(+), 22 deletions(-) diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/delete_text_handler.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/delete_text_handler.dart index 5e2fdfd453..5e96e75a99 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/delete_text_handler.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/delete_text_handler.dart @@ -2,14 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.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; if (selection == null) { return KeyEventResult.ignored; @@ -22,7 +16,7 @@ FlowyKeyEventHandler deleteTextHandler = (editorState, event) { return KeyEventResult.ignored; } - TransactionBuilder transactionBuilder = TransactionBuilder(editorState); + final transactionBuilder = TransactionBuilder(editorState); if (textNodes.length == 1) { final textNode = textNodes.first; final index = textNode.delta.prevRunePosition(selection.start.offset); @@ -74,23 +68,90 @@ FlowyKeyEventHandler deleteTextHandler = (editorState, event) { } } } else { - 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, - ); + _deleteNodes(transactionBuilder, textNodes, selection); } transactionBuilder.commit(); 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().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 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; }; From c42f9001c4007bb865f9a1b3d0a86df504df3c1a Mon Sep 17 00:00:00 2001 From: Vincent Chan Date: Thu, 11 Aug 2022 16:40:07 +0800 Subject: [PATCH 2/3] feat: select all --- .../copy_paste_handler.dart | 1 - .../default_key_event_handlers.dart | 2 ++ .../select_all_handler.dart | 26 +++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/select_all_handler.dart diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart index 0b87fc0fd4..a5f392a4eb 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart @@ -1,5 +1,4 @@ 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/document/node_iterator.dart'; import 'package:flutter/material.dart'; diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/default_key_event_handlers.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/default_key_event_handlers.dart index d03211461c..f99caab04a 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/default_key_event_handlers.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/default_key_event_handlers.dart @@ -7,6 +7,7 @@ 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/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/select_all_handler.dart'; import 'package:flowy_editor/src/service/keyboard_service.dart'; List defaultKeyEventHandlers = [ @@ -19,4 +20,5 @@ List defaultKeyEventHandlers = [ enterWithoutShiftInTextNodesHandler, updateTextStyleByCommandXHandler, whiteSpaceHandler, + selectAllHandler, ]; diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/select_all_handler.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/select_all_handler.dart new file mode 100644 index 0000000000..f99569218c --- /dev/null +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/select_all_handler.dart @@ -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; +}; From 716d1f93e754a9c5a2e86b46e461e3675999a5aa Mon Sep 17 00:00:00 2001 From: Vincent Chan Date: Thu, 11 Aug 2022 17:21:02 +0800 Subject: [PATCH 3/3] feat: page up down handler --- .../default_key_event_handlers.dart | 2 ++ .../page_up_down_handler.dart | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/page_up_down_handler.dart diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/default_key_event_handlers.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/default_key_event_handlers.dart index f99caab04a..e617804a77 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/default_key_event_handlers.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/default_key_event_handlers.dart @@ -8,6 +8,7 @@ import 'package:flowy_editor/src/service/internal_key_event_handlers/slash_handl 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/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'; List defaultKeyEventHandlers = [ @@ -21,4 +22,5 @@ List defaultKeyEventHandlers = [ updateTextStyleByCommandXHandler, whiteSpaceHandler, selectAllHandler, + pageUpDownHandler, ]; diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/page_up_down_handler.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/page_up_down_handler.dart new file mode 100644 index 0000000000..5acdcdcb0d --- /dev/null +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/page_up_down_handler.dart @@ -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; +};