From 089b220798daba187c845a53df768fcf9c99ddbb Mon Sep 17 00:00:00 2001 From: Mukund-Tandon Date: Thu, 13 Jul 2023 13:47:54 +0530 Subject: [PATCH 1/5] feat: added support to changes image asset from markown to document --- .../decoder/document_markdown_decoder.dart | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart b/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart index 3ea2719fe..d6cf4495d 100644 --- a/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart +++ b/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart @@ -52,7 +52,7 @@ class DocumentMarkdownDecoder extends Converter { Node _convertLineToNode(String line) { final decoder = DeltaMarkdownDecoder(); - + final assetRegex = RegExp(r'\!\[.*\]\(.*\)'); // Heading Style if (line.startsWith('### ')) { return headingNode( @@ -91,6 +91,18 @@ class DocumentMarkdownDecoder extends Converter { return Node(type: 'divider'); } else if (line.startsWith('```') && line.endsWith('```')) { return _codeBlockNodeFromMarkdown(line, decoder); + } else if(assetRegex.hasMatch(line)){ + var match = assetRegex.firstMatch(line); + String? filepath = match?.group(1); + //checking if filepath is present or if the filepath is an image or not + if(filepath == null || (!filepath.endsWith('.png') && !filepath.endsWith('.jpg') && !filepath.endsWith('.jpeg') )){ + return paragraphNode( + attributes: {'delta': decoder.convert(line).toJson()}, + ); + } + else{ + return imageNode(url: filepath); + } } if (line.isNotEmpty) { From 5a66b86b9fdb478866f7a3940f073ecca5cf9578 Mon Sep 17 00:00:00 2001 From: Mukund-Tandon Date: Thu, 13 Jul 2023 14:50:51 +0530 Subject: [PATCH 2/5] fix: fixed image regex and geting image path --- .../decoder/document_markdown_decoder.dart | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart b/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart index d6cf4495d..961d7ee22 100644 --- a/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart +++ b/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart @@ -52,7 +52,7 @@ class DocumentMarkdownDecoder extends Converter { Node _convertLineToNode(String line) { final decoder = DeltaMarkdownDecoder(); - final assetRegex = RegExp(r'\!\[.*\]\(.*\)'); + final assetRegex = RegExp(r'^!\[.*\]\(.*\)$'); // Heading Style if (line.startsWith('### ')) { return headingNode( @@ -91,9 +91,9 @@ class DocumentMarkdownDecoder extends Converter { return Node(type: 'divider'); } else if (line.startsWith('```') && line.endsWith('```')) { return _codeBlockNodeFromMarkdown(line, decoder); - } else if(assetRegex.hasMatch(line)){ - var match = assetRegex.firstMatch(line); - String? filepath = match?.group(1); + } else if(assetRegex.hasMatch(line.trim())){ + + String? filepath = extractImagePath(line.trim()); //checking if filepath is present or if the filepath is an image or not if(filepath == null || (!filepath.endsWith('.png') && !filepath.endsWith('.jpg') && !filepath.endsWith('.jpeg') )){ return paragraphNode( @@ -115,7 +115,18 @@ class DocumentMarkdownDecoder extends Converter { attributes: {'delta': Delta().toJson()}, ); } - + String? extractImagePath(String text) { + const startDelimiter = "!["; + const endDelimiter = "]("; + final startIndex = text.indexOf(startDelimiter); + final endIndex = text.indexOf(endDelimiter, startIndex + startDelimiter.length); + + if (startIndex != -1 && endIndex != -1) { + return text.substring(endIndex + endDelimiter.length, text.length - 1); + } else { + return null; + } +} Node _codeBlockNodeFromMarkdown( String markdown, DeltaMarkdownDecoder decoder, From f4149efdb844470853bb03b03c1020f9b20c917c Mon Sep 17 00:00:00 2001 From: Mukund-Tandon Date: Fri, 14 Jul 2023 15:56:06 +0530 Subject: [PATCH 3/5] fix: fixed file being detected as a url --- .../decoder/document_markdown_decoder.dart | 66 ++++++++++++++----- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart b/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart index 961d7ee22..5dbb40bf1 100644 --- a/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart +++ b/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart @@ -52,7 +52,9 @@ class DocumentMarkdownDecoder extends Converter { Node _convertLineToNode(String line) { final decoder = DeltaMarkdownDecoder(); - final assetRegex = RegExp(r'^!\[.*\]\(.*\)$'); + final imageRegex = RegExp(r'^!\[.*\]\(.*\)$'); + final assetRegex = RegExp(r'^\[.*\]\(.*\)$'); + final htmlRegex = RegExp('^(http|https)://'); // Heading Style if (line.startsWith('### ')) { return headingNode( @@ -91,18 +93,31 @@ class DocumentMarkdownDecoder extends Converter { return Node(type: 'divider'); } else if (line.startsWith('```') && line.endsWith('```')) { return _codeBlockNodeFromMarkdown(line, decoder); - } else if(assetRegex.hasMatch(line.trim())){ - - String? filepath = extractImagePath(line.trim()); + } else if (imageRegex.hasMatch(line.trim())) { + String? filepath = extractImagePath(line.trim()); //checking if filepath is present or if the filepath is an image or not - if(filepath == null || (!filepath.endsWith('.png') && !filepath.endsWith('.jpg') && !filepath.endsWith('.jpeg') )){ + if (filepath == null || + (!filepath.endsWith('.png') && + !filepath.endsWith('.jpg') && + !filepath.endsWith('.jpeg'))) { return paragraphNode( attributes: {'delta': decoder.convert(line).toJson()}, ); - } - else{ + } else { return imageNode(url: filepath); } + } else if (assetRegex.hasMatch(line.trim())) { + //this might be a url or a file like pdf,videos,etc + String? filepath = extractFilePath(line.trim()); + if (filepath != null && !htmlRegex.hasMatch(filepath)) { + return paragraphNode( + text: "This file is cuurently not supported : $line", + ); + } else { + return paragraphNode( + attributes: {'delta': decoder.convert(line).toJson()}, + ); + } } if (line.isNotEmpty) { @@ -115,18 +130,35 @@ class DocumentMarkdownDecoder extends Converter { attributes: {'delta': Delta().toJson()}, ); } + String? extractImagePath(String text) { - const startDelimiter = "!["; - const endDelimiter = "]("; - final startIndex = text.indexOf(startDelimiter); - final endIndex = text.indexOf(endDelimiter, startIndex + startDelimiter.length); - - if (startIndex != -1 && endIndex != -1) { - return text.substring(endIndex + endDelimiter.length, text.length - 1); - } else { - return null; + const startDelimiter = "!["; + const endDelimiter = "]("; + final startIndex = text.indexOf(startDelimiter); + final endIndex = + text.indexOf(endDelimiter, startIndex + startDelimiter.length); + + if (startIndex != -1 && endIndex != -1) { + return text.substring(endIndex + endDelimiter.length, text.length - 1); + } else { + return null; + } } -} + + String? extractFilePath(String text) { + const startDelimiter = "["; + const endDelimiter = "]("; + final startIndex = text.indexOf(startDelimiter); + final endIndex = + text.indexOf(endDelimiter, startIndex + startDelimiter.length); + + if (startIndex != -1 && endIndex != -1) { + return text.substring(endIndex + endDelimiter.length, text.length - 1); + } else { + return null; + } + } + Node _codeBlockNodeFromMarkdown( String markdown, DeltaMarkdownDecoder decoder, From a0ca6d91da2376a6c1260b2792059816812ce8ae Mon Sep 17 00:00:00 2001 From: Mukund-Tandon Date: Fri, 14 Jul 2023 20:26:09 +0530 Subject: [PATCH 4/5] test: added test for detecting image and files from markdown --- .../document_markdown_decoder_test.dart | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/plugins/markdown/decoder/document_markdown_decoder_test.dart b/test/plugins/markdown/decoder/document_markdown_decoder_test.dart index c0707a8ad..63e62dcc0 100644 --- a/test/plugins/markdown/decoder/document_markdown_decoder_test.dart +++ b/test/plugins/markdown/decoder/document_markdown_decoder_test.dart @@ -186,6 +186,35 @@ void main() async { ] } }, + { + "type": "paragraph", + "data": { + "delta": [] + } + }, + { + "type": "paragraph", + "data": { + "delta": [ + { + "insert": "This file is cuurently not supported : [Example file.pdf](path/to/file.pdf)" + } + ] + } + }, + { + "type": "paragraph", + "data": { + "delta": [] + } + }, + { + "type": "image", + "data": { + "url": "path/to/image.png", + "align": "center" + } + }, { "type": "paragraph", "data": { @@ -334,6 +363,10 @@ You can also use ***AppFlowy Editor*** as a component to build your own app. * Select text to trigger to the toolbar to format your notes. If you have questions or feedback, please submit an issue on Github or join the community along with 1000+ builders! + +[Example file.pdf](path/to/file.pdf) + +![Example image](path/to/image.png) '''; final result = DocumentMarkdownDecoder().convert(markdown); final data = jsonDecode(example); From 800ebbaedbf4a89a5112ec00970a29b5bf38a1b8 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Wed, 19 Jul 2023 16:28:58 +0800 Subject: [PATCH 5/5] chore: format code --- .../decoder/document_markdown_decoder.dart | 63 ++++++------------- pubspec.yaml | 2 + .../document_markdown_decoder_test.dart | 4 +- 3 files changed, 22 insertions(+), 47 deletions(-) diff --git a/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart b/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart index 5dbb40bf1..6529bbd60 100644 --- a/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart +++ b/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart @@ -1,8 +1,13 @@ import 'dart:convert'; import 'package:appflowy_editor/appflowy_editor.dart'; +import 'package:path/path.dart' as p; class DocumentMarkdownDecoder extends Converter { + final imageRegex = RegExp(r'^!\[[^\]]*\]\((.*?)\)'); + final assetRegex = RegExp(r'^\[[^\]]*\]\((.*?)\)'); + final htmlRegex = RegExp('^(http|https)://'); + @override Document convert(String input) { final lines = input.split('\n'); @@ -52,9 +57,6 @@ class DocumentMarkdownDecoder extends Converter { Node _convertLineToNode(String line) { final decoder = DeltaMarkdownDecoder(); - final imageRegex = RegExp(r'^!\[.*\]\(.*\)$'); - final assetRegex = RegExp(r'^\[.*\]\(.*\)$'); - final htmlRegex = RegExp('^(http|https)://'); // Heading Style if (line.startsWith('### ')) { return headingNode( @@ -94,29 +96,18 @@ class DocumentMarkdownDecoder extends Converter { } else if (line.startsWith('```') && line.endsWith('```')) { return _codeBlockNodeFromMarkdown(line, decoder); } else if (imageRegex.hasMatch(line.trim())) { - String? filepath = extractImagePath(line.trim()); - //checking if filepath is present or if the filepath is an image or not - if (filepath == null || - (!filepath.endsWith('.png') && - !filepath.endsWith('.jpg') && - !filepath.endsWith('.jpeg'))) { - return paragraphNode( - attributes: {'delta': decoder.convert(line).toJson()}, - ); - } else { - return imageNode(url: filepath); + final filePath = extractImagePath(line.trim()); + // checking if filepath is present or if the filepath is an image or not + if (filePath == null || + !['.png', '.jpg', 'jpeg'].contains(p.extension(filePath))) { + return paragraphNode(text: line.trim()); } + return imageNode(url: filePath); } else if (assetRegex.hasMatch(line.trim())) { - //this might be a url or a file like pdf,videos,etc - String? filepath = extractFilePath(line.trim()); + // this might be a url or a file like pdf, videos, etc + final filepath = extractFilePath(line.trim()); if (filepath != null && !htmlRegex.hasMatch(filepath)) { - return paragraphNode( - text: "This file is cuurently not supported : $line", - ); - } else { - return paragraphNode( - attributes: {'delta': decoder.convert(line).toJson()}, - ); + return paragraphNode(text: line); } } @@ -132,31 +123,13 @@ class DocumentMarkdownDecoder extends Converter { } String? extractImagePath(String text) { - const startDelimiter = "!["; - const endDelimiter = "]("; - final startIndex = text.indexOf(startDelimiter); - final endIndex = - text.indexOf(endDelimiter, startIndex + startDelimiter.length); - - if (startIndex != -1 && endIndex != -1) { - return text.substring(endIndex + endDelimiter.length, text.length - 1); - } else { - return null; - } + final match = imageRegex.firstMatch(text); + return match?.group(1); } String? extractFilePath(String text) { - const startDelimiter = "["; - const endDelimiter = "]("; - final startIndex = text.indexOf(startDelimiter); - final endIndex = - text.indexOf(endDelimiter, startIndex + startDelimiter.length); - - if (startIndex != -1 && endIndex != -1) { - return text.substring(endIndex + endDelimiter.length, text.length - 1); - } else { - return null; - } + final match = assetRegex.firstMatch(text); + return match?.group(1); } Node _codeBlockNodeFromMarkdown( diff --git a/pubspec.yaml b/pubspec.yaml index 97e3dc072..a449362de 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,6 +35,8 @@ dependencies: nanoid: ^1.0.0 visibility_detector: ^0.4.0+2 file_picker: ^5.3.1 + path: ^1.8.3 + dev_dependencies: flutter_test: sdk: flutter diff --git a/test/plugins/markdown/decoder/document_markdown_decoder_test.dart b/test/plugins/markdown/decoder/document_markdown_decoder_test.dart index 63e62dcc0..3040a5537 100644 --- a/test/plugins/markdown/decoder/document_markdown_decoder_test.dart +++ b/test/plugins/markdown/decoder/document_markdown_decoder_test.dart @@ -197,11 +197,11 @@ void main() async { "data": { "delta": [ { - "insert": "This file is cuurently not supported : [Example file.pdf](path/to/file.pdf)" + "insert": "[Example file.pdf](path/to/file.pdf)" } ] } - }, + }, { "type": "paragraph", "data": {