Skip to content

Commit

Permalink
[Quill] - Added tests to lock down regular text followed by block sty…
Browse files Browse the repository at this point in the history
…les (Resolves #2303) (#2318)
  • Loading branch information
matthew-carroll authored Sep 16, 2024
1 parent a213ed3 commit 196b2a0
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 4 deletions.
1 change: 1 addition & 0 deletions super_editor_quill/lib/src/parsing/parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ MutableDocument parseQuillDeltaDocument(
return parseQuillDeltaOps(
deltaDocument["ops"],
customEditor: customEditor,
blockFormats: blockFormats,
inlineFormats: inlineFormats,
inlineEmbedFormats: inlineEmbedFormats,
embedBlockFormats: embedBlockFormats,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@ class EquivalentQuillDocumentMatcher extends Matcher {
}

@override
bool matches(covariant Object target, Map<dynamic, dynamic> matchState) {
return _calculateMismatchReason(target, matchState) == null;
bool matches(covariant Object item, Map<dynamic, dynamic> matchState) {
return _calculateMismatchReason(item, matchState) == null;
}

@override
Description describeMismatch(
covariant Object target,
covariant Object item,
Description mismatchDescription,
Map matchState,
bool verbose,
) {
final mismatchReason = _calculateMismatchReason(target, matchState);
final mismatchReason = _calculateMismatchReason(item, matchState);
if (mismatchReason != null) {
mismatchDescription.add(mismatchReason);
}
Expand Down
104 changes: 104 additions & 0 deletions super_editor_quill/test/parsing_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,33 @@ void main() {
expect(document.nodeCount, 7);
});

test("plain text followed by block format", () {
final document = parseQuillDeltaDocument(
{
"ops": [
{"insert": "This is regular text\nThis is a code block"},
{
"attributes": {"code-block": "plain"},
"insert": "\n"
},
],
},
);

expect(
(document.getNodeAt(0)! as ParagraphNode).text.text,
"This is regular text",
);
expect((document.getNodeAt(0)! as ParagraphNode).getMetadataValue("blockType"), paragraphAttribution);
expect(
(document.getNodeAt(1)! as ParagraphNode).text.text,
"This is a code block",
);
expect((document.getNodeAt(1)! as ParagraphNode).getMetadataValue("blockType"), codeAttribution);
expect((document.getNodeAt(2)! as ParagraphNode).text.text, "");
expect(document.nodeCount, 3);
});

test("multiline code block", () {
// Notice that Delta encodes each line of a code block as a separate attributed
// delta. But when a Quill editor renders the code block, it's rendered as one
Expand Down Expand Up @@ -686,6 +713,39 @@ void main() {
),
);
});

test("plain text followed by custom block format", () {
final document = parseQuillDeltaDocument(
{
"ops": [
{"insert": "This is regular text\nThis is a banner"},
{
"attributes": {
"banner-color": "red",
},
"insert": "\n"
},
],
},
blockFormats: [
const _BannerBlockFormat(),
...defaultBlockFormats,
],
);

expect(
(document.getNodeAt(0)! as ParagraphNode).text.text,
"This is regular text",
);
expect((document.getNodeAt(0)! as ParagraphNode).getMetadataValue("blockType"), paragraphAttribution);
expect(
(document.getNodeAt(1)! as ParagraphNode).text.text,
"This is a banner",
);
expect(
(document.getNodeAt(1)! as ParagraphNode).getMetadataValue("blockType"), const _BannerAttribution("red"));
expect(document.nodeCount, 3);
});
});
});
}
Expand All @@ -708,6 +768,50 @@ class _CustomListItemBlockFormat extends FilterByNameBlockDeltaFormat {
}
}

class _BannerBlockFormat extends FilterByNameBlockDeltaFormat {
const _BannerBlockFormat() : super("banner-color");

@override
List<EditRequest>? doApplyFormat(Editor editor, Object value) {
if (value is! String) {
return null;
}

final composer = editor.context.find<MutableDocumentComposer>(Editor.composerKey);
return [
ChangeParagraphBlockTypeRequest(
nodeId: composer.selection!.extent.nodeId,
blockType: _BannerAttribution(value),
),
];
}
}

class _BannerAttribution implements Attribution {
const _BannerAttribution(this.color);

@override
String get id => "banner-$color";

final String color;

@override
bool canMergeWith(Attribution other) {
if (other is! _BannerAttribution) {
return false;
}

return color == other.color;
}

@override
bool operator ==(Object other) =>
identical(this, other) || other is _BannerAttribution && runtimeType == other.runtimeType && color == other.color;

@override
int get hashCode => color.hashCode;
}

class _UserTagEmbedParser implements InlineEmbedFormat {
const _UserTagEmbedParser();

Expand Down
74 changes: 74 additions & 0 deletions super_editor_quill/test/serializing_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,45 @@ void main() {

expect(deltas, quillDocumentEquivalentTo(expectedDeltas));
});

test("doesn't merge custom block with previous delta", () {
final deltas = MutableDocument(
nodes: [
ParagraphNode(
id: "1",
text: AttributedText(
"This is a regular paragraph.",
),
),
ParagraphNode(
id: "2",
text: AttributedText(
"This is a banner (a custom block style).",
),
metadata: {
'blockType': const _BannerAttribution('red'),
},
),
],
).toQuillDeltas(
serializers: [
const _BannerDeltaSerializer(),
...defaultDeltaSerializers,
],
);

final expectedDeltas = Delta.fromJson([
{"insert": "This is a regular paragraph.\nThis is a banner (a custom block style)."},
{
"insert": "\n",
"attributes": {
"banner-color": "red",
},
},
]);

expect(deltas, quillDocumentEquivalentTo(expectedDeltas));
});
});
});
}
Expand Down Expand Up @@ -340,3 +379,38 @@ class _UserTagAttribution implements Attribution {
@override
int get hashCode => userId.hashCode;
}

class _BannerDeltaSerializer extends TextBlockDeltaSerializer {
const _BannerDeltaSerializer();

@override
Map<String, dynamic> getBlockFormats(TextNode textBlock) {
final bannerAttribution = textBlock.metadata['blockType'];
if (bannerAttribution is! _BannerAttribution) {
return super.getBlockFormats(textBlock);
}

final formats = super.getBlockFormats(textBlock);
formats['banner-color'] = bannerAttribution.color;

return formats;
}
}

class _BannerAttribution implements Attribution {
const _BannerAttribution(this.color);

@override
String get id => "banner-$color";

final String color;

@override
bool canMergeWith(Attribution other) {
if (other is! _BannerAttribution) {
return false;
}

return color == other.color;
}
}

0 comments on commit 196b2a0

Please sign in to comment.