@ckeditor/ckeditor5-image 39.0.1 → 40.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/LICENSE.md +1 -1
  3. package/README.md +3 -3
  4. package/build/image.js +1 -1
  5. package/build/image.js.map +1 -0
  6. package/build/translations/pt-br.js +1 -1
  7. package/ckeditor5-metadata.json +12 -0
  8. package/lang/translations/ar.po +1 -0
  9. package/lang/translations/ast.po +1 -0
  10. package/lang/translations/az.po +1 -0
  11. package/lang/translations/bg.po +1 -0
  12. package/lang/translations/bn.po +1 -0
  13. package/lang/translations/bs.po +1 -0
  14. package/lang/translations/ca.po +1 -0
  15. package/lang/translations/cs.po +1 -0
  16. package/lang/translations/da.po +1 -0
  17. package/lang/translations/de-ch.po +1 -0
  18. package/lang/translations/de.po +1 -0
  19. package/lang/translations/el.po +1 -0
  20. package/lang/translations/en-au.po +1 -0
  21. package/lang/translations/en-gb.po +1 -0
  22. package/lang/translations/en.po +1 -0
  23. package/lang/translations/eo.po +1 -0
  24. package/lang/translations/es.po +1 -0
  25. package/lang/translations/et.po +1 -0
  26. package/lang/translations/eu.po +1 -0
  27. package/lang/translations/fa.po +1 -0
  28. package/lang/translations/fi.po +1 -0
  29. package/lang/translations/fr.po +1 -0
  30. package/lang/translations/gl.po +1 -0
  31. package/lang/translations/he.po +1 -0
  32. package/lang/translations/hi.po +1 -0
  33. package/lang/translations/hr.po +1 -0
  34. package/lang/translations/hu.po +1 -0
  35. package/lang/translations/id.po +1 -0
  36. package/lang/translations/it.po +1 -0
  37. package/lang/translations/ja.po +1 -0
  38. package/lang/translations/jv.po +1 -0
  39. package/lang/translations/km.po +1 -0
  40. package/lang/translations/kn.po +1 -0
  41. package/lang/translations/ko.po +1 -0
  42. package/lang/translations/ku.po +1 -0
  43. package/lang/translations/lt.po +1 -0
  44. package/lang/translations/lv.po +1 -0
  45. package/lang/translations/ms.po +1 -0
  46. package/lang/translations/nb.po +1 -0
  47. package/lang/translations/ne.po +1 -0
  48. package/lang/translations/nl.po +1 -0
  49. package/lang/translations/no.po +1 -0
  50. package/lang/translations/pl.po +1 -0
  51. package/lang/translations/pt-br.po +2 -1
  52. package/lang/translations/pt.po +1 -0
  53. package/lang/translations/ro.po +1 -0
  54. package/lang/translations/ru.po +1 -0
  55. package/lang/translations/si.po +1 -0
  56. package/lang/translations/sk.po +1 -0
  57. package/lang/translations/sq.po +1 -0
  58. package/lang/translations/sr-latn.po +1 -0
  59. package/lang/translations/sr.po +1 -0
  60. package/lang/translations/sv.po +1 -0
  61. package/lang/translations/th.po +1 -0
  62. package/lang/translations/tk.po +1 -0
  63. package/lang/translations/tr.po +1 -0
  64. package/lang/translations/tt.po +1 -0
  65. package/lang/translations/ug.po +1 -0
  66. package/lang/translations/uk.po +1 -0
  67. package/lang/translations/ur.po +1 -0
  68. package/lang/translations/uz.po +1 -0
  69. package/lang/translations/vi.po +1 -0
  70. package/lang/translations/zh-cn.po +1 -0
  71. package/lang/translations/zh.po +1 -0
  72. package/package.json +3 -7
  73. package/src/augmentation.d.ts +56 -55
  74. package/src/augmentation.js +5 -5
  75. package/src/autoimage.d.ts +52 -52
  76. package/src/autoimage.js +132 -132
  77. package/src/image/converters.d.ts +66 -66
  78. package/src/image/converters.js +232 -242
  79. package/src/image/imageblockediting.d.ts +58 -55
  80. package/src/image/imageblockediting.js +152 -136
  81. package/src/image/imageediting.d.ts +30 -30
  82. package/src/image/imageediting.js +63 -74
  83. package/src/image/imageinlineediting.d.ts +59 -56
  84. package/src/image/imageinlineediting.js +176 -160
  85. package/src/image/imageloadobserver.d.ts +48 -48
  86. package/src/image/imageloadobserver.js +52 -52
  87. package/src/image/imagetypecommand.d.ts +44 -40
  88. package/src/image/imagetypecommand.js +80 -77
  89. package/src/image/insertimagecommand.d.ts +66 -66
  90. package/src/image/insertimagecommand.js +120 -120
  91. package/src/image/replaceimagesourcecommand.d.ts +34 -34
  92. package/src/image/replaceimagesourcecommand.js +44 -44
  93. package/src/image/ui/utils.d.ts +25 -25
  94. package/src/image/ui/utils.js +44 -44
  95. package/src/image/utils.d.ts +64 -52
  96. package/src/image/utils.js +121 -100
  97. package/src/image.d.ts +34 -34
  98. package/src/image.js +38 -38
  99. package/src/imageblock.d.ts +33 -33
  100. package/src/imageblock.js +37 -37
  101. package/src/imagecaption/imagecaptionediting.d.ts +89 -89
  102. package/src/imagecaption/imagecaptionediting.js +225 -225
  103. package/src/imagecaption/imagecaptionui.d.ts +26 -26
  104. package/src/imagecaption/imagecaptionui.js +61 -61
  105. package/src/imagecaption/imagecaptionutils.d.ts +38 -38
  106. package/src/imagecaption/imagecaptionutils.js +62 -62
  107. package/src/imagecaption/toggleimagecaptioncommand.d.ts +66 -66
  108. package/src/imagecaption/toggleimagecaptioncommand.js +138 -138
  109. package/src/imagecaption.d.ts +26 -26
  110. package/src/imagecaption.js +30 -30
  111. package/src/imageconfig.d.ts +713 -713
  112. package/src/imageconfig.js +5 -5
  113. package/src/imageinline.d.ts +33 -33
  114. package/src/imageinline.js +37 -37
  115. package/src/imageinsert/imageinsertui.d.ts +44 -44
  116. package/src/imageinsert/imageinsertui.js +141 -141
  117. package/src/imageinsert/ui/imageinsertformrowview.d.ts +61 -61
  118. package/src/imageinsert/ui/imageinsertformrowview.js +54 -54
  119. package/src/imageinsert/ui/imageinsertpanelview.d.ts +106 -106
  120. package/src/imageinsert/ui/imageinsertpanelview.js +161 -161
  121. package/src/imageinsert/utils.d.ts +25 -25
  122. package/src/imageinsert/utils.js +58 -58
  123. package/src/imageinsert.d.ts +33 -33
  124. package/src/imageinsert.js +37 -37
  125. package/src/imageinsertviaurl.d.ts +30 -30
  126. package/src/imageinsertviaurl.js +34 -34
  127. package/src/imageresize/imageresizebuttons.d.ts +67 -67
  128. package/src/imageresize/imageresizebuttons.js +217 -217
  129. package/src/imageresize/imageresizeediting.d.ts +37 -37
  130. package/src/imageresize/imageresizeediting.js +165 -114
  131. package/src/imageresize/imageresizehandles.d.ts +31 -30
  132. package/src/imageresize/imageresizehandles.js +114 -107
  133. package/src/imageresize/resizeimagecommand.d.ts +42 -42
  134. package/src/imageresize/resizeimagecommand.js +63 -61
  135. package/src/imageresize.d.ts +27 -27
  136. package/src/imageresize.js +31 -31
  137. package/src/imagesizeattributes.d.ts +34 -0
  138. package/src/imagesizeattributes.js +143 -0
  139. package/src/imagestyle/converters.d.ts +24 -24
  140. package/src/imagestyle/converters.js +79 -79
  141. package/src/imagestyle/imagestylecommand.d.ts +68 -65
  142. package/src/imagestyle/imagestylecommand.js +107 -101
  143. package/src/imagestyle/imagestyleediting.d.ts +50 -50
  144. package/src/imagestyle/imagestyleediting.js +108 -108
  145. package/src/imagestyle/imagestyleui.d.ts +56 -56
  146. package/src/imagestyle/imagestyleui.js +192 -192
  147. package/src/imagestyle/utils.d.ts +101 -101
  148. package/src/imagestyle/utils.js +329 -329
  149. package/src/imagestyle.d.ts +32 -32
  150. package/src/imagestyle.js +36 -36
  151. package/src/imagetextalternative/imagetextalternativecommand.d.ts +34 -34
  152. package/src/imagetextalternative/imagetextalternativecommand.js +44 -44
  153. package/src/imagetextalternative/imagetextalternativeediting.d.ts +28 -28
  154. package/src/imagetextalternative/imagetextalternativeediting.js +35 -35
  155. package/src/imagetextalternative/imagetextalternativeui.d.ts +68 -68
  156. package/src/imagetextalternative/imagetextalternativeui.js +173 -173
  157. package/src/imagetextalternative/ui/textalternativeformview.d.ts +72 -72
  158. package/src/imagetextalternative/ui/textalternativeformview.js +121 -121
  159. package/src/imagetextalternative.d.ts +29 -29
  160. package/src/imagetextalternative.js +33 -33
  161. package/src/imagetoolbar.d.ts +35 -35
  162. package/src/imagetoolbar.js +57 -57
  163. package/src/imageupload/imageuploadediting.d.ts +111 -111
  164. package/src/imageupload/imageuploadediting.js +337 -335
  165. package/src/imageupload/imageuploadprogress.d.ts +42 -42
  166. package/src/imageupload/imageuploadprogress.js +211 -211
  167. package/src/imageupload/imageuploadui.d.ts +23 -23
  168. package/src/imageupload/imageuploadui.js +57 -57
  169. package/src/imageupload/uploadimagecommand.d.ts +60 -60
  170. package/src/imageupload/uploadimagecommand.js +100 -100
  171. package/src/imageupload/utils.d.ts +33 -33
  172. package/src/imageupload/utils.js +112 -112
  173. package/src/imageupload.d.ts +32 -32
  174. package/src/imageupload.js +36 -36
  175. package/src/imageutils.d.ts +125 -102
  176. package/src/imageutils.js +306 -248
  177. package/src/index.d.ts +48 -47
  178. package/src/index.js +39 -38
  179. package/src/pictureediting.d.ts +88 -88
  180. package/src/pictureediting.js +130 -130
  181. package/theme/image.css +38 -11
  182. package/theme/imageresize.css +5 -0
