flutter_widget_from_html icon indicating copy to clipboard operation
flutter_widget_from_html copied to clipboard

How to Add Read More/Read Less functionality

Open davie1989 opened this issue 3 years ago • 3 comments

Use case

This package is great. It would be the only package one will need if it has read more / read less functionality. Since adding read more functionality is always likely to happen as far as rendering html text is concerned.

Proposal

I want to use this package to render html content on my flutter app. And some of my contents can be quite long. So, it will make sense to enable read more /read less functionality. Does this package have such functionality or any idea how to add such functionality to this package?

Thank you.

davie1989 avatar Mar 16 '23 01:03 davie1989

This is where a widget factory would help, where you listen to specific classes and put the content from them into an appropriate collapse widget.

Our accordion widget factory is doing something similar. The CustomCollapsible just shows the header and if not collapsed even the content. It's possible to show the content on tap:

class CustomWidgetFactory extends WidgetFactory {
  @override
  void parse(BuildMetadata meta) {
    final dom.Element element = meta.element;

    if (element.classes.contains('accordion-section')) {
      Widget? header;
      bool initialCollapsed = true;

      meta.register(
        BuildOp(
          onChild: (collapseMeta) {
            final dom.Element collapseElement = collapseMeta.element;

            // ignore grand children etc.
            if (collapseElement.parent != element) {
              return;
            }

            if (element.classes.contains('accordion-header')) {
              collapseMeta.register(
                BuildOp(
                  onWidgets: (_, widgets) {
                    header = AbsorbPointer(
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: widgets.toList(),
                      ),
                    );

                    return [];
                  },
                ),
              );
            }

            if (element.classes.contains('accordion-content')) {
              final String? styles = collapseMeta.element.attributes['style'];

              if (styles != null) {
                if (styles.contains(RegExp(r'display\s*?:\s*?block'))) {
                  initialCollapsed = false;
                }

                if (styles.contains(RegExp(r'display\s*?:\s*?none'))) {
                  initialCollapsed = true;

                  /// Remove display none from style attribute since otherwise the content is not displayed
                  _removeStyleAttribute(collapseMeta, r'display\s*?:\s*?none');
                }
              }
            }
          },
          onWidgets: (_, widgets) => [
            CustomCollapsible(
              header: header ?? const SizedBox.shrink(),
              initialCollapsed: initialCollapsed,
              children: widgets.toList(),
            )
          ],
        ),
      );
    }

    return super.parse(meta);
  }

  /// Removes style attribute from meta attributes.
  void _removeStyleAttribute(BuildMetadata meta, String styleAttribute) {
    meta.element.attributes.update(
      'style',
      (value) => value.replaceAll(RegExp(styleAttribute), ''),
    );
  }
}

Html looks like this:

<div class="accordion-section">
    <div class="accordion-header">
        <a target="_self">Show or hide content</a>
    </div>
    <div class="accordion-content">
        <p>Content</p>
    </div>
</div>

DFelten avatar Mar 18 '23 09:03 DFelten

Thanks for the response. However, this will not apply since the content is like news feed content (user generated content) which we display on our website written in ReactJs, on our mobile lite version written in React Native.

We cannot have the accordion class in the content to create the read more / read less functionality.

davie1989 avatar Mar 18 '23 21:03 davie1989