Skip to content

Commit e722421

Browse files
committed
Add support for the style tag
1 parent 89a89ba commit e722421

File tree

2 files changed

+72
-19
lines changed

2 files changed

+72
-19
lines changed

lib/html_parser.dart

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,20 @@ class HtmlParser extends StatelessWidget {
6666

6767
@override
6868
Widget build(BuildContext context) {
69+
Map<String, Map<String, List<css.Expression>>> declarations = _getExternalCSSDeclarations(htmlData.getElementsByTagName("style"));
6970
StyledElement lexedTree = lexDomTree(
7071
htmlData,
7172
customRender.keys.toList(),
7273
tagsList,
7374
navigationDelegateForIframe,
7475
);
75-
StyledElement inlineStyledTree = applyInlineStyles(lexedTree);
76-
StyledElement customStyledTree = _applyCustomStyles(inlineStyledTree);
77-
StyledElement cascadedStyledTree = _cascadeStyles(customStyledTree);
76+
StyledElement? externalCSSStyledTree;
77+
if (declarations.isNotEmpty) {
78+
externalCSSStyledTree = _applyExternalCSS(declarations, lexedTree);
79+
}
80+
StyledElement inlineStyledTree = _applyInlineStyles(externalCSSStyledTree ?? lexedTree);
81+
StyledElement customStyledTree = _applyCustomStyles(style, inlineStyledTree);
82+
StyledElement cascadedStyledTree = _cascadeStyles(style, customStyledTree);
7883
StyledElement cleanedTree = cleanTree(cascadedStyledTree);
7984
InlineSpan parsedTree = parseTree(
8085
RenderContext(
@@ -189,34 +194,59 @@ class HtmlParser extends StatelessWidget {
189194
}
190195
}
191196

192-
static StyledElement applyInlineStyles(StyledElement tree) {
197+
static Map<String, Map<String, List<css.Expression>>> _getExternalCSSDeclarations(List<dom.Element> styles) {
198+
String fullCSS = "";
199+
for (final e in styles) {
200+
fullCSS = fullCSS + e.innerHtml;
201+
}
202+
if (fullCSS.isNotEmpty) {
203+
final declarations = parseExternalCSS(fullCSS);
204+
return declarations;
205+
} else {
206+
return {};
207+
}
208+
}
209+
210+
static StyledElement _applyExternalCSS(Map<String, Map<String, List<css.Expression>>> declarations, StyledElement tree) {
211+
declarations.forEach((key, style) {
212+
if (tree.matchesSelector(key)) {
213+
tree.style = tree.style.merge(declarationsToStyle(style));
214+
}
215+
});
216+
217+
tree.children.forEach((e) => _applyExternalCSS(declarations, e));
218+
219+
return tree;
220+
}
221+
222+
static StyledElement _applyInlineStyles(StyledElement tree) {
193223
if (tree.attributes.containsKey("style")) {
194224
tree.style = tree.style.merge(inlineCSSToStyle(tree.attributes['style']));
195225
}
196226

197-
tree.children.forEach(applyInlineStyles);
227+
tree.children.forEach(_applyInlineStyles);
198228
return tree;
199229
}
200230

201231
/// [applyCustomStyles] applies the [Style] objects passed into the [Html]
202232
/// widget onto the [StyledElement] tree, no cascading of styles is done at this point.
203-
StyledElement _applyCustomStyles(StyledElement tree) {
233+
static StyledElement _applyCustomStyles(Map<String, Style> style, StyledElement tree) {
204234
style.forEach((key, style) {
205235
if (tree.matchesSelector(key)) {
206236
tree.style = tree.style.merge(style);
207237
}
208238
});
209-
tree.children.forEach(_applyCustomStyles);
239+
tree.children.forEach((e) => _applyCustomStyles(style, e));
210240

211241
return tree;
212242
}
213243

214244
/// [_cascadeStyles] cascades all of the inherited styles down the tree, applying them to each
215245
/// child that doesn't specify a different style.
216-
StyledElement _cascadeStyles(StyledElement tree) {
246+
static StyledElement _cascadeStyles(Map<String, Style> style, StyledElement tree) {
217247
tree.children.forEach((child) {
218248
child.style = tree.style.copyOnlyInherited(child.style);
219-
_cascadeStyles(child);
249+
_cascadeStyles(style, child);
220250
});
221251

222252
return tree;

lib/src/css_parser.dart

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import 'package:flutter/material.dart';
88
import 'package:flutter_html/src/utils.dart';
99
import 'package:flutter_html/style.dart';
1010

11-
Style declarationsToStyle(Map<String?, List<css.Expression>> declarations) {
11+
Style declarationsToStyle(Map<String, List<css.Expression>> declarations) {
1212
Style style = new Style();
1313
declarations.forEach((property, value) {
1414
if (value.isNotEmpty) {
@@ -104,31 +104,54 @@ Style declarationsToStyle(Map<String?, List<css.Expression>> declarations) {
104104

105105
Style inlineCSSToStyle(String? inlineStyle) {
106106
final sheet = cssparser.parse("*{$inlineStyle}");
107-
final declarations = DeclarationVisitor().getDeclarations(sheet)!;
108-
return declarationsToStyle(declarations);
107+
final declarations = DeclarationVisitor().getDeclarations(sheet);
108+
return declarationsToStyle(declarations["*"]!);
109+
}
110+
111+
Map<String, Map<String, List<css.Expression>>> parseExternalCSS(String css) {
112+
final sheet = cssparser.parse(css);
113+
return DeclarationVisitor().getDeclarations(sheet);
109114
}
110115

111116
class DeclarationVisitor extends css.Visitor {
112-
Map<String?, List<css.Expression>>? _result;
113-
String? _currentProperty;
117+
Map<String, Map<String, List<css.Expression>>> _result = {};
118+
Map<String, List<css.Expression>> _properties = {};
119+
late String _selector;
120+
late String _currentProperty;
114121

115-
Map<String?, List<css.Expression>>? getDeclarations(css.StyleSheet sheet) {
116-
_result = new Map<String?, List<css.Expression>>();
117-
sheet.visit(this);
122+
Map<String, Map<String, List<css.Expression>>> getDeclarations(css.StyleSheet sheet) {
123+
sheet.topLevels.forEach((element) {
124+
if (element.span != null) {
125+
_selector = element.span!.text;
126+
element.visit(this);
127+
if (_result[_selector] != null) {
128+
_properties.forEach((key, value) {
129+
if (_result[_selector]![key] != null) {
130+
_result[_selector]![key]!.addAll(new List<css.Expression>.from(value));
131+
} else {
132+
_result[_selector]![key] = new List<css.Expression>.from(value);
133+
}
134+
});
135+
} else {
136+
_result[_selector] = new Map<String, List<css.Expression>>.from(_properties);
137+
}
138+
_properties.clear();
139+
}
140+
});
118141
return _result;
119142
}
120143

121144
@override
122145
void visitDeclaration(css.Declaration node) {
123146
_currentProperty = node.property;
124-
_result![_currentProperty] = <css.Expression>[];
147+
_properties[_currentProperty] = <css.Expression>[];
125148
node.expression!.visit(this);
126149
}
127150

128151
@override
129152
void visitExpressions(css.Expressions node) {
130153
node.expressions.forEach((expression) {
131-
_result![_currentProperty]!.add(expression);
154+
_properties[_currentProperty]!.add(expression);
132155
});
133156
}
134157
}

0 commit comments

Comments
 (0)