Skip to content

Commit b88d400

Browse files
committed
Fix merge conflicts
2 parents 2698376 + 6ce25f6 commit b88d400

File tree

4 files changed

+71
-39
lines changed

4 files changed

+71
-39
lines changed

example/lib/main.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,10 @@ class _MyHomePageState extends State<MyHomePage> {
167167
// Custom placeholder image for broken links
168168
networkSourceMatcher(): networkImageRender(altWidget: (_) => FlutterLogo()),
169169
},
170-
onLinkTap: (url) {
170+
onLinkTap: (url, _, __, ___) {
171171
print("Opening $url...");
172172
},
173-
onImageTap: (src) {
173+
onImageTap: (src, _, __, ___) {
174174
print(src);
175175
},
176176
onImageError: (exception, stackTrace) {

lib/html_parser.dart

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ import 'package:html/dom.dart' as dom;
1616
import 'package:html/parser.dart' as htmlparser;
1717
import 'package:webview_flutter/webview_flutter.dart';
1818

19-
typedef OnTap = void Function(String? url);
19+
typedef OnTap = void Function(
20+
String? url,
21+
RenderContext? context,
22+
Map<String, String?>? attributes,
23+
dom.Element? element,
24+
);
2025
typedef CustomRender = dynamic Function(
2126
RenderContext context,
2227
Widget parsedChild,
@@ -272,35 +277,52 @@ class HtmlParser extends StatelessWidget {
272277
),
273278
);
274279
} else if (tree.style.display == Display.LIST_ITEM) {
280+
List<InlineSpan> getChildren(StyledElement tree) {
281+
InlineSpan tabSpan = WidgetSpan(child: Text("\t", textAlign: TextAlign.right));
282+
List<InlineSpan> children = tree.children.map((tree) => parseTree(newContext, tree)).toList();
283+
if (tree.style.listStylePosition == ListStylePosition.INSIDE) {
284+
children.insert(0, tabSpan);
285+
}
286+
return children;
287+
}
288+
275289
return WidgetSpan(
276290
child: ContainerSpan(
277291
newContext: newContext,
278292
style: tree.style,
279293
shrinkWrap: context.parser.shrinkWrap,
280-
child: Stack(
294+
child: Row(
295+
crossAxisAlignment: CrossAxisAlignment.start,
296+
mainAxisSize: MainAxisSize.min,
297+
textDirection: tree.style.direction,
281298
children: [
282-
if (tree.style.listStylePosition == ListStylePosition.OUTSIDE ||
283-
tree.style.listStylePosition == null)
284-
PositionedDirectional(
285-
width: 30, //TODO derive this from list padding.
286-
start: 0,
287-
child: Text('${newContext.style.markerContent}\t',
288-
textAlign: TextAlign.right,
289-
style: newContext.style.generateTextStyle()),
290-
),
299+
tree.style.listStylePosition == ListStylePosition.OUTSIDE ?
291300
Padding(
292-
padding: EdgeInsetsDirectional.only(start: 30), //TODO derive this from list padding.
293-
child: StyledText(
294-
textSpan: TextSpan(
295-
text: (tree.style.listStylePosition == ListStylePosition.INSIDE)
296-
? '${newContext.style.markerContent}\t'
297-
: null,
298-
children: tree.children.map((tree) => parseTree(newContext, tree)).toList(),
299-
style: newContext.style.generateTextStyle(),
300-
),
301-
style: newContext.style,
302-
renderContext: context,
301+
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),
302+
child: Text(
303+
"${newContext.style.markerContent}",
304+
textAlign: TextAlign.right,
305+
style: newContext.style.generateTextStyle()
303306
),
307+
) : Container(height: 0, width: 0),
308+
Text("\t", textAlign: TextAlign.right),
309+
Expanded(
310+
child: Padding(
311+
padding: tree.style.listStylePosition == ListStylePosition.INSIDE ?
312+
EdgeInsets.only(left: tree.style.direction != TextDirection.rtl ? 10.0 : 0.0, right: tree.style.direction == TextDirection.rtl ? 10.0 : 0.0) : EdgeInsets.zero,
313+
child: StyledText(
314+
textSpan: TextSpan(
315+
text: (tree.style.listStylePosition ==
316+
ListStylePosition.INSIDE)
317+
? '${newContext.style.markerContent}'
318+
: null,
319+
children: getChildren(tree),
320+
style: newContext.style.generateTextStyle(),
321+
),
322+
style: newContext.style,
323+
renderContext: context,
324+
)
325+
)
304326
)
305327
],
306328
),
@@ -330,7 +352,7 @@ class HtmlParser extends StatelessWidget {
330352
: childStyle.merge(childSpan.style)),
331353
semanticsLabel: childSpan.semanticsLabel,
332354
recognizer: TapGestureRecognizer()
333-
..onTap = () => onLinkTap?.call(tree.href),
355+
..onTap = () => onLinkTap?.call(tree.href, context, tree.attributes, tree.element),
334356
);
335357
} else {
336358
return WidgetSpan(
@@ -341,7 +363,7 @@ class HtmlParser extends StatelessWidget {
341363
MultipleTapGestureRecognizer>(
342364
() => MultipleTapGestureRecognizer(),
343365
(instance) {
344-
instance..onTap = () => onLinkTap?.call(tree.href);
366+
instance..onTap = () => onLinkTap?.call(tree.href, context, tree.attributes, tree.element);
345367
},
346368
),
347369
},
@@ -489,7 +511,7 @@ class HtmlParser extends StatelessWidget {
489511
static StyledElement _processListCharactersRecursive(
490512
StyledElement tree, ListQueue<Context<int>> olStack) {
491513
if (tree.name == 'ol') {
492-
olStack.add(Context(0));
514+
olStack.add(Context((tree.attributes['start'] != null ? int.tryParse(tree.attributes['start'] ?? "") ?? 1 : 1) - 1));
493515
} else if (tree.style.display == Display.LIST_ITEM && tree.style.listStyleType != null) {
494516
switch (tree.style.listStyleType!) {
495517
case ListStyleType.DISC:

lib/src/css_parser.dart

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ Style declarationsToStyle(Map<String?, List<css.Expression>> declarations) {
1010
declarations.forEach((property, value) {
1111
switch (property) {
1212
case 'background-color':
13-
style.backgroundColor = ExpressionMapping.expressionToColor(value.first);
13+
style.backgroundColor = ExpressionMapping.expressionToColor(value.first) ?? style.backgroundColor;
1414
break;
1515
case 'color':
16-
style.color = ExpressionMapping.expressionToColor(value.first);
16+
style.color = ExpressionMapping.expressionToColor(value.first) ?? style.color;
1717
break;
1818
case 'direction':
1919
style.direction = ExpressionMapping.expressionToDirection(value.first);
@@ -25,13 +25,13 @@ Style declarationsToStyle(Map<String?, List<css.Expression>> declarations) {
2525
style.lineHeight = ExpressionMapping.expressionToLineHeight(value.first);
2626
break;
2727
case 'font-family':
28-
style.fontFamily = ExpressionMapping.expressionToFontFamily(value.first);
28+
style.fontFamily = ExpressionMapping.expressionToFontFamily(value.first) ?? style.fontFamily;
2929
break;
3030
case 'font-feature-settings':
3131
style.fontFeatureSettings = ExpressionMapping.expressionToFontFeatureSettings(value);
3232
break;
3333
case 'font-size':
34-
style.fontSize = ExpressionMapping.expressionToFontSize(value.first);
34+
style.fontSize = ExpressionMapping.expressionToFontSize(value.first) ?? style.fontSize;
3535
break;
3636
case 'font-style':
3737
style.fontStyle = ExpressionMapping.expressionToFontStyle(value.first);
@@ -46,18 +46,18 @@ Style declarationsToStyle(Map<String?, List<css.Expression>> declarations) {
4646
List<css.LiteralTerm?>? textDecorationList = value.whereType<css.LiteralTerm>().toList();
4747
/// List<css.LiteralTerm> might include other values than the ones we want for [textDecorationList], so make sure to remove those before passing it to [ExpressionMapping]
4848
textDecorationList.removeWhere((element) => element != null && element.text != "none" && element.text != "overline" && element.text != "underline" && element.text != "line-through");
49-
css.Expression? textDecorationColor = value.firstWhere((element) => element is css.HexColorTerm || element is css.FunctionTerm, orElse: null);
50-
List<css.LiteralTerm?>? temp = value.whereType<css.LiteralTerm>().toList();
49+
css.Expression textDecorationColor = value.firstWhere((css.Expression? element) => element is css.HexColorTerm || element is css.FunctionTerm,
50+
orElse: () => css.HexColorTerm(null, style.textDecorationColor!.value.toRadixString(16), null));
51+
List<css.LiteralTerm?>? potentialStyles = value.whereType<css.LiteralTerm>().toList();
5152
/// List<css.LiteralTerm> might include other values than the ones we want for [textDecorationStyle], so make sure to remove those before passing it to [ExpressionMapping]
52-
temp.removeWhere((element) => element != null && element.text != "solid" && element.text != "double" && element.text != "dashed" && element.text != "dotted" && element.text != "wavy");
53-
css.LiteralTerm? textDecorationStyle = temp.last;
53+
potentialStyles.removeWhere((element) => element != null && element.text != "solid" && element.text != "double" && element.text != "dashed" && element.text != "dotted" && element.text != "wavy");
54+
css.LiteralTerm? textDecorationStyle = potentialStyles.isNotEmpty ? potentialStyles.last : null;
5455
style.textDecoration = ExpressionMapping.expressionToTextDecorationLine(textDecorationList);
55-
/// flutter tracing isn't working properly here, [textDecorationColor] could be null, ignore this warning for now
56-
if (textDecorationColor != null) style.textDecorationColor = ExpressionMapping.expressionToColor(textDecorationColor);
56+
style.textDecorationColor = ExpressionMapping.expressionToColor(textDecorationColor) ?? style.textDecorationColor;
5757
if (textDecorationStyle != null) style.textDecorationStyle = ExpressionMapping.expressionToTextDecorationStyle(textDecorationStyle);
5858
break;
5959
case 'text-decoration-color':
60-
style.textDecorationColor = ExpressionMapping.expressionToColor(value.first);
60+
style.textDecorationColor = ExpressionMapping.expressionToColor(value.first) ?? style.textDecorationColor;
6161
break;
6262
case 'text-decoration-line':
6363
style.textDecoration = ExpressionMapping.expressionToTextDecorationLine(value as List<css.LiteralTerm>);

lib/src/replaced_element.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
88
import 'package:flutter/widgets.dart';
99
import 'package:flutter_html/html_parser.dart';
1010
import 'package:flutter_html/src/html_elements.dart';
11+
import 'package:flutter_html/src/utils.dart';
1112
import 'package:flutter_html/style.dart';
1213
import 'package:flutter_svg/flutter_svg.dart';
1314
import 'package:html/dom.dart' as dom;
@@ -75,7 +76,16 @@ class ImageContentElement extends ReplacedElement {
7576
for (final entry in context.parser.imageRenders.entries) {
7677
if (entry.key.call(attributes, element)) {
7778
final widget = entry.value.call(context, attributes, element);
78-
return widget;
79+
return RawGestureDetector(
80+
child: widget,
81+
gestures: {
82+
MultipleTapGestureRecognizer: GestureRecognizerFactoryWithHandlers<MultipleTapGestureRecognizer>(
83+
() => MultipleTapGestureRecognizer(), (instance) {
84+
instance..onTap = () => context.parser.onImageTap?.call(src, context, attributes, element);
85+
},
86+
),
87+
},
88+
);
7989
}
8090
}
8191
return SizedBox(width: 0, height: 0);

0 commit comments

Comments
 (0)