diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/markdown_syntax_to_styled_text.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/markdown_syntax_to_styled_text.dart index 6652bba874..94caff83b1 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/markdown_syntax_to_styled_text.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/markdown_syntax_to_styled_text.dart @@ -188,23 +188,6 @@ ShortcutEventHandler doubleTildeToStrikethrough = (editorState, event) { return KeyEventResult.handled; }; -ShortcutEventHandler greaterToBlockquote = (editorState, event) { - final selectionService = editorState.service.selectionService; - final selection = selectionService.currentSelection.value; - final textNodes = selectionService.currentSelectedNodes.whereType(); - if (selection == null || !selection.isSingle || textNodes.length != 1) { - return KeyEventResult.ignored; - } - - //only convert > at the start of a paragraph - if (selection.startIndex != 0) { - return KeyEventResult.ignored; - } - formatQuote(editorState); - - return KeyEventResult.handled; -}; - ShortcutEventHandler markdownLinkOrImageHandler = (editorState, event) { final selectionService = editorState.service.selectionService; final selection = selectionService.currentSelection.value; diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/whitespace_handler.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/whitespace_handler.dart index 8732c0f0ea..5821733564 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/whitespace_handler.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/whitespace_handler.dart @@ -20,6 +20,8 @@ const _bulletedListSymbols = ['*', '-']; const _checkboxListSymbols = ['[x]', '-[x]']; const _unCheckboxListSymbols = ['[]', '-[]']; +const _quoteSymbols = ['>']; + final _numberRegex = RegExp(r'^(\d+)\.'); ShortcutEventHandler whiteSpaceHandler = (editorState, event) { @@ -49,6 +51,8 @@ ShortcutEventHandler whiteSpaceHandler = (editorState, event) { return _toBulletedList(editorState, textNode); } else if (_countOfSign(text, selection) != 0) { return _toHeadingStyle(editorState, textNode, selection); + } else if (_quoteSymbols.contains(text)) { + return _toQuoteStyle(editorState, textNode); } else if (numberMatch != null) { final matchText = numberMatch.group(0); final numText = numberMatch.group(1); @@ -196,3 +200,22 @@ int _countOfSign(String text, Selection selection) { } return 0; } + +KeyEventResult _toQuoteStyle(EditorState editorState, TextNode textNode) { + if (textNode.subtype == BuiltInAttributeKey.quote) { + return KeyEventResult.ignored; + } + final transaction = editorState.transaction + ..deleteText(textNode, 0, 1) + ..updateNode(textNode, { + BuiltInAttributeKey.subtype: BuiltInAttributeKey.quote, + }) + ..afterSelection = Selection.collapsed( + Position( + path: textNode.path, + offset: 0, + ), + ); + editorState.apply(transaction); + return KeyEventResult.handled; +} diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/built_in_shortcut_events.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/built_in_shortcut_events.dart index f4093152f1..c960558b24 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/built_in_shortcut_events.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/built_in_shortcut_events.dart @@ -285,11 +285,6 @@ List builtInShortcutEvents = [ command: 'shift+tilde', handler: doubleTildeToStrikethrough, ), - ShortcutEvent( - key: 'Greater to blockquote', - command: 'shift+greater', - handler: greaterToBlockquote, - ), ShortcutEvent( key: 'Markdown link or image', command: 'shift+parenthesis right', diff --git a/frontend/app_flowy/packages/appflowy_editor/test/infra/test_raw_key_event.dart b/frontend/app_flowy/packages/appflowy_editor/test/infra/test_raw_key_event.dart index 5730b9cb15..5102407e1b 100644 --- a/frontend/app_flowy/packages/appflowy_editor/test/infra/test_raw_key_event.dart +++ b/frontend/app_flowy/packages/appflowy_editor/test/infra/test_raw_key_event.dart @@ -148,9 +148,6 @@ extension on LogicalKeyboardKey { if (this == LogicalKeyboardKey.tilde) { return PhysicalKeyboardKey.backquote; } - if (this == LogicalKeyboardKey.greater) { - return PhysicalKeyboardKey.intlBackslash; - } throw UnimplementedError(); } } diff --git a/frontend/app_flowy/packages/appflowy_editor/test/service/internal_key_event_handlers/markdown_syntax_to_styled_text_test.dart b/frontend/app_flowy/packages/appflowy_editor/test/service/internal_key_event_handlers/markdown_syntax_to_styled_text_test.dart index bdf4704a87..662c7982b4 100644 --- a/frontend/app_flowy/packages/appflowy_editor/test/service/internal_key_event_handlers/markdown_syntax_to_styled_text_test.dart +++ b/frontend/app_flowy/packages/appflowy_editor/test/service/internal_key_event_handlers/markdown_syntax_to_styled_text_test.dart @@ -256,76 +256,5 @@ void main() async { expect(textNode.toPlainText(), text); }); }); - - group('convert geater to blockquote', () { - Future insertGreater( - EditorWidgetTester editor, { - int repeat = 1, - }) async { - for (var i = 0; i < repeat; i++) { - await editor.pressLogicKey( - LogicalKeyboardKey.greater, - isShiftPressed: true, - ); - } - } - - testWidgets('>AppFlowy to blockquote AppFlowy', (tester) async { - const text = 'AppFlowy'; - final editor = tester.editor..insertTextNode(''); - await editor.startTesting(); - await editor.updateSelection( - Selection.single(path: [0], startOffset: 0), - ); - await insertGreater(editor); - final textNode = editor.nodeAtPath([0]) as TextNode; - for (var i = 0; i < text.length; i++) { - await editor.insertText(textNode, text[i], i); - } - - final isQuote = textNode.subtype == BuiltInAttributeKey.quote; - expect(isQuote, true); - expect(textNode.toPlainText(), 'AppFlowy'); - }); - - testWidgets('AppFlowy> nothing changes', (tester) async { - const text = 'AppFlowy'; - final editor = tester.editor..insertTextNode(''); - await editor.startTesting(); - await editor.updateSelection( - Selection.single(path: [0], startOffset: 0), - ); - final textNode = editor.nodeAtPath([0]) as TextNode; - for (var i = 0; i < text.length; i++) { - await editor.insertText(textNode, text[i], i); - } - await insertGreater(editor); - - final isQuote = textNode.subtype == BuiltInAttributeKey.quote; - expect(isQuote, false); - expect(textNode.toPlainText(), text); - }); - - testWidgets('> in front of text to blockquote', (tester) async { - const text = 'AppFlowy'; - final editor = tester.editor..insertTextNode(''); - await editor.startTesting(); - await editor.updateSelection( - Selection.single(path: [0], startOffset: 0), - ); - final textNode = editor.nodeAtPath([0]) as TextNode; - for (var i = 0; i < text.length; i++) { - await editor.insertText(textNode, text[i], i); - } - await editor.updateSelection( - Selection.single(path: [0], startOffset: 0), - ); - await insertGreater(editor); - - final isQuote = textNode.subtype == BuiltInAttributeKey.quote; - expect(isQuote, true); - expect(textNode.toPlainText(), text); - }); - }); }); } diff --git a/frontend/app_flowy/packages/appflowy_editor/test/service/internal_key_event_handlers/white_space_handler_test.dart b/frontend/app_flowy/packages/appflowy_editor/test/service/internal_key_event_handlers/white_space_handler_test.dart index f62d977ece..4349dc7a79 100644 --- a/frontend/app_flowy/packages/appflowy_editor/test/service/internal_key_event_handlers/white_space_handler_test.dart +++ b/frontend/app_flowy/packages/appflowy_editor/test/service/internal_key_event_handlers/white_space_handler_test.dart @@ -184,6 +184,10 @@ void main() async { Selection.single(path: [0], startOffset: 0), ); + await editor.insertText(textNode, '>', 0); + await editor.pressLogicKey(LogicalKeyboardKey.space); + expect(textNode.subtype, BuiltInAttributeKey.quote); + await editor.insertText(textNode, '*', 0); await editor.pressLogicKey(LogicalKeyboardKey.space); expect(textNode.subtype, BuiltInAttributeKey.bulletedList); @@ -227,5 +231,65 @@ void main() async { expect(textNode.subtype, null); expect(textNode.toPlainText(), text); }); + + group('convert geater to blockquote', () { + testWidgets('> AppFlowy to blockquote AppFlowy', (tester) async { + const text = 'AppFlowy'; + final editor = tester.editor..insertTextNode(''); + await editor.startTesting(); + await editor.updateSelection( + Selection.single(path: [0], startOffset: 0), + ); + + final textNode = editor.nodeAtPath([0]) as TextNode; + await editor.insertText(textNode, '>', 0); + await editor.pressLogicKey(LogicalKeyboardKey.space); + expect(textNode.subtype, BuiltInAttributeKey.quote); + for (var i = 0; i < text.length; i++) { + await editor.insertText(textNode, text[i], i); + } + expect(textNode.toPlainText(), 'AppFlowy'); + }); + + testWidgets('AppFlowy > nothing changes', (tester) async { + const text = 'AppFlowy >'; + final editor = tester.editor..insertTextNode(''); + await editor.startTesting(); + await editor.updateSelection( + Selection.single(path: [0], startOffset: 0), + ); + + final textNode = editor.nodeAtPath([0]) as TextNode; + for (var i = 0; i < text.length; i++) { + await editor.insertText(textNode, text[i], i); + } + await editor.pressLogicKey(LogicalKeyboardKey.space); + final isQuote = textNode.subtype == BuiltInAttributeKey.quote; + expect(isQuote, false); + expect(textNode.toPlainText(), text); + }); + + testWidgets('> in front of text to blockquote', (tester) async { + const text = 'AppFlowy'; + final editor = tester.editor..insertTextNode(''); + await editor.startTesting(); + await editor.updateSelection( + Selection.single(path: [0], startOffset: 0), + ); + final textNode = editor.nodeAtPath([0]) as TextNode; + for (var i = 0; i < text.length; i++) { + await editor.insertText(textNode, text[i], i); + } + await editor.updateSelection( + Selection.single(path: [0], startOffset: 0), + ); + await editor.insertText(textNode, '>', 0); + await editor.pressLogicKey(LogicalKeyboardKey.space); + + final isQuote = textNode.subtype == BuiltInAttributeKey.quote; + expect(isQuote, true); + expect(textNode.toPlainText(), text); + }); + }); }); }