From e12d64e6c4f1673a84fc729cc74287480d6f34c6 Mon Sep 17 00:00:00 2001
From: Cat <114286961+CatHood0@users.noreply.github.com>
Date: Sun, 7 Jul 2024 16:56:25 -0400
Subject: [PATCH] Feat: New way to get Delta from HTML inputs (#1984)

---
 lib/src/models/documents/delta_x.dart | 30 ++--------
 lib/src/utils/delta_x_utils.dart      | 80 ---------------------------
 pubspec.yaml                          |  1 +
 test/utils/delta_x_test.dart          |  1 +
 4 files changed, 7 insertions(+), 105 deletions(-)
 delete mode 100644 lib/src/utils/delta_x_utils.dart

diff --git a/lib/src/models/documents/delta_x.dart b/lib/src/models/documents/delta_x.dart
index 30d03594..d30e3f4d 100644
--- a/lib/src/models/documents/delta_x.dart
+++ b/lib/src/models/documents/delta_x.dart
@@ -1,9 +1,8 @@
-import 'package:html2md/html2md.dart' as html2md;
+import 'package:flutter_quill_delta_from_html/flutter_quill_delta_from_html.dart';
 import 'package:markdown/markdown.dart' as md;
 import 'package:meta/meta.dart';
 import '../../../markdown_quill.dart';
 import '../../../quill_delta.dart';
-import '../../utils/delta_x_utils.dart';
 
 @immutable
 @experimental
@@ -16,34 +15,15 @@ class DeltaX {
   /// used for **production applications**.
   @experimental
   static Delta fromMarkdown(String markdownText) {
-    final mdDocument = md.Document(
-      encodeHtml: false,
-      inlineSyntaxes: [UnderlineSyntax(), VideoSyntax()],
-    );
+    final mdDocument = md.Document(encodeHtml: false);
     final mdToDelta = MarkdownToDelta(markdownDocument: mdDocument);
     return mdToDelta.convert(markdownText);
   }
 
   /// Convert the HTML Raw string to [Delta]
-  ///
-  /// It will run using the following steps:
-  ///
-  /// 1. Convert the html to markdown string using `html2md` package
-  /// 2. Convert the markdown string to [Delta] using [fromMarkdown]
-  ///
-  /// This api is **experimental** and designed to be used **internally** and shouldn't
-  /// used for **production applications**.
-  ///
   @experimental
-  static Delta fromHtml(String htmlText) {
-    final markdownText = html2md.convert(
-      htmlText,
-      rules: [underlineRule, videoRule],
-      styleOptions: {'emDelimiter': '*'},
-    ).replaceAll(
-      'unsafe:',
-      '',
-    );
-    return fromMarkdown(markdownText);
+  static Delta fromHtml(String htmlText, {List<CustomHtmlPart>? customBlocks}) {
+    final htmlToDelta = HtmlToDelta(customBlocks: customBlocks);
+    return htmlToDelta.convert(htmlText);
   }
 }
diff --git a/lib/src/utils/delta_x_utils.dart b/lib/src/utils/delta_x_utils.dart
deleted file mode 100644
index 497fa29b..00000000
--- a/lib/src/utils/delta_x_utils.dart
+++ /dev/null
@@ -1,80 +0,0 @@
-import 'package:html2md/html2md.dart' as hmd;
-import 'package:markdown/markdown.dart' as md;
-
-// [ character
-const int _$lbracket = 0x5B;
-final RegExp _youtubeVideoUrlValidator = RegExp(
-    r'^((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube\.com|youtu.be))(\/(?:[\w\-]+\?v=|embed\/|v\/)?)([\w\-]+)(\S+)?$');
-
-///Local syntax implementation for underline
-class UnderlineSyntax extends md.DelimiterSyntax {
-  UnderlineSyntax()
-      : super(
-          '<und>',
-          requiresDelimiterRun: true,
-          allowIntraWord: true,
-          tags: [md.DelimiterTag('u', 5)],
-        );
-}
-
-class VideoSyntax extends md.LinkSyntax {
-  VideoSyntax({super.linkResolver})
-      : super(
-          pattern: r'\[!\[',
-          startCharacter: _$lbracket,
-        );
-
-  @override
-  md.Element createNode(
-    String destination,
-    String? title, {
-    required List<md.Node> Function() getChildren,
-  }) {
-    final element = md.Element.empty('video');
-    element.attributes['src'] = destination;
-    if (title != null && title.isNotEmpty) {
-      element.attributes['title'] = title;
-    }
-    return element;
-  }
-}
-
-///This rule avoid the default converter from html2md ignore underline tag for <u> or <ins>
-final underlineRule =
-    hmd.Rule('underline', filters: ['u', 'ins'], replacement: (content, node) {
-  //Is used a local underline implemenation since markdown just use underline with html tags
-  return '<und>$content<und>';
-});
-final videoRule = hmd.Rule('video', filters: ['iframe', 'video'],
-    replacement: (content, node) {
-  //This need to be verified by a different way of iframes, since video tag can have <source> children
-  if (node.nodeName == 'video') {
-    //if has children then just will be taked as different part of code
-    if (node.childNum > 0) {
-      var child = node.firstChild!;
-      var src = child.getAttribute('src');
-      if (src == null) {
-        child = node.childNodes().last;
-        src = child.getAttribute('src');
-      }
-      if (!_youtubeVideoUrlValidator.hasMatch(src ?? '')) {
-        return '<video>${child.outerHTML}</video>';
-      }
-      return '[![$content]($src)';
-    }
-    final src = node.getAttribute('src');
-    if (src == null || !_youtubeVideoUrlValidator.hasMatch(src)) {
-      return node.outerHTML;
-    }
-    return '[![$content]($src)';
-  }
-  //by now, we can only access to src
-  final src = node.getAttribute('src');
-  //if the source is null or is not valid youtube url, then just return the html instead remove it
-  //by now is only available validation for youtube videos
-  if (src == null || !_youtubeVideoUrlValidator.hasMatch(src)) {
-    return node.outerHTML;
-  }
-  final title = node.getAttribute('title');
-  return '[![$title]($src)';
-});
diff --git a/pubspec.yaml b/pubspec.yaml
index 01d10348..5e730ad3 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -54,6 +54,7 @@ dependencies:
   flutter_colorpicker: ^1.1.0
 
   # For converting HTML to Quill delta
+  flutter_quill_delta_from_html: ^1.1.8
   markdown: ^7.2.1
   html2md: ^1.3.1
   charcode: ^1.3.1
diff --git a/test/utils/delta_x_test.dart b/test/utils/delta_x_test.dart
index dc0bfa1d..e4367da8 100644
--- a/test/utils/delta_x_test.dart
+++ b/test/utils/delta_x_test.dart
@@ -33,6 +33,7 @@ void main() {
   ]);
 
   final expectedDeltaVideo = Delta.fromOperations([
+    Operation.insert('\n'),
     Operation.insert({'video': 'https://www.youtube.com/embed/dQw4w9WgXcQ'}),
     Operation.insert('\n'),
   ]);