diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/appflowy_editor.dart b/frontend/app_flowy/packages/appflowy_editor/lib/appflowy_editor.dart index f646577a8a..cc8e9556d7 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/appflowy_editor.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/appflowy_editor.dart @@ -33,4 +33,8 @@ export 'src/render/selection_menu/selection_menu_widget.dart'; export 'src/l10n/l10n.dart'; export 'src/render/style/plugin_styles.dart'; export 'src/render/style/editor_style.dart'; -export 'src/plugins/markdown/delta_markdown_encoder.dart'; +export 'src/plugins/markdown/encoder/delta_markdown_encoder.dart'; +export 'src/plugins/markdown/encoder/document_markdown_encoder.dart'; +export 'src/plugins/markdown/encoder/parser/node_parser.dart'; +export 'src/plugins/markdown/encoder/parser/text_node_parser.dart'; +export 'src/plugins/markdown/encoder/parser/image_node_parser.dart'; diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/document_markdown_encoder.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/document_markdown_encoder.dart deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/delta_markdown_encoder.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/encoder/delta_markdown_encoder.dart similarity index 100% rename from frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/delta_markdown_encoder.dart rename to frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/encoder/delta_markdown_encoder.dart diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/encoder/document_markdown_encoder.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/encoder/document_markdown_encoder.dart new file mode 100644 index 0000000000..52c2bd3756 --- /dev/null +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/encoder/document_markdown_encoder.dart @@ -0,0 +1,39 @@ +import 'dart:convert'; + +import 'package:appflowy_editor/src/core/document/document.dart'; +import 'package:appflowy_editor/src/plugins/markdown/encoder/parser/image_node_parser.dart'; +import 'package:appflowy_editor/src/plugins/markdown/encoder/parser/node_parser.dart'; +import 'package:appflowy_editor/src/plugins/markdown/encoder/parser/text_node_parser.dart'; + +class DocumentMarkdownEncoder extends Converter { + DocumentMarkdownEncoder({ + this.parsers = const [ + TextNodeParser(), + ImageNodeParser(), + ], + }); + + final List parsers; + + @override + String convert(Document input) { + final buffer = StringBuffer(); + for (final node in input.root.children) { + NodeParser? parser = + parsers.firstWhereOrNull((element) => element.id == node.type); + if (parser != null) { + buffer.write(parser.transform(node)); + } + } + return buffer.toString(); + } +} + +extension IterableExtension on Iterable { + T? firstWhereOrNull(bool Function(T element) test) { + for (var element in this) { + if (test(element)) return element; + } + return null; + } +} diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/encoder/parser/image_node_parser.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/encoder/parser/image_node_parser.dart new file mode 100644 index 0000000000..5db9f1b558 --- /dev/null +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/encoder/parser/image_node_parser.dart @@ -0,0 +1,14 @@ +import 'package:appflowy_editor/src/core/document/node.dart'; +import 'package:appflowy_editor/src/plugins/markdown/encoder/parser/node_parser.dart'; + +class ImageNodeParser extends NodeParser { + const ImageNodeParser(); + + @override + String get id => 'image'; + + @override + String transform(Node node) { + return '![](${node.attributes['image_src']})'; + } +} diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/encoder/parser/node_parser.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/encoder/parser/node_parser.dart new file mode 100644 index 0000000000..9cbdabfbb9 --- /dev/null +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/encoder/parser/node_parser.dart @@ -0,0 +1,8 @@ +import 'package:appflowy_editor/src/core/document/node.dart'; + +abstract class NodeParser { + const NodeParser(); + + String get id; + String transform(Node node); +} diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/encoder/parser/text_node_parser.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/encoder/parser/text_node_parser.dart new file mode 100644 index 0000000000..fe60db7c7e --- /dev/null +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/encoder/parser/text_node_parser.dart @@ -0,0 +1,57 @@ +import 'package:appflowy_editor/src/core/document/node.dart'; +import 'package:appflowy_editor/src/core/legacy/built_in_attribute_keys.dart'; +import 'package:appflowy_editor/src/plugins/markdown/encoder/delta_markdown_encoder.dart'; +import 'package:appflowy_editor/src/plugins/markdown/encoder/parser/node_parser.dart'; + +class TextNodeParser extends NodeParser { + const TextNodeParser(); + + @override + String get id => 'text'; + + @override + String transform(Node node) { + assert(node is TextNode); + final textNode = node as TextNode; + final markdown = DeltaMarkdownEncoder().convert(textNode.delta); + final attributes = textNode.attributes; + var result = markdown; + var suffix = '\n'; + if (attributes.isNotEmpty && + attributes.containsKey(BuiltInAttributeKey.subtype)) { + final subtype = attributes[BuiltInAttributeKey.subtype]; + if (subtype == 'heading') { + final heading = attributes[BuiltInAttributeKey.heading]; + if (heading == 'h1') { + result = '# $markdown'; + } else if (heading == 'h2') { + result = '## $markdown'; + } else if (heading == 'h3') { + result = '### $markdown'; + } else if (heading == 'h4') { + result = '#### $markdown'; + } else if (heading == 'h5') { + result = '##### $markdown'; + } else if (heading == 'h6') { + result = '###### $markdown'; + } + } else if (subtype == 'quote') { + result = '> $markdown'; + } else if (subtype == 'code-block') { + result = '```\n$markdown\n```'; + } else if (subtype == 'bulleted-list') { + result = '* $markdown'; + } else if (subtype == 'number-list') { + final number = attributes['number']; + result = '$number. $markdown'; + } else if (subtype == 'checkbox') { + if (attributes[BuiltInAttributeKey.checkbox] == true) { + result = '- [x] $markdown'; + } else { + result = '- [ ] $markdown'; + } + } + } + return '$result$suffix'; + } +} diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/markdown_encoder.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/markdown_encoder.dart deleted file mode 100644 index 8b13789179..0000000000 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/plugins/markdown/markdown_encoder.dart +++ /dev/null @@ -1 +0,0 @@ -