@ckeditor/ckeditor5-image
Version:
Image feature for CKEditor 5.
108 lines (107 loc) • 4.81 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';
/**
* The image style command. It is used to apply {@link module:image/imageconfig~ImageStyleConfig#options image style option}
* to a selected image.
*
* **Note**: Executing this command may change the image model element if the desired style requires an image of a different
* type. See {@link module:image/imagestyle/imagestylecommand~ImageStyleCommand#execute} to learn more.
*/
export default class ImageStyleCommand extends Command {
/**
* Creates an instance of the image style command. When executed, the command applies one of
* {@link module:image/imageconfig~ImageStyleConfig#options style options} to the currently selected image.
*
* @param editor The editor instance.
* @param styles The style options that this command supports.
*/
constructor(editor, styles) {
super(editor);
this._defaultStyles = {
imageBlock: false,
imageInline: false
};
this._styles = new Map(styles.map(style => {
if (style.isDefault) {
for (const modelElementName of style.modelElements) {
this._defaultStyles[modelElementName] = style.name;
}
}
return [style.name, style];
}));
}
/**
* @inheritDoc
*/
refresh() {
const editor = this.editor;
const imageUtils = editor.plugins.get('ImageUtils');
const element = imageUtils.getClosestSelectedImageElement(this.editor.model.document.selection);
this.isEnabled = !!element;
if (!this.isEnabled) {
this.value = false;
}
else if (element.hasAttribute('imageStyle')) {
this.value = element.getAttribute('imageStyle');
}
else {
this.value = this._defaultStyles[element.name];
}
}
/**
* Executes the command and applies the style to the currently selected image:
*
* ```ts
* editor.execute( 'imageStyle', { value: 'side' } );
* ```
*
* **Note**: Executing this command may change the image model element if the desired style requires an image
* of a different type. Learn more about {@link module:image/imageconfig~ImageStyleOptionDefinition#modelElements model element}
* configuration for the style option.
*
* @param options.value The name of the style (as configured in {@link module:image/imageconfig~ImageStyleConfig#options}).
* @param options.setImageSizes Specifies whether the image `width` and `height` attributes should be set automatically.
* The default is `true`.
* @fires execute
*/
execute(options = {}) {
const editor = this.editor;
const model = editor.model;
const imageUtils = editor.plugins.get('ImageUtils');
model.change(writer => {
const requestedStyle = options.value;
const { setImageSizes = true } = options;
let imageElement = imageUtils.getClosestSelectedImageElement(model.document.selection);
// Change the image type if a style requires it.
if (requestedStyle && this.shouldConvertImageType(requestedStyle, imageElement)) {
this.editor.execute(imageUtils.isBlockImage(imageElement) ? 'imageTypeInline' : 'imageTypeBlock', { setImageSizes });
// Update the imageElement to the newly created image.
imageElement = imageUtils.getClosestSelectedImageElement(model.document.selection);
}
// Default style means that there is no `imageStyle` attribute in the model.
// https://github.com/ckeditor/ckeditor5-image/issues/147
if (!requestedStyle || this._styles.get(requestedStyle).isDefault) {
writer.removeAttribute('imageStyle', imageElement);
}
else {
writer.setAttribute('imageStyle', requestedStyle, imageElement);
}
if (setImageSizes) {
imageUtils.setImageNaturalSizeAttributes(imageElement);
}
});
}
/**
* Returns `true` if requested style change would trigger the image type change.
*
* @param requestedStyle The name of the style (as configured in {@link module:image/imageconfig~ImageStyleConfig#options}).
* @param imageElement The image model element.
*/
shouldConvertImageType(requestedStyle, imageElement) {
const supportedTypes = this._styles.get(requestedStyle).modelElements;
return !supportedTypes.includes(imageElement.name);
}
}