TLDR; I want to insert a compiled Vue JS component into the CKEditor editable body, as part of the downcasting process of a plugin.
I have a custom CKEditor image plugin, for a CMS-style site. The user inserts an image by selecting their image from an image picker (outside CKEditor), and then a CKEditor command is executed to insert the image:
const model = this.editor.model;
model.change(writer => {
const imageElement = writer.createElement('custom-image');
const insertAtSelection = findOptimalInsertionPosition(model.document.selection, model);
model.insertContent(imageElement, insertAtSelection);
});
There is a plugin which registers the 'custom-image' element into the schema, inside the plugin's init
method:
const schema = this.editor.model.schema;
schema.register('custom-image', {
isObject: true,
isBlock: true,
allowIn: '$root'
});
Then, there is a downcast handler registered (also inside the plugin's init
method):
const conversion = this.editor.conversion;
// A similar handler is used for editingDowncast
conversion.for('dataDowncast').elementToElement({
model: 'custom-image',
view: (modelElement, viewWriter) => {
return writer.createContainerElement('div', {
class: 'custom-image',
});
}
});
Now, I have a Vue component, with a reference to the DOM node I would like to insert inside the newly created div.custom-image
(ContainerElement
).
I've tried creating a handler on the downcastDispatcher, like so:
this.editor.editing.downcastDispatcher.on("insert:custom-image", (evt, data, conversionApi) => {
const el = ... // Vue component is created here
const viewElement = conversionApi.mapper.toViewElement(data.item);
const domNode = view.domConverter.mapViewToDom(viewElement);
domNode.appendChild(el);
});
The problem is 1) viewElement
doesn't seem to have been added to the DOM yet (so mapViewToDom
returns undefined), and 2) if I wait for viewElement
to be added to the DOM (using setTimeout, a nasty hack), the contents of the Vue component are mostly stripped, because the schema doesn't allow for them.
The Vue component that is being added is quite complex, and talks to the application outside CKEditor. Recreating the component using CKEditor's model would be quite messy. It is also used in the view-side of the application, so it would be nice to be able to reuse the same component as part of the editing and viewing part of the app.
So, what would be the best way to solve this issue?