@ckeditor/ckeditor5-image 27.1.0 → 29.2.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 (167) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +3 -3
  3. package/build/image.js +1 -1
  4. package/build/translations/ar.js +1 -0
  5. package/build/translations/ast.js +1 -0
  6. package/build/translations/az.js +1 -0
  7. package/build/translations/bg.js +1 -0
  8. package/build/translations/cs.js +1 -0
  9. package/build/translations/da.js +1 -0
  10. package/build/translations/de-ch.js +1 -0
  11. package/build/translations/de.js +1 -0
  12. package/build/translations/el.js +1 -0
  13. package/build/translations/en-au.js +1 -0
  14. package/build/translations/en-gb.js +1 -0
  15. package/build/translations/eo.js +1 -0
  16. package/build/translations/es.js +1 -0
  17. package/build/translations/et.js +1 -0
  18. package/build/translations/eu.js +1 -0
  19. package/build/translations/fa.js +1 -0
  20. package/build/translations/fi.js +1 -0
  21. package/build/translations/fr.js +1 -0
  22. package/build/translations/gl.js +1 -0
  23. package/build/translations/he.js +1 -0
  24. package/build/translations/hi.js +1 -0
  25. package/build/translations/hr.js +1 -0
  26. package/build/translations/hu.js +1 -0
  27. package/build/translations/id.js +1 -0
  28. package/build/translations/it.js +1 -0
  29. package/build/translations/ja.js +1 -0
  30. package/build/translations/km.js +1 -0
  31. package/build/translations/kn.js +1 -0
  32. package/build/translations/ko.js +1 -0
  33. package/build/translations/ku.js +1 -0
  34. package/build/translations/lt.js +1 -0
  35. package/build/translations/lv.js +1 -0
  36. package/build/translations/nb.js +1 -0
  37. package/build/translations/ne.js +1 -0
  38. package/build/translations/nl.js +1 -0
  39. package/build/translations/no.js +1 -0
  40. package/build/translations/pl.js +1 -0
  41. package/build/translations/pt-br.js +1 -0
  42. package/build/translations/pt.js +1 -0
  43. package/build/translations/ro.js +1 -0
  44. package/build/translations/ru.js +1 -0
  45. package/build/translations/si.js +1 -0
  46. package/build/translations/sk.js +1 -0
  47. package/build/translations/sq.js +1 -0
  48. package/build/translations/sr-latn.js +1 -0
  49. package/build/translations/sr.js +1 -0
  50. package/build/translations/sv.js +1 -0
  51. package/build/translations/th.js +1 -0
  52. package/build/translations/tk.js +1 -0
  53. package/build/translations/tr.js +1 -0
  54. package/build/translations/ug.js +1 -0
  55. package/build/translations/uk.js +1 -0
  56. package/build/translations/vi.js +1 -0
  57. package/build/translations/zh-cn.js +1 -0
  58. package/build/translations/zh.js +1 -0
  59. package/ckeditor5-metadata.json +233 -0
  60. package/lang/contexts.json +3 -0
  61. package/lang/translations/ar.po +12 -0
  62. package/lang/translations/ast.po +12 -0
  63. package/lang/translations/az.po +12 -0
  64. package/lang/translations/bg.po +12 -0
  65. package/lang/translations/cs.po +12 -0
  66. package/lang/translations/da.po +12 -0
  67. package/lang/translations/de-ch.po +113 -0
  68. package/lang/translations/de.po +15 -3
  69. package/lang/translations/el.po +12 -0
  70. package/lang/translations/en-au.po +12 -0
  71. package/lang/translations/en-gb.po +12 -0
  72. package/lang/translations/en.po +12 -0
  73. package/lang/translations/eo.po +12 -0
  74. package/lang/translations/es.po +12 -0
  75. package/lang/translations/et.po +12 -0
  76. package/lang/translations/eu.po +12 -0
  77. package/lang/translations/fa.po +12 -0
  78. package/lang/translations/fi.po +12 -0
  79. package/lang/translations/fr.po +12 -0
  80. package/lang/translations/gl.po +12 -0
  81. package/lang/translations/he.po +12 -0
  82. package/lang/translations/hi.po +12 -0
  83. package/lang/translations/hr.po +12 -0
  84. package/lang/translations/hu.po +13 -1
  85. package/lang/translations/id.po +21 -9
  86. package/lang/translations/it.po +12 -0
  87. package/lang/translations/ja.po +12 -0
  88. package/lang/translations/km.po +12 -0
  89. package/lang/translations/kn.po +12 -0
  90. package/lang/translations/ko.po +12 -0
  91. package/lang/translations/ku.po +12 -0
  92. package/lang/translations/lt.po +12 -0
  93. package/lang/translations/lv.po +12 -0
  94. package/lang/translations/nb.po +12 -0
  95. package/lang/translations/ne.po +12 -0
  96. package/lang/translations/nl.po +12 -0
  97. package/lang/translations/no.po +12 -0
  98. package/lang/translations/pl.po +20 -8
  99. package/lang/translations/pt-br.po +12 -0
  100. package/lang/translations/pt.po +12 -0
  101. package/lang/translations/ro.po +21 -9
  102. package/lang/translations/ru.po +12 -0
  103. package/lang/translations/si.po +12 -0
  104. package/lang/translations/sk.po +12 -0
  105. package/lang/translations/sq.po +12 -0
  106. package/lang/translations/sr-latn.po +12 -0
  107. package/lang/translations/sr.po +12 -0
  108. package/lang/translations/sv.po +12 -0
  109. package/lang/translations/th.po +12 -0
  110. package/lang/translations/tk.po +12 -0
  111. package/lang/translations/tr.po +12 -0
  112. package/lang/translations/ug.po +12 -0
  113. package/lang/translations/uk.po +12 -0
  114. package/lang/translations/vi.po +12 -0
  115. package/lang/translations/zh-cn.po +12 -0
  116. package/lang/translations/zh.po +12 -0
  117. package/package.json +36 -29
  118. package/src/autoimage.js +6 -4
  119. package/src/image/converters.js +192 -13
  120. package/src/image/imageblockediting.js +179 -0
  121. package/src/image/imageediting.js +13 -70
  122. package/src/image/imageinlineediting.js +204 -0
  123. package/src/image/imagetypecommand.js +105 -0
  124. package/src/image/insertimagecommand.js +77 -10
  125. package/src/image/ui/utils.js +3 -3
  126. package/src/image/utils.js +70 -121
  127. package/src/image.js +7 -19
  128. package/src/imageblock.js +46 -0
  129. package/src/imagecaption/imagecaptionediting.js +202 -230
  130. package/src/imagecaption/imagecaptionui.js +78 -0
  131. package/src/imagecaption/toggleimagecaptioncommand.js +165 -0
  132. package/src/imagecaption/utils.js +25 -40
  133. package/src/imagecaption.js +3 -2
  134. package/src/imageinline.js +46 -0
  135. package/src/imageinsert/imageinsertui.js +5 -6
  136. package/src/imageinsert.js +16 -4
  137. package/src/imageresize/imageresizebuttons.js +1 -1
  138. package/src/imageresize/imageresizeediting.js +21 -8
  139. package/src/imageresize/imageresizehandles.js +30 -8
  140. package/src/imageresize/resizeimagecommand.js +8 -5
  141. package/src/imagestyle/converters.js +25 -17
  142. package/src/imagestyle/imagestylecommand.js +73 -33
  143. package/src/imagestyle/imagestyleediting.js +113 -52
  144. package/src/imagestyle/imagestyleui.js +197 -31
  145. package/src/imagestyle/utils.js +300 -85
  146. package/src/imagestyle.js +218 -47
  147. package/src/imagetextalternative/imagetextalternativecommand.js +10 -7
  148. package/src/imagetextalternative/imagetextalternativeediting.js +9 -1
  149. package/src/imagetextalternative/imagetextalternativeui.js +2 -2
  150. package/src/imagetextalternative.js +1 -1
  151. package/src/imagetoolbar.js +33 -11
  152. package/src/imageupload/imageuploadediting.js +91 -31
  153. package/src/imageupload/imageuploadprogress.js +17 -9
  154. package/src/imageupload/imageuploadui.js +1 -1
  155. package/src/imageupload/uploadimagecommand.js +50 -24
  156. package/src/imageupload/utils.js +3 -2
  157. package/src/imageupload.js +1 -1
  158. package/src/imageutils.js +342 -0
  159. package/src/index.js +22 -47
  160. package/src/pictureediting.js +149 -0
  161. package/theme/image.css +101 -21
  162. package/theme/imagecaption.css +24 -2
  163. package/theme/imageresize.css +11 -0
  164. package/theme/imagestyle.css +76 -0
  165. package/theme/imageuploadicon.css +8 -2
  166. package/theme/imageuploadprogress.css +12 -8
  167. package/build/image.js.map +0 -1
