Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow and preserve image width and height #14233

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/ckeditor5-html-support/tests/integrations/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -2406,6 +2406,8 @@ describe( 'ImageElementSupport', () => {
'src',
'srcset',
'linkHref',
'width',
'height',
'htmlImgAttributes',
'htmlFigureAttributes',
'htmlLinkAttributes'
Expand Down Expand Up @@ -2440,6 +2442,8 @@ describe( 'ImageElementSupport', () => {
'alt',
'src',
'srcset',
'width',
'height',
'htmlA',
'htmlImgAttributes'
] );
Expand Down
2 changes: 2 additions & 0 deletions packages/ckeditor5-image/src/augmentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import type {
ImageCaptionUtils,
ImageInsertUI,
ImageResizeEditing,
ImageSizeAttributes,
ImageStyleEditing,
ImageStyleUI,
ImageTextAlternativeEditing,
Expand Down Expand Up @@ -76,6 +77,7 @@ declare module '@ckeditor/ckeditor5-core' {
[ ImageCaptionUtils.pluginName ]: ImageCaptionUtils;
[ ImageInsertUI.pluginName ]: ImageInsertUI;
[ ImageResizeEditing.pluginName ]: ImageResizeEditing;
[ ImageSizeAttributes.pluginName ]: ImageSizeAttributes;
[ ImageStyleEditing.pluginName ]: ImageStyleEditing;
[ ImageStyleUI.pluginName ]: ImageStyleUI;
[ ImageTextAlternativeEditing.pluginName ]: ImageTextAlternativeEditing;
Expand Down
26 changes: 5 additions & 21 deletions packages/ckeditor5-image/src/image/converters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import type {
import { first, type GetCallback } from 'ckeditor5/src/utils';
import type ImageUtils from '../imageutils';

type SrcsetAttributeType = null | { data: unknown; width: unknown };

/**
* Returns a function that converts the image view representation:
*
Expand Down Expand Up @@ -178,7 +176,7 @@ export function upcastPicture( imageUtils: ImageUtils ): ( dispatcher: UpcastDis
}

/**
* Converter used to convert the `srcset` model image attribute to the `srcset`, `sizes` and `width` attributes in the view.
* Converter used to convert the `srcset` model image attribute to the `srcset` and `sizes` attributes in the view.
*
* @internal
* @param imageType The type of the image.
Expand All @@ -197,27 +195,13 @@ export function downcastSrcsetAttribute(
const img = imageUtils.findViewImgElement( element )!;

if ( data.attributeNewValue === null ) {
const srcset = data.attributeOldValue as SrcsetAttributeType;

if ( srcset && srcset.data ) {
writer.removeAttribute( 'srcset', img );
writer.removeAttribute( 'sizes', img );

if ( srcset.width ) {
writer.removeAttribute( 'width', img );
}
}
writer.removeAttribute( 'srcset', img );
writer.removeAttribute( 'sizes', img );
} else {
const srcset = data.attributeNewValue as SrcsetAttributeType;

if ( srcset && srcset.data ) {
writer.setAttribute( 'srcset', srcset.data, img );
if ( data.attributeNewValue ) {
writer.setAttribute( 'srcset', data.attributeNewValue, img );
// Always outputting `100vw`. See https://github.com/ckeditor/ckeditor5-image/issues/2.
writer.setAttribute( 'sizes', '100vw', img );

if ( srcset.width ) {
writer.setAttribute( 'width', srcset.width, img );
}
}
}
};
Expand Down
3 changes: 2 additions & 1 deletion packages/ckeditor5-image/src/image/imageblockediting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from './converters';

import ImageEditing from './imageediting';
import ImageSizeAttributes from '../imagesizeattributes';
import ImageTypeCommand from './imagetypecommand';
import ImageUtils from '../imageutils';
import {
Expand All @@ -41,7 +42,7 @@ export default class ImageBlockEditing extends Plugin {
* @inheritDoc
*/
public static get requires() {
return [ ImageEditing, ImageUtils, ClipboardPipeline ] as const;
return [ ImageEditing, ImageSizeAttributes, ImageUtils, ClipboardPipeline ] as const;
}

/**
Expand Down
16 changes: 4 additions & 12 deletions packages/ckeditor5-image/src/image/imageediting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,13 @@ export default class ImageEditing extends Plugin {
.attributeToAttribute( {
view: {
name: 'img',
key: 'srcset'
attributes: {
srcset: /.+/
}
},
model: {
key: 'srcset',
value: ( viewImage: ViewElement ) => {
const value: Record<string, string> = {
data: viewImage.getAttribute( 'srcset' )!
};

if ( viewImage.hasAttribute( 'width' ) ) {
value.width = viewImage.getAttribute( 'width' )!;
}

return value;
}
value: ( viewImage: ViewElement ) => viewImage.getAttribute( 'srcset' )
}
} );

Expand Down
3 changes: 2 additions & 1 deletion packages/ckeditor5-image/src/image/imageinlineediting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from './converters';

import ImageEditing from './imageediting';
import ImageSizeAttributes from '../imagesizeattributes';
import ImageTypeCommand from './imagetypecommand';
import ImageUtils from '../imageutils';
import {
Expand All @@ -40,7 +41,7 @@ export default class ImageInlineEditing extends Plugin {
* @inheritDoc
*/
public static get requires() {
return [ ImageEditing, ImageUtils, ClipboardPipeline ] as const;
return [ ImageEditing, ImageSizeAttributes, ImageUtils, ClipboardPipeline ] as const;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,11 @@ export default class ImageResizeEditing extends Plugin {

private _registerSchema(): void {
if ( this.editor.plugins.has( 'ImageBlockEditing' ) ) {
this.editor.model.schema.extend( 'imageBlock', { allowAttributes: 'width' } );
this.editor.model.schema.extend( 'imageBlock', { allowAttributes: 'resizedWidth' } );
}

if ( this.editor.plugins.has( 'ImageInlineEditing' ) ) {
this.editor.model.schema.extend( 'imageInline', { allowAttributes: 'width' } );
this.editor.model.schema.extend( 'imageInline', { allowAttributes: 'resizedWidth' } );
}
}

Expand All @@ -100,7 +100,7 @@ export default class ImageResizeEditing extends Plugin {

// Dedicated converter to propagate image's attribute to the img tag.
editor.conversion.for( 'downcast' ).add( dispatcher =>
dispatcher.on( `attribute:width:${ imageType }`, ( evt, data, conversionApi ) => {
dispatcher.on( `attribute:resizedWidth:${ imageType }`, ( evt, data, conversionApi ) => {
if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
return;
}
Expand All @@ -127,7 +127,7 @@ export default class ImageResizeEditing extends Plugin {
}
},
model: {
key: 'width',
key: 'resizedWidth',
value: ( viewElement: ViewElement ) => viewElement.getStyle( 'width' )
}
} );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ export default class ResizeImageCommand extends Command {

this.isEnabled = !!element;

if ( !element || !element.hasAttribute( 'width' ) ) {
if ( !element || !element.hasAttribute( 'resizedWidth' ) ) {
this.value = null;
} else {
this.value = {
width: element.getAttribute( 'width' ) as string,
width: element.getAttribute( 'resizedWidth' ) as string,
height: null
};
}
Expand Down Expand Up @@ -71,7 +71,7 @@ export default class ResizeImageCommand extends Command {

if ( imageElement ) {
model.change( writer => {
writer.setAttribute( 'width', options.width, imageElement );
writer.setAttribute( 'resizedWidth', options.width, imageElement );
} );
}
}
Expand Down
112 changes: 112 additions & 0 deletions packages/ckeditor5-image/src/imagesizeattributes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/**
* @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
*/

/**
* @module image/imagesizeattributes
*/

import { Plugin } from 'ckeditor5/src/core';
import type { DowncastDispatcher, DowncastAttributeEvent, ViewElement, Element } from 'ckeditor5/src/engine';
import ImageUtils from './imageutils';

/**
* This plugin enables `width` and `size` attributes in inline and block image elements.
*/
export default class ImageSizeAttributes extends Plugin {
/**
* @inheritDoc
*/
public static get requires() {
return [ ImageUtils ] as const;
}

/**
* @inheritDoc
*/
public static get pluginName(): 'ImageSizeAttributes' {
return 'ImageSizeAttributes';
}

/**
* @inheritDoc
*/
public afterInit(): void {
this._registerSchema();
this._registerConverters( 'imageBlock' );
this._registerConverters( 'imageInline' );
}

/**
* Registers the `width` and `height` attributes for inline and block images.
*/
private _registerSchema(): void {
if ( this.editor.plugins.has( 'ImageBlockEditing' ) ) {
this.editor.model.schema.extend( 'imageBlock', { allowAttributes: [ 'width', 'height' ] } );
}

if ( this.editor.plugins.has( 'ImageInlineEditing' ) ) {
this.editor.model.schema.extend( 'imageInline', { allowAttributes: [ 'width', 'height' ] } );
}
}

/**
* Registers converters for `width` and `height` attributes.
*/
private _registerConverters( imageType: 'imageBlock' | 'imageInline' ): void {
const editor = this.editor;
const imageUtils = editor.plugins.get( 'ImageUtils' );
const viewElementName = imageType === 'imageBlock' ? 'figure' : 'img';

editor.conversion.for( 'upcast' )
.attributeToAttribute( {
view: {
name: viewElementName,
attributes: {
width: /.+/
}
},
model: {
key: 'width',
value: ( viewElement: ViewElement ) => viewElement.getAttribute( 'width' )
}
} )
.attributeToAttribute( {
view: {
name: viewElementName,
attributes: {
height: /.+/
}
},
model: {
key: 'height',
value: ( viewElement: ViewElement ) => viewElement.getAttribute( 'height' )
}
} );

// Dedicated converter to propagate attributes to the <img> element.
editor.conversion.for( 'downcast' ).add( dispatcher => {
attachDowncastConverter( dispatcher, 'width', 'width' );
attachDowncastConverter( dispatcher, 'height', 'height' );
} );

function attachDowncastConverter( dispatcher: DowncastDispatcher, modelAttributeName: string, viewAttributeName: string ) {
dispatcher.on<DowncastAttributeEvent>( `attribute:${ modelAttributeName }:${ imageType }`, ( evt, data, conversionApi ) => {
if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
return;
}

const viewWriter = conversionApi.writer;
const viewElement = conversionApi.mapper.toViewElement( data.item as Element )!;
const img = imageUtils.findViewImgElement( viewElement )!;

if ( data.attributeNewValue !== null ) {
viewWriter.setAttribute( viewAttributeName, data.attributeNewValue, img );
} else {
viewWriter.removeAttribute( viewAttributeName, img );
}
} );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -396,8 +396,8 @@ export default class ImageUploadEditing extends Plugin {
.join( ', ' );

if ( srcsetAttribute != '' ) {
writer.setAttribute( 'srcset', {
data: srcsetAttribute,
writer.setAttributes( {
srcset: srcsetAttribute,
width: maxWidth
}, image );
}
Expand Down
1 change: 1 addition & 0 deletions packages/ckeditor5-image/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export { default as ImageResize } from './imageresize';
export { default as ImageResizeButtons } from './imageresize/imageresizebuttons';
export { default as ImageResizeEditing } from './imageresize/imageresizeediting';
export { default as ImageResizeHandles } from './imageresize/imageresizehandles';
export { default as ImageSizeAttributes } from './imagesizeattributes';
export { default as ImageStyle } from './imagestyle';
export { default as ImageStyleEditing } from './imagestyle/imagestyleediting';
export { default as ImageStyleUI } from './imagestyle/imagestyleui';
Expand Down
Loading