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 |
|
10 | import { Plugin } from 'ckeditor5/src/core';
|
11 |
|
12 | import ImageEditing from './image/imageediting';
|
13 | import ImageUtils from './imageutils';
|
14 | import {
|
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 | */
|
69 | export 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 | }
|