@ckeditor/ckeditor5-image
Version:
Image feature for CKEditor 5.
166 lines (165 loc) • 5.95 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 { Plugin } from 'ckeditor5/src/core';
import ImageUtils from '../imageutils';
import ResizeImageCommand from './resizeimagecommand';
import { widthAndHeightStylesAreBothSet } from '../image/utils';
/**
* The image resize editing feature.
*
* It adds the ability to resize each image using handles or manually by
* {@link module:image/imageresize/imageresizebuttons~ImageResizeButtons} buttons.
*/
export default class ImageResizeEditing extends Plugin {
/**
* @inheritDoc
*/
static get requires() {
return [ImageUtils];
}
/**
* @inheritDoc
*/
static get pluginName() {
return 'ImageResizeEditing';
}
/**
* @inheritDoc
*/
constructor(editor) {
super(editor);
editor.config.define('image', {
resizeUnit: '%',
resizeOptions: [{
name: 'resizeImage:original',
value: null,
icon: 'original'
},
{
name: 'resizeImage:25',
value: '25',
icon: 'small'
},
{
name: 'resizeImage:50',
value: '50',
icon: 'medium'
},
{
name: 'resizeImage:75',
value: '75',
icon: 'large'
}]
});
}
/**
* @inheritDoc
*/
init() {
const editor = this.editor;
const resizeImageCommand = new ResizeImageCommand(editor);
this._registerSchema();
this._registerConverters('imageBlock');
this._registerConverters('imageInline');
// Register `resizeImage` command and add `imageResize` command as an alias for backward compatibility.
editor.commands.add('resizeImage', resizeImageCommand);
editor.commands.add('imageResize', resizeImageCommand);
}
_registerSchema() {
if (this.editor.plugins.has('ImageBlockEditing')) {
this.editor.model.schema.extend('imageBlock', { allowAttributes: ['resizedWidth', 'resizedHeight'] });
}
if (this.editor.plugins.has('ImageInlineEditing')) {
this.editor.model.schema.extend('imageInline', { allowAttributes: ['resizedWidth', 'resizedHeight'] });
}
}
/**
* Registers image resize converters.
*
* @param imageType The type of the image.
*/
_registerConverters(imageType) {
const editor = this.editor;
const imageUtils = editor.plugins.get('ImageUtils');
// Dedicated converter to propagate image's attribute to the img tag.
editor.conversion.for('downcast').add(dispatcher => dispatcher.on(`attribute:resizedWidth:${imageType}`, (evt, data, conversionApi) => {
if (!conversionApi.consumable.consume(data.item, evt.name)) {
return;
}
const viewWriter = conversionApi.writer;
const viewImg = conversionApi.mapper.toViewElement(data.item);
if (data.attributeNewValue !== null) {
viewWriter.setStyle('width', data.attributeNewValue, viewImg);
viewWriter.addClass('image_resized', viewImg);
}
else {
viewWriter.removeStyle('width', viewImg);
viewWriter.removeClass('image_resized', viewImg);
}
}));
editor.conversion.for('dataDowncast').attributeToAttribute({
model: {
name: imageType,
key: 'resizedHeight'
},
view: modelAttributeValue => ({
key: 'style',
value: {
'height': modelAttributeValue
}
})
});
editor.conversion.for('editingDowncast').add(dispatcher => dispatcher.on(`attribute:resizedHeight:${imageType}`, (evt, data, conversionApi) => {
if (!conversionApi.consumable.consume(data.item, evt.name)) {
return;
}
const viewWriter = conversionApi.writer;
const viewImg = conversionApi.mapper.toViewElement(data.item);
const target = imageType === 'imageInline' ? imageUtils.findViewImgElement(viewImg) : viewImg;
if (data.attributeNewValue !== null) {
viewWriter.setStyle('height', data.attributeNewValue, target);
}
else {
viewWriter.removeStyle('height', target);
}
}));
editor.conversion.for('upcast')
.attributeToAttribute({
view: {
name: imageType === 'imageBlock' ? 'figure' : 'img',
styles: {
width: /.+/
}
},
model: {
key: 'resizedWidth',
value: (viewElement) => {
if (widthAndHeightStylesAreBothSet(viewElement)) {
return null;
}
return viewElement.getStyle('width');
}
}
});
editor.conversion.for('upcast')
.attributeToAttribute({
view: {
name: imageType === 'imageBlock' ? 'figure' : 'img',
styles: {
height: /.+/
}
},
model: {
key: 'resizedHeight',
value: (viewElement) => {
if (widthAndHeightStylesAreBothSet(viewElement)) {
return null;
}
return viewElement.getStyle('height');
}
}
});
}
}