Skip to content

Commit

Permalink
fix: Fix various issues with list rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
Sub6Resources committed Oct 21, 2022
1 parent deb726a commit 520ff3c
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 196 deletions.
159 changes: 41 additions & 118 deletions lib/custom_render.dart
Original file line number Diff line number Diff line change
Expand Up @@ -155,112 +155,49 @@ CustomRender blockElementRender({Style? style, List<InlineSpan>? children}) =>
});

CustomRender listElementRender(
{Style? style, Widget? child, List<InlineSpan>? children}) =>
CustomRender.inlineSpan(
inlineSpan: (context, buildChildren) {
final listStyleType = style?.listStyleType ??
context.style.listStyleType ??
ListStyleType.decimal;
final counterStyle =
CounterStyleRegistry.lookup(listStyleType.counterStyle);
String counterContent;
if (style?.marker?.content.isNormal ??
context.style.marker?.content.isNormal ??
true) {
counterContent = counterStyle.generateMarkerContent(
context.tree.counters.lastOrNull?.value ?? 0);
} else if (!(style?.marker?.content.display ??
context.style.marker?.content.display ??
true)) {
counterContent = '';
} else {
counterContent = style?.marker?.content.replacementContent ??
context.style.marker?.content.replacementContent ??
counterStyle.generateMarkerContent(
context.tree.counters.lastOrNull?.value ?? 0);
}
final markerWidget = counterContent.isNotEmpty
? Text.rich(TextSpan(
{Style? style, Widget? child, List<InlineSpan>? children}) {
return CustomRender.inlineSpan(
inlineSpan: (context, buildChildren) {
final usedStyle = style ?? context.style;
final listStyleType = usedStyle.listStyleType ?? ListStyleType.decimal;
final counterStyle =
CounterStyleRegistry.lookup(listStyleType.counterStyle);
String counterContent;
if (usedStyle.marker?.content.isNormal ?? true) {
counterContent = counterStyle.generateMarkerContent(
context.tree.counters.lastOrNull?.value ?? 0,
);
} else if (!(usedStyle.marker?.content.display ?? true)) {
counterContent = '';
} else {
counterContent = usedStyle.marker?.content.replacementContent ??
counterStyle.generateMarkerContent(
context.tree.counters.lastOrNull?.value ?? 0,
);
}
final listChildren = buildChildren()
..insertAll(
0,
[
if (usedStyle.listStylePosition == ListStylePosition.inside)
TextSpan(
text: counterContent,
style: context.tree.style.marker?.style?.generateTextStyle(),
))
: const SizedBox(width: 0, height: 0); //TODO this is hardcoded

return WidgetSpan(
child: CssBoxWidget(
key: context.key,
style: style ?? context.tree.style,
shrinkWrap: context.parser.shrinkWrap,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
textDirection: style?.direction ?? context.tree.style.direction,
children: [
(style?.listStylePosition ??
context.tree.style.listStylePosition) ==
ListStylePosition.outside
? Padding(
padding: style?.padding?.nonNegative ??
context.tree.style.padding?.nonNegative ??
EdgeInsets.only(
left: (style?.direction ??
context.tree.style.direction) !=
TextDirection.rtl
? 10.0
: 0.0,
right: (style?.direction ??
context.tree.style.direction) ==
TextDirection.rtl
? 10.0
: 0.0),
child: markerWidget,
)
: const SizedBox(height: 0, width: 0),
const Text("\u0020",
textAlign: TextAlign.right,
style: TextStyle(fontWeight: FontWeight.w400)),
Expanded(
child: Padding(
padding: (style?.listStylePosition ??
context.tree.style.listStylePosition) ==
ListStylePosition.inside
? EdgeInsets.only(
left: (style?.direction ??
context.tree.style.direction) !=
TextDirection.rtl
? 10.0
: 0.0,
right: (style?.direction ??
context.tree.style.direction) ==
TextDirection.rtl
? 10.0
: 0.0)
: EdgeInsets.zero,
child: CssBoxWidget.withInlineSpanChildren(
children: _getListElementChildren(
style?.listStylePosition ??
context.tree.style.listStylePosition,
buildChildren)
..insertAll(
0,
context.tree.style.listStylePosition ==
ListStylePosition.inside
? [
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: markerWidget)
]
: []),
style: style ?? context.style,
),
),
),
],
),
),
style: usedStyle.marker?.style?.generateTextStyle(),
),
],
);
},
);

return WidgetSpan(
child: CssBoxWidget.withInlineSpanChildren(
key: context.key,
style: usedStyle,
shrinkWrap: context.parser.shrinkWrap,
children: listChildren,
),
);
},
);
}

