visitElementBefore method
Called when an Element has been reached, before its children have been visited.
Returns false to skip its children.
Implementation
@override
bool visitElementBefore(Element element) {
_elementStack.add(element);
switch (element.tag) {
// Block elements
case 'h1':
case 'h2':
case 'h3':
case 'h4':
case 'h5':
case 'h6':
_ensureNewline();
_startHeading(element.tag);
return true;
case 'p':
_ensureNewline();
if (_inBlockquote) {
_writeBlockquotePrefix();
}
// Start paragraph buffering for text wrapping
if (options.width != null) {
_inParagraph = true;
_paragraphBuffer.clear();
}
_startTextStyle();
return true;
case 'blockquote':
_ensureNewline();
_inBlockquote = true;
_blockquoteDepth++;
return true;
case 'pre':
_ensureNewline();
_startCodeBlock(element);
return true;
case 'ul':
if (_listDepth == 0) {
_ensureNewline();
} else {
// Nested list: add newline after parent item text
_buffer.write('\n');
}
_listDepth++;
return true;
case 'ol':
if (_listDepth == 0) {
_ensureNewline();
} else {
// Nested list: add newline after parent item text
_buffer.write('\n');
}
_listDepth++;
_listCounters.add(
int.tryParse(element.attributes['start'] ?? '1') ?? 1,
);
return true;
case 'li':
_startListItem(element);
_startTextStyle();
return true;
case 'hr':
_ensureNewline();
_renderHorizontalRule();
return false; // No children to visit
case 'table':
_ensureNewline();
_tableHeaders.clear();
_tableRows.clear();
_tableAlignments.clear();
return true;
case 'thead':
_inTableHeader = true;
return true;
case 'tbody':
_inTableHeader = false;
return true;
case 'tr':
_currentTableRow.clear();
return true;
case 'th':
_inTableCell = true;
_currentCellBuffer.clear();
// Capture alignment from header cells
final align = element.attributes['align'];
if (align != null) {
_tableAlignments.add(_parseTableAlign(align));
}
return true;
case 'td':
_inTableCell = true;
_currentCellBuffer.clear();
return true;
// Inline elements
case 'em':
_startInlineStyle(_getEmphasisStyle());
return true;
case 'strong':
_startInlineStyle(_getStrongStyle());
return true;
case 'code':
// Check if inside a pre block (code block vs inline code)
if (!_isInsidePreBlock()) {
_startInlineStyle(_getCodeStyle());
}
return true;
case 'a':
_pendingLinkUrl = element.attributes['href'];
_startLink();
return true;
case 'del':
_startInlineStyle(_getStrikethroughStyle());
return true;
case 'br':
_buffer.write('\n');
if (_inBlockquote) {
_writeBlockquotePrefix();
}
return false;
case 'img':
_renderImage(element);
return false;
case 'input':
// Task list checkbox
final checked = element.attributes['checked'] != null;
final char = checked
? options.checkboxChecked
: options.checkboxUnchecked;
_buffer.write(char);
_buffer.write(' ');
return false;
default:
return true;
}
}