Skip to content

Commit

Permalink
fix(html): Fix div line break
Browse files Browse the repository at this point in the history
* Try append new line when munched `div`.
  * This may bring some empty lines, but still works better than before.
* Remove trailing empty lines in cards.
  • Loading branch information
realth000 committed Sep 14, 2024
1 parent 6010ec5 commit 8a5fc75
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 18 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- 主页:修复部分网络不稳定的情况下将加载失败显示为未登录的问题。
- 网页:修复解析网页时,在折叠/展开按钮上的文字丢失颜色的问题。
- 网页:修复解析网页中的颜色时,部分颜色解析失败或错误的问题。
- 网页:修复解析`div`时布局错误的问题。
-初步处理, 现在某些情况下会多一些空行。
- 网页:修复折叠卡片的尾部多余的空行。

### Changed

Expand Down
68 changes: 50 additions & 18 deletions lib/utils/html/html_muncher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import 'package:tsdm_client/widgets/network_indicator_image.dart';
import 'package:tsdm_client/widgets/quoted_text.dart';
import 'package:universal_html/html.dart' as uh;

/// Use the same span to append line break.
const emptySpan = TextSpan(text: '\n');

/// Use an empty span.
// final null = WidgetSpan(child: Container());

Expand All @@ -35,6 +38,10 @@ Widget munchElement(BuildContext context, uh.Element rootElement) {
if (ret == null) {
return const SizedBox.shrink();
}
// Remove trailing empty spaces.
while (ret.lastOrNull == emptySpan) {
ret.removeLast();
}

// Alignment in this page requires a fixed max width that equals to website
// page width.
Expand Down Expand Up @@ -68,6 +75,11 @@ class _MunchState {
/// When in a `<pre>`, all text should be treated as raw text.
bool inPre = false;

/// Flag indicate current node inside a div or not.
///
/// Make sure one line break when (nested or not) div ended.
bool inDiv = false;

/// If true, use [String.trim], if false, use [String.trimLeft].
bool trimAll = false;

Expand Down Expand Up @@ -271,8 +283,7 @@ final class _Muncher with LoggerMixin {
// Parse according to element types.
final span = switch (localName) {
'img' => _buildImg(node),
'br' =>
state.headingBrNodePassed ? [const TextSpan(text: '\n')] : null,
'br' => state.headingBrNodePassed ? [emptySpan] : null,
'font' => _buildFont(node),
'strong' => _buildStrong(node),
'u' => _buildUnderline(node),
Expand Down Expand Up @@ -448,7 +459,7 @@ final class _Muncher with LoggerMixin {
if (ret == null) {
return null;
}
return [...ret, const TextSpan(text: '\n')];
return [...ret, emptySpan];
}

final styleMap = Map.fromEntries(styleEntries);
Expand All @@ -469,7 +480,7 @@ final class _Muncher with LoggerMixin {
return null;
}

return [...ret, const TextSpan(text: '\n')];
return [...ret, emptySpan];
}

List<InlineSpan> _buildBlockQuote(uh.Element element) {
Expand All @@ -490,11 +501,12 @@ final class _Muncher with LoggerMixin {
WidgetSpan(
child: QuotedText.rich(TextSpan(children: ret)),
),
const TextSpan(text: '\n'),
emptySpan,
];
}

List<InlineSpan>? _munchDiv(uh.Element element) {
final origInDiv = state.inDiv;
_divMap ??= {
'blockcode': _buildBlockCode,
'locked': _buildLockedArea,
Expand All @@ -505,12 +517,18 @@ final class _Muncher with LoggerMixin {
'rwdbst': _buildBountyBestAnswer,
};

state.inDiv = true;
// Find the first munch executor, use `_munch` if none found.
final executor = _divMap!.entries
.firstWhereOrNull((e) => element.classes.contains(e.key))
?.value ??
_munch;
final ret = executor(element);
state.inDiv = origInDiv;

if (ret != null && ret.isNotEmpty && ret.last != emptySpan) {
ret.add(emptySpan);
}
return ret;
}

Expand Down Expand Up @@ -546,7 +564,7 @@ final class _Muncher with LoggerMixin {
elevation: state.elevation,
),
),
const TextSpan(text: '\n'),
emptySpan,
];
state.elevation -= 1;
return ret;
Expand Down Expand Up @@ -598,6 +616,9 @@ final class _Muncher with LoggerMixin {
if (content == null) {
return null;
}
while (content.lastOrNull == emptySpan) {
content.removeLast();
}
state.headingBrNodePassed = true;
return [
WidgetSpan(
Expand All @@ -607,7 +628,7 @@ final class _Muncher with LoggerMixin {
elevation: elevation,
),
),
const TextSpan(text: '\n'),
emptySpan,
];
}

Expand Down Expand Up @@ -772,7 +793,7 @@ final class _Muncher with LoggerMixin {
if (ret == null) {
return null;
}
return [...ret, const TextSpan(text: ' ')];
return [...ret, emptySpan];
}
List<InlineSpan>? _buildH1(uh.Element element) {
Expand All @@ -783,9 +804,9 @@ final class _Muncher with LoggerMixin {
return null;
}
return [
const TextSpan(text: '\n'),
emptySpan,
...ret,
const TextSpan(text: '\n'),
emptySpan,
];
}
Expand All @@ -797,9 +818,9 @@ final class _Muncher with LoggerMixin {
return null;
}
return [
const TextSpan(text: '\n'),
emptySpan,
...ret,
const TextSpan(text: '\n'),
emptySpan,
];
}
Expand All @@ -811,9 +832,9 @@ final class _Muncher with LoggerMixin {
return null;
}
return [
const TextSpan(text: '\n'),
emptySpan,
...ret,
const TextSpan(text: '\n'),
emptySpan,
];
}
Expand All @@ -825,9 +846,9 @@ final class _Muncher with LoggerMixin {
return null;
}
return [
const TextSpan(text: '\n'),
emptySpan,
...ret,
const TextSpan(text: '\n'),
emptySpan,
];
}
Expand All @@ -839,7 +860,7 @@ final class _Muncher with LoggerMixin {
return [
const TextSpan(text: '• '),
...ret,
const TextSpan(text: '\n'),
emptySpan,
];
}
Expand Down Expand Up @@ -921,6 +942,17 @@ final class _Muncher with LoggerMixin {
return null;
}
// Trim all trailing whitespace in card.
final ch = dataSpanList.lastOrNull;
if (ch != null) {
while (ch.lastOrNull == emptySpan ||
((ch.lastOrNull is TextSpan) &&
((ch.last as TextSpan).text?.trim().isEmpty ?? false))) {
ch.removeLast();
}
dataSpanList.last = ch;
}
return [
WidgetSpan(
child: SpoilerCard(
Expand All @@ -929,7 +961,7 @@ final class _Muncher with LoggerMixin {
elevation: state.elevation,
),
),
const TextSpan(text: '\n'),
emptySpan,
];
}
Expand Down

0 comments on commit 8a5fc75

Please sign in to comment.