CustomRender replacedElementRender(
{PlaceholderAlignment? alignment,
Expand Down Expand Up @@ -546,20 +483,6 @@ Map<CustomRenderMatcher, CustomRender> generateDefaultRenders() {
};
}

List<InlineSpan> _getListElementChildren(
ListStylePosition? position, Function() buildChildren) {
List<InlineSpan> children = buildChildren.call();
if (position == ListStylePosition.inside) {
const tabSpan = WidgetSpan(
child: Text("\t",
textAlign: TextAlign.right,
style: TextStyle(fontWeight: FontWeight.w400)),
);
children.insert(0, tabSpan);
}
return children;
}

InlineSpan _getInteractableChildren(RenderContext context,
InteractableElement tree, InlineSpan childSpan, TextStyle childStyle) {
if (childSpan is TextSpan) {
Expand Down
60 changes: 50 additions & 10 deletions lib/html_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,9 @@ class HtmlParser extends StatelessWidget {
tree = _removeEmptyElements(tree);

tree = _calculateRelativeValues(tree, devicePixelRatio);
tree = _processListMarkers(tree);
tree = _preprocessListMarkers(tree);
tree = _processCounters(tree);
tree = _processListMarkers(tree);
tree = _processBeforesAndAfters(tree);
tree = _collapseMargins(tree);
return tree;
Expand Down Expand Up @@ -532,9 +533,9 @@ class HtmlParser extends StatelessWidget {
.replaceAll(RegExp(" {2,}"), " ");
}

/// [processListMarkers] adds marker pseudo elements to the front of all list
/// [preprocessListMarkers] adds marker pseudo elements to the front of all list
/// items.
static StyledElement _processListMarkers(StyledElement tree) {
static StyledElement _preprocessListMarkers(StyledElement tree) {
tree.style.listStylePosition ??= ListStylePosition.outside;

if (tree.style.display == Display.listItem) {
Expand All @@ -544,6 +545,10 @@ class HtmlParser extends StatelessWidget {
style: tree.style,
);

// Inherit styles from originating widget
tree.style.marker!.style =
tree.style.copyOnlyInherited(tree.style.marker!.style ?? Style());

// Add the implicit counter-increment on `list-item` if it isn't set
// explicitly already
tree.style.counterIncrement ??= {};
Expand All @@ -561,7 +566,7 @@ class HtmlParser extends StatelessWidget {
}

for (var child in tree.children) {
_processListMarkers(child);
_preprocessListMarkers(child);
}

return tree;
Expand All @@ -584,15 +589,20 @@ class HtmlParser extends StatelessWidget {
// Increment any counters that are to be incremented
if (tree.style.counterIncrement != null) {
tree.style.counterIncrement!.forEach((counterName, increment) {
tree.counters.lastWhereOrNull(
(counter) => counter.name == counterName,
)?.increment(increment ?? 1);
tree.counters
.lastWhereOrNull(
(counter) => counter.name == counterName,
)
?.increment(increment ?? 1);

// If we didn't newly create the counter, increment the counter in the old copy as well.
if(tree.style.counterReset == null || !tree.style.counterReset!.containsKey(counterName)) {
counters?.lastWhereOrNull(
if (tree.style.counterReset == null ||
!tree.style.counterReset!.containsKey(counterName)) {
counters
?.lastWhereOrNull(
(counter) => counter.name == counterName,
)?.increment(increment ?? 1);
)
?.increment(increment ?? 1);
}
});
}
Expand All @@ -604,6 +614,36 @@ class HtmlParser extends StatelessWidget {
return tree;
}

static StyledElement _processListMarkers(StyledElement tree) {
if (tree.style.display == Display.listItem) {
final listStyleType = tree.style.listStyleType ?? ListStyleType.decimal;
final counterStyle = CounterStyleRegistry.lookup(
listStyleType.counterStyle,
);
String counterContent;
if (tree.style.marker?.content.isNormal ?? true) {
counterContent = counterStyle.generateMarkerContent(
tree.counters.lastOrNull?.value ?? 0,
);
} else if (!(tree.style.marker?.content.display ?? true)) {
counterContent = '';
} else {
counterContent = tree.style.marker?.content.replacementContent ??
counterStyle.generateMarkerContent(
tree.counters.lastOrNull?.value ?? 0,
);
}
tree.style.marker = Marker(
content: Content(counterContent), style: tree.style.marker?.style);
}

for (var child in tree.children) {
_processListMarkers(child);
}

return tree;
}

/// [_processBeforesAndAfters] adds text content to the beginning and end of
/// the list of the trees children according to the `before` and `after` Style
/// properties.
Expand Down
Loading

0 comments on commit 520ff3c

Please sign in to comment.