Skip to content

Commit 199b601

Browse files
CatHood0CatHood0
andauthored
Fix: data loss when parsing Delta to Document (#7)
* Fix: data loss when parsing Delta to Document * Chore: removed unnecessary annonymous method * Chore: removed unnecessary validations --------- Co-authored-by: CatHood0 <santiagowmar@gmail.com>
1 parent 49adb25 commit 199b601

File tree

3 files changed

+76
-24
lines changed

3 files changed

+76
-24
lines changed

lib/core/blocks/document.dart

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,30 @@ class Document {
1818
void insert(Paragraph paragraph) {
1919
final Paragraph? lastParagraph = paragraphs.lastOrNull;
2020
if (lastParagraph != null) {
21-
if (lastParagraph.isEmpty || (lastParagraph.last?.isEmpty ?? false)) {
22-
if (lastParagraph.isSealed) {
23-
lastParagraph.unseal();
24-
}
21+
if (lastParagraph.shouldBreakToNext) {
22+
lastParagraph.unseal();
23+
lastParagraph
24+
..removeLastLineIfNeeded()
25+
..seal();
26+
updateLast(lastParagraph);
27+
}
28+
29+
if (lastParagraph.isEmpty) {
30+
lastParagraph.unseal();
2531
lastParagraph.insertAll(paragraph.lines);
2632
lastParagraph.setType(paragraph.type);
27-
lastParagraph.blockAttributes = lastParagraph.blockAttributes;
33+
lastParagraph.blockAttributes = paragraph.blockAttributes;
2834
if ((lastParagraph.isBlock ||
2935
lastParagraph.isEmbed ||
3036
lastParagraph.isNewLine) &&
3137
!lastParagraph.isSealed) {
3238
lastParagraph.seal(sealLines: true);
3339
}
34-
updateLast(paragraph);
40+
updateLast(lastParagraph);
3541
return;
3642
}
3743
}
44+
3845
paragraphs.add(paragraph);
3946
}
4047

lib/core/blocks/paragraph.dart

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class Paragraph {
6161
String? id,
6262
}) : _lines = List<Line>.from(lines),
6363
id = id == null || id.trim().isEmpty ? nanoid(8) : id,
64-
_sealed = type == ParagraphType.block
64+
_sealed = type == ParagraphType.block || type == ParagraphType.embed
6565
? true
6666
: lines.isNotEmpty && lines.length == 1 && lines.first.isNotEmpty
6767
? lines.first.length > 1
@@ -80,22 +80,37 @@ class Paragraph {
8080
_sealed = true;
8181

8282
@visibleForTesting
83-
factory Paragraph.fragment(TextFragment frag, {String? id}) {
83+
factory Paragraph.fragment(
84+
TextFragment frag, {
85+
String? id,
86+
Map<String, dynamic>? blockAttributes,
87+
}) {
8488
return Paragraph.sealed(
8589
id: id,
8690
lines: <Line>[
8791
Line(fragments: <TextFragment>[frag.clone])
8892
],
89-
type: ParagraphType.inline,
93+
type: frag.data is! String
94+
? ParagraphType.embed
95+
: frag.data == '\n'
96+
? ParagraphType.lineBreak
97+
: blockAttributes != null
98+
? ParagraphType.block
99+
: ParagraphType.inline,
100+
blockAttributes:
101+
blockAttributes?.isNotEmpty ?? false ? blockAttributes : null,
90102
);
91103
}
92104

93-
factory Paragraph.withLine({String? id}) {
105+
factory Paragraph.withLine({
106+
String? id,
107+
Iterable<TextFragment>? fragments,
108+
}) {
94109
return Paragraph(
95110
id: id,
96111
lines: <Line>[
97112
Line(
98-
fragments: [],
113+
fragments: [...?fragments],
99114
),
100115
],
101116
type: ParagraphType.inline,
@@ -114,14 +129,14 @@ class Paragraph {
114129
Map<String, dynamic>? blockAttributes,
115130
String? id,
116131
}) {
117-
return Paragraph(
132+
return Paragraph.sealed(
118133
id: id,
119134
lines: <Line>[
120135
Line.newLine(),
121136
],
122137
blockAttributes: blockAttributes,
123138
type: ParagraphType.lineBreak,
124-
)..seal();
139+
);
125140
}
126141

127142
/// Constructs a [Paragraph] instance from a Object embed.
@@ -132,7 +147,7 @@ class Paragraph {
132147
Map<String, dynamic>? blockAttributes,
133148
String? id,
134149
}) {
135-
return Paragraph(
150+
return Paragraph.sealed(
136151
id: id,
137152
lines: <Line>[
138153
Line.fromData(data: data, attributes: attributes),
@@ -143,23 +158,31 @@ class Paragraph {
143158
? ParagraphType.block
144159
: ParagraphType.inline
145160
: ParagraphType.embed,
146-
)..seal();
161+
);
147162
}
148163

149164
/// Constructs a [Paragraph] instance from a Quill Delta embed operation.
150165
///
151166
/// This factory method creates a paragraph with a single line from the provided embed operation.
152167
///
153168
/// [operation] is the Quill Delta operation representing the embed.
154-
factory Paragraph.fromEmbed(fq.Operation operation, {String? id}) {
155-
return Paragraph(
169+
factory Paragraph.fromEmbed(
170+
fq.Operation operation, {
171+
String? id,
172+
Map<String, dynamic>? blockAttributes,
173+
}) {
174+
final bool isInlineOp = operation.data is String;
175+
return Paragraph.sealed(
156176
id: id,
157177
lines: <Line>[
158-
Line.fromData(data: operation.data!, attributes: operation.attributes),
178+
Line.fromData(
179+
data: operation.data!,
180+
attributes: operation.attributes,
181+
),
159182
],
160-
type:
161-
operation.data is String ? ParagraphType.inline : ParagraphType.embed,
162-
)..seal();
183+
blockAttributes: blockAttributes,
184+
type: isInlineOp ? ParagraphType.inline : ParagraphType.embed,
185+
);
163186
}
164187

165188
/// Get all the Lines into this Paragraph

test/flutter_quill_delta_easy_parser_test.dart

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,36 @@ import 'package:flutter_quill_delta_easy_parser/flutter_quill_delta_easy_parser.
33
import 'package:flutter_test/flutter_test.dart';
44

55
void main() {
6+
test('Ensure that is fixed: "Issue: Data Loss When Parsing Document #33"', () {
7+
final Delta delta = Delta()
8+
..insert("My delta can innovate all of the existent editors\n")
9+
..insert({"img": "path"})
10+
..insert('\n\n\n');
11+
12+
final Document expectedDocument = Document(
13+
paragraphs: [
14+
Paragraph.fragment(TextFragment(data: "My delta can innovate all of the existent editors")),
15+
Paragraph.fragment(TextFragment(
16+
data: {"img": "path"},
17+
)),
18+
Paragraph.newLine(),
19+
Paragraph.newLine(),
20+
Paragraph.newLine(),
21+
],
22+
);
23+
24+
final Document? parsedDocument = DocumentParser().parseDelta(delta: delta);
25+
_execExpects(parsedDocument, expectedDocument);
26+
});
27+
628
test('Should split newlines in two different Paragraphs', () {
729
final Delta delta = Delta()
8-
..insert("my_delta\n")
30+
..insert("\n")
931
..insert('\n');
1032

1133
final Document expectedDocument = Document(
1234
paragraphs: [
13-
Paragraph.fragment(TextFragment(data: "my_delta")),
35+
Paragraph.newLine(),
1436
Paragraph.newLine(),
1537
],
1638
);
@@ -327,7 +349,7 @@ void _execExpects(Document? parsedDocument, Document expectedDocument) {
327349
expect(
328350
parsedDocument?.paragraphs[i].blockAttributes,
329351
expectedDocument.paragraphs[i].blockAttributes,
330-
reason: 'Block difference at paragraph(index: $i).\n'
352+
reason: 'Block difference at paragraph(index: [$i]).\n'
331353
'Parsed: ${parsedDocument?.paragraphs[i].blockAttributes},\nExpected: ${expectedDocument.paragraphs[i].blockAttributes}',
332354
);
333355
expect(

0 commit comments

Comments
 (0)