Skip to content

Commit 350fcf1

Browse files
authored
Merge pull request #5904 from marcellamaki/fix-linebreaks
update how linebreaks are saved so they render properly in perseus
2 parents d6fcaf5 + 6cba2b2 commit 350fcf1

2 files changed

Lines changed: 35 additions & 6 deletions

File tree

contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/utils/markdownSerializer.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,25 @@ export const createCustomMarkdownSerializer = editor => {
5757
switch (node.type.name) {
5858
case 'doc': {
5959
const parts = [];
60-
// Process all children
6160
if (node.content && node.content.size > 0) {
6261
for (let i = 0; i < node.content.size; i++) {
6362
const child = node.content.content[i];
64-
if (child) parts.push(serializeNode(child, null, depth));
63+
if (child)
64+
parts.push({ type: child.type?.name, md: serializeNode(child, null, depth) });
6565
}
6666
}
67-
return parts.join('\n\n');
67+
// Use a hard break ( \n) between consecutive plain paragraphs so Perseus
68+
// renders them as <br> (inline-safe). All other block transitions keep \n\n
69+
// so marked still parses lists, headings, etc. correctly.
70+
return parts
71+
.map((part, idx) => {
72+
if (idx === 0) return part.md;
73+
const prev = parts[idx - 1];
74+
const separator =
75+
prev.type === 'paragraph' && part.type === 'paragraph' ? ' \n' : '\n\n';
76+
return separator + part.md;
77+
})
78+
.join('');
6879
}
6980

7081
case 'paragraph': {

contentcuration/contentcuration/frontend/shared/views/TipTapEditor/__tests__/markdownSerializer.spec.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,32 @@ describe('createCustomMarkdownSerializer', () => {
177177
expect(getMarkdown()).toBe('- Item 1\n - Nested 1.1\n- Item 2');
178178
});
179179

180-
it('should place two newlines between block elements', () => {
180+
it('should use a hard break between consecutive paragraphs so Perseus renders them as <br>', () => {
181181
const docContent = [
182182
{ type: 'paragraph', content: [{ type: 'text', text: 'First paragraph.' }] },
183183
{ type: 'paragraph', content: [{ type: 'text', text: 'Second paragraph.' }] },
184184
];
185185
const mockEditor = createMockEditor(docContent);
186186
const getMarkdown = createCustomMarkdownSerializer(mockEditor);
187-
expect(getMarkdown()).toBe('First paragraph.\n\nSecond paragraph.');
187+
expect(getMarkdown()).toBe('First paragraph. \nSecond paragraph.');
188+
});
189+
190+
it('should use two newlines between a paragraph and a non-paragraph block', () => {
191+
const docContent = [
192+
{ type: 'paragraph', content: [{ type: 'text', text: 'Intro.' }] },
193+
{
194+
type: 'bulletList',
195+
content: [
196+
{
197+
type: 'listItem',
198+
content: [{ type: 'paragraph', content: [{ type: 'text', text: 'Item A' }] }],
199+
},
200+
],
201+
},
202+
];
203+
const mockEditor = createMockEditor(docContent);
204+
const getMarkdown = createCustomMarkdownSerializer(mockEditor);
205+
expect(getMarkdown()).toBe('Intro.\n\n- Item A');
188206
});
189207
});
190208

@@ -405,7 +423,7 @@ describe('createCustomMarkdownSerializer', () => {
405423
const mockEditor = createMockEditor(docContent);
406424
const getMarkdown = createCustomMarkdownSerializer(mockEditor);
407425
expect(getMarkdown()).toBe(
408-
'<p style="text-align: center">Centered</p>\n\nNormal\n\n<p style="text-align: right">Right</p>',
426+
'<p style="text-align: center">Centered</p> \nNormal \n<p style="text-align: right">Right</p>',
409427
);
410428
});
411429

0 commit comments

Comments
 (0)