visitElementAfter method

  1. @override
void visitElementAfter(
  1. Element element
)

Called when an Element has been reached, after its children have been visited.

Will not be called if visitElementBefore returns false.

Implementation

@override
void visitElementAfter(md.Element element) {
  final String tag = element.tag;

  if (_isBlockTag(tag)) {
    _addAnonymousBlockIfNeeded();

    final _BlockElement current = _blocks.removeLast();
    Widget child;

    if (current.children.isNotEmpty) {
      child = Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: fitContent
            ? CrossAxisAlignment.start
            : CrossAxisAlignment.stretch,
        children: current.children,
      );
    } else {
      child = const SizedBox();
    }

    if (_isListTag(tag)) {
      assert(_listIndents.isNotEmpty);
      _listIndents.removeLast();
    } else if (tag == 'li') {
      if (_listIndents.isNotEmpty) {
        if (element.children!.isEmpty) {
          element.children!.add(md.Text(''));
        }
        Widget bullet;
        final dynamic el = element.children![0];
        if (el is md.Element && el.attributes['type'] == 'checkbox') {
          final bool val = el.attributes.containsKey('checked');
          bullet = _buildCheckbox(val);
        } else {
          bullet = _buildBullet(_listIndents.last);
        }
        child = Row(
          mainAxisSize: fitContent ? MainAxisSize.min : MainAxisSize.max,
          textBaseline: listItemCrossAxisAlignment ==
                  MarkdownListItemCrossAxisAlignment.start
              ? null
              : TextBaseline.alphabetic,
          crossAxisAlignment: listItemCrossAxisAlignment ==
                  MarkdownListItemCrossAxisAlignment.start
              ? CrossAxisAlignment.start
              : CrossAxisAlignment.baseline,
          children: <Widget>[
            SizedBox(
              width: styleSheet.listIndent! +
                  styleSheet.listBulletPadding!.left +
                  styleSheet.listBulletPadding!.right,
              child: bullet,
            ),
            Flexible(
              fit: fitContent ? FlexFit.loose : FlexFit.tight,
              child: child,
            )
          ],
        );
      }
    } else if (tag == 'table') {
      child = Table(
        defaultColumnWidth: styleSheet.tableColumnWidth!,
        defaultVerticalAlignment: styleSheet.tableVerticalAlignment,
        border: styleSheet.tableBorder,
        children: _tables.removeLast().rows,
      );
    } else if (tag == 'blockquote') {
      _isInBlockquote = false;
      child = DecoratedBox(
        decoration: styleSheet.blockquoteDecoration!,
        child: Padding(
          padding: styleSheet.blockquotePadding!,
          child: child,
        ),
      );
    } else if (tag == 'pre') {
      child = Container(
        clipBehavior: Clip.hardEdge,
        decoration: styleSheet.codeblockDecoration,
        child: child,
      );
    } else if (tag == 'hr') {
      child = Container(decoration: styleSheet.horizontalRuleDecoration);
    }

    _addBlockChild(child);
  } else {
    final _InlineElement current = _inlines.removeLast();
    final _InlineElement parent = _inlines.last;
    EdgeInsets padding = EdgeInsets.zero;

    if (paddingBuilders.containsKey(tag)) {
      padding = paddingBuilders[tag]!.getPadding();
    }

    if (builders.containsKey(tag)) {
      final Widget? child = builders[tag]!.visitElementAfterWithContext(
        delegate.context,
        element,
        styleSheet.styles[tag],
        parent.style,
      );
      if (child != null) {
        if (current.children.isEmpty) {
          current.children.add(child);
        } else {
          current.children[0] = child;
        }
      }
    } else if (tag == 'img') {
      // create an image widget for this image
      current.children.add(_buildPadding(
        padding,
        _buildImage(
          element.attributes['src']!,
          element.attributes['title'],
          element.attributes['alt'],
        ),
      ));
    } else if (tag == 'br') {
      current.children.add(_buildRichText(const TextSpan(text: '\n')));
    } else if (tag == 'th' || tag == 'td') {
      TextAlign? align;
      final String? alignAttribute = element.attributes['align'];
      if (alignAttribute == null) {
        align = tag == 'th' ? styleSheet.tableHeadAlign : TextAlign.left;
      } else {
        switch (alignAttribute) {
          case 'left':
            align = TextAlign.left;
          case 'center':
            align = TextAlign.center;
          case 'right':
            align = TextAlign.right;
        }
      }
      final Widget child = _buildTableCell(
        _mergeInlineChildren(current.children, align),
        textAlign: align,
      );
      _tables.single.rows.last.children.add(child);
    } else if (tag == 'a') {
      _linkHandlers.removeLast();
    } else if (tag == 'sup') {
      final Widget c = current.children.last;
      TextSpan? textSpan;
      if (c is Text && c.textSpan is TextSpan) {
        textSpan = c.textSpan! as TextSpan;
      } else if (c is SelectableText && c.textSpan is TextSpan) {
        textSpan = c.textSpan;
      }
      if (textSpan != null) {
        final Widget richText = _buildRichText(
          TextSpan(
            recognizer: textSpan.recognizer,
            text: element.textContent,
            style: textSpan.style?.copyWith(
              fontFeatures: <FontFeature>[
                const FontFeature.enable('sups'),
                if (styleSheet.superscriptFontFeatureTag != null)
                  FontFeature.enable(styleSheet.superscriptFontFeatureTag!),
              ],
            ),
          ),
        );
        current.children.removeLast();
        current.children.add(richText);
      }
    }

    if (current.children.isNotEmpty) {
      parent.children.addAll(current.children);
    }
  }
  if (_currentBlockTag == tag) {
    _currentBlockTag = null;
  }
  _lastVisitedTag = tag;
}