Sub6Resources / flutter_html

A Flutter widget for rendering static html as Flutter widgets (Will render over 80 different html tags!)
https://pub.dev/packages/flutter_html
MIT License
1.77k stars 838 forks source link

Nest other elements in `<ruby>` #968

Closed AlienKevin closed 2 years ago

AlienKevin commented 2 years ago

Describe your feature request

I'm making a Cantonese dictionary and would love some support for nesting bold text (<b>) and linked ruby section (<a><ruby>...</ruby></a>) in <ruby>. Here's a sample use case:

<ruby>
<b>中</b><rt>zung1</rt>
<b>秋</b><rt>cau1</rt>
<b>節</b><rt>zit3</rt>
嗰<rt>go2</rt>
陣<rt>zan6</rt>
<a href="燙火膏">
    <ruby>
    燙<rt>tong3</rt>
    火<rt>fo2</rt>
    膏<rt>gou1</rt>
    </ruby>
</a>
<rt></rt>
特<rt>dak6</rt>
別<rt>bit6</rt>
好<rt>hou2</rt>
賣<rt>maai6</rt>
。<rt></rt>
</ruby>

which would display as:

example ruby

version

flutter_html: 2.2.1
AlienKevin commented 2 years ago

I implemented a simple temporary workaround for the <b> tag by adding a textStyle attribute. I believe that a generalized version that can handle <i> and even <a> tags would replace the textNode with an arbitrary html element that is parsed and rendered. Using this method, we should be able to even embed <ruby> elements recursively inside another <ruby> element.

Widget toWidget(RenderContext context) {
    String? textNode;
    TextStyle? textStyle;
    List<Widget> widgets = <Widget>[];
    ...
    context.tree.children.forEach((c) {
      if (c is TextContentElement) {
        textNode = c.text;
        textStyle = null;
      } else if (c.name == "b") {
        textNode = c.element!.innerHtml;
        textStyle = TextStyle(
          fontWeight: FontWeight.bold,
        );
      } else if (c.name == "rt" && textNode != null) {
        final widget = Stack(
          ...
            ContainerSpan(
                newContext: context,
                style: context.style,
                child: Text(textNode!.trim(),
                    style: context.style.generateTextStyle().merge(textStyle)),
            ),
          ],
        );
        widgets.add(widget);
      }
    });
AlienKevin commented 2 years ago

@tneotia @erickok Thanks for the fix! Embedding links with rubies inside another ruby is now working. However, the components are not vertically aligned:

<ruby class="clause">
A<rt>ei1</rt>
B<rt>bi1</rt>
<a href="CD">
<ruby>
C<rt>si1</rt>
D<rt>di1</rt>
</ruby>
</a><rt></rt>
E<rt>ji1</rt>
F<rt>e1 fu4</rt>
</ruby>
not vertically aligned ruby components