@ckeditor/ckeditor5-image 47.6.1-alpha.1 → 48.0.0-alpha.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 (289) hide show
  1. package/LICENSE.md +1 -1
  2. package/ckeditor5-metadata.json +25 -25
  3. package/{src → dist}/autoimage.d.ts +4 -4
  4. package/{src → dist}/image/converters.d.ts +1 -1
  5. package/{src → dist}/image/imageblockediting.d.ts +2 -2
  6. package/{src → dist}/image/imageediting.d.ts +1 -1
  7. package/{src → dist}/image/imageinlineediting.d.ts +2 -2
  8. package/{src → dist}/image/imageloadobserver.d.ts +1 -1
  9. package/{src → dist}/image/imageplaceholder.d.ts +1 -1
  10. package/{src → dist}/image/imagetypecommand.d.ts +2 -2
  11. package/{src → dist}/image/insertimagecommand.d.ts +2 -2
  12. package/{src → dist}/image/replaceimagesourcecommand.d.ts +2 -2
  13. package/{src → dist}/image/ui/utils.d.ts +2 -2
  14. package/{src → dist}/image/utils.d.ts +2 -2
  15. package/{src → dist}/image.d.ts +1 -1
  16. package/{src → dist}/imageblock.d.ts +2 -2
  17. package/{src → dist}/imagecaption/imagecaptionediting.d.ts +2 -2
  18. package/{src → dist}/imagecaption/imagecaptionui.d.ts +1 -1
  19. package/{src → dist}/imagecaption/imagecaptionutils.d.ts +2 -2
  20. package/{src → dist}/imagecaption/toggleimagecaptioncommand.d.ts +1 -1
  21. package/{src → dist}/imagecaption.d.ts +1 -1
  22. package/{src → dist}/imageconfig.d.ts +25 -16
  23. package/{src → dist}/imageinline.d.ts +2 -2
  24. package/{src → dist}/imageinsert/imageinsertui.d.ts +3 -3
  25. package/{src → dist}/imageinsert/imageinsertviaurlui.d.ts +2 -2
  26. package/{src → dist}/imageinsert/ui/imageinsertformview.d.ts +2 -2
  27. package/{src → dist}/imageinsert/ui/imageinserturlview.d.ts +2 -2
  28. package/{src → dist}/imageinsert.d.ts +1 -1
  29. package/{src → dist}/imageinsertviaurl.d.ts +1 -1
  30. package/{src → dist}/imageresize/imagecustomresizeui.d.ts +2 -2
  31. package/{src → dist}/imageresize/imageresizebuttons.d.ts +1 -1
  32. package/{src → dist}/imageresize/imageresizeediting.d.ts +1 -1
  33. package/{src → dist}/imageresize/imageresizehandles.d.ts +2 -2
  34. package/{src → dist}/imageresize/resizeimagecommand.d.ts +1 -1
  35. package/{src → dist}/imageresize/ui/imagecustomresizeformview.d.ts +2 -4
  36. package/{src → dist}/imageresize/utils/getselectedimageeditornodes.d.ts +2 -2
  37. package/{src → dist}/imageresize/utils/getselectedimagepossibleresizerange.d.ts +1 -1
  38. package/{src → dist}/imageresize/utils/getselectedimagewidthinunits.d.ts +1 -1
  39. package/{src → dist}/imageresize.d.ts +1 -1
  40. package/{src → dist}/imagesizeattributes.d.ts +1 -1
  41. package/{src → dist}/imagestyle/converters.d.ts +2 -2
  42. package/{src → dist}/imagestyle/imagestylecommand.d.ts +2 -2
  43. package/{src → dist}/imagestyle/imagestyleediting.d.ts +1 -1
  44. package/{src → dist}/imagestyle/imagestyleui.d.ts +1 -1
  45. package/{src → dist}/imagestyle/utils.d.ts +1 -1
  46. package/{src → dist}/imagestyle.d.ts +1 -1
  47. package/{src → dist}/imagetextalternative/imagetextalternativecommand.d.ts +1 -1
  48. package/{src → dist}/imagetextalternative/imagetextalternativeediting.d.ts +1 -1
  49. package/{src → dist}/imagetextalternative/imagetextalternativeui.d.ts +2 -2
  50. package/{src → dist}/imagetextalternative/ui/textalternativeformview.d.ts +2 -4
  51. package/{src → dist}/imagetextalternative.d.ts +1 -1
  52. package/{src → dist}/imagetoolbar.d.ts +2 -2
  53. package/{src → dist}/imageupload/imageuploadediting.d.ts +5 -5
  54. package/{src → dist}/imageupload/imageuploadprogress.d.ts +1 -1
  55. package/{src → dist}/imageupload/imageuploadui.d.ts +1 -1
  56. package/{src → dist}/imageupload/uploadimagecommand.d.ts +2 -2
  57. package/{src → dist}/imageupload/utils.d.ts +1 -1
  58. package/{src → dist}/imageupload.d.ts +1 -1
  59. package/{src → dist}/imageutils.d.ts +2 -2
  60. package/dist/index-content.css +97 -100
  61. package/dist/index-editor.css +313 -190
  62. package/dist/index.css +388 -458
  63. package/dist/index.css.map +1 -1
  64. package/dist/index.js +1 -2
  65. package/dist/index.js.map +1 -1
  66. package/{src → dist}/pictureediting.d.ts +1 -1
  67. package/package.json +29 -53
  68. package/build/image.js +0 -5
  69. package/build/translations/af.js +0 -1
  70. package/build/translations/ar.js +0 -1
  71. package/build/translations/ast.js +0 -1
  72. package/build/translations/az.js +0 -1
  73. package/build/translations/be.js +0 -1
  74. package/build/translations/bg.js +0 -1
  75. package/build/translations/bn.js +0 -1
  76. package/build/translations/bs.js +0 -1
  77. package/build/translations/ca.js +0 -1
  78. package/build/translations/cs.js +0 -1
  79. package/build/translations/da.js +0 -1
  80. package/build/translations/de-ch.js +0 -1
  81. package/build/translations/de.js +0 -1
  82. package/build/translations/el.js +0 -1
  83. package/build/translations/en-au.js +0 -1
  84. package/build/translations/en-gb.js +0 -1
  85. package/build/translations/eo.js +0 -1
  86. package/build/translations/es-co.js +0 -1
  87. package/build/translations/es.js +0 -1
  88. package/build/translations/et.js +0 -1
  89. package/build/translations/eu.js +0 -1
  90. package/build/translations/fa.js +0 -1
  91. package/build/translations/fi.js +0 -1
  92. package/build/translations/fr.js +0 -1
  93. package/build/translations/gl.js +0 -1
  94. package/build/translations/gu.js +0 -1
  95. package/build/translations/he.js +0 -1
  96. package/build/translations/hi.js +0 -1
  97. package/build/translations/hr.js +0 -1
  98. package/build/translations/hu.js +0 -1
  99. package/build/translations/hy.js +0 -1
  100. package/build/translations/id.js +0 -1
  101. package/build/translations/it.js +0 -1
  102. package/build/translations/ja.js +0 -1
  103. package/build/translations/jv.js +0 -1
  104. package/build/translations/kk.js +0 -1
  105. package/build/translations/km.js +0 -1
  106. package/build/translations/kn.js +0 -1
  107. package/build/translations/ko.js +0 -1
  108. package/build/translations/ku.js +0 -1
  109. package/build/translations/lt.js +0 -1
  110. package/build/translations/lv.js +0 -1
  111. package/build/translations/ms.js +0 -1
  112. package/build/translations/nb.js +0 -1
  113. package/build/translations/ne.js +0 -1
  114. package/build/translations/nl.js +0 -1
  115. package/build/translations/no.js +0 -1
  116. package/build/translations/oc.js +0 -1
  117. package/build/translations/pl.js +0 -1
  118. package/build/translations/pt-br.js +0 -1
  119. package/build/translations/pt.js +0 -1
  120. package/build/translations/ro.js +0 -1
  121. package/build/translations/ru.js +0 -1
  122. package/build/translations/si.js +0 -1
  123. package/build/translations/sk.js +0 -1
  124. package/build/translations/sl.js +0 -1
  125. package/build/translations/sq.js +0 -1
  126. package/build/translations/sr-latn.js +0 -1
  127. package/build/translations/sr.js +0 -1
  128. package/build/translations/sv.js +0 -1
  129. package/build/translations/th.js +0 -1
  130. package/build/translations/ti.js +0 -1
  131. package/build/translations/tk.js +0 -1
  132. package/build/translations/tr.js +0 -1
  133. package/build/translations/tt.js +0 -1
  134. package/build/translations/ug.js +0 -1
  135. package/build/translations/uk.js +0 -1
  136. package/build/translations/ur.js +0 -1
  137. package/build/translations/uz.js +0 -1
  138. package/build/translations/vi.js +0 -1
  139. package/build/translations/zh-cn.js +0 -1
  140. package/build/translations/zh.js +0 -1
  141. package/lang/contexts.json +0 -48
  142. package/lang/translations/af.po +0 -196
  143. package/lang/translations/ar.po +0 -196
  144. package/lang/translations/ast.po +0 -196
  145. package/lang/translations/az.po +0 -196
  146. package/lang/translations/be.po +0 -196
  147. package/lang/translations/bg.po +0 -196
  148. package/lang/translations/bn.po +0 -196
  149. package/lang/translations/bs.po +0 -196
  150. package/lang/translations/ca.po +0 -196
  151. package/lang/translations/cs.po +0 -196
  152. package/lang/translations/da.po +0 -196
  153. package/lang/translations/de-ch.po +0 -196
  154. package/lang/translations/de.po +0 -196
  155. package/lang/translations/el.po +0 -196
  156. package/lang/translations/en-au.po +0 -196
  157. package/lang/translations/en-gb.po +0 -196
  158. package/lang/translations/en.po +0 -196
  159. package/lang/translations/eo.po +0 -196
  160. package/lang/translations/es-co.po +0 -196
  161. package/lang/translations/es.po +0 -196
  162. package/lang/translations/et.po +0 -196
  163. package/lang/translations/eu.po +0 -196
  164. package/lang/translations/fa.po +0 -196
  165. package/lang/translations/fi.po +0 -196
  166. package/lang/translations/fr.po +0 -196
  167. package/lang/translations/gl.po +0 -196
  168. package/lang/translations/gu.po +0 -196
  169. package/lang/translations/he.po +0 -196
  170. package/lang/translations/hi.po +0 -196
  171. package/lang/translations/hr.po +0 -196
  172. package/lang/translations/hu.po +0 -196
  173. package/lang/translations/hy.po +0 -196
  174. package/lang/translations/id.po +0 -196
  175. package/lang/translations/it.po +0 -196
  176. package/lang/translations/ja.po +0 -196
  177. package/lang/translations/jv.po +0 -196
  178. package/lang/translations/kk.po +0 -196
  179. package/lang/translations/km.po +0 -196
  180. package/lang/translations/kn.po +0 -196
  181. package/lang/translations/ko.po +0 -196
  182. package/lang/translations/ku.po +0 -196
  183. package/lang/translations/lt.po +0 -196
  184. package/lang/translations/lv.po +0 -196
  185. package/lang/translations/ms.po +0 -196
  186. package/lang/translations/nb.po +0 -196
  187. package/lang/translations/ne.po +0 -196
  188. package/lang/translations/nl.po +0 -196
  189. package/lang/translations/no.po +0 -196
  190. package/lang/translations/oc.po +0 -196
  191. package/lang/translations/pl.po +0 -196
  192. package/lang/translations/pt-br.po +0 -196
  193. package/lang/translations/pt.po +0 -196
  194. package/lang/translations/ro.po +0 -196
  195. package/lang/translations/ru.po +0 -196
  196. package/lang/translations/si.po +0 -196
  197. package/lang/translations/sk.po +0 -196
  198. package/lang/translations/sl.po +0 -196
  199. package/lang/translations/sq.po +0 -196
  200. package/lang/translations/sr-latn.po +0 -196
  201. package/lang/translations/sr.po +0 -196
  202. package/lang/translations/sv.po +0 -196
  203. package/lang/translations/th.po +0 -196
  204. package/lang/translations/ti.po +0 -196
  205. package/lang/translations/tk.po +0 -196
  206. package/lang/translations/tr.po +0 -196
  207. package/lang/translations/tt.po +0 -196
  208. package/lang/translations/ug.po +0 -196
  209. package/lang/translations/uk.po +0 -196
  210. package/lang/translations/ur.po +0 -196
  211. package/lang/translations/uz.po +0 -196
  212. package/lang/translations/vi.po +0 -196
  213. package/lang/translations/zh-cn.po +0 -196
  214. package/lang/translations/zh.po +0 -196
  215. package/src/augmentation.js +0 -5
  216. package/src/autoimage.js +0 -148
  217. package/src/image/converters.js +0 -236
  218. package/src/image/imageblockediting.js +0 -159
  219. package/src/image/imageediting.js +0 -69
  220. package/src/image/imageinlineediting.js +0 -178
  221. package/src/image/imageloadobserver.js +0 -52
  222. package/src/image/imageplaceholder.js +0 -119
  223. package/src/image/imagetypecommand.js +0 -84
  224. package/src/image/insertimagecommand.js +0 -125
  225. package/src/image/replaceimagesourcecommand.js +0 -75
  226. package/src/image/ui/utils.js +0 -46
  227. package/src/image/utils.js +0 -125
  228. package/src/image.js +0 -44
  229. package/src/imageblock.js +0 -44
  230. package/src/imagecaption/imagecaptionediting.js +0 -238
  231. package/src/imagecaption/imagecaptionui.js +0 -68
  232. package/src/imagecaption/imagecaptionutils.js +0 -68
  233. package/src/imagecaption/toggleimagecaptioncommand.js +0 -138
  234. package/src/imagecaption.js +0 -36
  235. package/src/imageconfig.js +0 -5
  236. package/src/imageinline.js +0 -44
  237. package/src/imageinsert/imageinsertui.js +0 -216
  238. package/src/imageinsert/imageinsertviaurlui.js +0 -175
  239. package/src/imageinsert/ui/imageinsertformview.js +0 -117
  240. package/src/imageinsert/ui/imageinserturlview.js +0 -102
  241. package/src/imageinsert.js +0 -43
  242. package/src/imageinsertviaurl.js +0 -41
  243. package/src/imageresize/imagecustomresizeui.js +0 -177
  244. package/src/imageresize/imageresizebuttons.js +0 -303
  245. package/src/imageresize/imageresizeediting.js +0 -206
  246. package/src/imageresize/imageresizehandles.js +0 -118
  247. package/src/imageresize/resizeimagecommand.js +0 -63
  248. package/src/imageresize/ui/imagecustomresizeformview.js +0 -264
  249. package/src/imageresize/utils/getselectedimageeditornodes.js +0 -25
  250. package/src/imageresize/utils/getselectedimagepossibleresizerange.js +0 -33
  251. package/src/imageresize/utils/getselectedimagewidthinunits.js +0 -42
  252. package/src/imageresize/utils/tryparsedimensionwithunit.js +0 -58
  253. package/src/imageresize.js +0 -38
  254. package/src/imagesizeattributes.js +0 -163
  255. package/src/imagestyle/converters.js +0 -118
  256. package/src/imagestyle/imagestylecommand.js +0 -117
  257. package/src/imagestyle/imagestyleediting.js +0 -127
  258. package/src/imagestyle/imagestyleui.js +0 -198
  259. package/src/imagestyle/utils.js +0 -333
  260. package/src/imagestyle.js +0 -42
  261. package/src/imagetextalternative/imagetextalternativecommand.js +0 -44
  262. package/src/imagetextalternative/imagetextalternativeediting.js +0 -41
  263. package/src/imagetextalternative/imagetextalternativeui.js +0 -183
  264. package/src/imagetextalternative/ui/textalternativeformview.js +0 -193
  265. package/src/imagetextalternative.js +0 -39
  266. package/src/imagetoolbar.js +0 -63
  267. package/src/imageupload/imageuploadediting.js +0 -482
  268. package/src/imageupload/imageuploadprogress.js +0 -222
  269. package/src/imageupload/imageuploadui.js +0 -135
  270. package/src/imageupload/uploadimagecommand.js +0 -110
  271. package/src/imageupload/utils.js +0 -114
  272. package/src/imageupload.js +0 -42
  273. package/src/imageutils.js +0 -309
  274. package/src/index.js +0 -67
  275. package/src/pictureediting.js +0 -136
  276. package/theme/image.css +0 -143
  277. package/theme/imagecaption.css +0 -53
  278. package/theme/imagecustomresizeform.css +0 -4
  279. package/theme/imageinsert.css +0 -14
  280. package/theme/imageplaceholder.css +0 -10
  281. package/theme/imageresize.css +0 -53
  282. package/theme/imagestyle.css +0 -120
  283. package/theme/imageuploadicon.css +0 -23
  284. package/theme/imageuploadloader.css +0 -18
  285. package/theme/imageuploadprogress.css +0 -19
  286. package/theme/textalternativeform.css +0 -4
  287. /package/{src → dist}/augmentation.d.ts +0 -0
  288. /package/{src → dist}/imageresize/utils/tryparsedimensionwithunit.d.ts +0 -0
  289. /package/{src → dist}/index.d.ts +0 -0
