fix(editor): tables with whole-number sizes, or none, show
The editor casts a table's sizes (its column width, row height, height, and each cell's width and height) to decimals, and finds a row's default height with a null check. JSON written elsewhere may hold whole numbers, 40 where the editor writes 40.0, or no sizes at all: such a table showed Flutter's error box instead. The Writing System paths in an archive brought over from elsewhere hold whole numbers. Opening content now gives its tables their sizes as the editor reads them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
42395a9dbc
commit
277994d31b
2 changed files with 102 additions and 1 deletions
|
|
@ -18,10 +18,56 @@ extension RichContentToDocument on RichContent {
|
|||
// A mutable deep copy: the editor keeps parts of the JSON it is given and
|
||||
// may change them in place, while RichContent's JSON is unmodifiable.
|
||||
final json = jsonDecode(jsonEncode(editorJson)) as Map<String, Object?>;
|
||||
_sizeTables(json['document']);
|
||||
return Document.fromJson(json);
|
||||
}
|
||||
}
|
||||
|
||||
/// The sizes a table keeps, with what it takes where it has none.
|
||||
final _tableSizes = {
|
||||
TableBlockKeys.colDefaultWidth: TableDefaults.colWidth,
|
||||
TableBlockKeys.rowDefaultHeight: TableDefaults.rowHeight,
|
||||
TableBlockKeys.colMinimumWidth: TableDefaults.colMinimumWidth,
|
||||
};
|
||||
|
||||
/// Gives the tables in [node] their sizes as the editor reads them, which
|
||||
/// casts them to decimals and fails on whole numbers or none (checked with
|
||||
/// our fork of v6.2): JSON written elsewhere, such as imports and archives,
|
||||
/// may hold `40` where the editor itself writes `40.0`.
|
||||
void _sizeTables(Object? node) {
|
||||
if (node is! Map<String, Object?>) {
|
||||
return;
|
||||
}
|
||||
double? decimal(Object? size) => switch (size) {
|
||||
final num size => size.toDouble(),
|
||||
final String size => double.tryParse(size),
|
||||
_ => null,
|
||||
};
|
||||
if (node['data'] case final Map<String, Object?> data) {
|
||||
switch (node['type']) {
|
||||
case TableBlockKeys.type:
|
||||
for (final MapEntry(:key, value: fallback) in _tableSizes.entries) {
|
||||
data[key] = decimal(data[key]) ?? fallback;
|
||||
}
|
||||
if (decimal(data[TableBlockKeys.colsHeight]) case final height?) {
|
||||
data[TableBlockKeys.colsHeight] = height;
|
||||
}
|
||||
case TableCellBlockKeys.type:
|
||||
for (final key in [
|
||||
TableCellBlockKeys.width,
|
||||
TableCellBlockKeys.height,
|
||||
]) {
|
||||
if (decimal(data[key]) case final size?) {
|
||||
data[key] = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node['children'] case final List<Object?> children) {
|
||||
children.forEach(_sizeTables);
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores the editor's document as [RichContent].
|
||||
extension DocumentToRichContent on Document {
|
||||
/// This document's content, in the current format.
|
||||
|
|
|
|||
|
|
@ -37,6 +37,61 @@ void main() {
|
|||
await tester.pump(const Duration(seconds: 1));
|
||||
}
|
||||
|
||||
testWidgets('shows a table whose sizes are whole numbers, or missing, as '
|
||||
'JSON written elsewhere may hold them', (tester) async {
|
||||
Map<String, Object?> cell(int column, int row, Map<String, Object?> data) =>
|
||||
{
|
||||
'type': 'table/cell',
|
||||
'data': {'colPosition': column, 'rowPosition': row, ...data},
|
||||
'children': [
|
||||
{
|
||||
'type': 'paragraph',
|
||||
'data': {
|
||||
'delta': [
|
||||
{'insert': '$column$row'},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
for (final (table, cells) in [
|
||||
// As an archive from elsewhere brought it: whole numbers.
|
||||
(
|
||||
{
|
||||
'colsLen': 2,
|
||||
'rowsLen': 1,
|
||||
'colsHeight': 82,
|
||||
'colDefaultWidth': 160,
|
||||
'rowDefaultHeight': 40,
|
||||
'colMinimumWidth': 40,
|
||||
},
|
||||
{'width': 80, 'height': 40},
|
||||
),
|
||||
// Without the editor's sizes.
|
||||
(<String, Object?>{'colsLen': 2, 'rowsLen': 1}, <String, Object?>{}),
|
||||
]) {
|
||||
await show(
|
||||
tester,
|
||||
RichContent({
|
||||
'document': {
|
||||
'type': 'page',
|
||||
'children': [
|
||||
{
|
||||
'type': 'table',
|
||||
'data': table,
|
||||
'children': [cell(0, 0, cells), cell(1, 0, cells)],
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(tester.takeException(), isNull);
|
||||
expect(find.textContaining('00', findRichText: true), findsOneWidget);
|
||||
expect(find.textContaining('10', findRichText: true), findsOneWidget);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('shows the content', (tester) async {
|
||||
await show(tester, paragraph('猫は動物です。'));
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue