8000 Add support for auto horizontal margins · Sub6Resources/flutter_html@735451c · GitHub
[go: up one dir, main page]

Skip to content

Commit 735451c

Browse files
committed
Add support for auto horizontal margins
Allow centering images with auto-margins
1 parent d5a2751 commit 735451c

File tree

8 files changed

+223
-60
lines changed

8 files changed

+223
-60
lines changed

example/lib/main.dart

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,20 @@ const htmlData = r"""
5353
<p>The should be <span style='color: rgba(0, 0, 0, 0.10);'>BLACK with 10% alpha style='color: rgba(0, 0, 0, 0.10);</span></p>
5454
<p>The should be <span style='color: rgb(0, 97, 0);'>GREEN style='color: rgb(0, 97, 0);</span></p>
5555
<p>The should be <span style='background-color: red; color: rgb(0, 97, 0);'>GREEN style='color: rgb(0, 97, 0);</span></p>
56-
<p style="text-align: center;"><span style="color: rgba(0, 0, 0, 0.95);">blasdafjklasdlkjfkl</span></p>
57-
<p style="text-align: right;"><span style="color: rgba(0, 0, 0, 0.95);">blasdafjklasdlkjfkl</span></p>
58-
<p style="text-align: justify;"><span style="color: rgba(0, 0, 0, 0.95);">blasdafjklasdlkjfkl</span></p>
59-
<p style="text-align: center;"><span style="color: rgba(0, 0, 0, 0.95);">blasdafjklasdlkjfkl</span></p>
56+
<h3>Text Alignment</h3>
57+
<p style="text-align: center;"><span style="color: rgba(0, 0, 0, 0.95);">Center Aligned Text</span></p>
58+
<p style="text-align: right;"><span style="color: rgba(0, 0, 0, 0.95);">Right Aligned Text</span></p>
59+
<p style="text-align: justify;"><span style="color: rgba(0, 0, 0, 0.95);">Justified Text</span></p>
60+
<p style="text-align: center;"><span style="color: rgba(0, 0, 0, 0.95);">Center Aligned Text</span></p>
61+
<h3>Auto Margins</h3>
62+
<div style="width: 150px; height: 20px; background-color: #ff9999;">Default Div</div>
63+
<div style="width: 150px; height: 20px; background-color: #99ff99; margin: auto;">margin: auto</div>
64+
<div style="width: 150px; height: 20px; background-color: #ff99ff; margin: 15px auto;">margin: 15px auto</div>
65+
<div style="width: 150px; height: 20px; background-color: #9999ff; margin-left: auto;">margin-left: auto</div>
66+
<p>With an image - non-block (should not center):</p>
67+
<img style="margin: auto;" src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png">
68+
<p>block image (should center):</p>
69+
<img style="display: block; margin: auto;" src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png">
6070
<h3>Table support (with custom styling!):</h3>
6171
<p>
6272
<q>Famous quote...</q>

lib/html_parser.dart

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -861,7 +861,7 @@ class HtmlParser extends StatelessWidget {
861861
if (tree.children.isEmpty) {
862862
// Handle case (4) from above.
863863
if ((tree.style.height ?? 0) == 0) {
864-
tree.style.margin = EdgeInsets.zero;
864+
tree.style.margin = tree.style.margin?.collapse() ?? Margins.zero;
865865
}
866866
return tree;
867867
}
@@ -877,72 +877,72 @@ class HtmlParser extends StatelessWidget {
877877
// Handle case (1) from above.
878878
// Top margins cannot collapse if the element has padding
879879
if ((tree.style.padding?.top ?? 0) == 0) {
880-
final parentTop = tree.style.margin?.top ?? 0;
881-
final firstChildTop = tree.children.first.style.margin?.top ?? 0;
880+
final parentTop = tree.style.margin?.top?.value ?? 0;
881+
final firstChildTop = tree.children.first.style.margin?.top?.value ?? 0;
882882
final newOuterMarginTop = max(parentTop, firstChildTop);
883883

884884
// Set the parent's margin
885885
if (tree.style.margin == null) {
886-
tree.style.margin = EdgeInsets.only(top: newOuterMarginTop);
886+
tree.style.margin = Margins.only(top: newOuterMarginTop);
887887
} else {
888-
tree.style.margin = tree.style.margin!.copyWith(top: newOuterMarginTop);
888+
tree.style.margin = tree.style.margin!.copyWithEdge(top: newOuterMarginTop);
889889
}
890890

891891
// And remove the child's margin
892892
if (tree.children.first.style.margin == null) {
893-
tree.children.first.style.margin = EdgeInsets.zero;
893+
tree.children.first.style.margin = Margins.zero;
894894
} else {
895895
tree.children.first.style.margin =
896-
tree.children.first.style.margin!.copyWith(top: 0);
896+
tree.children.first.style.margin!.copyWithEdge(top: 0);
897897
}
898898
}
899899

900900
// Handle case (3) from above.
901901
// Bottom margins cannot collapse if the element has padding
902902
if ((tree.style.padding?.bottom ?? 0) == 0) {
903-
final parentBottom = tree.style.margin?.bottom ?? 0;
904-
final lastChildBottom = tree.children.last.style.margin?.bottom ?? 0;
903+
final parentBottom = tree.style.margin?.bottom?.value ?? 0;
904+
final lastChildBottom = tree.children.last.style.margin?.bottom?.value ?? 0;
905905
final newOuterMarginBottom = max(parentBottom, lastChildBottom);
906906

907907
// Set the parent's margin
908908
if (tree.style.margin == null) {
909-
tree.style.margin = EdgeInsets.only(bottom: newOuterMarginBottom);
909+
tree.style.margin = Margins.only(bottom: newOuterMarginBottom);
910910
} else {
911911
tree.style.margin =
912-
tree.style.margin!.copyWith(bottom: newOuterMarginBottom);
912+
tree.style.margin!.copyWithEdge(bottom: newOuterMarginBottom);
913913
}
914914

915915
// And remove the child's margin
916916
if (tree.children.last.style.margin == null) {
917-
tree.children.last.style.margin = EdgeInsets.zero;
917+
tree.children.last.style.margin = Margins.zero;
918918
} else {
919919
tree.children.last.style.margin =
920-
tree.children.last.style.margin!.copyWith(bottom: 0);
920+
tree.children.last.style.margin!.copyWithEdge(bottom: 0);
921921
}
922922
}
923923

924924
// Handle case (2) from above.
925925
if (tree.children.length > 1) {
926926
for (int i = 1; i < tree.children.length; i++) {
927927
final previousSiblingBottom =
928-
tree.children[i - 1].style.margin?.bottom ?? 0;
929-
final thisTop = tree.children[i].style.margin?.top ?? 0;
928+
tree.children[i - 1].style.margin?.bottom?.value ?? 0;
929+
final thisTop = tree.children[i].style.margin?.top?.value ?? 0;
930930
final newInternalMargin = max(previousSiblingBottom, thisTop) / 2;
931931

932932
if (tree.children[i - 1].style.margin == null) {
933933
tree.children[i - 1].style.margin =
934-
EdgeInsets.only(bottom: newInternalMargin);
934+
Margins.only(bottom: newInternalMargin);
935935
} else {
936936
tree.children[i - 1].style.margin = tree.children[i - 1].style.margin!
937-
.copyWith(bottom: newInternalMargin);
937+
.copyWithEdge(bottom: newInternalMargin);
938938
}
939939

940940
if (tree.children[i].style.margin == null) {
941941
tree.children[i].style.margin =
942-
EdgeInsets.only(top: newInternalMargin);
942+
Margins.only(top: newInternalMargin);
943943
} else {
944944
tree.children[i].style.margin =
945-
tree.children[i].style.margin!.copyWith(top: newInternalMargin);
945+
tree.children[i].style.margin!.copyWithEdge(top: newInternalMargin);
946946
}
947947
}
948948
}
@@ -1049,15 +1049,15 @@ class ContainerSpan extends StatelessWidget {
10491049

10501050
@override
10511051
Widget build(BuildContext _) {
1052-
return Container(
1052+
Widget container = Container(
10531053
decoration: BoxDecoration(
10541054
border: style.border,
10551055
color: style.backgroundColor,
10561056
),
10571057
height: style.height,
10581058
width: style.width,
10591059
padding: style.padding?.nonNegative,
1060 10000 -
margin: style.margin?.nonNegative,
1060+
margin: style.margin?.asInsets.nonNegative,
10611061
alignment: shrinkWrap ? null : style.alignment,
10621062
child: child ??
10631063
StyledText(
@@ -1069,6 +1069,12 @@ class ContainerSpan extends StatelessWidget {
10691069
renderContext: newContext,
10701070
),
10711071
);
1072+
1073+
if (style.margin?.isAutoHorizontal ?? false) {
1074+
return Align(alignment: style.margin!.alignment, child: container);
1075+
}
1076+
1077+
return container;
10721078
}
10731079
}
10741080

lib/image_render.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import 'dart:convert';
44
import 'package:flutter/material.dart';
55
import 'package:flutter_html/html_parser.dart';
66
import 'package:flutter_svg/flutter_svg.dart';
7-
import 'package:flutter_svg/parser.dart';
87
import 'package:html/dom.dart' as dom;
98

109
typedef ImageSourceMatcher = bool Function(

lib/src/css_parser.dart

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -246,30 +246,31 @@ Style declarationsToStyle(Map<String, List<css.Expression>> declarations) {
246246
&& !(element is css.EmTerm)
247247
&& !(element is css.RemTerm)
248248
&& !(element is css.NumberTerm)
249+
&& !(element.text == 'auto')
249250
);
250-
List<double?> margin = ExpressionMapping.expressionToPadding(marginLengths);
251-
style.margin = (style.margin ?? EdgeInsets.zero).copyWith(
252-
left: margin[0],
253-
right: margin[1],
254-
top: margin[2],
255-
bottom: margin[3],
251+
Margins margin = ExpressionMapping.expressionToMargins(marginLengths);
252+
style.margin = (style.margin ?? Margins.all(0)).copyWith(
253+
left: margin.left,
254+
right: margin.right,
255+
top: margin.top,
256+
bottom: margin.bottom,
256257
);
257258
break;
258259
case 'margin-left':
259-
style.margin = (style.margin ?? EdgeInsets.zero).copyWith(
260-
left: ExpressionMapping.expressionToPaddingLength(value.first));
260+
style.margin = (style.margin ?? Margins.zero).copyWith(
261+
left: ExpressionMapping.expressionToMargin(value.first));
261262
break;
262263
case 'margin-right':
263-
style.margin = (style.margin ?? EdgeInsets.zero).copyWith(
264-
right: ExpressionMapping.expressionToPaddingLength(value.first));
264+
style.margin = (style.margin ?? Margins.zero).copyWith(
265+
right: ExpressionMapping.expressionToMargin(value.first));
265266
break;
266267
case 'margin-top':
267-
style.margin = (style.margin ?? EdgeInsets.zero).copyWith(
268-
top: ExpressionMapping.expressionToPaddingLength(value.first));
268+
style.margin = (style.margin ?? Margins.zero).copyWith(
269+
top: ExpressionMapping.expressionToMargin(value.first));
269270
break;
270271
case 'margin-bottom':
271-
style.margin = (style.margin ?? EdgeInsets.zero).copyWith(
272-
bottom: ExpressionMapping.expressionToPaddingLength(value.first));
272+
style.margin = (style.margin ?? Margins.zero).copyWith(
273+
bottom: ExpressionMapping.expressionToMargin(value.first));
273274
break;
274275
case 'padding':
275276
List<css.LiteralTerm>? paddingLengths = value.whereType<css.LiteralTerm>().toList();
@@ -748,6 +749,45 @@ class ExpressionMapping {
748749
return null;
749750
}
750751

752+
static Margin? expressionToMargin(css.Expression value) {
753+
if ((value is css.LiteralTerm) && value.text == 'auto') {
754+
return AutoMargin();
755+
} else {
756+
return InsetMargin(expressionToPaddingLength(value) ?? 0);
757+
}
758+
}
759+
760+
static Margins expressionToMargins(List<css.Expression>? lengths) {
761+
Margin? left;
762+
Margin? right;
763+
Margin? top;
764+
Margin? bottom;
765+
if (lengths != null && lengths.isNotEmpty) {
766+
top = expressionToMargin(lengths.first);
767+
if (lengths.length == 4) {
768+
right = expressionToMargin(lengths[1]);
769+
bottom = expressionToMargin(lengths[2]);
770+
left = expressionToMargin(lengths.last);
771+
}
772+
if (lengths.length == 3) {
773+
left = expressionToMargin(lengths[1]);
774+
right = expressionToMargin(lengths[1]);
775+
bottom = expressionToMargin(lengths.last);
776+
}
777+
if (lengths.length == 2) {
778+
bottom = expressionToMargin(lengths.first);
779+
left = expressionToMargin(lengths.last);
780+
right = expressionToMargin(lengths.last);
781+
}
782+
if (lengths.length == 1) {
783+
bottom = expressionToMargin(lengths.first);
784+
left = expressionToMargin(lengths.first);
785+
right = expressionToMargin(lengths.first);
786+
}
787+
}
788+
return Margins(left: left, right: right, top: top, bottom: bottom);
789+
}
790+
751791
static List<double?> expressionToPadding(List<css.Expression>? lengths) {
752792
double? left;
753793
double? right;

lib/src/layout_element.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class TableLayoutElement extends LayoutElement {
3535
return Container(
3636
key: AnchorKey.of(context.parser.key, this),
3737
padding: style.padding?.nonNegative,
38-
margin: style.margin?.nonNegative,
38+
margin: style.margin?.asInsets.nonNegative,
3939
alignment: style.alignment,
4040
decoration: BoxDecoration(
4141
color: style.backgroundColor,

lib/src/replaced_element.dart

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class ImageContentElement extends ReplacedElement {
8484
for (final entry in context.parser.imageRenders.entries) {
8585
if (entry.key.call(attributes, element)) {
8686
final widget = entry.value.call(context, attributes, element);
87-
return Builder(
87+
final builder = Builder(
8888
builder: (buildContext) {
8989
return GestureDetector(
9090
key: AnchorKey.of(context.parser.key, this),
@@ -98,6 +98,22 @@ class ImageContentElement extends ReplacedElement {
9898
);
9999
}
100100
);
101+
102+
// Ensure that images with `display: block` and `margin: auto` will
103+
// expand and center
104+
// It is expected behavior that images are by default 'inline' so do not
105+
// center with auto margins unless explicitly 'block'.
106+
if(context.style.display == Display.BLOCK && (context.style.margin?.isAutoHorizontal ?? false)) {
107+
return SizedBox(
108+
width: double.infinity,
109+
child: Align(
110+
alignment: style.margin?.alignment ?? Alignment.centerLeft,
111+
child: builder,
112+
)
113+
);
114+
}
115+
116+
return builder;
101117
}
102118
}
103119
return SizedBox(width: 0, height: 0);

0 commit comments

Comments
 (0)
0