@@ -1,159 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
- */
5
- /**
6
- * @module image/image/imageblockediting
7
- */
8
- import { Plugin } from 'ckeditor5/src/core.js';
9
- import { ClipboardPipeline } from 'ckeditor5/src/clipboard.js';
10
- import { ViewUpcastWriter } from 'ckeditor5/src/engine.js';
11
- import { downcastImageAttribute, downcastSrcsetAttribute, upcastImageFigure } from './converters.js';
12
- import { ImageEditing } from './imageediting.js';
13
- import { ImageSizeAttributes } from '../imagesizeattributes.js';
14
- import { ImageTypeCommand } from './imagetypecommand.js';
15
- import { ImageUtils } from '../imageutils.js';
16
- import { getImgViewElementMatcher, createBlockImageViewElement, determineImageTypeForInsertionAtSelection } from './utils.js';
17
- import { ImagePlaceholder } from './imageplaceholder.js';
18
- /**
19
- * The image block plugin.
20
- *
21
- * It registers:
22
- *
23
- * * `<imageBlock>` as a block element in the document schema, and allows `alt`, `src` and `srcset` attributes.
24
- * * converters for editing and data pipelines.,
25
- * * {@link module:image/image/imagetypecommand~ImageTypeCommand `'imageTypeBlock'`} command that converts inline images into
26
- * block images.
27
- */
28
- export class ImageBlockEditing extends Plugin {
29
- /**
30
- * @inheritDoc
31
- */
32
- static get requires() {
33
- return [ImageEditing, ImageSizeAttributes, ImageUtils, ImagePlaceholder, ClipboardPipeline];
34
- }
35
- /**
36
- * @inheritDoc
37
- */
38
- static get pluginName() {
39
- return 'ImageBlockEditing';
40
- }
41
- /**
42
- * @inheritDoc
43
- */
44
- static get isOfficialPlugin() {
45
- return true;
46
- }
47
- /**
48
- * @inheritDoc
49
- */
50
- init() {
51
- const editor = this.editor;
52
- const schema = editor.model.schema;
53
- // Converters 'alt' and 'srcset' are added in 'ImageEditing' plugin.
54
- schema.register('imageBlock', {
55
- inheritAllFrom: '$blockObject',
56
- allowAttributes: ['alt', 'src', 'srcset']
57
- });
58
- this._setupConversion();
59
- if (editor.plugins.has('ImageInlineEditing')) {
60
- editor.commands.add('imageTypeBlock', new ImageTypeCommand(this.editor, 'imageBlock'));
61
- this._setupClipboardIntegration();
62
- }
63
- }
64
- /**
65
- * Configures conversion pipelines to support upcasting and downcasting
66
- * block images (block image widgets) and their attributes.
67
- */
68
- _setupConversion() {
69
- const editor = this.editor;
70
- const t = editor.t;
71
- const conversion = editor.conversion;
72
- const imageUtils = editor.plugins.get('ImageUtils');
73
- conversion.for('dataDowncast')
74
- .elementToStructure({
75
- model: 'imageBlock',
76
- view: (modelElement, { writer }) => createBlockImageViewElement(writer)
77
- });
78
- conversion.for('editingDowncast')
79
- .elementToStructure({
80
- model: 'imageBlock',
81
- view: (modelElement, { writer }) => imageUtils.toImageWidget(createBlockImageViewElement(writer), writer, t('image widget'))
82
- });
83
- conversion.for('downcast')
84
- .add(downcastImageAttribute(imageUtils, 'imageBlock', 'src'))
85
- .add(downcastImageAttribute(imageUtils, 'imageBlock', 'alt'))
86
- .add(downcastSrcsetAttribute(imageUtils, 'imageBlock'));
87
- // More image related upcasts are in 'ImageEditing' plugin.
88
- conversion.for('upcast')
89
- .elementToElement({
90
- view: getImgViewElementMatcher(editor, 'imageBlock'),
91
- model: (viewImage, { writer }) => writer.createElement('imageBlock', viewImage.hasAttribute('src') ? { src: viewImage.getAttribute('src') } : undefined)
92
- })
93
- .add(upcastImageFigure(imageUtils));
94
- }
95
- /**
96
- * Integrates the plugin with the clipboard pipeline.
97
- *
98
- * Idea is that the feature should recognize the user's intent when an **inline** image is
99
- * pasted or dropped. If such an image is pasted/dropped:
100
- *
101
- * * into an empty block (e.g. an empty paragraph),
102
- * * on another object (e.g. some block widget).
103
- *
104
- * it gets converted into a block image on the fly. We assume this is the user's intent
105
- * if they decided to put their image there.
106
- *
107
- * See the `ImageInlineEditing` for the similar integration that works in the opposite direction.
108
- *
109
- * The feature also sets image `width` and `height` attributes on paste.
110
- */
111
- _setupClipboardIntegration() {
112
- const editor = this.editor;
113
- const model = editor.model;
114
- const editingView = editor.editing.view;
115
- const imageUtils = editor.plugins.get('ImageUtils');
116
- const clipboardPipeline = editor.plugins.get('ClipboardPipeline');
117
- this.listenTo(clipboardPipeline, 'inputTransformation', (evt, data) => {
118
- const docFragmentChildren = Array.from(data.content.getChildren());
119
- let modelRange;
120
- // Make sure only <img> elements are dropped or pasted. Otherwise, if there some other HTML
121
- // mixed up, this should be handled as a regular paste.
122
- if (!docFragmentChildren.every(imageUtils.isInlineImageView)) {
123
- return;
124
- }
125
- // When drag and dropping, data.targetRanges specifies where to drop because
126
- // this is usually a different place than the current model selection (the user
127
- // uses a drop marker to specify the drop location).
128
- if (data.targetRanges) {
129
- modelRange = editor.editing.mapper.toModelRange(data.targetRanges[0]);
130
- }
131
- // Pasting, however, always occurs at the current model selection.
132
- else {
133
- modelRange = model.document.selection.getFirstRange();
134
- }
135
- const selection = model.createSelection(modelRange);
136
- // Convert inline images into block images only when the currently selected block is empty
137
- // (e.g. an empty paragraph) or some object is selected (to replace it).
138
- if (determineImageTypeForInsertionAtSelection(model.schema, selection) === 'imageBlock') {
139
- const writer = new ViewUpcastWriter(editingView.document);
140
- // Wrap <img ... /> -> <figure class="image"><img .../></figure>
141
- const blockViewImages = docFragmentChildren.map(inlineViewImage => writer.createElement('figure', { class: 'image' }, inlineViewImage));
142
- data.content = writer.createDocumentFragment(blockViewImages);
143
- }
144
- });
145
- this.listenTo(clipboardPipeline, 'contentInsertion', (evt, data) => {
146
- if (data.method !== 'paste') {
147
- return;
148
- }
149
- model.change(writer => {
150
- const range = writer.createRangeIn(data.content);
151
- for (const item of range.getItems()) {
152
- if (item.is('element', 'imageBlock')) {
153
- imageUtils.setImageNaturalSizeAttributes(item);
154
- }
155
- }
156
- });
157
- });
158
- }
159
- }
@@ -1,69 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
- */
5
- /**
6
- * @module image/image/imageediting
7
- */
8
- import { Plugin } from 'ckeditor5/src/core.js';
9
- import { ImageLoadObserver } from './imageloadobserver.js';
10
- import { InsertImageCommand } from './insertimagecommand.js';
11
- import { ReplaceImageSourceCommand } from './replaceimagesourcecommand.js';
12
- import { ImageUtils } from '../imageutils.js';
13
- /**
14
- * The image engine plugin. This module loads common code shared between
15
- * {@link module:image/image/imageinlineediting~ImageInlineEditing} and
16
- * {@link module:image/image/imageblockediting~ImageBlockEditing} plugins.
17
- *
18
- * This plugin registers the {@link module:image/image/insertimagecommand~InsertImageCommand 'insertImage'} command.
19
- */
20
- export class ImageEditing extends Plugin {
21
- /**
22
- * @inheritDoc
23
- */
24
- static get requires() {
25
- return [ImageUtils];
26
- }
27
- /**
28
- * @inheritDoc
29
- */
30
- static get pluginName() {
31
- return 'ImageEditing';
32
- }
33
- /**
34
- * @inheritDoc
35
- */
36
- static get isOfficialPlugin() {
37
- return true;
38
- }
39
- /**
40
- * @inheritDoc
41
- */
42
- init() {
43
- const editor = this.editor;
44
- const conversion = editor.conversion;
45
- // See https://github.com/ckeditor/ckeditor5-image/issues/142.
46
- editor.editing.view.addObserver(ImageLoadObserver);
47
- conversion.for('upcast')
48
- .attributeToAttribute({
49
- view: {
50
- name: 'img',
51
- key: 'alt'
52
- },
53
- model: 'alt'
54
- })
55
- .attributeToAttribute({
56
- view: {
57
- name: 'img',
58
- key: 'srcset'
59
- },
60
- model: 'srcset'
61
- });
62
- const insertImageCommand = new InsertImageCommand(editor);
63
- const replaceImageSourceCommand = new ReplaceImageSourceCommand(editor);
64
- editor.commands.add('insertImage', insertImageCommand);
65
- editor.commands.add('replaceImageSource', replaceImageSourceCommand);
66
- // `imageInsert` is an alias for backward compatibility.
67
- editor.commands.add('imageInsert', insertImageCommand);
68
- }
69
- }
@@ -1,178 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
- */
5
- /**
6
- * @module image/image/imageinlineediting
7
- */
8
- import { Plugin } from 'ckeditor5/src/core.js';
9
- import { ClipboardPipeline } from 'ckeditor5/src/clipboard.js';
10
- import { ViewUpcastWriter } from 'ckeditor5/src/engine.js';
11
- import { downcastImageAttribute, downcastSrcsetAttribute } from './converters.js';
12
- import { ImageEditing } from './imageediting.js';
13
- import { ImageSizeAttributes } from '../imagesizeattributes.js';
14
- import { ImageTypeCommand } from './imagetypecommand.js';
15
- import { ImageUtils } from '../imageutils.js';
16
- import { getImgViewElementMatcher, createInlineImageViewElement, determineImageTypeForInsertionAtSelection } from './utils.js';
17
- import { ImagePlaceholder } from './imageplaceholder.js';
18
- /**
19
- * The image inline plugin.
20
- *
21
- * It registers:
22
- *
23
- * * `<imageInline>` as an inline element in the document schema, and allows `alt`, `src` and `srcset` attributes.
24
- * * converters for editing and data pipelines.
25
- * * {@link module:image/image/imagetypecommand~ImageTypeCommand `'imageTypeInline'`} command that converts block images into
26
- * inline images.
27
- */
28
- export class ImageInlineEditing extends Plugin {
29
- /**
30
- * @inheritDoc
31
- */
32
- static get requires() {
33
- return [ImageEditing, ImageSizeAttributes, ImageUtils, ImagePlaceholder, ClipboardPipeline];
34
- }
35
- /**
36
- * @inheritDoc
37
- */
38
- static get pluginName() {
39
- return 'ImageInlineEditing';
40
- }
41
- /**
42
- * @inheritDoc
43
- */
44
- static get isOfficialPlugin() {
45
- return true;
46
- }
47
- /**
48
- * @inheritDoc
49
- */
50
- init() {
51
- const editor = this.editor;
52
- const schema = editor.model.schema;
53
- // Converters 'alt' and 'srcset' are added in 'ImageEditing' plugin.
54
- schema.register('imageInline', {
55
- inheritAllFrom: '$inlineObject',
56
- allowAttributes: ['alt', 'src', 'srcset'],
57
- // Disallow inline images in captions (at least for now).
58
- // This is the best spot to do that because independent packages can introduce captions (ImageCaption, TableCaption, etc.).
59
- disallowIn: ['caption']
60
- });
61
- this._setupConversion();
62
- if (editor.plugins.has('ImageBlockEditing')) {
63
- editor.commands.add('imageTypeInline', new ImageTypeCommand(this.editor, 'imageInline'));
64
- this._setupClipboardIntegration();
65
- }
66
- }
67
- /**
68
- * Configures conversion pipelines to support upcasting and downcasting
69
- * inline images (inline image widgets) and their attributes.
70
- */
71
- _setupConversion() {
72
- const editor = this.editor;
73
- const t = editor.t;
74
- const conversion = editor.conversion;
75
- const imageUtils = editor.plugins.get('ImageUtils');
76
- conversion.for('dataDowncast')
77
- .elementToElement({
78
- model: 'imageInline',
79
- view: (modelElement, { writer }) => writer.createEmptyElement('img')
80
- });
81
- conversion.for('editingDowncast')
82
- .elementToStructure({
83
- model: 'imageInline',
84
- view: (modelElement, { writer }) => imageUtils.toImageWidget(createInlineImageViewElement(writer), writer, t('image widget'))
85
- });
86
- conversion.for('downcast')
87
- .add(downcastImageAttribute(imageUtils, 'imageInline', 'src'))
88
- .add(downcastImageAttribute(imageUtils, 'imageInline', 'alt'))
89
- .add(downcastSrcsetAttribute(imageUtils, 'imageInline'));
90
- // More image related upcasts are in 'ImageEditing' plugin.
91
- conversion.for('upcast')
92
- .elementToElement({
93
- view: getImgViewElementMatcher(editor, 'imageInline'),
94
- model: (viewImage, { writer }) => writer.createElement('imageInline', viewImage.hasAttribute('src') ? { src: viewImage.getAttribute('src') } : undefined)
95
- });
96
- }
97
- /**
98
- * Integrates the plugin with the clipboard pipeline.
99
- *
100
- * Idea is that the feature should recognize the user's intent when an **block** image is
101
- * pasted or dropped. If such an image is pasted/dropped into a non-empty block
102
- * (e.g. a paragraph with some text) it gets converted into an inline image on the fly.
103
- *
104
- * We assume this is the user's intent if they decided to put their image there.
105
- *
106
- * **Note**: If a block image has a caption, it will not be converted to an inline image
107
- * to avoid the confusion. Captions are added on purpose and they should never be lost
108
- * in the clipboard pipeline.
109
- *
110
- * See the `ImageBlockEditing` for the similar integration that works in the opposite direction.
111
- *
112
- * The feature also sets image `width` and `height` attributes when pasting.
113
- */
114
- _setupClipboardIntegration() {
115
- const editor = this.editor;
116
- const model = editor.model;
117
- const editingView = editor.editing.view;
118
- const imageUtils = editor.plugins.get('ImageUtils');
119
- const clipboardPipeline = editor.plugins.get('ClipboardPipeline');
120
- this.listenTo(clipboardPipeline, 'inputTransformation', (evt, data) => {
121
- const docFragmentChildren = Array.from(data.content.getChildren());
122
- let modelRange;
123
- // Make sure only <figure class="image"></figure> elements are dropped or pasted. Otherwise, if there some other HTML
124
- // mixed up, this should be handled as a regular paste.
125
- if (!docFragmentChildren.every(imageUtils.isBlockImageView)) {
126
- return;
127
- }
128
- // When drag and dropping, data.targetRanges specifies where to drop because
129
- // this is usually a different place than the current model selection (the user
130
- // uses a drop marker to specify the drop location).
131
- if (data.targetRanges) {
132
- modelRange = editor.editing.mapper.toModelRange(data.targetRanges[0]);
133
- }
134
- // Pasting, however, always occurs at the current model selection.
135
- else {
136
- modelRange = model.document.selection.getFirstRange();
137
- }
138
- const selection = model.createSelection(modelRange);
139
- // Convert block images into inline images only when pasting or dropping into non-empty blocks
140
- // and when the block is not an object (e.g. pasting to replace another widget).
141
- if (determineImageTypeForInsertionAtSelection(model.schema, selection) === 'imageInline') {
142
- const writer = new ViewUpcastWriter(editingView.document);
143
- // Unwrap <figure class="image"><img .../></figure> -> <img ... />
144
- // but <figure class="image"><img .../><figcaption>...</figcaption></figure> -> stays the same
145
- const inlineViewImages = docFragmentChildren.map(blockViewImage => {
146
- // If there's just one child, it can be either <img /> or <a><img></a>.
147
- // If there are other children than <img>, this means that the block image
148
- // has a caption or some other features and this kind of image should be
149
- // pasted/dropped without modifications.
150
- if (blockViewImage.childCount === 1) {
151
- // Pass the attributes which are present only in the <figure> to the <img>
152
- // (e.g. the style="width:10%" attribute applied by the ImageResize plugin).
153
- Array.from(blockViewImage.getAttributes())
154
- .forEach(attribute => writer.setAttribute(...attribute, imageUtils.findViewImgElement(blockViewImage)));
155
- return blockViewImage.getChild(0);
156
- }
157
- else {
158
- return blockViewImage;
159
- }
160
- });
161
- data.content = writer.createDocumentFragment(inlineViewImages);
162
- }
163
- });
164
- this.listenTo(clipboardPipeline, 'contentInsertion', (evt, data) => {
165
- if (data.method !== 'paste') {
166
- return;
167
- }
168
- model.change(writer => {
169
- const range = writer.createRangeIn(data.content);
170
- for (const item of range.getItems()) {
171
- if (item.is('element', 'imageInline')) {
172
- imageUtils.setImageNaturalSizeAttributes(item);
173
- }
174
- }
175
- });
176
- });
177
- }
178
- }
@@ -1,52 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
- */
5
- /**
6
- * @module image/image/imageloadobserver
7
- */
8
- import { Observer } from 'ckeditor5/src/engine.js';
9
- /**
10
- * Observes all new images added to the {@link module:engine/view/document~ViewDocument},
11
- * fires {@link module:engine/view/document~ViewDocument#event:imageLoaded} and
12
- * {@link module:engine/view/document~ViewDocument#event:layoutChanged} event every time when the new image
13
- * has been loaded.
14
- *
15
- * **Note:** This event is not fired for images that has been added to the document and rendered as `complete` (already loaded).
16
- */
17
- export class ImageLoadObserver extends Observer {
18
- /**
19
- * @inheritDoc
20
- */
21
- observe(domRoot) {
22
- this.listenTo(domRoot, 'load', (event, domEvent) => {
23
- const domElement = domEvent.target;
24
- if (this.checkShouldIgnoreEventFromTarget(domElement)) {
25
- return;
26
- }
27
- if (domElement.tagName == 'IMG') {
28
- this._fireEvents(domEvent);
29
- }
30
- // Use capture phase for better performance (#4504).
31
- }, { useCapture: true });
32
- }
33
- /**
34
- * @inheritDoc
35
- */
36
- stopObserving(domRoot) {
37
- this.stopListening(domRoot);
38
- }
39
- /**
40
- * Fires {@link module:engine/view/document~ViewDocument#event:layoutChanged} and
41
- * {@link module:engine/view/document~ViewDocument#event:imageLoaded}
42
- * if observer {@link #isEnabled is enabled}.
43
- *
44
- * @param domEvent The DOM event.
45
- */
46
- _fireEvents(domEvent) {
47
- if (this.isEnabled) {
48
- this.document.fire('layoutChanged');
49
- this.document.fire('imageLoaded', domEvent);
50
- }
51
- }
52
- }
@@ -1,119 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
- */
5
- /**
6
- * @module image/image/imageplaceholder
7
- */
8
- import { Plugin } from 'ckeditor5/src/core.js';
9
- import { ImageUtils } from '../imageutils.js';
10
- import { ImageLoadObserver } from './imageloadobserver.js';
11
- import '../../theme/imageplaceholder.css';
12
- /**
13
- * Adds support for image placeholder that is automatically removed when the image is loaded.
14
- */
15
- export class ImagePlaceholder extends Plugin {
16
- /**
17
- * @inheritDoc
18
- */
19
- static get requires() {
20
- return [ImageUtils];
21
- }
22
- /**
23
- * @inheritDoc
24
- */
25
- static get pluginName() {
26
- return 'ImagePlaceholder';
27
- }
28
- /**
29
- * @inheritDoc
30
- */
31
- static get isOfficialPlugin() {
32
- return true;
33
- }
34
- /**
35
- * @inheritDoc
36
- */
37
- afterInit() {
38
- this._setupSchema();
39
- this._setupConversion();
40
- this._setupLoadListener();
41
- }
42
- /**
43
- * Extends model schema.
44
- */
45
- _setupSchema() {
46
- const schema = this.editor.model.schema;
47
- // Wait for ImageBlockEditing or ImageInlineEditing to register their elements first,
48
- // that's why doing this in afterInit() instead of init().
49
- if (schema.isRegistered('imageBlock')) {
50
- schema.extend('imageBlock', {
51
- allowAttributes: ['placeholder']
52
- });
53
- }
54
- if (schema.isRegistered('imageInline')) {
55
- schema.extend('imageInline', {
56
- allowAttributes: ['placeholder']
57
- });
58
- }
59
- }
60
- /**
61
- * Registers converters.
62
- */
63
- _setupConversion() {
64
- const editor = this.editor;
65
- const conversion = editor.conversion;
66
- const imageUtils = editor.plugins.get('ImageUtils');
67
- conversion.for('editingDowncast').add(dispatcher => {
68
- dispatcher.on('attribute:placeholder', (evt, data, conversionApi) => {
69
- if (!conversionApi.consumable.test(data.item, evt.name)) {
70
- return;
71
- }
72
- if (!data.item.is('element', 'imageBlock') && !data.item.is('element', 'imageInline')) {
73
- return;
74
- }
75
- conversionApi.consumable.consume(data.item, evt.name);
76
- const viewWriter = conversionApi.writer;
77
- const element = conversionApi.mapper.toViewElement(data.item);
78
- const img = imageUtils.findViewImgElement(element);
79
- if (data.attributeNewValue) {
80
- viewWriter.addClass('image_placeholder', img);
81
- viewWriter.setStyle('background-image', `url(${data.attributeNewValue})`, img);
82
- viewWriter.setCustomProperty('editingPipeline:doNotReuseOnce', true, img);
83
- }
84
- else {
85
- viewWriter.removeClass('image_placeholder', img);
86
- viewWriter.removeStyle('background-image', img);
87
- }
88
- });
89
- });
90
- }
91
- /**
92
- * Prepares listener for image load.
93
- */
94
- _setupLoadListener() {
95
- const editor = this.editor;
96
- const model = editor.model;
97
- const editing = editor.editing;
98
- const editingView = editing.view;
99
- const imageUtils = editor.plugins.get('ImageUtils');
100
- editingView.addObserver(ImageLoadObserver);
101
- this.listenTo(editingView.document, 'imageLoaded', (evt, domEvent) => {
102
- const imgViewElement = editingView.domConverter.mapDomToView(domEvent.target);
103
- if (!imgViewElement) {
104
- return;
105
- }
106
- const viewElement = imageUtils.getImageWidgetFromImageView(imgViewElement);
107
- if (!viewElement) {
108
- return;
109
- }
110
- const modelElement = editing.mapper.toModelElement(viewElement);
111
- if (!modelElement || !modelElement.hasAttribute('placeholder')) {
112
- return;
113
- }
114
- model.enqueueChange({ isUndoable: false }, writer => {
115
- writer.removeAttribute('placeholder', modelElement);
116
- });
117
- });
118
- }
119
- }
@@ -1,84 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
- */
5
- import { Command } from 'ckeditor5/src/core.js';
6
- /**
7
- * The image type command. It changes the type of a selected image, depending on the configuration.
8
- */
9
- export class ImageTypeCommand extends Command {
10
- /**
11
- * Model element name the command converts to.
12
- */
13
- _modelElementName;
14
- /**
15
- * @inheritDoc
16
- *
17
- * @param modelElementName Model element name the command converts to.
18
- */
19
- constructor(editor, modelElementName) {
20
- super(editor);
21
- this._modelElementName = modelElementName;
22
- }
23
- /**
24
- * @inheritDoc
25
- */
26
- refresh() {
27
- const editor = this.editor;
28
- const imageUtils = editor.plugins.get('ImageUtils');
29
- const element = imageUtils.getClosestSelectedImageElement(this.editor.model.document.selection);
30
- if (this._modelElementName === 'imageBlock') {
31
- this.isEnabled = imageUtils.isInlineImage(element);
32
- }
33
- else {
34
- this.isEnabled = imageUtils.isBlockImage(element);
35
- }
36
- }
37
- /**
38
- * Executes the command and changes the type of a selected image.
39
- *
40
- * @fires execute
41
- * @param options.setImageSizes Specifies whether the image `width` and `height` attributes should be set automatically.
42
- * The default is `true`.
43
- * @returns An object containing references to old and new model image elements
44
- * (for before and after the change) so external integrations can hook into the decorated
45
- * `execute` event and handle this change. `null` if the type change failed.
46
- */
47
- execute(options = {}) {
48
- const editor = this.editor;
49
- const model = this.editor.model;
50
- const imageUtils = editor.plugins.get('ImageUtils');
51
- const oldElement = imageUtils.getClosestSelectedImageElement(model.document.selection);
52
- const attributes = Object.fromEntries(oldElement.getAttributes());
53
- // Don't change image type if "src" is missing (a broken image), unless there's "uploadId" set.
54
- // This state may happen during image upload (before it finishes) and it should be possible to change type
55
- // of the image in the meantime.
56
- if (!attributes.src && !attributes.uploadId) {
57
- return null;
58
- }
59
- return model.change(writer => {
60
- const { setImageSizes = true } = options;
61
- // Get all markers that contain the old image element.
62
- const markers = Array.from(model.markers)
63
- .filter(marker => marker.getRange().containsItem(oldElement));
64
- const newElement = imageUtils.insertImage(attributes, model.createSelection(oldElement, 'on'), this._modelElementName, { setImageSizes });
65
- if (!newElement) {
66
- return null;
67
- }
68
- const newElementRange = writer.createRangeOn(newElement);
69
- // Expand the previously intersecting markers' ranges to include the new image element.
70
- for (const marker of markers) {
71
- const markerRange = marker.getRange();
72
- // Join the survived part of the old marker range with the new element range
73
- // (loosely because there could be some new paragraph or the existing one might got split).
74
- const range = markerRange.root.rootName != '$graveyard' ?
75
- markerRange.getJoined(newElementRange, true) : newElementRange;
76
- writer.updateMarker(marker, { range });
77
- }
78
- return {
79
- oldElement,
80
- newElement
81
- };
82
- });
83
- }
84
- }