@ckeditor/ckeditor5-image
Version:
Image feature for CKEditor 5.
139 lines (138 loc) • 5.89 kB
JavaScript
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
import { Command } from 'ckeditor5/src/core';
import ImageBlockEditing from '../image/imageblockediting';
/**
* The toggle image caption command.
*
* This command is registered by {@link module:image/imagecaption/imagecaptionediting~ImageCaptionEditing} as the
* `'toggleImageCaption'` editor command.
*
* Executing this command:
*
* * either adds or removes the image caption of a selected image (depending on whether the caption is present or not),
* * removes the image caption if the selection is anchored in one.
*
* ```ts
* // Toggle the presence of the caption.
* editor.execute( 'toggleImageCaption' );
* ```
*
* **Note**: Upon executing this command, the selection will be set on the image if previously anchored in the caption element.
*
* **Note**: You can move the selection to the caption right away as it shows up upon executing this command by using
* the `focusCaptionOnShow` option:
*
* ```ts
* editor.execute( 'toggleImageCaption', { focusCaptionOnShow: true } );
* ```
*/
export default class ToggleImageCaptionCommand extends Command {
/**
* @inheritDoc
*/
refresh() {
const editor = this.editor;
const imageCaptionUtils = editor.plugins.get('ImageCaptionUtils');
const imageUtils = editor.plugins.get('ImageUtils');
// Only block images can get captions.
if (!editor.plugins.has(ImageBlockEditing)) {
this.isEnabled = false;
this.value = false;
return;
}
const selection = editor.model.document.selection;
const selectedElement = selection.getSelectedElement();
if (!selectedElement) {
const ancestorCaptionElement = imageCaptionUtils.getCaptionFromModelSelection(selection);
this.isEnabled = !!ancestorCaptionElement;
this.value = !!ancestorCaptionElement;
return;
}
// Block images support captions by default but the command should also be enabled for inline
// images because toggling the caption when one is selected should convert it into a block image.
this.isEnabled = imageUtils.isImage(selectedElement);
if (!this.isEnabled) {
this.value = false;
}
else {
this.value = !!imageCaptionUtils.getCaptionFromImageModelElement(selectedElement);
}
}
/**
* Executes the command.
*
* ```ts
* editor.execute( 'toggleImageCaption' );
* ```
*
* @param options Options for the executed command.
* @param options.focusCaptionOnShow When true and the caption shows up, the selection will be moved into it straight away.
* @fires execute
*/
execute(options = {}) {
const { focusCaptionOnShow } = options;
this.editor.model.change(writer => {
if (this.value) {
this._hideImageCaption(writer);
}
else {
this._showImageCaption(writer, focusCaptionOnShow);
}
});
}
/**
* Shows the caption of the `<imageBlock>` or `<imageInline>`. Also:
*
* * it converts `<imageInline>` to `<imageBlock>` to show the caption,
* * it attempts to restore the caption content from the `ImageCaptionEditing` caption registry,
* * it moves the selection to the caption right away, it the `focusCaptionOnShow` option was set.
*/
_showImageCaption(writer, focusCaptionOnShow) {
const model = this.editor.model;
const selection = model.document.selection;
const imageCaptionEditing = this.editor.plugins.get('ImageCaptionEditing');
const imageUtils = this.editor.plugins.get('ImageUtils');
let selectedImage = selection.getSelectedElement();
const savedCaption = imageCaptionEditing._getSavedCaption(selectedImage);
// Convert imageInline -> image first.
if (imageUtils.isInlineImage(selectedImage)) {
this.editor.execute('imageTypeBlock');
// Executing the command created a new model element. Let's pick it again.
selectedImage = selection.getSelectedElement();
}
// Try restoring the caption from the ImageCaptionEditing plugin storage.
const newCaptionElement = savedCaption || writer.createElement('caption');
writer.append(newCaptionElement, selectedImage);
if (focusCaptionOnShow) {
writer.setSelection(newCaptionElement, 'in');
}
}
/**
* Hides the caption of a selected image (or an image caption the selection is anchored to).
*
* The content of the caption is stored in the `ImageCaptionEditing` caption registry to make this
* a reversible action.
*/
_hideImageCaption(writer) {
const editor = this.editor;
const selection = editor.model.document.selection;
const imageCaptionEditing = editor.plugins.get('ImageCaptionEditing');
const imageCaptionUtils = editor.plugins.get('ImageCaptionUtils');
let selectedImage = selection.getSelectedElement();
let captionElement;
if (selectedImage) {
captionElement = imageCaptionUtils.getCaptionFromImageModelElement(selectedImage);
}
else {
captionElement = imageCaptionUtils.getCaptionFromModelSelection(selection);
selectedImage = captionElement.parent;
}
// Store the caption content so it can be restored quickly if the user changes their mind even if they toggle image<->imageInline.
imageCaptionEditing._saveCaption(selectedImage, captionElement);
writer.setSelection(selectedImage, 'on');
writer.remove(captionElement);
}
}