@@ -1,66 +1,66 @@
1
- /**
2
- * @license Copyright (c) 2003-2023, 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/image/converters
7
- */
8
- import type { DowncastDispatcher, UpcastDispatcher } from 'ckeditor5/src/engine';
9
- import type ImageUtils from '../imageutils';
10
- /**
11
- * Returns a function that converts the image view representation:
12
- *
13
- * ```html
14
- * <figure class="image"><img src="..." alt="..."></img></figure>
15
- * ```
16
- *
17
- * to the model representation:
18
- *
19
- * ```html
20
- * <imageBlock src="..." alt="..."></imageBlock>
21
- * ```
22
- *
23
- * The entire content of the `<figure>` element except the first `<img>` is being converted as children
24
- * of the `<imageBlock>` model element.
25
- *
26
- * @internal
27
- */
28
- export declare function upcastImageFigure(imageUtils: ImageUtils): (dispatcher: UpcastDispatcher) => void;
29
- /**
30
- * Returns a function that converts the image view representation:
31
- *
32
- * ```html
33
- * <picture><source ... /><source ... />...<img ... /></picture>
34
- * ```
35
- *
36
- * to the model representation as the `sources` attribute:
37
- *
38
- * ```html
39
- * <image[Block|Inline] ... sources="..."></image[Block|Inline]>
40
- * ```
41
- *
42
- * @internal
43
- */
44
- export declare function upcastPicture(imageUtils: ImageUtils): (dispatcher: UpcastDispatcher) => void;
45
- /**
46
- * Converter used to convert the `srcset` model image attribute to the `srcset`, `sizes` and `width` attributes in the view.
47
- *
48
- * @internal
49
- * @param imageType The type of the image.
50
- */
51
- export declare function downcastSrcsetAttribute(imageUtils: ImageUtils, imageType: 'imageBlock' | 'imageInline'): (dispatcher: DowncastDispatcher) => void;
52
- /**
53
- * Converts the `source` model attribute to the `<picture><source /><source />...<img /></picture>`
54
- * view structure.
55
- *
56
- * @internal
57
- */
58
- export declare function downcastSourcesAttribute(imageUtils: ImageUtils): (dispatcher: DowncastDispatcher) => void;
59
- /**
60
- * Converter used to convert a given image attribute from the model to the view.
61
- *
62
- * @internal
63
- * @param imageType The type of the image.
64
- * @param attributeKey The name of the attribute to convert.
65
- */
66
- export declare function downcastImageAttribute(imageUtils: ImageUtils, imageType: 'imageBlock' | 'imageInline', attributeKey: string): (dispatcher: DowncastDispatcher) => void;
1
+ /**
2
+ * @license Copyright (c) 2003-2023, 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/image/converters
7
+ */
8
+ import type { DowncastDispatcher, UpcastDispatcher } from 'ckeditor5/src/engine';
9
+ import type ImageUtils from '../imageutils';
10
+ /**
11
+ * Returns a function that converts the image view representation:
12
+ *
13
+ * ```html
14
+ * <figure class="image"><img src="..." alt="..."></img></figure>
15
+ * ```
16
+ *
17
+ * to the model representation:
18
+ *
19
+ * ```html
20
+ * <imageBlock src="..." alt="..."></imageBlock>
21
+ * ```
22
+ *
23
+ * The entire content of the `<figure>` element except the first `<img>` is being converted as children
24
+ * of the `<imageBlock>` model element.
25
+ *
26
+ * @internal
27
+ */
28
+ export declare function upcastImageFigure(imageUtils: ImageUtils): (dispatcher: UpcastDispatcher) => void;
29
+ /**
30
+ * Returns a function that converts the image view representation:
31
+ *
32
+ * ```html
33
+ * <picture><source ... /><source ... />...<img ... /></picture>
34
+ * ```
35
+ *
36
+ * to the model representation as the `sources` attribute:
37
+ *
38
+ * ```html
39
+ * <image[Block|Inline] ... sources="..."></image[Block|Inline]>
40
+ * ```
41
+ *
42
+ * @internal
43
+ */
44
+ export declare function upcastPicture(imageUtils: ImageUtils): (dispatcher: UpcastDispatcher) => void;
45
+ /**
46
+ * Converter used to convert the `srcset` model image attribute to the `srcset` and `sizes` attributes in the view.
47
+ *
48
+ * @internal
49
+ * @param imageType The type of the image.
50
+ */
51
+ export declare function downcastSrcsetAttribute(imageUtils: ImageUtils, imageType: 'imageBlock' | 'imageInline'): (dispatcher: DowncastDispatcher) => void;
52
+ /**
53
+ * Converts the `source` model attribute to the `<picture><source /><source />...<img /></picture>`
54
+ * view structure.
55
+ *
56
+ * @internal
57
+ */
58
+ export declare function downcastSourcesAttribute(imageUtils: ImageUtils): (dispatcher: DowncastDispatcher) => void;
59
+ /**
60
+ * Converter used to convert a given image attribute from the model to the view.
61
+ *
62
+ * @internal
63
+ * @param imageType The type of the image.
64
+ * @param attributeKey The name of the attribute to convert.
65
+ */
66
+ export declare function downcastImageAttribute(imageUtils: ImageUtils, imageType: 'imageBlock' | 'imageInline', attributeKey: string): (dispatcher: DowncastDispatcher) => void;
@@ -1,242 +1,232 @@
1
- /**
2
- * @license Copyright (c) 2003-2023, 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
- import { first } from 'ckeditor5/src/utils';
6
- /**
7
- * Returns a function that converts the image view representation:
8
- *
9
- * ```html
10
- * <figure class="image"><img src="..." alt="..."></img></figure>
11
- * ```
12
- *
13
- * to the model representation:
14
- *
15
- * ```html
16
- * <imageBlock src="..." alt="..."></imageBlock>
17
- * ```
18
- *
19
- * The entire content of the `<figure>` element except the first `<img>` is being converted as children
20
- * of the `<imageBlock>` model element.
21
- *
22
- * @internal
23
- */
24
- export function upcastImageFigure(imageUtils) {
25
- const converter = (evt, data, conversionApi) => {
26
- // Do not convert if this is not an "image figure".
27
- if (!conversionApi.consumable.test(data.viewItem, { name: true, classes: 'image' })) {
28
- return;
29
- }
30
- // Find an image element inside the figure element.
31
- const viewImage = imageUtils.findViewImgElement(data.viewItem);
32
- // Do not convert if image element is absent or was already converted.
33
- if (!viewImage || !conversionApi.consumable.test(viewImage, { name: true })) {
34
- return;
35
- }
36
- // Consume the figure to prevent other converters from processing it again.
37
- conversionApi.consumable.consume(data.viewItem, { name: true, classes: 'image' });
38
- // Convert view image to model image.
39
- const conversionResult = conversionApi.convertItem(viewImage, data.modelCursor);
40
- // Get image element from conversion result.
41
- const modelImage = first(conversionResult.modelRange.getItems());
42
- // When image wasn't successfully converted then finish conversion.
43
- if (!modelImage) {
44
- // Revert consumed figure so other features can convert it.
45
- conversionApi.consumable.revert(data.viewItem, { name: true, classes: 'image' });
46
- return;
47
- }
48
- // Convert rest of the figure element's children as an image children.
49
- conversionApi.convertChildren(data.viewItem, modelImage);
50
- conversionApi.updateConversionResult(modelImage, data);
51
- };
52
- return dispatcher => {
53
- dispatcher.on('element:figure', converter);
54
- };
55
- }
56
- /**
57
- * Returns a function that converts the image view representation:
58
- *
59
- * ```html
60
- * <picture><source ... /><source ... />...<img ... /></picture>
61
- * ```
62
- *
63
- * to the model representation as the `sources` attribute:
64
- *
65
- * ```html
66
- * <image[Block|Inline] ... sources="..."></image[Block|Inline]>
67
- * ```
68
- *
69
- * @internal
70
- */
71
- export function upcastPicture(imageUtils) {
72
- const sourceAttributeNames = ['srcset', 'media', 'type', 'sizes'];
73
- const converter = (evt, data, conversionApi) => {
74
- const pictureViewElement = data.viewItem;
75
- // Do not convert <picture> if already consumed.
76
- if (!conversionApi.consumable.test(pictureViewElement, { name: true })) {
77
- return;
78
- }
79
- const sources = new Map();
80
- // Collect all <source /> elements attribute values.
81
- for (const childSourceElement of pictureViewElement.getChildren()) {
82
- if (childSourceElement.is('element', 'source')) {
83
- const attributes = {};
84
- for (const name of sourceAttributeNames) {
85
- if (childSourceElement.hasAttribute(name)) {
86
- // Don't collect <source /> attribute if already consumed somewhere else.
87
- if (conversionApi.consumable.test(childSourceElement, { attributes: name })) {
88
- attributes[name] = childSourceElement.getAttribute(name);
89
- }
90
- }
91
- }
92
- if (Object.keys(attributes).length) {
93
- sources.set(childSourceElement, attributes);
94
- }
95
- }
96
- }
97
- const imgViewElement = imageUtils.findViewImgElement(pictureViewElement);
98
- // Don't convert when a picture has no <img/> inside (it is broken).
99
- if (!imgViewElement) {
100
- return;
101
- }
102
- let modelImage = data.modelCursor.parent;
103
- // - In case of an inline image (cursor parent in a <paragraph>), the <img/> must be converted right away
104
- // because no converter handled it yet and otherwise there would be no model element to set the sources attribute on.
105
- // - In case of a block image, the <figure class="image"> converter (in ImageBlockEditing) converts the
106
- // <img/> right away on its own and the modelCursor is already inside an imageBlock and there's nothing special
107
- // to do here.
108
- if (!modelImage.is('element', 'imageBlock')) {
109
- const conversionResult = conversionApi.convertItem(imgViewElement, data.modelCursor);
110
- // Set image range as conversion result.
111
- data.modelRange = conversionResult.modelRange;
112
- // Continue conversion where image conversion ends.
113
- data.modelCursor = conversionResult.modelCursor;
114
- modelImage = first(conversionResult.modelRange.getItems());
115
- }
116
- conversionApi.consumable.consume(pictureViewElement, { name: true });
117
- // Consume only these <source/> attributes that were actually collected and will be passed on
118
- // to the image model element.
119
- for (const [sourceElement, attributes] of sources) {
120
- conversionApi.consumable.consume(sourceElement, { attributes: Object.keys(attributes) });
121
- }
122
- if (sources.size) {
123
- conversionApi.writer.setAttribute('sources', Array.from(sources.values()), modelImage);
124
- }
125
- // Convert rest of the <picture> children as an image children. Other converters may want to consume them.
126
- conversionApi.convertChildren(pictureViewElement, modelImage);
127
- };
128
- return dispatcher => {
129
- dispatcher.on('element:picture', converter);
130
- };
131
- }
132
- /**
133
- * Converter used to convert the `srcset` model image attribute to the `srcset`, `sizes` and `width` attributes in the view.
134
- *
135
- * @internal
136
- * @param imageType The type of the image.
137
- */
138
- export function downcastSrcsetAttribute(imageUtils, imageType) {
139
- const converter = (evt, data, conversionApi) => {
140
- if (!conversionApi.consumable.consume(data.item, evt.name)) {
141
- return;
142
- }
143
- const writer = conversionApi.writer;
144
- const element = conversionApi.mapper.toViewElement(data.item);
145
- const img = imageUtils.findViewImgElement(element);
146
- if (data.attributeNewValue === null) {
147
- const srcset = data.attributeOldValue;
148
- if (srcset && srcset.data) {
149
- writer.removeAttribute('srcset', img);
150
- writer.removeAttribute('sizes', img);
151
- if (srcset.width) {
152
- writer.removeAttribute('width', img);
153
- }
154
- }
155
- }
156
- else {
157
- const srcset = data.attributeNewValue;
158
- if (srcset && srcset.data) {
159
- writer.setAttribute('srcset', srcset.data, img);
160
- // Always outputting `100vw`. See https://github.com/ckeditor/ckeditor5-image/issues/2.
161
- writer.setAttribute('sizes', '100vw', img);
162
- if (srcset.width) {
163
- writer.setAttribute('width', srcset.width, img);
164
- }
165
- }
166
- }
167
- };
168
- return dispatcher => {
169
- dispatcher.on(`attribute:srcset:${imageType}`, converter);
170
- };
171
- }
172
- /**
173
- * Converts the `source` model attribute to the `<picture><source /><source />...<img /></picture>`
174
- * view structure.
175
- *
176
- * @internal
177
- */
178
- export function downcastSourcesAttribute(imageUtils) {
179
- const converter = (evt, data, conversionApi) => {
180
- if (!conversionApi.consumable.consume(data.item, evt.name)) {
181
- return;
182
- }
183
- const viewWriter = conversionApi.writer;
184
- const element = conversionApi.mapper.toViewElement(data.item);
185
- const imgElement = imageUtils.findViewImgElement(element);
186
- const attributeNewValue = data.attributeNewValue;
187
- if (attributeNewValue && attributeNewValue.length) {
188
- // Make sure <picture> does not break attribute elements, for instance <a> in linked images.
189
- const pictureElement = viewWriter.createContainerElement('picture', null, attributeNewValue.map(sourceAttributes => {
190
- return viewWriter.createEmptyElement('source', sourceAttributes);
191
- }));
192
- // Collect all wrapping attribute elements.
193
- const attributeElements = [];
194
- let viewElement = imgElement.parent;
195
- while (viewElement && viewElement.is('attributeElement')) {
196
- const parentElement = viewElement.parent;
197
- viewWriter.unwrap(viewWriter.createRangeOn(imgElement), viewElement);
198
- attributeElements.unshift(viewElement);
199
- viewElement = parentElement;
200
- }
201
- // Insert the picture and move img into it.
202
- viewWriter.insert(viewWriter.createPositionBefore(imgElement), pictureElement);
203
- viewWriter.move(viewWriter.createRangeOn(imgElement), viewWriter.createPositionAt(pictureElement, 'end'));
204
- // Apply collected attribute elements over the new picture element.
205
- for (const attributeElement of attributeElements) {
206
- viewWriter.wrap(viewWriter.createRangeOn(pictureElement), attributeElement);
207
- }
208
- }
209
- // Both setting "sources" to an empty array and removing the attribute should unwrap the <img />.
210
- // Unwrap once if the latter followed the former, though.
211
- else if (imgElement.parent.is('element', 'picture')) {
212
- const pictureElement = imgElement.parent;
213
- viewWriter.move(viewWriter.createRangeOn(imgElement), viewWriter.createPositionBefore(pictureElement));
214
- viewWriter.remove(pictureElement);
215
- }
216
- };
217
- return dispatcher => {
218
- dispatcher.on('attribute:sources:imageBlock', converter);
219
- dispatcher.on('attribute:sources:imageInline', converter);
220
- };
221
- }
222
- /**
223
- * Converter used to convert a given image attribute from the model to the view.
224
- *
225
- * @internal
226
- * @param imageType The type of the image.
227
- * @param attributeKey The name of the attribute to convert.
228
- */
229
- export function downcastImageAttribute(imageUtils, imageType, attributeKey) {
230
- const converter = (evt, data, conversionApi) => {
231
- if (!conversionApi.consumable.consume(data.item, evt.name)) {
232
- return;
233
- }
234
- const viewWriter = conversionApi.writer;
235
- const element = conversionApi.mapper.toViewElement(data.item);
236
- const img = imageUtils.findViewImgElement(element);
237
- viewWriter.setAttribute(data.attributeKey, data.attributeNewValue || '', img);
238
- };
239
- return dispatcher => {
240
- dispatcher.on(`attribute:${attributeKey}:${imageType}`, converter);
241
- };
242
- }
1
+ /**
2
+ * @license Copyright (c) 2003-2023, 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
+ import { first } from 'ckeditor5/src/utils';
6
+ /**
7
+ * Returns a function that converts the image view representation:
8
+ *
9
+ * ```html
10
+ * <figure class="image"><img src="..." alt="..."></img></figure>
11
+ * ```
12
+ *
13
+ * to the model representation:
14
+ *
15
+ * ```html
16
+ * <imageBlock src="..." alt="..."></imageBlock>
17
+ * ```
18
+ *
19
+ * The entire content of the `<figure>` element except the first `<img>` is being converted as children
20
+ * of the `<imageBlock>` model element.
21
+ *
22
+ * @internal
23
+ */
24
+ export function upcastImageFigure(imageUtils) {
25
+ const converter = (evt, data, conversionApi) => {
26
+ // Do not convert if this is not an "image figure".
27
+ if (!conversionApi.consumable.test(data.viewItem, { name: true, classes: 'image' })) {
28
+ return;
29
+ }
30
+ // Find an image element inside the figure element.
31
+ const viewImage = imageUtils.findViewImgElement(data.viewItem);
32
+ // Do not convert if image element is absent or was already converted.
33
+ if (!viewImage || !conversionApi.consumable.test(viewImage, { name: true })) {
34
+ return;
35
+ }
36
+ // Consume the figure to prevent other converters from processing it again.
37
+ conversionApi.consumable.consume(data.viewItem, { name: true, classes: 'image' });
38
+ // Convert view image to model image.
39
+ const conversionResult = conversionApi.convertItem(viewImage, data.modelCursor);
40
+ // Get image element from conversion result.
41
+ const modelImage = first(conversionResult.modelRange.getItems());
42
+ // When image wasn't successfully converted then finish conversion.
43
+ if (!modelImage) {
44
+ // Revert consumed figure so other features can convert it.
45
+ conversionApi.consumable.revert(data.viewItem, { name: true, classes: 'image' });
46
+ return;
47
+ }
48
+ // Convert rest of the figure element's children as an image children.
49
+ conversionApi.convertChildren(data.viewItem, modelImage);
50
+ conversionApi.updateConversionResult(modelImage, data);
51
+ };
52
+ return dispatcher => {
53
+ dispatcher.on('element:figure', converter);
54
+ };
55
+ }
56
+ /**
57
+ * Returns a function that converts the image view representation:
58
+ *
59
+ * ```html
60
+ * <picture><source ... /><source ... />...<img ... /></picture>
61
+ * ```
62
+ *
63
+ * to the model representation as the `sources` attribute:
64
+ *
65
+ * ```html
66
+ * <image[Block|Inline] ... sources="..."></image[Block|Inline]>
67
+ * ```
68
+ *
69
+ * @internal
70
+ */
71
+ export function upcastPicture(imageUtils) {
72
+ const sourceAttributeNames = ['srcset', 'media', 'type', 'sizes'];
73
+ const converter = (evt, data, conversionApi) => {
74
+ const pictureViewElement = data.viewItem;
75
+ // Do not convert <picture> if already consumed.
76
+ if (!conversionApi.consumable.test(pictureViewElement, { name: true })) {
77
+ return;
78
+ }
79
+ const sources = new Map();
80
+ // Collect all <source /> elements attribute values.
81
+ for (const childSourceElement of pictureViewElement.getChildren()) {
82
+ if (childSourceElement.is('element', 'source')) {
83
+ const attributes = {};
84
+ for (const name of sourceAttributeNames) {
85
+ if (childSourceElement.hasAttribute(name)) {
86
+ // Don't collect <source /> attribute if already consumed somewhere else.
87
+ if (conversionApi.consumable.test(childSourceElement, { attributes: name })) {
88
+ attributes[name] = childSourceElement.getAttribute(name);
89
+ }
90
+ }
91
+ }
92
+ if (Object.keys(attributes).length) {
93
+ sources.set(childSourceElement, attributes);
94
+ }
95
+ }
96
+ }
97
+ const imgViewElement = imageUtils.findViewImgElement(pictureViewElement);
98
+ // Don't convert when a picture has no <img/> inside (it is broken).
99
+ if (!imgViewElement) {
100
+ return;
101
+ }
102
+ let modelImage = data.modelCursor.parent;
103
+ // - In case of an inline image (cursor parent in a <paragraph>), the <img/> must be converted right away
104
+ // because no converter handled it yet and otherwise there would be no model element to set the sources attribute on.
105
+ // - In case of a block image, the <figure class="image"> converter (in ImageBlockEditing) converts the
106
+ // <img/> right away on its own and the modelCursor is already inside an imageBlock and there's nothing special
107
+ // to do here.
108
+ if (!modelImage.is('element', 'imageBlock')) {
109
+ const conversionResult = conversionApi.convertItem(imgViewElement, data.modelCursor);
110
+ // Set image range as conversion result.
111
+ data.modelRange = conversionResult.modelRange;
112
+ // Continue conversion where image conversion ends.
113
+ data.modelCursor = conversionResult.modelCursor;
114
+ modelImage = first(conversionResult.modelRange.getItems());
115
+ }
116
+ conversionApi.consumable.consume(pictureViewElement, { name: true });
117
+ // Consume only these <source/> attributes that were actually collected and will be passed on
118
+ // to the image model element.
119
+ for (const [sourceElement, attributes] of sources) {
120
+ conversionApi.consumable.consume(sourceElement, { attributes: Object.keys(attributes) });
121
+ }
122
+ if (sources.size) {
123
+ conversionApi.writer.setAttribute('sources', Array.from(sources.values()), modelImage);
124
+ }
125
+ // Convert rest of the <picture> children as an image children. Other converters may want to consume them.
126
+ conversionApi.convertChildren(pictureViewElement, modelImage);
127
+ };
128
+ return dispatcher => {
129
+ dispatcher.on('element:picture', converter);
130
+ };
131
+ }
132
+ /**
133
+ * Converter used to convert the `srcset` model image attribute to the `srcset` and `sizes` attributes in the view.
134
+ *
135
+ * @internal
136
+ * @param imageType The type of the image.
137
+ */
138
+ export function downcastSrcsetAttribute(imageUtils, imageType) {
139
+ const converter = (evt, data, conversionApi) => {
140
+ if (!conversionApi.consumable.consume(data.item, evt.name)) {
141
+ return;
142
+ }
143
+ const writer = conversionApi.writer;
144
+ const element = conversionApi.mapper.toViewElement(data.item);
145
+ const img = imageUtils.findViewImgElement(element);
146
+ if (data.attributeNewValue === null) {
147
+ writer.removeAttribute('srcset', img);
148
+ writer.removeAttribute('sizes', img);
149
+ }
150
+ else {
151
+ if (data.attributeNewValue) {
152
+ writer.setAttribute('srcset', data.attributeNewValue, img);
153
+ // Always outputting `100vw`. See https://github.com/ckeditor/ckeditor5-image/issues/2.
154
+ writer.setAttribute('sizes', '100vw', img);
155
+ }
156
+ }
157
+ };
158
+ return dispatcher => {
159
+ dispatcher.on(`attribute:srcset:${imageType}`, converter);
160
+ };
161
+ }
162
+ /**
163
+ * Converts the `source` model attribute to the `<picture><source /><source />...<img /></picture>`
164
+ * view structure.
165
+ *
166
+ * @internal
167
+ */
168
+ export function downcastSourcesAttribute(imageUtils) {
169
+ const converter = (evt, data, conversionApi) => {
170
+ if (!conversionApi.consumable.consume(data.item, evt.name)) {
171
+ return;
172
+ }
173
+ const viewWriter = conversionApi.writer;
174
+ const element = conversionApi.mapper.toViewElement(data.item);
175
+ const imgElement = imageUtils.findViewImgElement(element);
176
+ const attributeNewValue = data.attributeNewValue;
177
+ if (attributeNewValue && attributeNewValue.length) {
178
+ // Make sure <picture> does not break attribute elements, for instance <a> in linked images.
179
+ const pictureElement = viewWriter.createContainerElement('picture', null, attributeNewValue.map(sourceAttributes => {
180
+ return viewWriter.createEmptyElement('source', sourceAttributes);
181
+ }));
182
+ // Collect all wrapping attribute elements.
183
+ const attributeElements = [];
184
+ let viewElement = imgElement.parent;
185
+ while (viewElement && viewElement.is('attributeElement')) {
186
+ const parentElement = viewElement.parent;
187
+ viewWriter.unwrap(viewWriter.createRangeOn(imgElement), viewElement);
188
+ attributeElements.unshift(viewElement);
189
+ viewElement = parentElement;
190
+ }
191
+ // Insert the picture and move img into it.
192
+ viewWriter.insert(viewWriter.createPositionBefore(imgElement), pictureElement);
193
+ viewWriter.move(viewWriter.createRangeOn(imgElement), viewWriter.createPositionAt(pictureElement, 'end'));
194
+ // Apply collected attribute elements over the new picture element.
195
+ for (const attributeElement of attributeElements) {
196
+ viewWriter.wrap(viewWriter.createRangeOn(pictureElement), attributeElement);
197
+ }
198
+ }
199
+ // Both setting "sources" to an empty array and removing the attribute should unwrap the <img />.
200
+ // Unwrap once if the latter followed the former, though.
201
+ else if (imgElement.parent.is('element', 'picture')) {
202
+ const pictureElement = imgElement.parent;
203
+ viewWriter.move(viewWriter.createRangeOn(imgElement), viewWriter.createPositionBefore(pictureElement));
204
+ viewWriter.remove(pictureElement);
205
+ }
206
+ };
207
+ return dispatcher => {
208
+ dispatcher.on('attribute:sources:imageBlock', converter);
209
+ dispatcher.on('attribute:sources:imageInline', converter);
210
+ };
211
+ }
212
+ /**
213
+ * Converter used to convert a given image attribute from the model to the view.
214
+ *
215
+ * @internal
216
+ * @param imageType The type of the image.
217
+ * @param attributeKey The name of the attribute to convert.
218
+ */
219
+ export function downcastImageAttribute(imageUtils, imageType, attributeKey) {
220
+ const converter = (evt, data, conversionApi) => {
221
+ if (!conversionApi.consumable.consume(data.item, evt.name)) {
222
+ return;
223
+ }
224
+ const viewWriter = conversionApi.writer;
225
+ const element = conversionApi.mapper.toViewElement(data.item);
226
+ const img = imageUtils.findViewImgElement(element);
227
+ viewWriter.setAttribute(data.attributeKey, data.attributeNewValue || '', img);
228
+ };
229
+ return dispatcher => {
230
+ dispatcher.on(`attribute:${attributeKey}:${imageType}`, converter);
231
+ };
232
+ }