UNPKG

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