UNPKG

4.72 kBJavaScriptView Raw
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 */
8import { Plugin } from 'ckeditor5/src/core.js';
9import ImageEditing from './image/imageediting.js';
10import ImageUtils from './imageutils.js';
11import { 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 */
65export 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}