@@ -7,155 +7,104 @@
7
7
  * @module image/image/utils
8
8
  */
9
9
 
10
- import { findOptimalInsertionPosition, checkSelectionOnObject, isWidget, toWidget } from 'ckeditor5/src/widget';
10
+ import { first } from 'ckeditor5/src/utils';
11
11
 
12
12
  /**
13
- * Converts a given {@link module:engine/view/element~Element} to an image widget:
14
- * * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to recognize the image widget element.
15
- * * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.
13
+ * Creates a view element representing the image of provided image type.
16
14
  *
17
- * @param {module:engine/view/element~Element} viewElement
18
- * @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer.
19
- * @param {String} label The element's label. It will be concatenated with the image `alt` attribute if one is present.
20
- * @returns {module:engine/view/element~Element}
21
- */
22
- export function toImageWidget( viewElement, writer, label ) {
23
- writer.setCustomProperty( 'image', true, viewElement );
24
-
25
- return toWidget( viewElement, writer, { label: labelCreator } );
26
-
27
- function labelCreator() {
28
- const imgElement = getViewImgFromWidget( viewElement );
29
- const altText = imgElement.getAttribute( 'alt' );
30
-
31
- return altText ? `${ altText } ${ label }` : label;
32
- }
33
- }
34
-
35
- /**
36
- * Checks if a given view element is an image widget.
15
+ * An 'imageBlock' type (block image):
37
16
  *
38
- * @param {module:engine/view/element~Element} viewElement
39
- * @returns {Boolean}
40
- */
41
- export function isImageWidget( viewElement ) {
42
- return !!viewElement.getCustomProperty( 'image' ) && isWidget( viewElement );
43
- }
44
-
45
- /**
46
- * Returns an image widget editing view element if one is selected.
17
+ * <figure class="image"><img></img></figure>
18
+ *
19
+ * An 'imageInline' type (inline image):
20
+ *
21
+ * <span class="image-inline"><img></img></span>
47
22
  *
48
- * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection
49
- * @returns {module:engine/view/element~Element|null}
23
+ * Note that `alt` and `src` attributes are converted separately, so they are not included.
24
+ *
25
+ * @protected
26
+ * @param {module:engine/view/downcastwriter~DowncastWriter} writer
27
+ * @param {'imageBlock'|'imageInline'} imageType The type of created image.
28
+ * @returns {module:engine/view/containerelement~ContainerElement}
50
29
  */
