Skip to content

Commit babe5c8

Browse files
content: Support parsing and handling inline styles for KaTeX content
1 parent 048eb90 commit babe5c8

File tree

2 files changed

+105
-2
lines changed

2 files changed

+105
-2
lines changed

lib/model/katex.dart

+84-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import 'package:csslib/parser.dart' as css_parser;
2+
import 'package:csslib/visitor.dart' as css_visitor;
13
import 'package:flutter/foundation.dart';
24
import 'package:html/dom.dart' as dom;
35

6+
import '../log.dart';
47
import 'content.dart';
58

69
class KatexParser {
@@ -225,11 +228,72 @@ class KatexParser {
225228
}
226229
if (text == null && spans == null) throw KatexHtmlParseError();
227230

231+
final inlineStyles = _parseSpanInlineStyles(element);
232+
228233
return KatexSpanNode(
229234
text: text,
230-
styles: styles,
235+
styles: inlineStyles != null
236+
? styles.merge(inlineStyles)
237+
: styles,
231238
nodes: spans ?? const []);
232239
}
240+
241+
KatexSpanStyles? _parseSpanInlineStyles(dom.Element element) {
242+
if (element.attributes case {'style': final styleStr}) {
243+
final stylesheet = css_parser.parse('*{$styleStr}');
244+
final topLevels = stylesheet.topLevels;
245+
if (topLevels.length != 1) throw KatexHtmlParseError();
246+
final topLevel = topLevels.single;
247+
if (topLevel is! css_visitor.RuleSet) throw KatexHtmlParseError();
248+
final rule = topLevel;
249+
250+
double? marginLeftEm;
251+
double? marginRightEm;
252+
double? paddingLeftEm;
253+
254+
for (final declaration in rule.declarationGroup.declarations) {
255+
if (declaration is! css_visitor.Declaration) throw KatexHtmlParseError();
256+
final property = declaration.property;
257+
258+
final expressions = declaration.expression;
259+
if (expressions is! css_visitor.Expressions) throw KatexHtmlParseError();
260+
if (expressions.expressions.length != 1) throw KatexHtmlParseError();
261+
final expression = expressions.expressions.single;
262+
263+
switch (property) {
264+
case 'margin-left':
265+
marginLeftEm = _getEm(expression);
266+
if (marginLeftEm != null) continue;
267+
268+
case 'margin-right':
269+
marginRightEm = _getEm(expression);
270+
if (marginRightEm != null) continue;
271+
272+
case 'padding-left':
273+
paddingLeftEm = _getEm(expression);
274+
if (paddingLeftEm != null) continue;
275+
276+
default:
277+
// TODO handle more CSS properties
278+
assert(debugLog('Unsupported CSS property: $property of type ${expression.runtimeType}'));
279+
}
280+
}
281+
282+
return KatexSpanStyles(
283+
marginLeftEm: marginLeftEm,
284+
marginRightEm: marginRightEm,
285+
paddingLeftEm: paddingLeftEm,
286+
);
287+
}
288+
return null;
289+
}
290+
291+
double? _getEm(css_visitor.Expression expression) {
292+
if (expression is css_visitor.EmTerm && expression.value is num) {
293+
return (expression.value as num).toDouble();
294+
}
295+
return null;
296+
}
233297
}
234298

235299
enum KatexSpanFontWeight {
@@ -248,13 +312,20 @@ enum KatexSpanTextAlign {
248312
}
249313

250314
class KatexSpanStyles {
315+
double? marginLeftEm;
316+
double? marginRightEm;
317+
double? paddingLeftEm;
318+
251319
String? fontFamily;
252320
double? fontSizeEm;
253321
KatexSpanFontStyle? fontStyle;
254322
KatexSpanFontWeight? fontWeight;
255323
KatexSpanTextAlign? textAlign;
256324

257325
KatexSpanStyles({
326+
this.marginLeftEm,
327+
this.marginRightEm,
328+
this.paddingLeftEm,
258329
this.fontFamily,
259330
this.fontSizeEm,
260331
this.fontStyle,
@@ -265,6 +336,9 @@ class KatexSpanStyles {
265336
@override
266337
int get hashCode => Object.hash(
267338
'KatexSpanStyles',
339+
marginLeftEm,
340+
marginRightEm,
341+
paddingLeftEm,
268342
fontFamily,
269343
fontSizeEm,
270344
fontStyle,
@@ -275,6 +349,9 @@ class KatexSpanStyles {
275349
@override
276350
bool operator ==(Object other) {
277351
return other is KatexSpanStyles &&
352+
other.marginLeftEm == marginLeftEm &&
353+
other.marginRightEm == marginRightEm &&
354+
other.paddingLeftEm == paddingLeftEm &&
278355
other.fontFamily == fontFamily &&
279356
other.fontSizeEm == fontSizeEm &&
280357
other.fontStyle == fontStyle &&
@@ -289,6 +366,9 @@ class KatexSpanStyles {
289366
if (this == _zero) return '${objectRuntimeType(this, 'KatexSpanStyles')}()';
290367

291368
final args = <String>[];
369+
if (marginLeftEm != null) args.add('marginLeftEm: $marginLeftEm');
370+
if (marginRightEm != null) args.add('marginRightEm: $marginRightEm');
371+
if (paddingLeftEm != null) args.add('paddingLeftEm: $paddingLeftEm');
292372
if (fontFamily != null) args.add('fontFamily: $fontFamily');
293373
if (fontSizeEm != null) args.add('fontSizeEm: $fontSizeEm');
294374
if (fontStyle != null) args.add('fontStyle: $fontStyle');
@@ -299,6 +379,9 @@ class KatexSpanStyles {
299379

300380
KatexSpanStyles merge(KatexSpanStyles other) {
301381
return KatexSpanStyles(
382+
marginLeftEm: other.marginLeftEm ?? marginLeftEm,
383+
marginRightEm: other.marginRightEm ?? marginRightEm,
384+
paddingLeftEm: other.paddingLeftEm ?? paddingLeftEm,
302385
fontFamily: other.fontFamily ?? fontFamily,
303386
fontSizeEm: other.fontSizeEm ?? fontSizeEm,
304387
fontStyle: other.fontStyle ?? fontStyle,

lib/widgets/content.dart

+21-1
Original file line numberDiff line numberDiff line change
@@ -916,13 +916,33 @@ class _KatexSpan extends StatelessWidget {
916916
};
917917
}
918918

919+
var margin = EdgeInsets.zero;
920+
final marginRightEm = styles.marginRightEm;
921+
final marginLeftEm = styles.marginLeftEm;
922+
if (marginRightEm != null && !marginRightEm.isNegative) {
923+
margin += EdgeInsets.only(right: marginRightEm * em);
924+
}
925+
if (marginLeftEm != null && !marginLeftEm.isNegative) {
926+
margin += EdgeInsets.only(left: marginLeftEm * em);
927+
}
928+
929+
var padding = EdgeInsets.zero;
930+
final paddingLeftEm = styles.paddingLeftEm;
931+
if (paddingLeftEm != null && !paddingLeftEm.isNegative) {
932+
padding += EdgeInsets.only(right: paddingLeftEm * em);
933+
}
934+
919935
if (textStyle != null || textAlign != null) {
920936
widget = DefaultTextStyle.merge(
921937
style: textStyle,
922938
textAlign: textAlign,
923939
child: widget);
924940
}
925-
return widget;
941+
return Container(
942+
margin: margin != EdgeInsets.zero ? margin : null,
943+
padding: padding != EdgeInsets.zero ? padding : null,
944+
child: widget,
945+
);
926946
}
927947
}
928948

0 commit comments

Comments
 (0)