Skip to content

Commit c07a0e3

Browse files
authored
Merge pull request Sub6Resources#669 from tneotia/feature/list-style-image
Add list-style, list-style-image, list-style-position from inline CSS, add list bullets from a widget, fix ListStylePosition.OUTSIDE not working
2 parents a6acfbe + b5de3bb commit c07a0e3

File tree

3 files changed

+93
-24
lines changed

3 files changed

+93
-24
lines changed

lib/html_parser.dart

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -420,11 +420,7 @@ class HtmlParser extends StatelessWidget {
420420
tree.style.listStylePosition == ListStylePosition.OUTSIDE ?
421421
Padding(
422422
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),
423-
child: Text(
424-
"${newContext.style.markerContent}",
425-
textAlign: TextAlign.right,
426-
style: newContext.style.generateTextStyle()
427-
),
423+
child: newContext.style.markerContent
428424
) : Container(height: 0, width: 0),
429425
Text("\t", textAlign: TextAlign.right),
430426
Expanded(
@@ -433,11 +429,10 @@ class HtmlParser extends StatelessWidget {
433429
EdgeInsets.only(left: tree.style.direction != TextDirection.rtl ? 10.0 : 0.0, right: tree.style.direction == TextDirection.rtl ? 10.0 : 0.0) : EdgeInsets.zero,
434430
child: StyledText(
435431
textSpan: TextSpan(
436-
text: (tree.style.listStylePosition ==
437-
ListStylePosition.INSIDE)
438-
? '${newContext.style.markerContent}'
439-
: null,
440-
children: getChildren(tree),
432+
children: getChildren(tree)..insertAll(0, tree.style.listStylePosition == ListStylePosition.INSIDE ?
433+
[
434+
WidgetSpan(alignment: PlaceholderAlignment.middle, child: newContext.style.markerContent ?? Container(height: 0, width: 0))
435+
] : []),
441436
style: newContext.style.generateTextStyle(),
442437
),
443438
style: newContext.style,
@@ -708,7 +703,10 @@ class HtmlParser extends StatelessWidget {
708703
/// bullet all list items according to the [ListStyleType] they have been given.
709704
static StyledElement _processListCharactersRecursive(
710705
StyledElement tree, ListQueue<Context> olStack) {
711-
if (tree.name == 'ol' && tree.style.listStyleType != null) {
706+
if (tree.style.listStylePosition == null) {
707+
tree.style.listStylePosition = ListStylePosition.OUTSIDE;
708+
}
709+
if (tree.name == 'ol' && tree.style.listStyleType != null && tree.style.listStyleType!.type == "marker") {
712710
switch (tree.style.listStyleType!) {
713711
case ListStyleType.LOWER_LATIN:
714712
case ListStyleType.LOWER_ALPHA:
@@ -728,26 +726,31 @@ class HtmlParser extends StatelessWidget {
728726
olStack.add(Context<int>((tree.attributes['start'] != null ? int.tryParse(tree.attributes['start'] ?? "") ?? 1 : 1) - 1));
729727
break;
730728
}
729+
} else if (tree.style.display == Display.LIST_ITEM && tree.style.listStyleType != null && tree.style.listStyleType!.type == "widget") {
730+
tree.style.markerContent = tree.style.listStyleType!.widget!;
731+
} else if (tree.style.display == Display.LIST_ITEM && tree.style.listStyleType != null && tree.style.listStyleType!.type == "image") {
732+
tree.style.markerContent = Image.network(tree.style.listStyleType!.text);
731733
} else if (tree.style.display == Display.LIST_ITEM && tree.style.listStyleType != null) {
734+
String marker = "";
732735
switch (tree.style.listStyleType!) {
733736
case ListStyleType.NONE:
734737
tree.style.markerContent = '';
735738
break;
736739
case ListStyleType.CIRCLE:
737-
tree.style.markerContent = '○';
740+
marker = '○';
738741
break;
739742
case ListStyleType.SQUARE:
740-
tree.style.markerContent = '■';
743+
marker = '■';
741744
break;
742745
case ListStyleType.DISC:
743-
tree.style.markerContent = '•';
746+
marker = '•';
744747
break;
745748
case ListStyleType.DECIMAL:
746749
if (olStack.isEmpty) {
747750
olStack.add(Context<int>((tree.attributes['start'] != null ? int.tryParse(tree.attributes['start'] ?? "") ?? 1 : 1) - 1));
748751
}
749752
olStack.last.data += 1;
750-
tree.style.markerContent = '${olStack.last.data}.';
753+
marker = '${olStack.last.data}.';
751754
break;
752755
case ListStyleType.LOWER_LATIN:
753756
case ListStyleType.LOWER_ALPHA:
@@ -762,7 +765,7 @@ class HtmlParser extends StatelessWidget {
762765
}
763766
}
764767
}
765-
tree.style.markerContent = olStack.last.data.toString() + ".";
768+
marker = olStack.last.data.toString() + ".";
766769
olStack.last.data = olStack.last.data.toString().nextLetter();
767770
break;
768771
case ListStyleType.UPPER_LATIN:
@@ -778,7 +781,7 @@ class HtmlParser extends StatelessWidget {
778781
}
779782
}
780783
}
781-
tree.style.markerContent = olStack.last.data.toString().toUpperCase() + ".";
784+
marker = olStack.last.data.toString().toUpperCase() + ".";
782785
olStack.last.data = olStack.last.data.toString().nextLetter();
783786
break;
784787
case ListStyleType.LOWER_ROMAN:
@@ -787,9 +790,9 @@ class HtmlParser extends StatelessWidget {
787790
}
788791
olStack.last.data += 1;
789792
if (olStack.last.data <= 0) {
790-
tree.style.markerContent = '${olStack.last.data}.';
793+
marker = '${olStack.last.data}.';
791794
} else {
792-
tree.style.markerContent = (olStack.last.data as int).toRomanNumeralString()!.toLowerCase() + ".";
795+
marker = (olStack.last.data as int).toRomanNumeralString()!.toLowerCase() + ".";
793796
}
794797
break;
795798
case ListStyleType.UPPER_ROMAN:
@@ -798,12 +801,16 @@ class HtmlParser extends StatelessWidget {
798801
}
799802
olStack.last.data += 1;
800803
if (olStack.last.data <= 0) {
801-
tree.style.markerContent = '${olStack.last.data}.';
804+
marker = '${olStack.last.data}.';
802805
} else {
803-
tree.style.markerContent = (olStack.last.data as int).toRomanNumeralString()! + ".";
806+
marker = (olStack.last.data as int).toRomanNumeralString()! + ".";
804807
}
805808
break;
806809
}
810+
tree.style.markerContent = Text(
811+
marker,
812+
textAlign: TextAlign.right,
813+
);
807814
}
808815

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

lib/src/css_parser.dart

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,42 @@ 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':
198+
css.LiteralTerm? position = value.firstWhereOrNull((e) => e is css.LiteralTerm && (e.text == "outside" || e.text == "inside")) as css.LiteralTerm?;
199+
css.UriTerm? image = value.firstWhereOrNull((e) => e is css.UriTerm) as css.UriTerm?;
200+
css.LiteralTerm? type = value.firstWhereOrNull((e) => e is css.LiteralTerm && e.text != "outside" && e.text != "inside") as css.LiteralTerm?;
201+
if (position != null) {
202+
switch (position.text) {
203+
case 'outside':
204+
style.listStylePosition = ListStylePosition.OUTSIDE;
205+
break;
206+
case 'inside':
207+
style.listStylePosition = ListStylePosition.INSIDE;
208+
break;
209+
}
210+
}
211+
if (image != null) {
212+
style.listStyleType = ExpressionMapping.expressionToListStyleType(image) ?? style.listStyleType;
213+
} else if (type != null) {
214+
style.listStyleType = ExpressionMapping.expressionToListStyleType(type) ?? style.listStyleType;
215+
}
216+
break;
217+
case 'list-style-image':
218+
if (value.first is css.UriTerm) {
219+
style.listStyleType = ExpressionMapping.expressionToListStyleType(value.first as css.UriTerm) ?? style.listStyleType;
220+
}
221+
break;
222+
case 'list-style-position':
223+
if (value.first is css.LiteralTerm) {
224+
switch ((value.first as css.LiteralTerm).text) {
225+
case 'outside':
226+
style.listStylePosition = ListStylePosition.OUTSIDE;
227+
break;
228+
case 'inside':
229+
style.listStylePosition = ListStylePosition.INSIDE;
230+
break;
231+
}
232+
}
197233
case 'height':
198234
style.height = ExpressionMapping.expressionToPaddingLength(value.first) ?? style.height;
199235
break;
@@ -671,6 +707,9 @@ class ExpressionMapping {
671707
}
672708

673709
static ListStyleType? expressionToListStyleType(css.LiteralTerm value) {
710+
if (value is css.UriTerm) {
711+
return ListStyleType.fromImage(value.text);
712+
}
674713
switch (value.text) {
675714
case 'disc':
676715
return ListStyleType.DISC;

lib/style.dart

Lines changed: 26 additions & 3 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,6 +519,29 @@ class LineHeight {
519519
static const normal = LineHeight(1.2);
520520
}
521521

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");
543+
}
544+
522545
enum ListStyleType {
523546
LOWER_ALPHA,
524547
UPPER_ALPHA,

0 commit comments

Comments
 (0)