Skip to content

Commit 5b55273

Browse files
committed
Add support for list-style-image and list-style-position from inline CSS, add support for setting a widget as the list bullet, fix ListStylePosition.INSIDE not working
1 parent 0a4df74 commit 5b55273

File tree

3 files changed

+72
-35
lines changed

3 files changed

+72
-35
lines changed

lib/html_parser.dart

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -352,11 +352,7 @@ class HtmlParser extends StatelessWidget {
352352
tree.style.listStylePosition == ListStylePosition.OUTSIDE ?
353353
Padding(
354354
padding: tree.style.padding ?? EdgeInsets.only(left: tree.style.direction != TextDirection.rtl ? 10.0 : 0.0, right: tree.style.direction == TextDirection.rtl ? 10.0 : 0.0),
355-
child: Text(
356-
"${newContext.style.markerContent}",
357-
textAlign: TextAlign.right,
358-
style: newContext.style.generateTextStyle()
359-
),
355+
child: newContext.style.markerContent
360356
) : Container(height: 0, width: 0),
361357
Text("\t", textAlign: TextAlign.right),
362358
Expanded(
@@ -365,11 +361,10 @@ class HtmlParser extends StatelessWidget {
365361
EdgeInsets.only(left: tree.style.direction != TextDirection.rtl ? 10.0 : 0.0, right: tree.style.direction == TextDirection.rtl ? 10.0 : 0.0) : EdgeInsets.zero,
366362
child: StyledText(
367363
textSpan: TextSpan(
368-
text: (tree.style.listStylePosition ==
369-
ListStylePosition.INSIDE)
370-
? '${newContext.style.markerContent}'
371-
: null,
372-
children: getChildren(tree),
364+
children: getChildren(tree)..insertAll(0, tree.style.listStylePosition == ListStylePosition.INSIDE ?
365+
[
366+
WidgetSpan(alignment: PlaceholderAlignment.middle, child: newContext.style.markerContent ?? Container(height: 0, width: 0))
367+
] : []),
373368
style: newContext.style.generateTextStyle(),
374369
),
375370
style: newContext.style,
@@ -585,7 +580,10 @@ class HtmlParser extends StatelessWidget {
585580
/// bullet all list items according to the [ListStyleType] they have been given.
586581
static StyledElement _processListCharactersRecursive(
587582
StyledElement tree, ListQueue<Context> olStack) {
588-
if (tree.name == 'ol' && tree.style.listStyleType != null) {
583+
if (tree.style.listStylePosition == null) {
584+
tree.style.listStylePosition = ListStylePosition.OUTSIDE;
585+
}
586+
if (tree.name == 'ol' && tree.style.listStyleType != null && tree.style.listStyleType!.type == "marker") {
589587
switch (tree.style.listStyleType!) {
590588
case ListStyleType.LOWER_LATIN:
591589
case ListStyleType.LOWER_ALPHA:
@@ -605,23 +603,28 @@ class HtmlParser extends StatelessWidget {
605603
olStack.add(Context<int>((tree.attributes['start'] != null ? int.tryParse(tree.attributes['start'] ?? "") ?? 1 : 1) - 1));
606604
break;
607605
}
606+
} else if (tree.style.display == Display.LIST_ITEM && tree.style.listStyleType != null && tree.style.listStyleType!.type == "widget") {
607+
tree.style.markerContent = tree.style.listStyleType!.widget!;
608+
} else if (tree.style.display == Display.LIST_ITEM && tree.style.listStyleType != null && tree.style.listStyleType!.type == "image") {
609+
tree.style.markerContent = Image.network(tree.style.listStyleType!.text);
608610
} else if (tree.style.display == Display.LIST_ITEM && tree.style.listStyleType != null) {
611+
String marker = "";
609612
switch (tree.style.listStyleType!) {
610613
case ListStyleType.CIRCLE:
611-
tree.style.markerContent = '○';
614+
marker = '○';
612615
break;
613616
case ListStyleType.SQUARE:
614-
tree.style.markerContent = '■';
617+
marker = '■';
615618
break;
616619
case ListStyleType.DISC:
617-
tree.style.markerContent = '•';
620+
marker = '•';
618621
break;
619622
case ListStyleType.DECIMAL:
620623
if (olStack.isEmpty) {
621624
olStack.add(Context<int>((tree.attributes['start'] != null ? int.tryParse(tree.attributes['start'] ?? "") ?? 1 : 1) - 1));
622625
}
623626
olStack.last.data += 1;
624-
tree.style.markerContent = '${olStack.last.data}.';
627+
marker = '${olStack.last.data}.';
625628
break;
626629
case ListStyleType.LOWER_LATIN:
627630
case ListStyleType.LOWER_ALPHA:
@@ -636,7 +639,7 @@ class HtmlParser extends StatelessWidget {
636639
}
637640
}
638641
}
639-
tree.style.markerContent = olStack.last.data.toString() + ".";
642+
marker = olStack.last.data.toString() + ".";
640643
olStack.last.data = olStack.last.data.toString().nextLetter();
641644
break;
642645
case ListStyleType.UPPER_LATIN:
@@ -652,7 +655,7 @@ class HtmlParser extends StatelessWidget {
652655
}
653656
}
654657
}
655-
tree.style.markerContent = olStack.last.data.toString().toUpperCase() + ".";
658+
marker = olStack.last.data.toString().toUpperCase() + ".";
656659
olStack.last.data = olStack.last.data.toString().nextLetter();
657660
break;
658661
case ListStyleType.LOWER_ROMAN:
@@ -661,9 +664,9 @@ class HtmlParser extends StatelessWidget {
661664
}
662665
olStack.last.data += 1;
663666
if (olStack.last.data <= 0) {
664-
tree.style.markerContent = '${olStack.last.data}.';
667+
marker = '${olStack.last.data}.';
665668
} else {
666-
tree.style.markerContent = (olStack.last.data as int).toRomanNumeralString()!.toLowerCase() + ".";
669+
marker = (olStack.last.data as int).toRomanNumeralString()!.toLowerCase() + ".";
667670
}
668671
break;
669672
case ListStyleType.UPPER_ROMAN:
@@ -672,12 +675,16 @@ class HtmlParser extends StatelessWidget {
672675
}
673676
olStack.last.data += 1;
674677
if (olStack.last.data <= 0) {
675-
tree.style.markerContent = '${olStack.last.data}.';
678+
marker = '${olStack.last.data}.';
676679
} else {
677-
tree.style.markerContent = (olStack.last.data as int).toRomanNumeralString()! + ".";
680+
marker = (olStack.last.data as int).toRomanNumeralString()! + ".";
678681
}
679682
break;
680683
}
684+
tree.style.markerContent = Text(
685+
marker,
686+
textAlign: TextAlign.right,
687+
);
681688
}
682689

683690
tree.children.forEach((e) => _processListCharactersRecursive(e, olStack));

lib/src/css_parser.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,23 @@ Style declarationsToStyle(Map<String, List<css.Expression>> declarations) {
194194
case 'font-weight':
195195
style.fontWeight = ExpressionMapping.expressionToFontWeight(value.first);
196196
break;
197+
case 'list-style-image':
198+
if (value.first is css.UriTerm) {
199+
style.listStyleType = ExpressionMapping.expressionToListStyleType(value.first as css.UriTerm) ?? style.listStyleType;
200+
}
201+
break;
202+
case 'list-style-position':
203+
if (value.first is css.LiteralTerm) {
204+
switch ((value.first as css.LiteralTerm).text) {
205+
case 'outside':
206+
style.listStylePosition = ListStylePosition.OUTSIDE;
207+
break;
208+
case 'inside':
209+
style.listStylePosition = ListStylePosition.INSIDE;
210+
break;
211+
}
212+
}
213+
break;
197214
case 'list-style-type':
198215
if (value.first is css.LiteralTerm) {
199216
style.listStyleType = ExpressionMapping.expressionToListStyleType(value.first as css.LiteralTerm) ?? style.listStyleType;
@@ -661,6 +678,9 @@ class ExpressionMapping {
661678
}
662679

663680
static ListStyleType? expressionToListStyleType(css.LiteralTerm value) {
681+
if (value is css.UriTerm) {
682+
return ListStyleType.fromImage(value.text);
683+
}
664684
switch (value.text) {
665685
case 'disc':
666686
return ListStyleType.DISC;

lib/style.dart

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ class Style {
175175
String? after;
176176
Border? border;
177177
Alignment? alignment;
178-
String? markerContent;
178+
Widget? markerContent;
179179

180180
/// MaxLine
181181
///
@@ -205,7 +205,7 @@ class Style {
205205
this.lineHeight,
206206
this.letterSpacing,
207207
this.listStyleType,
208-
this.listStylePosition = ListStylePosition.OUTSIDE,
208+
this.listStylePosition,
209209
this.padding,
210210
this.margin,
211211
this.textAlign,
@@ -388,7 +388,7 @@ class Style {
388388
String? after,
389389
Border? border,
390390
Alignment? alignment,
391-
String? markerContent,
391+
Widget? markerContent,
392392
int? maxLines,
393393
TextOverflow? textOverflow,
394394
bool? beforeAfterNull,
@@ -519,17 +519,27 @@ class LineHeight {
519519
static const normal = LineHeight(1.2);
520520
}
521521

522-
enum ListStyleType {
523-
LOWER_ALPHA,
524-
UPPER_ALPHA,
525-
LOWER_LATIN,
526-
UPPER_LATIN,
527-
CIRCLE,
528-
DISC,
529-
DECIMAL,
530-
LOWER_ROMAN,
531-
UPPER_ROMAN,
532-
SQUARE,
522+
class ListStyleType {
523+
final String text;
524+
final String type;
525+
final Widget? widget;
526+
527+
const ListStyleType(this.text, {this.type = "marker", this.widget});
528+
529+
factory ListStyleType.fromImage(String url) => ListStyleType(url, type: "image");
530+
531+
factory ListStyleType.fromWidget(Widget widget) => ListStyleType("", widget: widget, type: "widget");
532+
533+
static const LOWER_ALPHA = ListStyleType("LOWER_ALPHA");
534+
static const UPPER_ALPHA = ListStyleType("UPPER_ALPHA");
535+
static const LOWER_LATIN = ListStyleType("LOWER_LATIN");
536+
static const UPPER_LATIN = ListStyleType("UPPER_LATIN");
537+
static const CIRCLE = ListStyleType("CIRCLE");
538+
static const DISC = ListStyleType("DISC");
539+
static const DECIMAL = ListStyleType("DECIMAL");
540+
static const LOWER_ROMAN = ListStyleType("LOWER_ROMAN");
541+
static const UPPER_ROMAN = ListStyleType("UPPER_ROMAN");
542+
static const SQUARE = ListStyleType("SQUARE");
533543
}
534544

535545
enum ListStylePosition {

0 commit comments

Comments
 (0)