From 8f5eb10d1c3188c1023102a78fe9a46c74b54264 Mon Sep 17 00:00:00 2001 From: alihassan143 Date: Mon, 11 Sep 2023 19:44:21 +0500 Subject: [PATCH 1/4] feat: table html encoder and decoder added --- .../html/encoder/parser/html_parser.dart | 1 + .../encoder/parser/table_node_parser.dart | 69 ++++++ lib/src/plugins/html/html_document.dart | 1 + .../plugins/html/html_document_decoder.dart | 234 +++++++++++++++--- .../decoder/document_html_decoder_test.dart | 125 ++++++++++ .../encoder/document_html_encoder_test.dart | 1 + .../parser/image_node_parser_test.dart | 1 + .../encoder/parser/text_node_parser_test.dart | 100 ++++++++ 8 files changed, 503 insertions(+), 29 deletions(-) create mode 100644 lib/src/plugins/html/encoder/parser/table_node_parser.dart diff --git a/lib/src/plugins/html/encoder/parser/html_parser.dart b/lib/src/plugins/html/encoder/parser/html_parser.dart index e394f24dc..d995c894d 100644 --- a/lib/src/plugins/html/encoder/parser/html_parser.dart +++ b/lib/src/plugins/html/encoder/parser/html_parser.dart @@ -4,5 +4,6 @@ export 'html_node_parser.dart'; export 'image_node_parser.dart'; export 'numbered_list_node_parser.dart'; export 'quote_node_parser.dart'; +export 'table_node_parser.dart'; export 'text_node_parser.dart'; export 'todo_list_node_parser.dart'; diff --git a/lib/src/plugins/html/encoder/parser/table_node_parser.dart b/lib/src/plugins/html/encoder/parser/table_node_parser.dart new file mode 100644 index 000000000..0d523722d --- /dev/null +++ b/lib/src/plugins/html/encoder/parser/table_node_parser.dart @@ -0,0 +1,69 @@ +import 'package:appflowy_editor/appflowy_editor.dart'; +import 'package:collection/collection.dart'; +import 'package:html/dom.dart' as dom; + +import '../../../../editor/block_component/table_block_component/util.dart'; + +class HtmlTableNodeParser extends HTMLNodeParser { + const HtmlTableNodeParser(); + + @override + String get id => TableBlockKeys.type; + + @override + String transformNodeToHTMLString( + Node node, { + required List encodeParsers, + }) { + assert(node.type == TableBlockKeys.type); + + return toHTMLString( + transformNodeToDomNodes(node, encodeParsers: encodeParsers), + ); + } + + @override + List transformNodeToDomNodes( + Node node, { + required List encodeParsers, + }) { + final int rowsLen = node.attributes['rowsLen'], + colsLen = node.attributes['colsLen']; + final List domNodes = []; + + for (var i = 0; i < rowsLen; i++) { + final List nodes = []; + for (var j = 0; j < colsLen; j++) { + final Node cell = getCellNode(node, j, i)!; + + for (final childnode in cell.children) { + HTMLNodeParser? parser = encodeParsers.firstWhereOrNull( + (element) => element.id == childnode.type, + ); + + if (parser != null) { + nodes.add( + wrapChildrenNodesWithTagName( + HTMLTags.tabledata, + childNodes: parser.transformNodeToDomNodes( + childnode, + encodeParsers: encodeParsers, + ), + ), + ); + } + } + } + final rowelement = + wrapChildrenNodesWithTagName(HTMLTags.tableRow, childNodes: nodes); + + domNodes.add(rowelement); + } + + final element = + wrapChildrenNodesWithTagName(HTMLTags.table, childNodes: domNodes); + return [ + element, + ]; + } +} diff --git a/lib/src/plugins/html/html_document.dart b/lib/src/plugins/html/html_document.dart index bb57c3280..dc359cb4d 100644 --- a/lib/src/plugins/html/html_document.dart +++ b/lib/src/plugins/html/html_document.dart @@ -28,6 +28,7 @@ String documentToHTML( const HTMLQuoteNodeParser(), const HTMLHeadingNodeParser(), const HTMLImageNodeParser(), + const HtmlTableNodeParser() ], ).encode(document); } diff --git a/lib/src/plugins/html/html_document_decoder.dart b/lib/src/plugins/html/html_document_decoder.dart index b8ef5d333..ae70260fc 100644 --- a/lib/src/plugins/html/html_document_decoder.dart +++ b/lib/src/plugins/html/html_document_decoder.dart @@ -2,6 +2,7 @@ import 'dart:collection'; import 'dart:convert'; import 'package:appflowy_editor/appflowy_editor.dart'; +import 'package:appflowy_editor/src/editor/block_component/table_block_component/table_node.dart'; import 'package:html/dom.dart' as dom; import 'package:html/parser.dart' show parse; @@ -78,12 +79,14 @@ class DocumentHTMLDecoder extends Converter { return _parseUnOrderListElement(element); case HTMLTags.orderedList: return _parseOrderListElement(element); + case HTMLTags.table: + return _parseTable(element); case HTMLTags.list: return [ _parseListElement( element, type: type, - ) + ), ]; case HTMLTags.paragraph: return _parseParagraphElement(element); @@ -96,6 +99,149 @@ class DocumentHTMLDecoder extends Converter { } } + Iterable _parseTable(dom.Element element) { + final List tablenodes = []; + int columnLenth = 0; + int rowLength = 0; + for (final data in element.children) { + final (col, row, rwdata) = _parsetableRows(data); + columnLenth = columnLenth + col; + rowLength = rowLength + row; + + tablenodes.addAll(rwdata); + } + + return [ + TableNode( + node: Node( + type: TableBlockKeys.type, + attributes: { + TableBlockKeys.rowsLen: rowLength, + TableBlockKeys.colsLen: columnLenth, + TableBlockKeys.colDefaultWidth: 60, + TableBlockKeys.rowDefaultHeight: 50, + TableBlockKeys.colMinimumWidth: 30, + }, + children: tablenodes, + ), + ).node, + ]; + } + + (int, int, List) _parsetableRows(dom.Element element) { + final List nodes = []; + int length = 0; + int rowLength = 0; + + for (final data in element.children) { + final tabledata = _parsetableData(data, rowPosition: rowLength); + if (length == 0) { + length = tabledata.length; + } + nodes.addAll(tabledata); + rowLength++; + } + return (length, rowLength, nodes); + } + + Iterable _parsetableData( + dom.Element element, { + required int rowPosition, + }) { + final List nodes = []; + int columnPosition = 0; + + for (final data in element.children) { + if (data.children.isEmpty) { + Attributes attributes = { + TableCellBlockKeys.colPosition: columnPosition, + TableCellBlockKeys.rowPosition: rowPosition, + }; + if (data.attributes.isNotEmpty) { + final deltaAttributes = _getDeltaAttributesFromHTMLAttributes( + element.attributes, + ) ?? + {}; + attributes.addAll(deltaAttributes); + } + + final node = Node( + type: TableCellBlockKeys.type, + attributes: attributes, + children: [paragraphNode(text: data.text)], + ); + + nodes.add(node); + } else { + Attributes attributes = { + TableCellBlockKeys.colPosition: columnPosition, + TableCellBlockKeys.rowPosition: rowPosition, + }; + if (data.attributes.isNotEmpty) { + final deltaAttributes = _getDeltaAttributesFromHTMLAttributes( + element.attributes, + ) ?? + {}; + attributes.addAll(deltaAttributes); + } + + final newnodes = Node( + type: TableCellBlockKeys.type, + attributes: attributes, + children: _parseTableSpecialNodes(data), + ); + + nodes.add(newnodes); + } + columnPosition++; + } + + return nodes; + } + + Iterable _parseTableSpecialNodes(dom.Element element) { + final List nodes = []; + + if (element.children.isNotEmpty) { + for (final childrens in element.children) { + nodes.addAll(_parseTableDataElementsData(childrens)); + } + } else { + nodes.addAll(_parseTableDataElementsData(element)); + } + return nodes; + } + + List _parseTableDataElementsData(dom.Element element) { + final List nodes = []; + final delta = Delta(); + final localName = element.localName; + + if (HTMLTags.formattingElements.contains(localName)) { + final attributes = _parserFormattingElementAttributes(element); + delta.insert(element.text, attributes: attributes); + } else if (HTMLTags.specialElements.contains(localName)) { + if (delta.isNotEmpty) { + nodes.add(paragraphNode(delta: delta)); + } + nodes.addAll( + _parseSpecialElements( + element, + type: ParagraphBlockKeys.type, + ), + ); + } else if (element is dom.Text) { + // skip the empty text node + + delta.insert(element.text); + } + + if (delta.isNotEmpty) { + nodes.add(paragraphNode(delta: delta)); + } + return nodes; + } + Attributes _parserFormattingElementAttributes( dom.Element element, ) { @@ -130,6 +276,7 @@ class DocumentHTMLDecoder extends Converter { attributes = {AppFlowyRichTextKeys.href: href}; } break; + case HTMLTags.strikethrough: attributes = {AppFlowyRichTextKeys.strikethrough: true}; break; @@ -152,7 +299,7 @@ class DocumentHTMLDecoder extends Converter { level: level, delta: delta, ), - ...specialNodes + ...specialNodes, ]; } @@ -247,8 +394,9 @@ class DocumentHTMLDecoder extends Converter { } Attributes? _getDeltaAttributesFromHTMLAttributes( - LinkedHashMap htmlAttributes, - ) { + LinkedHashMap htmlAttributes, { + AttributeType attributeType = AttributeType.none, + }) { final Attributes attributes = {}; final style = htmlAttributes['style']; final css = _getCssFromString(style); @@ -283,38 +431,58 @@ class DocumentHTMLDecoder extends Converter { } } } + if (attributeType == AttributeType.none) { + // background color + final backgroundColor = css['background-color']; + if (backgroundColor != null) { + final highlightColor = backgroundColor.tryToColor()?.toHex(); + if (highlightColor != null) { + attributes[AppFlowyRichTextKeys.highlightColor] = highlightColor; + } + } - // background color - final backgroundColor = css['background-color']; - if (backgroundColor != null) { - final highlightColor = backgroundColor.tryToColor()?.toHex(); - if (highlightColor != null) { - attributes[AppFlowyRichTextKeys.highlightColor] = highlightColor; + // background + final background = css['background']; + if (background != null) { + final highlightColor = background.tryToColor()?.toHex(); + if (highlightColor != null) { + attributes[AppFlowyRichTextKeys.highlightColor] = highlightColor; + } } - } - // background - final background = css['background']; - if (background != null) { - final highlightColor = background.tryToColor()?.toHex(); - if (highlightColor != null) { - attributes[AppFlowyRichTextKeys.highlightColor] = highlightColor; + // color + final color = css['color']; + if (color != null) { + final textColor = color.tryToColor()?.toHex(); + if (textColor != null) { + attributes[AppFlowyRichTextKeys.textColor] = textColor; + } } - } - // color - final color = css['color']; - if (color != null) { - final textColor = color.tryToColor()?.toHex(); - if (textColor != null) { - attributes[AppFlowyRichTextKeys.textColor] = textColor; + // italic + final fontStyle = css['font-style']; + if (fontStyle == 'italic') { + attributes[AppFlowyRichTextKeys.italic] = true; } } + if (attributeType == AttributeType.tablerow) { + final regex = RegExp('[^0-9]'); + final width = css['width']; + if (width != null) { + String rowWidth = width.toString(); + rowWidth = rowWidth.replaceAll(regex, ''); + int newrowWidth = int.parse(rowWidth); - // italic - final fontStyle = css['font-style']; - if (fontStyle == 'italic') { - attributes[AppFlowyRichTextKeys.italic] = true; + attributes[TableCellBlockKeys.width] = newrowWidth; + } + final height = css['height']; + if (height != null) { + String rowHeight = height.toString(); + rowHeight = rowHeight.replaceAll(regex, ''); + int newhieght = int.parse(rowHeight); + + attributes[TableCellBlockKeys.height] = newhieght; + } } return attributes.isEmpty ? null : attributes; @@ -360,6 +528,10 @@ class HTMLTags { static const blockQuote = 'blockquote'; static const div = 'div'; static const divider = 'hr'; + static const table = 'table'; + static const tableRow = 'tr'; + static const tableheader = "th"; + static const tabledata = "td"; static List formattingElements = [ HTMLTags.anchor, @@ -382,19 +554,23 @@ class HTMLTags { HTMLTags.orderedList, HTMLTags.div, HTMLTags.list, + HTMLTags.table, HTMLTags.paragraph, HTMLTags.blockQuote, HTMLTags.checkbox, - HTMLTags.image + HTMLTags.image, ]; static bool isTopLevel(String tag) { return tag == h1 || tag == h2 || tag == h3 || + tag == table || tag == checkbox || tag == paragraph || tag == div || tag == blockQuote; } } + +enum AttributeType { table, tablerow, none } diff --git a/test/plugins/html/decoder/document_html_decoder_test.dart b/test/plugins/html/decoder/document_html_decoder_test.dart index cd41bf3d8..966530c48 100644 --- a/test/plugins/html/decoder/document_html_decoder_test.dart +++ b/test/plugins/html/decoder/document_html_decoder_test.dart @@ -12,6 +12,11 @@ void main() async { expect(result.toJson(), example); }); + test('html table parser document', () async { + final result = DocumentHTMLDecoder().convert(htmlTable); + + expect(result.toJson(), htmlTablejson); + }); test('nested parser document', () async { final result = DocumentHTMLDecoder().convert(nestedHTML); expect(result.toJson(), nestedDelta); @@ -21,6 +26,126 @@ void main() async { const rawHTML = '''

AppFlowyEditor

👋 Welcome to AppFlowy Editor

AppFlowy Editor is a highly customizable rich-text editor

Here is an example your you can give a try

Span element

Span element two

Span element three

This is an anchor tag!

Features!

  • [x] Customizable
  • [x] Test-covered
  • [ ] more to come!
  • First item
  • Second item
  • List element
This is a quote!

Code block

Italic one

Italic two

Bold tag

You can also use AppFlowy Editor as a component to build your own app.

Awesome features

If you have questions or feedback, please submit an issue on Github or join the community along with 1000+ builders!

'''; +const htmlTable = + ''''

a

c

b

d

'''; +const htmlTablejson = { + "document": { + "type": "page", + "children": [ + { + "type": "paragraph", + "data": { + "delta": [ + {"insert": "'"} + ], + }, + }, + { + "type": "table", + "children": [ + { + "type": "table/cell", + "children": [ + { + "type": "heading", + "data": { + "delta": [ + {"insert": "a"} + ], + "level": 2 + } + } + ], + "data": { + "colPosition": 0, + "rowPosition": 0, + "height": 50.0, + "width": 60.0 + } + }, + { + "type": "table/cell", + "children": [ + { + "type": "paragraph", + "data": { + "delta": [ + { + "insert": "c", + "attributes": {"italic": true}, + } + ] + } + } + ], + "data": { + "colPosition": 1, + "rowPosition": 0, + "height": 50.0, + "width": 60.0 + } + }, + { + "type": "table/cell", + "children": [ + { + "type": "paragraph", + "data": { + "delta": [ + { + "insert": "b", + "attributes": {"bold": true} + } + ] + } + } + ], + "data": { + "colPosition": 0, + "rowPosition": 1, + "height": 50.0, + "width": 60.0 + }, + }, + { + "type": "table/cell", + "children": [ + { + "type": "paragraph", + "data": { + "delta": [ + {"insert": "d"} + ] + } + } + ], + "data": { + "colPosition": 1, + "rowPosition": 1, + "height": 50.0, + "width": 60.0 + } + } + ], + "data": { + "rowsLen": 2, + "colsLen": 2, + "colDefaultWidth": 60, + "rowDefaultHeight": 50, + "colMinimumWidth": 30 + } + }, + { + "type": "paragraph", + "data": { + "delta": [ + {"insert": "'"} + ] + } + } + ] + } +}; const example = { 'document': { diff --git a/test/plugins/html/encoder/document_html_encoder_test.dart b/test/plugins/html/encoder/document_html_encoder_test.dart index 2a6402b2c..92f5be689 100644 --- a/test/plugins/html/encoder/document_html_encoder_test.dart +++ b/test/plugins/html/encoder/document_html_encoder_test.dart @@ -10,6 +10,7 @@ void main() async { const HTMLQuoteNodeParser(), const HTMLHeadingNodeParser(), const HTMLImageNodeParser(), + const HtmlTableNodeParser() ]; group('document_html_encoder_test.dart', () { setUpAll(() { diff --git a/test/plugins/html/encoder/parser/image_node_parser_test.dart b/test/plugins/html/encoder/parser/image_node_parser_test.dart index 6f2d9e447..5ff0e036e 100644 --- a/test/plugins/html/encoder/parser/image_node_parser_test.dart +++ b/test/plugins/html/encoder/parser/image_node_parser_test.dart @@ -10,6 +10,7 @@ void main() async { const HTMLQuoteNodeParser(), const HTMLHeadingNodeParser(), const HTMLImageNodeParser(), + const HtmlTableNodeParser() ]; group('html_image_node_parser.dart', () { test('parser image node', () { diff --git a/test/plugins/html/encoder/parser/text_node_parser_test.dart b/test/plugins/html/encoder/parser/text_node_parser_test.dart index 0166cdbce..74f1f362c 100644 --- a/test/plugins/html/encoder/parser/text_node_parser_test.dart +++ b/test/plugins/html/encoder/parser/text_node_parser_test.dart @@ -1,4 +1,5 @@ import 'package:appflowy_editor/appflowy_editor.dart'; +import 'package:appflowy_editor/src/editor/block_component/table_block_component/table_node.dart'; import 'package:flutter_test/flutter_test.dart'; void main() async { @@ -10,6 +11,7 @@ void main() async { const HTMLQuoteNodeParser(), const HTMLHeadingNodeParser(), const HTMLImageNodeParser(), + const HtmlTableNodeParser() ]; group('html_text_node_parser.dart', () { const text = 'Welcome to AppFlowy'; @@ -247,5 +249,103 @@ void main() async { '''

Welcome to AppFlowy

''', ); }); + test('table node parser test', () { + final tableNode = TableNode.fromJson({ + 'type': TableBlockKeys.type, + 'data': { + TableBlockKeys.colsLen: 2, + TableBlockKeys.rowsLen: 2, + TableBlockKeys.colDefaultWidth: 60, + TableBlockKeys.rowDefaultHeight: 50, + TableBlockKeys.colMinimumWidth: 30 + }, + 'children': [ + { + 'type': TableCellBlockKeys.type, + 'data': { + TableCellBlockKeys.colPosition: 0, + TableCellBlockKeys.rowPosition: 0, + TableCellBlockKeys.width: 35 + }, + 'children': [ + { + 'type': 'heading', + 'data': { + 'level': 2, + 'delta': [ + {'insert': 'a'} + ] + } + } + ] + }, + { + 'type': TableCellBlockKeys.type, + 'data': { + TableCellBlockKeys.colPosition: 0, + TableCellBlockKeys.rowPosition: 1 + }, + 'children': [ + { + 'type': 'paragraph', + 'data': { + 'delta': [ + { + 'insert': 'b', + 'attributes': {'bold': true} + } + ] + } + } + ] + }, + { + 'type': TableCellBlockKeys.type, + 'data': { + TableCellBlockKeys.colPosition: 1, + TableCellBlockKeys.rowPosition: 0 + }, + 'children': [ + { + 'type': 'paragraph', + 'data': { + 'delta': [ + { + 'insert': 'c', + 'attributes': {'italic': true} + } + ] + } + } + ] + }, + { + 'type': TableCellBlockKeys.type, + 'data': { + TableCellBlockKeys.colPosition: 1, + TableCellBlockKeys.rowPosition: 1 + }, + 'children': [ + { + 'type': 'paragraph', + 'data': { + 'delta': [ + {'insert': 'd'} + ] + } + } + ] + } + ] + }); + + expect( + const HtmlTableNodeParser().transformNodeToHTMLString( + tableNode.node, + encodeParsers: parser, + ), + '''

a

c

b

d

''', + ); + }); }); } From 47b72b7cc2a0984f089025b46357bc5eccaa23de Mon Sep 17 00:00:00 2001 From: alihassan143 Date: Wed, 13 Sep 2023 14:37:21 +0500 Subject: [PATCH 2/4] feat: html table encoder test added --- .../encoder/parser/table_node_parser.dart | 4 +- .../plugins/html/html_document_decoder.dart | 81 +++++------- .../decoder/document_html_decoder_test.dart | 28 ++--- .../parser/table_node_parser_test.dart | 116 ++++++++++++++++++ .../encoder/parser/text_node_parser_test.dart | 99 --------------- 5 files changed, 165 insertions(+), 163 deletions(-) create mode 100644 test/plugins/html/encoder/parser/table_node_parser_test.dart diff --git a/lib/src/plugins/html/encoder/parser/table_node_parser.dart b/lib/src/plugins/html/encoder/parser/table_node_parser.dart index 0d523722d..682cf1ef7 100644 --- a/lib/src/plugins/html/encoder/parser/table_node_parser.dart +++ b/lib/src/plugins/html/encoder/parser/table_node_parser.dart @@ -27,8 +27,8 @@ class HtmlTableNodeParser extends HTMLNodeParser { Node node, { required List encodeParsers, }) { - final int rowsLen = node.attributes['rowsLen'], - colsLen = node.attributes['colsLen']; + final int rowsLen = node.attributes[TableBlockKeys.rowsLen], + colsLen = node.attributes[TableBlockKeys.colsLen]; final List domNodes = []; for (var i = 0; i < rowsLen; i++) { diff --git a/lib/src/plugins/html/html_document_decoder.dart b/lib/src/plugins/html/html_document_decoder.dart index ec2161375..a52c873db 100644 --- a/lib/src/plugins/html/html_document_decoder.dart +++ b/lib/src/plugins/html/html_document_decoder.dart @@ -118,9 +118,9 @@ class DocumentHTMLDecoder extends Converter { attributes: { TableBlockKeys.rowsLen: rowLength, TableBlockKeys.colsLen: columnLenth, - TableBlockKeys.colDefaultWidth: 60, - TableBlockKeys.rowDefaultHeight: 50, - TableBlockKeys.colMinimumWidth: 30, + TableBlockKeys.colDefaultWidth: TableDefaults.colWidth, + TableBlockKeys.rowDefaultHeight: TableDefaults.rowHeight, + TableBlockKeys.colMinimumWidth: TableDefaults.colMinimumWidth, }, children: tablenodes, ), @@ -130,18 +130,18 @@ class DocumentHTMLDecoder extends Converter { (int, int, List) _parsetableRows(dom.Element element) { final List nodes = []; - int length = 0; + int colLength = 0; int rowLength = 0; for (final data in element.children) { final tabledata = _parsetableData(data, rowPosition: rowLength); - if (length == 0) { - length = tabledata.length; + if (colLength == 0) { + colLength = tabledata.length; } nodes.addAll(tabledata); rowLength++; } - return (length, rowLength, nodes); + return (colLength, rowLength, nodes); } Iterable _parsetableData( @@ -152,47 +152,32 @@ class DocumentHTMLDecoder extends Converter { int columnPosition = 0; for (final data in element.children) { - if (data.children.isEmpty) { - Attributes attributes = { - TableCellBlockKeys.colPosition: columnPosition, - TableCellBlockKeys.rowPosition: rowPosition, - }; - if (data.attributes.isNotEmpty) { - final deltaAttributes = _getDeltaAttributesFromHTMLAttributes( - element.attributes, - ) ?? - {}; - attributes.addAll(deltaAttributes); - } - - final node = Node( - type: TableCellBlockKeys.type, - attributes: attributes, - children: [paragraphNode(text: data.text)], - ); + Attributes attributes = { + TableCellBlockKeys.colPosition: columnPosition, + TableCellBlockKeys.rowPosition: rowPosition, + }; + if (data.attributes.isNotEmpty) { + final deltaAttributes = _getDeltaAttributesFromHTMLAttributes( + element.attributes, + ) ?? + {}; + attributes.addAll(deltaAttributes); + } - nodes.add(node); + List children; + if (data.children.isEmpty) { + children = [paragraphNode(text: data.text)]; } else { - Attributes attributes = { - TableCellBlockKeys.colPosition: columnPosition, - TableCellBlockKeys.rowPosition: rowPosition, - }; - if (data.attributes.isNotEmpty) { - final deltaAttributes = _getDeltaAttributesFromHTMLAttributes( - element.attributes, - ) ?? - {}; - attributes.addAll(deltaAttributes); - } + children = _parseTableSpecialNodes(data).toList(); + } - final newnodes = Node( - type: TableCellBlockKeys.type, - attributes: attributes, - children: _parseTableSpecialNodes(data), - ); + final node = Node( + type: TableCellBlockKeys.type, + attributes: attributes, + children: children, + ); - nodes.add(newnodes); - } + nodes.add(node); columnPosition++; } @@ -395,7 +380,7 @@ class DocumentHTMLDecoder extends Converter { Attributes? _getDeltaAttributesFromHTMLAttributes( LinkedHashMap htmlAttributes, { - AttributeType attributeType = AttributeType.none, + HtmlAttributeType attributeType = HtmlAttributeType.none, }) { final Attributes attributes = {}; final style = htmlAttributes['style']; @@ -431,7 +416,7 @@ class DocumentHTMLDecoder extends Converter { } } } - if (attributeType == AttributeType.none) { + if (attributeType == HtmlAttributeType.none) { // background color final backgroundColor = css['background-color']; if (backgroundColor != null) { @@ -465,7 +450,7 @@ class DocumentHTMLDecoder extends Converter { attributes[AppFlowyRichTextKeys.italic] = true; } } - if (attributeType == AttributeType.tablerow) { + if (attributeType == HtmlAttributeType.tablerow) { final regex = RegExp('[^0-9]'); final width = css['width']; if (width != null) { @@ -577,4 +562,4 @@ class HTMLTags { } } -enum AttributeType { table, tablerow, none } +enum HtmlAttributeType { table, tablerow, none } diff --git a/test/plugins/html/decoder/document_html_decoder_test.dart b/test/plugins/html/decoder/document_html_decoder_test.dart index 966530c48..1e9188bc6 100644 --- a/test/plugins/html/decoder/document_html_decoder_test.dart +++ b/test/plugins/html/decoder/document_html_decoder_test.dart @@ -37,8 +37,8 @@ const htmlTablejson = { "data": { "delta": [ {"insert": "'"} - ], - }, + ] + } }, { "type": "table", @@ -59,8 +59,8 @@ const htmlTablejson = { "data": { "colPosition": 0, "rowPosition": 0, - "height": 50.0, - "width": 60.0 + "height": 40.0, + "width": 80.0 } }, { @@ -81,8 +81,8 @@ const htmlTablejson = { "data": { "colPosition": 1, "rowPosition": 0, - "height": 50.0, - "width": 60.0 + "height": 40.0, + "width": 80.0 } }, { @@ -103,9 +103,9 @@ const htmlTablejson = { "data": { "colPosition": 0, "rowPosition": 1, - "height": 50.0, - "width": 60.0 - }, + "height": 40.0, + "width": 80.0 + } }, { "type": "table/cell", @@ -122,17 +122,17 @@ const htmlTablejson = { "data": { "colPosition": 1, "rowPosition": 1, - "height": 50.0, - "width": 60.0 + "height": 40.0, + "width": 80.0 } } ], "data": { "rowsLen": 2, "colsLen": 2, - "colDefaultWidth": 60, - "rowDefaultHeight": 50, - "colMinimumWidth": 30 + "colDefaultWidth": 80, + "rowDefaultHeight": 40, + "colMinimumWidth":40 } }, { diff --git a/test/plugins/html/encoder/parser/table_node_parser_test.dart b/test/plugins/html/encoder/parser/table_node_parser_test.dart new file mode 100644 index 000000000..ba7550693 --- /dev/null +++ b/test/plugins/html/encoder/parser/table_node_parser_test.dart @@ -0,0 +1,116 @@ +import 'package:appflowy_editor/appflowy_editor.dart'; +import 'package:appflowy_editor/src/editor/block_component/table_block_component/table_node.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() async { + List parser = [ + const HTMLTextNodeParser(), + const HTMLBulletedListNodeParser(), + const HTMLNumberedListNodeParser(), + const HTMLTodoListNodeParser(), + const HTMLQuoteNodeParser(), + const HTMLHeadingNodeParser(), + const HTMLImageNodeParser(), + const HtmlTableNodeParser() + ]; + group('html_image_node_parser.dart', () { + test('table node parser test', () { + final tableNode = TableNode.fromJson({ + 'type': TableBlockKeys.type, + 'data': { + TableBlockKeys.colsLen: 2, + TableBlockKeys.rowsLen: 2, + TableBlockKeys.colDefaultWidth: 60, + TableBlockKeys.rowDefaultHeight: 50, + TableBlockKeys.colMinimumWidth: 30, + }, + 'children': [ + { + 'type': TableCellBlockKeys.type, + 'data': { + TableCellBlockKeys.colPosition: 0, + TableCellBlockKeys.rowPosition: 0, + TableCellBlockKeys.width: 35, + }, + 'children': [ + { + 'type': 'heading', + 'data': { + 'level': 2, + 'delta': [ + {'insert': 'a'}, + ], + }, + } + ], + }, + { + 'type': TableCellBlockKeys.type, + 'data': { + TableCellBlockKeys.colPosition: 0, + TableCellBlockKeys.rowPosition: 1, + }, + 'children': [ + { + 'type': 'paragraph', + 'data': { + 'delta': [ + { + 'insert': 'b', + 'attributes': {'bold': true}, + } + ], + }, + } + ], + }, + { + 'type': TableCellBlockKeys.type, + 'data': { + TableCellBlockKeys.colPosition: 1, + TableCellBlockKeys.rowPosition: 0, + }, + 'children': [ + { + 'type': 'paragraph', + 'data': { + 'delta': [ + { + 'insert': 'c', + 'attributes': {'italic': true}, + } + ], + }, + } + ], + }, + { + 'type': TableCellBlockKeys.type, + 'data': { + TableCellBlockKeys.colPosition: 1, + TableCellBlockKeys.rowPosition: 1, + }, + 'children': [ + { + 'type': 'paragraph', + 'data': { + 'delta': [ + {'insert': 'd'}, + ], + }, + } + ], + } + ], + }); + + expect( + const HtmlTableNodeParser().transformNodeToHTMLString( + tableNode.node, + encodeParsers: parser, + ), + '''

a

c

b

d

''', + ); + }); + }); +} diff --git a/test/plugins/html/encoder/parser/text_node_parser_test.dart b/test/plugins/html/encoder/parser/text_node_parser_test.dart index 74f1f362c..d75aafaaa 100644 --- a/test/plugins/html/encoder/parser/text_node_parser_test.dart +++ b/test/plugins/html/encoder/parser/text_node_parser_test.dart @@ -1,5 +1,4 @@ import 'package:appflowy_editor/appflowy_editor.dart'; -import 'package:appflowy_editor/src/editor/block_component/table_block_component/table_node.dart'; import 'package:flutter_test/flutter_test.dart'; void main() async { @@ -242,110 +241,12 @@ void main() async { .toJson(), }, ); - expect( const HTMLTextNodeParser() .transformNodeToHTMLString(node, encodeParsers: parser), '''

Welcome to AppFlowy

''', ); }); - test('table node parser test', () { - final tableNode = TableNode.fromJson({ - 'type': TableBlockKeys.type, - 'data': { - TableBlockKeys.colsLen: 2, - TableBlockKeys.rowsLen: 2, - TableBlockKeys.colDefaultWidth: 60, - TableBlockKeys.rowDefaultHeight: 50, - TableBlockKeys.colMinimumWidth: 30 - }, - 'children': [ - { - 'type': TableCellBlockKeys.type, - 'data': { - TableCellBlockKeys.colPosition: 0, - TableCellBlockKeys.rowPosition: 0, - TableCellBlockKeys.width: 35 - }, - 'children': [ - { - 'type': 'heading', - 'data': { - 'level': 2, - 'delta': [ - {'insert': 'a'} - ] - } - } - ] - }, - { - 'type': TableCellBlockKeys.type, - 'data': { - TableCellBlockKeys.colPosition: 0, - TableCellBlockKeys.rowPosition: 1 - }, - 'children': [ - { - 'type': 'paragraph', - 'data': { - 'delta': [ - { - 'insert': 'b', - 'attributes': {'bold': true} - } - ] - } - } - ] - }, - { - 'type': TableCellBlockKeys.type, - 'data': { - TableCellBlockKeys.colPosition: 1, - TableCellBlockKeys.rowPosition: 0 - }, - 'children': [ - { - 'type': 'paragraph', - 'data': { - 'delta': [ - { - 'insert': 'c', - 'attributes': {'italic': true} - } - ] - } - } - ] - }, - { - 'type': TableCellBlockKeys.type, - 'data': { - TableCellBlockKeys.colPosition: 1, - TableCellBlockKeys.rowPosition: 1 - }, - 'children': [ - { - 'type': 'paragraph', - 'data': { - 'delta': [ - {'insert': 'd'} - ] - } - } - ] - } - ] - }); - expect( - const HtmlTableNodeParser().transformNodeToHTMLString( - tableNode.node, - encodeParsers: parser, - ), - '''

a

c

b

d

''', - ); - }); }); } From f8affaabe71fda535bd50aaf76bb411d95e0683b Mon Sep 17 00:00:00 2001 From: alihassan143 Date: Wed, 13 Sep 2023 14:42:25 +0500 Subject: [PATCH 3/4] feat: fix the test ran issues --- .../decoder/document_html_decoder_test.dart | 312 +++++++++--------- .../encoder/parser/text_node_parser_test.dart | 3 +- 2 files changed, 157 insertions(+), 158 deletions(-) diff --git a/test/plugins/html/decoder/document_html_decoder_test.dart b/test/plugins/html/decoder/document_html_decoder_test.dart index 1e9188bc6..58c48c717 100644 --- a/test/plugins/html/decoder/document_html_decoder_test.dart +++ b/test/plugins/html/decoder/document_html_decoder_test.dart @@ -36,9 +36,9 @@ const htmlTablejson = { "type": "paragraph", "data": { "delta": [ - {"insert": "'"} - ] - } + {"insert": "'"}, + ], + }, }, { "type": "table", @@ -50,18 +50,18 @@ const htmlTablejson = { "type": "heading", "data": { "delta": [ - {"insert": "a"} + {"insert": "a"}, ], - "level": 2 - } + "level": 2, + }, } ], "data": { "colPosition": 0, "rowPosition": 0, "height": 40.0, - "width": 80.0 - } + "width": 80.0, + }, }, { "type": "table/cell", @@ -74,16 +74,16 @@ const htmlTablejson = { "insert": "c", "attributes": {"italic": true}, } - ] - } + ], + }, } ], "data": { "colPosition": 1, "rowPosition": 0, "height": 40.0, - "width": 80.0 - } + "width": 80.0, + }, }, { "type": "table/cell", @@ -94,18 +94,18 @@ const htmlTablejson = { "delta": [ { "insert": "b", - "attributes": {"bold": true} + "attributes": {"bold": true}, } - ] - } + ], + }, } ], "data": { "colPosition": 0, "rowPosition": 1, "height": 40.0, - "width": 80.0 - } + "width": 80.0, + }, }, { "type": "table/cell", @@ -114,17 +114,17 @@ const htmlTablejson = { "type": "paragraph", "data": { "delta": [ - {"insert": "d"} - ] - } + {"insert": "d"}, + ], + }, } ], "data": { "colPosition": 1, "rowPosition": 1, "height": 40.0, - "width": 80.0 - } + "width": 80.0, + }, } ], "data": { @@ -132,19 +132,19 @@ const htmlTablejson = { "colsLen": 2, "colDefaultWidth": 80, "rowDefaultHeight": 40, - "colMinimumWidth":40 - } + "colMinimumWidth": 40, + }, }, { "type": "paragraph", "data": { "delta": [ - {"insert": "'"} - ] - } + {"insert": "'"}, + ], + }, } - ] - } + ], + }, }; const example = { @@ -156,9 +156,9 @@ const example = { 'data': { 'level': 1, 'delta': [ - {'insert': 'AppFlowyEditor'} - ] - } + {'insert': 'AppFlowyEditor'}, + ], + }, }, { 'type': 'heading', @@ -168,15 +168,15 @@ const example = { {'insert': '👋 '}, { 'insert': 'Welcome to', - 'attributes': {'bold': true} + 'attributes': {'bold': true}, }, {'insert': ' '}, { 'insert': 'AppFlowy Editor', - 'attributes': {'bold': true, 'italic': true} + 'attributes': {'bold': true, 'italic': true}, } - ] - } + ], + }, }, { 'type': 'paragraph', @@ -185,15 +185,15 @@ const example = { {'insert': 'AppFlowy Editor is a '}, { 'insert': 'highly customizable', - 'attributes': {'bold': true} + 'attributes': {'bold': true}, }, {'insert': ' '}, { 'insert': 'rich-text editor', - 'attributes': {'italic': true} + 'attributes': {'italic': true}, } - ] - } + ], + }, }, { 'type': 'paragraph', @@ -202,16 +202,16 @@ const example = { {'insert': ' '}, { 'insert': 'Here', - 'attributes': {'underline': true} + 'attributes': {'underline': true}, }, {'insert': ' is an example '}, { 'insert': 'your', - 'attributes': {'strikethrough': true} + 'attributes': {'strikethrough': true}, }, - {'insert': ' you can give a try'} - ] - } + {'insert': ' you can give a try'}, + ], + }, }, { 'type': 'paragraph', @@ -220,10 +220,10 @@ const example = { {'insert': ' '}, { 'insert': 'Span element', - 'attributes': {'bold': true, 'italic': true} + 'attributes': {'bold': true, 'italic': true}, } - ] - } + ], + }, }, { 'type': 'paragraph', @@ -232,10 +232,10 @@ const example = { {'insert': ' '}, { 'insert': 'Span element two', - 'attributes': {'underline': true} + 'attributes': {'underline': true}, } - ] - } + ], + }, }, { 'type': 'paragraph', @@ -244,10 +244,10 @@ const example = { {'insert': ' '}, { 'insert': 'Span element three', - 'attributes': {'bold': true, 'strikethrough': true} + 'attributes': {'bold': true, 'strikethrough': true}, } - ] - } + ], + }, }, { 'type': 'paragraph', @@ -256,75 +256,75 @@ const example = { {'insert': ' '}, { 'insert': 'This is an anchor tag!', - 'attributes': {'href': 'https://appflowy.io'} + 'attributes': {'href': 'https://appflowy.io'}, } - ] - } + ], + }, }, { 'type': 'heading', 'data': { 'level': 3, 'delta': [ - {'insert': 'Features!'} - ] - } + {'insert': 'Features!'}, + ], + }, }, { 'type': 'bulleted_list', 'data': { 'delta': [ - {'insert': '[x] Customizable'} - ] - } + {'insert': '[x] Customizable'}, + ], + }, }, { 'type': 'bulleted_list', 'data': { 'delta': [ - {'insert': '[x] Test-covered'} - ] - } + {'insert': '[x] Test-covered'}, + ], + }, }, { 'type': 'bulleted_list', 'data': { 'delta': [ - {'insert': '[ ] more to come!'} - ] - } + {'insert': '[ ] more to come!'}, + ], + }, }, { 'type': 'bulleted_list', 'data': { 'delta': [ - {'insert': 'First item'} - ] - } + {'insert': 'First item'}, + ], + }, }, { 'type': 'bulleted_list', 'data': { 'delta': [ - {'insert': 'Second item'} - ] - } + {'insert': 'Second item'}, + ], + }, }, { 'type': 'bulleted_list', 'data': { 'delta': [ - {'insert': 'List element'} - ] - } + {'insert': 'List element'}, + ], + }, }, { 'type': 'quote', 'data': { 'delta': [ - {'insert': 'This is a quote!'} - ] - } + {'insert': 'This is a quote!'}, + ], + }, }, { 'type': 'paragraph', @@ -332,10 +332,10 @@ const example = { 'delta': [ { 'insert': ' Code block', - 'attributes': {'code': true} + 'attributes': {'code': true}, } - ] - } + ], + }, }, { 'type': 'paragraph', @@ -344,10 +344,10 @@ const example = { {'insert': ' '}, { 'insert': 'Italic one', - 'attributes': {'italic': true} + 'attributes': {'italic': true}, } - ] - } + ], + }, }, { 'type': 'paragraph', @@ -356,10 +356,10 @@ const example = { {'insert': ' '}, { 'insert': 'Italic two', - 'attributes': {'italic': true} + 'attributes': {'italic': true}, } - ] - } + ], + }, }, { 'type': 'paragraph', @@ -368,10 +368,10 @@ const example = { {'insert': ' '}, { 'insert': 'Bold tag', - 'attributes': {'bold': true} + 'attributes': {'bold': true}, } - ] - } + ], + }, }, { 'type': 'paragraph', @@ -380,20 +380,20 @@ const example = { {'insert': 'You can also use '}, { 'insert': 'AppFlowy Editor', - 'attributes': {'bold': true, 'italic': true} + 'attributes': {'bold': true, 'italic': true}, }, - {'insert': ' as a component to build your own app. '} - ] - } + {'insert': ' as a component to build your own app. '}, + ], + }, }, { 'type': 'heading', 'data': { 'level': 3, 'delta': [ - {'insert': 'Awesome features'} - ] - } + {'insert': 'Awesome features'}, + ], + }, }, { 'type': 'paragraph', @@ -401,21 +401,21 @@ const example = { 'delta': [ { 'insert': - 'If you have questions or feedback, please submit an issue on Github or join the community along with 1000+ builders!' + 'If you have questions or feedback, please submit an issue on Github or join the community along with 1000+ builders!', } - ] - } + ], + }, }, { 'type': 'paragraph', - 'data': {'delta': []} + 'data': {'delta': []}, }, { 'type': 'paragraph', - 'data': {'delta': []} + 'data': {'delta': []}, } - ] - } + ], + }, }; const nestedHTML = '''

Welcome to the playground

In case you were wondering what the black box at the bottom is – it's the debug view, showing the current state of the editor. You can disable it by pressing on the settings control in the bottom-left of your screen and toggling the debug view setting. The playground is a demo environment built with @lexical/react. Try typing in some text with different formats.

Make sure to check out the various plugins in the toolbar. You can also use #hashtags or @-mentions too!

If you'd like to find out more about Lexical, you can:

  • Playground code can be found here.
  • Playground code can be found here.

Lastly, we're constantly adding cool new features to this playground. So make sure you check back here when you next get a chance 🙂.

'''; @@ -428,9 +428,9 @@ const nestedDelta = { 'data': { 'level': 1, 'delta': [ - {'insert': 'Welcome to the playground'} - ] - } + {'insert': 'Welcome to the playground'}, + ], + }, }, { 'type': 'quote', @@ -438,11 +438,11 @@ const nestedDelta = { 'delta': [ { 'insert': - 'In case you were wondering what the black box at the bottom is – it\'s the debug view, showing the current state of the editor. You can disable it by pressing on the settings control in the bottom-left of your screen and toggling the debug view setting. The playground is a demo environment built with ' + 'In case you were wondering what the black box at the bottom is – it\'s the debug view, showing the current state of the editor. You can disable it by pressing on the settings control in the bottom-left of your screen and toggling the debug view setting. The playground is a demo environment built with ', }, { 'insert': '@lexical/react', - 'attributes': {'code': true} + 'attributes': {'code': true}, }, {'insert': '. Try typing in '}, { @@ -450,24 +450,24 @@ const nestedDelta = { 'attributes': { 'bold': true, "italic": true, - 'href': 'https://appflowy.io' - } + 'href': 'https://appflowy.io', + }, }, {'insert': ' with '}, { 'insert': 'different', - 'attributes': {'italic': true} + 'attributes': {'italic': true}, }, - {'insert': ' formats.'} - ] - } + {'insert': ' formats.'}, + ], + }, }, { 'type': 'image', 'data': { 'url': 'https://richtexteditor.com/images/editor-image.png', 'align': 'center', - } + }, }, { 'type': 'paragraph', @@ -475,14 +475,14 @@ const nestedDelta = { 'delta': [ { 'insert': - 'Make sure to check out the various plugins in the toolbar. You can also use #hashtags or @-mentions too!' + 'Make sure to check out the various plugins in the toolbar. You can also use #hashtags or @-mentions too!', } - ] - } + ], + }, }, { 'type': 'paragraph', - 'data': {'delta': []} + 'data': {'delta': []}, }, { 'type': 'paragraph', @@ -490,10 +490,10 @@ const nestedDelta = { 'delta': [ { 'insert': - 'If you\'d like to find out more about Lexical, you can:' + 'If you\'d like to find out more about Lexical, you can:', } - ] - } + ], + }, }, { 'type': 'bulleted_list', @@ -502,11 +502,11 @@ const nestedDelta = { {'insert': 'Visit the '}, { 'insert': 'Lexical website', - 'attributes': {'href': 'https://lexical.dev/'} + 'attributes': {'href': 'https://lexical.dev/'}, }, - {'insert': ' for documentation and more information.'} - ] - } + {'insert': ' for documentation and more information.'}, + ], + }, }, { 'type': 'bulleted_list', @@ -516,10 +516,10 @@ const nestedDelta = { 'data': { 'url': 'https://richtexteditor.com/images/editor-image.png', 'align': 'center', - } + }, } ], - 'data': {'delta': []} + 'data': {'delta': []}, }, { 'type': 'bulleted_list', @@ -528,11 +528,11 @@ const nestedDelta = { {'insert': 'Check out the code on our '}, { 'insert': 'GitHub repository', - 'attributes': {'href': 'https://github.com/facebook/lexical'} + 'attributes': {'href': 'https://github.com/facebook/lexical'}, }, - {'insert': '.'} - ] - } + {'insert': '.'}, + ], + }, }, { 'type': 'bulleted_list', @@ -543,12 +543,12 @@ const nestedDelta = { 'insert': 'here', 'attributes': { 'href': - 'https://github.com/facebook/lexical/tree/main/packages/lexical-playground' - } + 'https://github.com/facebook/lexical/tree/main/packages/lexical-playground', + }, }, - {'insert': '.'} - ] - } + {'insert': '.'}, + ], + }, }, { 'type': 'bulleted_list', @@ -557,11 +557,11 @@ const nestedDelta = { {'insert': 'Join our '}, { 'insert': 'Discord Server', - 'attributes': {'href': 'https://discord.com/invite/KmG4wQnnD9'} + 'attributes': {'href': 'https://discord.com/invite/KmG4wQnnD9'}, }, - {'insert': ' and chat with the team.'} - ] - } + {'insert': ' and chat with the team.'}, + ], + }, }, { 'type': 'bulleted_list', @@ -572,12 +572,12 @@ const nestedDelta = { 'insert': 'here', 'attributes': { 'href': - 'https://github.com/facebook/lexical/tree/main/packages/lexical-playground' - } + 'https://github.com/facebook/lexical/tree/main/packages/lexical-playground', + }, }, - {'insert': '.'} - ] - } + {'insert': '.'}, + ], + }, }, { 'type': 'paragraph', @@ -585,15 +585,15 @@ const nestedDelta = { 'delta': [ { 'insert': - 'Lastly, we\'re constantly adding cool new features to this playground. So make sure you check back here when you next get a chance 🙂.' + 'Lastly, we\'re constantly adding cool new features to this playground. So make sure you check back here when you next get a chance 🙂.', } - ] - } + ], + }, }, { 'type': 'paragraph', - 'data': {'delta': []} + 'data': {'delta': []}, } - ] - } + ], + }, }; diff --git a/test/plugins/html/encoder/parser/text_node_parser_test.dart b/test/plugins/html/encoder/parser/text_node_parser_test.dart index d75aafaaa..5a9f2be7b 100644 --- a/test/plugins/html/encoder/parser/text_node_parser_test.dart +++ b/test/plugins/html/encoder/parser/text_node_parser_test.dart @@ -10,7 +10,7 @@ void main() async { const HTMLQuoteNodeParser(), const HTMLHeadingNodeParser(), const HTMLImageNodeParser(), - const HtmlTableNodeParser() + const HtmlTableNodeParser(), ]; group('html_text_node_parser.dart', () { const text = 'Welcome to AppFlowy'; @@ -247,6 +247,5 @@ void main() async { '''

Welcome to AppFlowy

''', ); }); - }); } From 5b2c02f04567cb18ab67e8e49b2106d10d5cbab7 Mon Sep 17 00:00:00 2001 From: alihassan143 Date: Wed, 20 Sep 2023 15:43:54 +0500 Subject: [PATCH 4/4] fix: removed unused code --- .../plugins/html/html_document_decoder.dart | 75 +++++++------------ 1 file changed, 26 insertions(+), 49 deletions(-) diff --git a/lib/src/plugins/html/html_document_decoder.dart b/lib/src/plugins/html/html_document_decoder.dart index a52c873db..cb8ed87d3 100644 --- a/lib/src/plugins/html/html_document_decoder.dart +++ b/lib/src/plugins/html/html_document_decoder.dart @@ -379,9 +379,8 @@ class DocumentHTMLDecoder extends Converter { } Attributes? _getDeltaAttributesFromHTMLAttributes( - LinkedHashMap htmlAttributes, { - HtmlAttributeType attributeType = HtmlAttributeType.none, - }) { + LinkedHashMap htmlAttributes, + ) { final Attributes attributes = {}; final style = htmlAttributes['style']; final css = _getCssFromString(style); @@ -416,58 +415,38 @@ class DocumentHTMLDecoder extends Converter { } } } - if (attributeType == HtmlAttributeType.none) { - // background color - final backgroundColor = css['background-color']; - if (backgroundColor != null) { - final highlightColor = backgroundColor.tryToColor()?.toHex(); - if (highlightColor != null) { - attributes[AppFlowyRichTextKeys.highlightColor] = highlightColor; - } - } - // background - final background = css['background']; - if (background != null) { - final highlightColor = background.tryToColor()?.toHex(); - if (highlightColor != null) { - attributes[AppFlowyRichTextKeys.highlightColor] = highlightColor; - } + // background color + final backgroundColor = css['background-color']; + if (backgroundColor != null) { + final highlightColor = backgroundColor.tryToColor()?.toHex(); + if (highlightColor != null) { + attributes[AppFlowyRichTextKeys.highlightColor] = highlightColor; } + } - // color - final color = css['color']; - if (color != null) { - final textColor = color.tryToColor()?.toHex(); - if (textColor != null) { - attributes[AppFlowyRichTextKeys.textColor] = textColor; - } + // background + final background = css['background']; + if (background != null) { + final highlightColor = background.tryToColor()?.toHex(); + if (highlightColor != null) { + attributes[AppFlowyRichTextKeys.highlightColor] = highlightColor; } + } - // italic - final fontStyle = css['font-style']; - if (fontStyle == 'italic') { - attributes[AppFlowyRichTextKeys.italic] = true; + // color + final color = css['color']; + if (color != null) { + final textColor = color.tryToColor()?.toHex(); + if (textColor != null) { + attributes[AppFlowyRichTextKeys.textColor] = textColor; } } - if (attributeType == HtmlAttributeType.tablerow) { - final regex = RegExp('[^0-9]'); - final width = css['width']; - if (width != null) { - String rowWidth = width.toString(); - rowWidth = rowWidth.replaceAll(regex, ''); - int newrowWidth = int.parse(rowWidth); - - attributes[TableCellBlockKeys.width] = newrowWidth; - } - final height = css['height']; - if (height != null) { - String rowHeight = height.toString(); - rowHeight = rowHeight.replaceAll(regex, ''); - int newhieght = int.parse(rowHeight); - attributes[TableCellBlockKeys.height] = newhieght; - } + // italic + final fontStyle = css['font-style']; + if (fontStyle == 'italic') { + attributes[AppFlowyRichTextKeys.italic] = true; } return attributes.isEmpty ? null : attributes; @@ -561,5 +540,3 @@ class HTMLTags { tag == blockQuote; } } - -enum HtmlAttributeType { table, tablerow, none }