diff --git a/lib/parser/default_html_to_ops.dart b/lib/parser/default_html_to_ops.dart index d1a2b5a..4757f0c 100644 --- a/lib/parser/default_html_to_ops.dart +++ b/lib/parser/default_html_to_ops.dart @@ -2,9 +2,9 @@ import 'package:dart_quill_delta/dart_quill_delta.dart'; import 'package:flutter_quill_delta_from_html/parser/extensions/node_ext.dart'; import 'package:flutter_quill_delta_from_html/parser/html_to_operation.dart'; import 'package:flutter_quill_delta_from_html/parser/html_utils.dart'; +import 'package:flutter_quill_delta_from_html/parser/node_processor.dart'; import 'package:flutter_quill_delta_from_html/parser/typedef/typedefs.dart'; import 'package:html/dom.dart' as dom; -import 'package:flutter_quill_delta_from_html/parser/node_processor.dart'; /// Default implementation of `HtmlOperations` for converting common HTML to Delta operations. /// @@ -59,10 +59,19 @@ class DefaultHtmlToOperations extends HtmlOperations { } inlineAttributes.addAll(styleAttributes); } + + // Check if paragraph is inside a list item + final isInsideListItem = element.parent?.localName == 'li'; + final nodes = element.nodes; //this store into all nodes into a paragraph, and //ensure getting all attributes or tags into a paragraph for (final node in nodes) { + // Skip
tags if inside a list item + if (isInsideListItem && node is dom.Element && node.isBreakLine) { + continue; + } + processNode( node, inlineAttributes, @@ -75,6 +84,12 @@ class DefaultHtmlToOperations extends HtmlOperations { if (blockAttributes.isNotEmpty) { blockAttributes.removeWhere((key, value) => value == null); delta.insert('\n', blockAttributes); + } else { + // Insert newline if parent is not a list, OR if parent is a list but current element is not the last child of
  • + final parent = element.parent; + if (parent?.isList == false) { + delta.insert('\n'); + } } return delta.toList(); @@ -239,6 +254,10 @@ class DefaultHtmlToOperations extends HtmlOperations { final List items = element.children.where((child) => child.localName == 'li').toList(); + final startAttr = element.attributes["start"]; + if (startAttr != null) { + attributes["start"] = startAttr; + } if (tagName == 'ul') { attributes['list'] = 'bullet'; } else if (tagName == 'ol') { diff --git a/lib/parser/html_to_delta.dart b/lib/parser/html_to_delta.dart index b5734e5..18cc6d5 100644 --- a/lib/parser/html_to_delta.dart +++ b/lib/parser/html_to_delta.dart @@ -170,7 +170,8 @@ class HtmlToDelta { //ensure insert a new line at the final to avoid any conflict with assertions if (delta.isNotEmpty) { final Operation lastOpdata = delta.last; - final bool lastDataIsNotNewLine = lastOpdata.data.toString() != '\n'; + final bool lastDataIsNotNewLine = lastOpdata.data.toString() != '\n' && + !lastOpdata.data.toString().endsWith('\n'); final bool hasAttributes = lastOpdata.attributes != null; if (lastDataIsNotNewLine && hasAttributes || lastDataIsNotNewLine || diff --git a/lib/parser/node_processor.dart b/lib/parser/node_processor.dart index 5862fe6..5d8f688 100644 --- a/lib/parser/node_processor.dart +++ b/lib/parser/node_processor.dart @@ -1,5 +1,6 @@ import 'package:dart_quill_delta/dart_quill_delta.dart'; import 'package:flutter_quill_delta_from_html/flutter_quill_delta_from_html.dart'; +import 'package:flutter_quill_delta_from_html/parser/default_html_to_ops.dart'; import 'package:html/dom.dart' as dom; /// Processes a DOM [node], converting it into Quill Delta operations. @@ -21,15 +22,14 @@ import 'package:html/dom.dart' as dom; /// processNode(htmlNode, {}, delta); /// print(delta.toJson()); // Output: [{"insert": "Hello, "}, {"insert": "World", "attributes": {"italic": true, "bold": true}}, {"insert": "!"}] /// ``` -void processNode( - dom.Node node, - Map attributes, - Delta delta, { - bool addSpanAttrs = false, - List? customBlocks, - List? removeTheseAttributesFromSpan, - CSSVarible? onDetectLineheightCssVariable, -}) { +void processNode(dom.Node node, + Map attributes, + Delta delta, { + bool addSpanAttrs = false, + List? customBlocks, + List? removeTheseAttributesFromSpan, + CSSVarible? onDetectLineheightCssVariable, + }) { if (node is dom.Text) { delta.insert(node.text, attributes.isEmpty ? null : attributes); } else if (node is dom.Element) { @@ -42,20 +42,33 @@ void processNode( if (node.isStrike) newAttributes['strike'] = true; if (node.isSubscript) newAttributes['script'] = 'sub'; if (node.isSuperscript) newAttributes['script'] = 'super'; + bool handledByCustomBlock = false; // Use custom block definitions if provided if (customBlocks != null && customBlocks.isNotEmpty) { for (var customBlock in customBlocks) { if (customBlock.matches(node)) { final operations = - customBlock.convert(node, currentAttributes: newAttributes); + customBlock.convert(node, currentAttributes: newAttributes); operations.forEach((Operation op) { delta.insert(op.data, op.attributes); }); + handledByCustomBlock = true; continue; } } - } else { + } + + if (!handledByCustomBlock) { + final htmlOperations =DefaultHtmlToOperations(onDetectLineheightCssVariable); + if(node.isCodeBlock){ + + final operations=htmlOperations.codeblockToOp(node); + operations.forEach((Operation op) { + delta.insert(op.data, op.attributes); + }); + return; + } // Handle tags if (node.isSpan) { final spanAttributes = parseStyleAttribute( @@ -77,6 +90,7 @@ void processNode( } } + // Handle tags if (node.isImg) { final String src = node.attributes['src'] ?? ''; @@ -89,11 +103,11 @@ void processNode( styles.isEmpty ? null : { - 'style': attributes.entries - .map((entry) => '${entry.key}:${entry.value}') - .toList() - .join(';'), - }, + 'style': attributes.entries + .map((entry) => '${entry.key}:${entry.value}') + .toList() + .join(';'), + }, ); } }