51
- export function getSelectedImageWidget( selection ) {
52
- const viewElement = selection.getSelectedElement();
30
+ export function createImageViewElement( writer, imageType ) {
31
+ const emptyElement = writer.createEmptyElement( 'img' );
53
32
 
54
- if ( viewElement && isImageWidget( viewElement ) ) {
55
- return viewElement;
56
- }
33
+ const container = imageType === 'imageBlock' ?
34
+ writer.createContainerElement( 'figure', { class: 'image' } ) :
35
+ writer.createContainerElement( 'span', { class: 'image-inline' }, { isAllowedInsideAttributeElement: true } );
57
36
 
58
- return null;
59
- }
37
+ writer.insert( writer.createPositionAt( container, 0 ), emptyElement );
60
38
 
61
- /**
62
- * Checks if the provided model element is an `image`.
63
- *
64
- * @param {module:engine/model/element~Element} modelElement
65
- * @returns {Boolean}
66
- */
67
- export function isImage( modelElement ) {
68
- return !!modelElement && modelElement.is( 'element', 'image' );
39
+ return container;
69
40
  }
70
41
 
71
42
  /**
72
- * Handles inserting single file. This method unifies image insertion using {@link module:widget/utils~findOptimalInsertionPosition} method.
73
- *
74
- * insertImage( model, { src: 'path/to/image.jpg' } );
43
+ * A function returning a `MatcherPattern` for a particular type of View images.
75
44
  *
76
- * @param {module:engine/model/model~Model} model
77
- * @param {Object} [attributes={}] Attributes of inserted image
78
- * @param {module:engine/model/position~Position} [insertPosition] Position to insert the image. If not specified,
79
- * the {@link module:widget/utils~findOptimalInsertionPosition} logic will be applied.
45
+ * @protected
46
+ * @param {module:core/editor/editor~Editor} editor
47
+ * @param {'imageBlock'|'imageInline'} matchImageType The type of created image.
48
+ * @returns {module:engine/view/matcher~MatcherPattern}
80
49
  */
81
- export function insertImage( model, attributes = {}, insertPosition = null ) {
82
- model.change( writer => {
83
- const imageElement = writer.createElement( 'image', attributes );
84
-
85
- const insertAtSelection = insertPosition || findOptimalInsertionPosition( model.document.selection, model );
50
+ export function getImgViewElementMatcher( editor, matchImageType ) {
51
+ if ( editor.plugins.has( 'ImageInlineEditing' ) !== editor.plugins.has( 'ImageBlockEditing' ) ) {
52
+ return {
53
+ name: 'img',
54
+ attributes: {
55
+ src: true
56
+ }
57
+ };
58
+ }
86
59
 
87
- model.insertContent( imageElement, insertAtSelection );
60
+ const imageUtils = editor.plugins.get( 'ImageUtils' );
88
61
 
89
- // Inserting an image might've failed due to schema regulations.
90
- if ( imageElement.parent ) {
91
- writer.setSelection( imageElement, 'on' );
62
+ return element => {
63
+ // Convert only images with src attribute.
64
+ if ( !imageUtils.isInlineImageView( element ) || !element.hasAttribute( 'src' ) ) {
65
+ return null;
92
66
  }
93
- } );
94
- }
95
67
 
96
- /**
97
- * Checks if image can be inserted at current model selection.
98
- *
99
- * @param {module:engine/model/model~Model} model
100
- * @returns {Boolean}
101
- */
102
- export function isImageAllowed( model ) {
103
- const schema = model.schema;
104
- const selection = model.document.selection;
68
+ // The <img> can be standalone, wrapped in <figure>...</figure> (ImageBlock plugin) or
69
+ // wrapped in <figure><a>...</a></figure> (LinkImage plugin).
70
+ const imageType = element.findAncestor( imageUtils.isBlockImageView ) ? 'imageBlock' : 'imageInline';
71
+
72
+ if ( imageType !== matchImageType ) {
73
+ return null;
74
+ }
105
75
 
106
- return isImageAllowedInParent( selection, schema, model ) &&
107
- !checkSelectionOnObject( selection, schema ) &&
108
- isInOtherImage( selection );
76
+ return { name: true, attributes: [ 'src' ] };
77
+ };
109
78
  }
110
79
 
111
80
  /**
112
- * Get view `<img>` element from the view widget (`<figure>`).
81
+ * Considering the current model selection, it returns the name of the model image element
82
+ * (`'imageBlock'` or `'imageInline'`) that will make most sense from the UX perspective if a new
83
+ * image was inserted (also: uploaded, dropped, pasted) at that selection.
113
84
  *
114
- * Assuming that image is always a first child of a widget (ie. `figureView.getChild( 0 )`) is unsafe as other features might
115
- * inject their own elements to the widget.
85
+ * The assumption is that inserting images into empty blocks or on other block widgets should
86
+ * produce block images. Inline images should be inserted in other cases, e.g. in paragraphs
87
+ * that already contain some text.
116
88
  *
117
- * The `<img>` can be wrapped to other elements, e.g. `<a>`. Nested check required.
118
- *
119
- * @param {module:engine/view/element~Element} figureView
120
- * @returns {module:engine/view/element~Element}
89
+ * @protected
90
+ * @param {module:engine/model/schema~Schema} schema
91
+ * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection
92
+ * @returns {'imageBlock'|'imageInline'}
121
93
  */
122
- export function getViewImgFromWidget( figureView ) {
123
- const figureChildren = [];
124
-
125
- for ( const figureChild of figureView.getChildren() ) {
126
- figureChildren.push( figureChild );
94
+ export function determineImageTypeForInsertionAtSelection( schema, selection ) {
95
+ const firstBlock = first( selection.getSelectedBlocks() );
127
96
 
128
- if ( figureChild.is( 'element' ) ) {
129
- figureChildren.push( ...figureChild.getChildren() );
130
- }
97
+ // Insert a block image if the selection is not in/on block elements or it's on a block widget.
98
+ if ( !firstBlock || schema.isObject( firstBlock ) ) {
99
+ return 'imageBlock';
131
100
  }
132
101
 
133
- return figureChildren.find( viewChild => viewChild.is( 'element', 'img' ) );
134
- }
135
-
136
- // Checks if image is allowed by schema in optimal insertion parent.
137
- //
138
- // @returns {Boolean}
139
- function isImageAllowedInParent( selection, schema, model ) {
140
- const parent = getInsertImageParent( selection, model );
141
-
142
- return schema.checkChild( parent, 'image' );
143
- }
144
-
145
- // Checks if selection is placed in other image (ie. in caption).
146
- function isInOtherImage( selection ) {
147
- return [ ...selection.focus.getAncestors() ].every( ancestor => !ancestor.is( 'element', 'image' ) );
148
- }
149
-
150
- // Returns a node that will be used to insert image with `model.insertContent` to check if image can be placed there.
151
- function getInsertImageParent( selection, model ) {
152
- const insertAt = findOptimalInsertionPosition( selection, model );
153
-
154
- const parent = insertAt.parent;
155
-
156
- if ( parent.isEmpty && !parent.is( 'element', '$root' ) ) {
157
- return parent.parent;
102
+ // A block image should also be inserted into an empty block element
103
+ // (that is not an empty list item so the list won't get split).
104
+ if ( firstBlock.isEmpty && firstBlock.name != 'listItem' ) {
105
+ return 'imageBlock';
158
106
  }
159
107
 
160
- return parent;
108
+ // Otherwise insert an inline image.
109
+ return 'imageInline';
161
110
  }
package/src/image.js CHANGED
@@ -8,25 +8,23 @@
8
8
  */
9
9
 
10
10
  import { Plugin } from 'ckeditor5/src/core';
11
- import { Widget } from 'ckeditor5/src/widget';
12
11
 
13
- import ImageEditing from './image/imageediting';
14
- import ImageTextAlternative from './imagetextalternative';
15
- import { isImageWidget } from './image/utils';
12
+ import ImageBlock from './imageblock';
13
+ import ImageInline from './imageinline';
16
14
 
17
15
  import '../theme/image.css';
18
16
 
19
17
  /**
20
18
  * The image plugin.
21
19
  *
22
- * For a detailed overview, check the {@glink features/image image feature} documentation.
20
+ * For a detailed overview, check the {@glink features/images/images-overview image feature} documentation.
23
21
  *
24
22
  * This is a "glue" plugin which loads the following plugins:
25
23
  *
26
- * * {@link module:image/image/imageediting~ImageEditing},
27
- * * {@link module:image/imagetextalternative~ImageTextAlternative}.
24
+ * * {@link module:image/imageblock~ImageBlock},
25
+ * * {@link module:image/imageinline~ImageInline},
28
26
  *
29
- * Usually, it is used in conjuction with other plugins from this package. See the {@glink api/image package page}
27
+ * Usually, it is used in conjunction with other plugins from this package. See the {@glink api/image package page}
30
28
  * for more information.
31
29
  *
32
30
  * @extends module:core/plugin~Plugin
@@ -36,7 +34,7 @@ export default class Image extends Plugin {
36
34
  * @inheritDoc
37
35
  */
38
36
  static get requires() {
39
- return [ ImageEditing, Widget, ImageTextAlternative ];
37
+ return [ ImageBlock, ImageInline ];
40
38
  }
41
39
 
42
40
  /**
@@ -45,16 +43,6 @@ export default class Image extends Plugin {
45
43
  static get pluginName() {
46
44
  return 'Image';
47
45
  }
48
-
49
- /**
50
- * Checks if a given view element is an image widget.
51
- *
52
- * @param {module:engine/view/element~Element} viewElement
53
- * @returns {Boolean}
54
- */
55
- isImageWidget( viewElement ) {
56
- return isImageWidget( viewElement );
57
- }
58
46
  }
59
47
 
60
48
  /**
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ /**
7
+ * @module image/imageblock
8
+ */
9
+
10
+ import { Plugin } from 'ckeditor5/src/core';
11
+ import { Widget } from 'ckeditor5/src/widget';
12
+
13
+ import ImageTextAlternative from './imagetextalternative';
14
+ import ImageBlockEditing from './image/imageblockediting';
15
+
16
+ import '../theme/image.css';
17
+
18
+ /**
19
+ * The image inline plugin.
20
+ *
21
+ * This is a "glue" plugin which loads the following plugins:
22
+ *
23
+ * * {@link module:image/image/imageblockediting~ImageBlockEditing},
24
+ * * {@link module:image/imagetextalternative~ImageTextAlternative}.
25
+ *
26
+ * Usually, it is used in conjunction with other plugins from this package. See the {@glink api/image package page}
27
+ * for more information.
28
+ *
29
+ * @extends module:core/plugin~Plugin
30
+ */
31
+ export default class ImageBlock extends Plugin {
32
+ /**
33
+ * @inheritDoc
34
+ */
35
+ static get requires() {
36
+ return [ ImageBlockEditing, Widget, ImageTextAlternative ];
37
+ }
38
+
39
+ /**
40
+ * @inheritDoc
41
+ */
42
+ static get pluginName() {
43
+ return 'ImageBlock';
44
+ }
45
+ }
46
+