flutter-quill icon indicating copy to clipboard operation
flutter-quill copied to clipboard

[Request] Please add raw html string to initialize at controller

Open paraslamsong opened this issue 2 years ago • 8 comments

Faced the problem to use html string but the package is not allowing to use html string as input.

paraslamsong avatar Feb 14 '23 12:02 paraslamsong

For now the solution is


 _controller.document = quill.Document.fromJson(
        jsonDecode(markdownToDelta(html2md.convert(htmlString))),
      );

With the use of other packages, html2md and delta_markdown

paraslamsong avatar Feb 14 '23 13:02 paraslamsong

The problem with converting HTML to Markdown is that we lose all the following properties:

  • Background Color
  • Color
  • Font
  • Size
  • Strikethrough
  • Superscript/Subscript
  • Underline
  • Text Alignment
  • Text Direction
  • Formula
  • Video

mmasdivins avatar Feb 22 '23 11:02 mmasdivins

You can write your own converter from HTML to Delta. It works for me

baoletrangia avatar Jun 23 '23 09:06 baoletrangia

The problem with converting HTML to Markdown is that we lose all the following properties:

  • Background Color
  • Color
  • Font
  • Size
  • Strikethrough
  • Superscript/Subscript
  • Underline
  • Text Alignment
  • Text Direction
  • Formula
  • Video

You can use my html to Delta converter i wrote.


class HtmlToDeltaConverter {
  static const _COLOR_PATTERN = r'color: rgb\((\d+), (\d+), (\d+)\);';

  static quill.Delta _parseInlineStyles(htmlDom.Element element) {
    var delta = quill.Delta();

    for (final node in element.nodes) {
      final attributes = _parseElementStyles(element);

      if (node is htmlDom.Text) {
        delta.insert(node.text, attributes);
      }else if (node is htmlDom.Element && node.localName == 'img') {
        final src = node.attributes['src'];
        if (src != null) {
          delta..insert({'image': src});
        }
      } else if (node is htmlDom.Element) {
        delta = delta.concat(_parseInlineStyles(node));
      }

    }

    return delta;
  }

  static Map<String, dynamic> _parseElementStyles(htmlDom.Element element) {
    Map<String, dynamic> attributes = {};

    if (element.localName == 'strong') attributes['bold'] = true;
    if (element.localName == 'em') attributes['italic'] = true;
    if (element.localName == 'u') attributes['underline'] = true;
    if (element.localName == 'del') attributes['strike'] = true;

    final style = element.attributes['style'];
    if (style != null) {
      final colorValue = _parseColorFromStyle(style);
      if (colorValue != null) attributes['color'] = colorValue;

      final bgColorValue = _parseBackgroundColorFromStyle(style);
      if (bgColorValue != null) attributes['background'] = bgColorValue;
    }

    return attributes;
  }

  static String? _parseColorFromStyle(String style) {
    if (RegExp(r'(^|\s)color:(\s|$)').hasMatch(style)) {
      return _parseRgbColorFromMatch(RegExp(_COLOR_PATTERN).firstMatch(style));
    }
    return null;
  }

  static String? _parseBackgroundColorFromStyle(String style) {
    if (RegExp(r'(^|\s)background-color:(\s|$)').hasMatch(style)) {
      return _parseRgbColorFromMatch(RegExp(_COLOR_PATTERN).firstMatch(style));
    }
    return null;
  }

  static String? _parseRgbColorFromMatch(RegExpMatch? colorMatch) {
    if (colorMatch != null) {
      try {
        final red = int.parse(colorMatch.group(1)!);
        final green = int.parse(colorMatch.group(2)!);
        final blue = int.parse(colorMatch.group(3)!);
        return '#${red.toRadixString(16).padLeft(2, '0')}${green.toRadixString(16).padLeft(2, '0')}${blue.toRadixString(16).padLeft(2, '0')}';
      } catch (e) {
        debugPrintStack(label: e.toString());
      }
    }
    return null;
  }

  static quill.Delta htmlToDelta(String html) {
    final document = htmlParse.parse(html);
    var delta = quill.Delta();

    for (final node in document.body?.nodes ?? []) {
      if (node is htmlDom.Element) {
        switch (node.localName) {
          case 'p':
            delta = delta.concat(_parseInlineStyles(node))..insert('\n');
            break;
          case 'br':
            delta..insert('\n');
            break;
        }
      }
    }

    return html.isNotEmpty ? delta : quill.Delta()..insert('\n');
  }
}

Using the сonverter:

@override
 void initState() {
   var delta = HtmlToDeltaConverter.htmlToDelta(widget.htmlString);

   _controller = quill.QuillController(
     document: quill.Document.fromDelta(delta),
     selection: TextSelection.collapsed(offset: 0),
   );
   
   super.initState();
 }

YanusScevola avatar Aug 16 '23 21:08 YanusScevola

I tried your converter with the following html:

<div class="Section0">
<p style="text-align:left;page-break-inside:auto;page-break-after:auto;page-break-before:avoid;line-height:normal;margin-top:0pt;margin-bottom:0pt;margin-left:0pt;text-indent:0pt;margin-right:0pt;border-top-style:hidden;border-left-style:hidden;border-right-style:hidden;border-bottom-style:hidden;">
<span lang="en-US" style="font-family:Arial;font-size: 16px;text-transform:none;font-weight:normal;font-style:normal;font-variant:normal;text-decoration: none;">Some text</span>
</p>
</div>

And it didn't work. Also which packages are you using for htmlDom and htmlParser? I used the following:

import 'package:html/parser.dart' as htmlParse;
import 'package:html/dom.dart' as htmlDom;

mmasdivins avatar Aug 24 '23 07:08 mmasdivins

Thank you for the report, we will take a look at this soon.

EchoEllet avatar Nov 08 '23 18:11 EchoEllet

Reopened because the converter is experimental and not perfect at all and it used only for pasting contents from external websites

EchoEllet avatar Dec 27 '23 10:12 EchoEllet

将HTML转换为Markdown的问题是,我们丢失了以下所有属性:

  • 背景颜色
  • 颜色
  • 字体
  • 尺寸
  • 罢工
  • 上标/下标
  • 下划线
  • 文本对齐
  • 文本方向
  • 公式
  • 视频

Has this problem been solved? How was it solved?

wahkim avatar May 06 '24 07:05 wahkim