@ckeditor/ckeditor5-table
Version:
Table feature for CKEditor 5.
129 lines (128 loc) • 4.74 kB
JavaScript
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
/**
* @module table/tablecaption/tablecaptionediting
*/
import { Plugin } from 'ckeditor5/src/core.js';
import { Element, enablePlaceholder } from 'ckeditor5/src/engine.js';
import { toWidgetEditable } from 'ckeditor5/src/widget.js';
import injectTableCaptionPostFixer from '../converters/table-caption-post-fixer.js';
import ToggleTableCaptionCommand from './toggletablecaptioncommand.js';
import { isTable, matchTableCaptionViewElement } from './utils.js';
/**
* The table caption editing plugin.
*/
export default class TableCaptionEditing extends Plugin {
/**
* @inheritDoc
*/
static get pluginName() {
return 'TableCaptionEditing';
}
/**
* @inheritDoc
*/
static get isOfficialPlugin() {
return true;
}
/**
* @inheritDoc
*/
constructor(editor) {
super(editor);
this._savedCaptionsMap = new WeakMap();
}
/**
* @inheritDoc
*/
init() {
const editor = this.editor;
const schema = editor.model.schema;
const view = editor.editing.view;
const t = editor.t;
if (!schema.isRegistered('caption')) {
schema.register('caption', {
allowIn: 'table',
allowContentOf: '$block',
isLimit: true
});
}
else {
schema.extend('caption', {
allowIn: 'table'
});
}
editor.commands.add('toggleTableCaption', new ToggleTableCaptionCommand(this.editor));
// View -> model converter for the data pipeline.
editor.conversion.for('upcast').elementToElement({
view: matchTableCaptionViewElement,
model: 'caption'
});
// Model -> view converter for the data pipeline.
editor.conversion.for('dataDowncast').elementToElement({
model: 'caption',
view: (modelElement, { writer }) => {
if (!isTable(modelElement.parent)) {
return null;
}
return writer.createContainerElement('figcaption');
}
});
// Model -> view converter for the editing pipeline.
editor.conversion.for('editingDowncast').elementToElement({
model: 'caption',
view: (modelElement, { writer }) => {
if (!isTable(modelElement.parent)) {
return null;
}
const figcaptionElement = writer.createEditableElement('figcaption');
writer.setCustomProperty('tableCaption', true, figcaptionElement);
figcaptionElement.placeholder = t('Enter table caption');
enablePlaceholder({
view,
element: figcaptionElement,
keepOnFocus: true
});
return toWidgetEditable(figcaptionElement, writer);
}
});
injectTableCaptionPostFixer(editor.model);
}
/**
* Returns the saved {@link module:engine/model/element~Element#toJSON JSONified} caption
* of a table model element.
*
* See {@link #_saveCaption}.
*
* @internal
* @param tableModelElement The model element the caption should be returned for.
* @returns The model caption element or `null` if there is none.
*/
_getSavedCaption(tableModelElement) {
const jsonObject = this._savedCaptionsMap.get(tableModelElement);
return jsonObject ? Element.fromJSON(jsonObject) : null;
}
/**
* Saves a {@link module:engine/model/element~Element#toJSON JSONified} caption for
* a table element to allow restoring it in the future.
*
* A caption is saved every time it gets hidden. The
* user should be able to restore it on demand.
*
* **Note**: The caption cannot be stored in the table model element attribute because,
* for instance, when the model state propagates to collaborators, the attribute would get
* lost (mainly because it does not convert to anything when the caption is hidden) and
* the states of collaborators' models would de-synchronize causing numerous issues.
*
* See {@link #_getSavedCaption}.
*
* @internal
* @param tableModelElement The model element the caption is saved for.
* @param caption The caption model element to be saved.
*/
_saveCaption(tableModelElement, caption) {
this._savedCaptionsMap.set(tableModelElement, caption.toJSON());
}
}