Commit 3107464d authored by Enrique Alcántara's avatar Enrique Alcántara Committed by Frédéric Caplette

Return DOM fragment in Markdown Serializer

Return DOMFragment along with ProseMirror document
in the MarkdownDeserializer
parent 4ba8a6f5
......@@ -34,15 +34,15 @@ export default Extension.create({
deserializer
.deserialize({ schema: editor.schema, content: markdown })
.then((doc) => {
if (!doc) {
.then(({ document }) => {
if (!document) {
return;
}
const { state, view } = editor;
const { tr, selection } = state;
tr.replaceWith(selection.from - 1, selection.to, doc.content);
tr.replaceWith(selection.from - 1, selection.to, document.content);
view.dispatch(tr);
eventHub.$emit(LOADING_SUCCESS_EVENT);
})
......
......@@ -40,13 +40,14 @@ export class ContentEditor {
try {
eventHub.$emit(LOADING_CONTENT_EVENT);
const newDoc = await deserializer.deserialize({
const { document } = await deserializer.deserialize({
schema: editor.schema,
content: serializedContent,
});
if (newDoc) {
if (document) {
tr.setSelection(selection)
.replaceSelectionWith(newDoc, false)
.replaceSelectionWith(document, false)
.setMeta('preventUpdate', true);
editor.view.dispatch(tr);
}
......
......@@ -4,16 +4,22 @@ export default ({ render }) => {
/**
* Converts a Markdown string into a ProseMirror JSONDocument based
* on a ProseMirror schema.
*
* @param {Object} options — The schema and content for deserialization
* @param {ProseMirror.Schema} params.schema A ProseMirror schema that defines
* the types of content supported in the document
* @param {String} params.content An arbitrary markdown string
* @returns A ProseMirror JSONDocument
*
* @returns An object with the following properties:
* - document: A ProseMirror document object generated from the deserialized Markdown
* - dom: The Markdown Deserializer renders Markdown as HTML to generate the ProseMirror
* document. The dom property contains the HTML generated from the Markdown Source.
*/
return {
deserialize: async ({ schema, content }) => {
const html = await render(content);
if (!html) return null;
if (!html) return {};
const parser = new DOMParser();
const { body } = parser.parseFromString(html, 'text/html');
......@@ -21,7 +27,7 @@ export default ({ render }) => {
// append original source as a comment that nodes can access
body.append(document.createComment(content));
return ProseMirrorDOMParser.fromSchema(schema).parse(body);
return { document: ProseMirrorDOMParser.fromSchema(schema).parse(body), dom: body };
},
};
};
......@@ -5,18 +5,26 @@ import {
} from '~/content_editor/constants';
import { ContentEditor } from '~/content_editor/services/content_editor';
import eventHubFactory from '~/helpers/event_hub_factory';
import { createTestEditor } from '../test_utils';
import { createTestEditor, createDocBuilder } from '../test_utils';
describe('content_editor/services/content_editor', () => {
let contentEditor;
let serializer;
let deserializer;
let eventHub;
let doc;
let p;
beforeEach(() => {
const tiptapEditor = createTestEditor();
jest.spyOn(tiptapEditor, 'destroy');
({
builders: { doc, p },
} = createDocBuilder({
tiptapEditor,
}));
serializer = { deserialize: jest.fn() };
deserializer = { deserialize: jest.fn() };
eventHub = eventHubFactory();
......@@ -34,8 +42,11 @@ describe('content_editor/services/content_editor', () => {
});
describe('when setSerializedContent succeeds', () => {
let document;
beforeEach(() => {
deserializer.deserialize.mockResolvedValueOnce('');
document = doc(p('document'));
deserializer.deserialize.mockResolvedValueOnce({ document });
});
it('emits loadingContent and loadingSuccess event in the eventHub', () => {
......@@ -50,6 +61,12 @@ describe('content_editor/services/content_editor', () => {
contentEditor.setSerializedContent('**bold text**');
});
it('sets the deserialized document in the tiptap editor object', async () => {
await contentEditor.setSerializedContent('**bold text**');
expect(contentEditor.tiptapEditor.state.doc.toJSON()).toEqual(document.toJSON());
});
});
describe('when setSerializedContent fails', () => {
......
......@@ -25,27 +25,38 @@ describe('content_editor/services/markdown_deserializer', () => {
renderMarkdown = jest.fn();
});
it('transforms HTML returned by render function to a ProseMirror document', async () => {
describe('when deserializing', () => {
let result;
const text = 'Bold text';
beforeEach(async () => {
const deserializer = createMarkdownDeserializer({ render: renderMarkdown });
const expectedDoc = doc(p(bold('Bold text')));
renderMarkdown.mockResolvedValueOnce('<p><strong>Bold text</strong></p>');
renderMarkdown.mockResolvedValueOnce(`<p><strong>${text}</strong></p>`);
const result = await deserializer.deserialize({
result = await deserializer.deserialize({
content: 'content',
schema: tiptapEditor.schema,
});
});
it('transforms HTML returned by render function to a ProseMirror document', async () => {
const expectedDoc = doc(p(bold(text)));
expect(result.toJSON()).toEqual(expectedDoc.toJSON());
expect(result.document.toJSON()).toEqual(expectedDoc.toJSON());
});
it('returns parsed HTML as a DOM object', () => {
expect(result.dom.innerHTML).toEqual(`<p><strong>${text}</strong></p><!--content-->`);
});
});
describe('when the render function returns an empty value', () => {
it('also returns null', async () => {
it('returns an empty object', async () => {
const deserializer = createMarkdownDeserializer({ render: renderMarkdown });
renderMarkdown.mockResolvedValueOnce(null);
expect(await deserializer.deserialize({ content: 'content' })).toBe(null);
expect(await deserializer.deserialize({ content: 'content' })).toEqual({});
});
});
});
......@@ -73,7 +73,7 @@ describe('content_editor/services/markdown_sourcemap', () => {
});
it('gets markdown source for a rendered HTML element', async () => {
const deserialized = await markdownDeserializer({
const { document } = await markdownDeserializer({
render: () => BULLET_LIST_HTML,
}).deserialize({
schema: tiptapEditor.schema,
......@@ -95,6 +95,6 @@ describe('content_editor/services/markdown_sourcemap', () => {
),
);
expect(deserialized.toJSON()).toEqual(expected.toJSON());
expect(document.toJSON()).toEqual(expected.toJSON());
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment