1 | /**
|
2 | * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
|
3 | * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4 | */
|
5 | /**
|
6 | * @module image/pictureediting
|
7 | */
|
8 | import { Plugin } from 'ckeditor5/src/core.js';
|
9 | import ImageEditing from './image/imageediting.js';
|
10 | import ImageUtils from './imageutils.js';
|
11 | import { downcastSourcesAttribute, upcastPicture } from './image/converters.js';
|
12 | /**
|
13 | * This plugin enables the [`<picture>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture) element support in the editor.
|
14 | *
|
15 | * * It enables the `sources` model attribute on `imageBlock` and `imageInline` model elements
|
16 | * (brought by {@link module:image/imageblock~ImageBlock} and {@link module:image/imageinline~ImageInline}, respectively).
|
17 | * * It translates the `sources` model element to the view (also: data) structure that may look as follows:
|
18 | *
|
19 | * ```html
|
20 | * <p>Inline image using picture:
|
21 | * <picture>
|
22 | * <source media="(min-width: 800px)" srcset="image-large.webp" type="image/webp">
|
23 | * <source media="(max-width: 800px)" srcset="image-small.webp" type="image/webp">
|
24 | * <!-- Other sources as specified in the "sources" model attribute... -->
|
25 | * <img src="image.png" alt="An image using picture" />
|
26 | * </picture>
|
27 | * </p>
|
28 | *
|
29 | * <p>Block image using picture:</p>
|
30 | * <figure class="image">
|
31 | * <picture>
|
32 | * <source media="(min-width: 800px)" srcset="image-large.webp" type="image/webp">
|
33 | * <source media="(max-width: 800px)" srcset="image-small.webp" type="image/webp">
|
34 | * <!-- Other sources as specified in the "sources" model attribute... -->
|
35 | * <img src="image.png" alt="An image using picture" />
|
36 | * </picture>
|
37 | * <figcaption>Caption of the image</figcaption>
|
38 | * </figure>
|
39 | * ```
|
40 | *
|
41 | * **Note:** The value of the `sources` {@glink framework/architecture/editing-engine#changing-the-model model attribute}
|
42 | * in both examples equals:
|
43 | *
|
44 | * ```css
|
45 | * [
|
46 | * {
|
47 | * media: '(min-width: 800px)',
|
48 | * srcset: 'image-large.webp',
|
49 | * type: 'image/webp'
|
50 | * },
|
51 | * {
|
52 | * media: '(max-width: 800px)',
|
53 | * srcset: 'image-small.webp',
|
54 | * type: 'image/webp'
|
55 | * }
|
56 | * ]
|
57 | * ```
|
58 | *
|
59 | * * It integrates with the {@link module:image/imageupload~ImageUpload} plugin so images uploaded in the editor
|
60 | * automatically render using `<picture>` if the {@glink features/images/image-upload/image-upload upload adapter}
|
61 | * supports image sources and provides neccessary data.
|
62 | *
|
63 | * @private
|
64 | */
|
65 | export default class PictureEditing extends Plugin {
|
66 | /**
|
67 | * @inheritDoc
|
68 | */
|
69 | static get requires() {
|
70 | return [ImageEditing, ImageUtils];
|
71 | }
|
72 | /**
|
73 | * @inheritDoc
|
74 | */
|
75 | static get pluginName() {
|
76 | return 'PictureEditing';
|
77 | }
|
78 | /**
|
79 | * @inheritDoc
|
80 | */
|
81 | afterInit() {
|
82 | const editor = this.editor;
|
83 | if (editor.plugins.has('ImageBlockEditing')) {
|
84 | editor.model.schema.extend('imageBlock', {
|
85 | allowAttributes: ['sources']
|
86 | });
|
87 | }
|
88 | if (editor.plugins.has('ImageInlineEditing')) {
|
89 | editor.model.schema.extend('imageInline', {
|
90 | allowAttributes: ['sources']
|
91 | });
|
92 | }
|
93 | this._setupConversion();
|
94 | this._setupImageUploadEditingIntegration();
|
95 | }
|
96 | /**
|
97 | * Configures conversion pipelines to support upcasting and downcasting images using the `<picture>` view element
|
98 | * and the model `sources` attribute.
|
99 | */
|
100 | _setupConversion() {
|
101 | const editor = this.editor;
|
102 | const conversion = editor.conversion;
|
103 | const imageUtils = editor.plugins.get('ImageUtils');
|
104 | conversion.for('upcast').add(upcastPicture(imageUtils));
|
105 | conversion.for('downcast').add(downcastSourcesAttribute(imageUtils));
|
106 | }
|
107 | /**
|
108 | * Makes it possible for uploaded images to get the `sources` model attribute and the `<picture>...</picture>`
|
109 | * view structure out-of-the-box if relevant data is provided along the
|
110 | * {@link module:image/imageupload/imageuploadediting~ImageUploadEditing#event:uploadComplete} event.
|
111 | */
|
112 | _setupImageUploadEditingIntegration() {
|
113 | const editor = this.editor;
|
114 | if (!editor.plugins.has('ImageUploadEditing')) {
|
115 | return;
|
116 | }
|
117 | const imageUploadEditing = editor.plugins.get('ImageUploadEditing');
|
118 | this.listenTo(imageUploadEditing, 'uploadComplete', (evt, { imageElement, data }) => {
|
119 | const sources = data.sources;
|
120 | if (!sources) {
|
121 | return;
|
122 | }
|
123 | editor.model.change(writer => {
|
124 | writer.setAttributes({
|
125 | sources
|
126 | }, imageElement);
|
127 | });
|
128 | });
|
129 | }
|
130 | }
|