@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
@@ -12,8 +12,8 @@ import { first } from 'ckeditor5/src/utils';
12
12
  /**
13
13
  * Returns a converter for the `imageStyle` attribute. It can be used for adding, changing and removing the attribute.
14
14
  *
15
- * @param {Object} styles An object containing available styles. See {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat}
16
- * for more details.
15
+ * @param {Array.<module:image/imagestyle~ImageStyleOptionDefinition>} styles
16
+ * An array containing available image style options.
17
17
  * @returns {Function} A model-to-view attribute converter.
18
18
  */
19
19
  export function modelToViewStyleAttribute( styles ) {
@@ -23,8 +23,8 @@ export function modelToViewStyleAttribute( styles ) {
23
23
  }
24
24
 
25
25
  // Check if there is class name associated with given value.
26
- const newStyle = getStyleByName( data.attributeNewValue, styles );
27
- const oldStyle = getStyleByName( data.attributeOldValue, styles );
26
+ const newStyle = getStyleDefinitionByName( data.attributeNewValue, styles );
27
+ const oldStyle = getStyleDefinitionByName( data.attributeOldValue, styles );
28
28
 
29
29
  const viewElement = conversionApi.mapper.toViewElement( data.item );
30
30
  const viewWriter = conversionApi.writer;
@@ -42,31 +42,39 @@ export function modelToViewStyleAttribute( styles ) {
42
42
  /**
43
43
  * Returns a view-to-model converter converting image CSS classes to a proper value in the model.
44
44
  *
45
- * @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} styles The styles for which the converter is created.
45
+ * @param {Array.<module:image/imagestyle~ImageStyleOptionDefinition>} styles
46
+ * Image style options for which the converter is created.
46
47
  * @returns {Function} A view-to-model converter.
47
48
  */
48
49
  export function viewToModelStyleAttribute( styles ) {
49
50
  // Convert only non–default styles.
50
- const filteredStyles = styles.filter( style => !style.isDefault );
51
+ const nonDefaultStyles = {
52
+ imageInline: styles.filter( style => !style.isDefault && style.modelElements.includes( 'imageInline' ) ),
53
+ imageBlock: styles.filter( style => !style.isDefault && style.modelElements.includes( 'imageBlock' ) )
54
+ };
51
55
 
52
56
  return ( evt, data, conversionApi ) => {
53
57
  if ( !data.modelRange ) {
54
58
  return;
55
59
  }
56
60
 
57
- const viewFigureElement = data.viewItem;
61
+ const viewElement = data.viewItem;
58
62
  const modelImageElement = first( data.modelRange.getItems() );
59
63
 
60
- // Check if `modelImageElement` exists (see: https://github.com/ckeditor/ckeditor5/issues/8270)
61
- // and `imageStyle` attribute is allowed for that element, otherwise stop conversion early.
62
- if ( modelImageElement && !conversionApi.schema.checkAttribute( modelImageElement, 'imageStyle' ) ) {
64
+ // Check if `modelImageElement` exists (see: #8270, and #9563)...
65
+ if ( !modelImageElement ) {
66
+ return;
67
+ }
68
+
69
+ // ...and the `imageStyle` attribute is allowed for that element, otherwise stop conversion early.
70
+ if ( !conversionApi.schema.checkAttribute( modelImageElement, 'imageStyle' ) ) {
63
71
  return;
64
72
  }
65
73
 
66
- // Convert style one by one.
67
- for ( const style of filteredStyles ) {
68
- // Try to consume class corresponding with style.
69
- if ( conversionApi.consumable.consume( viewFigureElement, { classes: style.className } ) ) {
74
+ // Convert styles one by one.
75
+ for ( const style of nonDefaultStyles[ modelImageElement.name ] ) {
76
+ // Try to consume class corresponding with the style.
77
+ if ( conversionApi.consumable.consume( viewElement, { classes: style.className } ) ) {
70
78
  // And convert this style to model attribute.
71
79
  conversionApi.writer.setAttribute( 'imageStyle', style.name, modelImageElement );
72
80
  }
@@ -77,9 +85,9 @@ export function viewToModelStyleAttribute( styles ) {
77
85
  // Returns the style with a given `name` from an array of styles.
78
86
  //
79
87
  // @param {String} name
80
- // @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat> } styles
81
- // @returns {module:image/imagestyle/imagestyleediting~ImageStyleFormat|undefined}
82
- function getStyleByName( name, styles ) {
88
+ // @param {Array.<module:image/imagestyle~ImageStyleOptionDefinition> } styles
89
+ // @returns {module:image/imagestyle~ImageStyleOptionDefinition|undefined}
90
+ function getStyleDefinitionByName( name, styles ) {
83
91
  for ( const style of styles ) {
84
92
  if ( style.name === name ) {
85
93
  return style;
@@ -8,90 +8,130 @@
8
8
  */
9
9
 
10
10
  import { Command } from 'ckeditor5/src/core';
11
- import { isImage } from '../image/utils';
12
11
 
13
12
  /**
14
- * The image style command. It is used to apply different image styles.
13
+ * The image style command. It is used to apply {@link module:image/imagestyle~ImageStyleConfig#options image style option}
14
+ * to a selected image.
15
+ *
16
+ * **Note**: Executing this command may change the image model element if the desired style requires an image of a different
17
+ * type. See {@link module:image/imagestyle/imagestylecommand~ImageStyleCommand#execute} to learn more.
15
18
  *
16
19
  * @extends module:core/command~Command
17
20
  */
18
21
  export default class ImageStyleCommand extends Command {
19
22
  /**
20
- * Creates an instance of the image style command. Each command instance is handling one style.
23
+ * Creates an instance of the image style command. When executed, the command applies one of
24
+ * {@link module:image/imagestyle~ImageStyleConfig#options style options} to the currently selected image.
21
25
  *
22
26
  * @param {module:core/editor/editor~Editor} editor The editor instance.
23
- * @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} styles The styles that this command supports.
27
+ * @param {Array.<module:image/imagestyle~ImageStyleOptionDefinition>} styles
28
+ * The style options that this command supports.
24
29
  */
25
30
  constructor( editor, styles ) {
26
31
  super( editor );
27
32
 
28
33
  /**
29
- * The name of the default style, if it is present. If there is no default style, it defaults to `false`.
34
+ * An object containing names of default style options for the inline and block images.
35
+ * If there is no default style option for the given image type in the configuration,
36
+ * the name will be `false`.
30
37
  *
31
- * @readonly
32
- * @type {Boolean|String}
38
+ * @private
39
+ * @type {Object.<String,module:image/imagestyle~ImageStyleOptionDefinition#name>}
33
40
  */
34
- this.defaultStyle = false;
41
+ this._defaultStyles = {
42
+ imageBlock: false,
43
+ imageInline: false
44
+ };
35
45
 
36
46
  /**
37
- * A style handled by this command.
47
+ * The styles handled by this command.
38
48
  *
39
- * @readonly
40
- * @member {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} #styles
49
+ * @private
50
+ * @type {module:image/imagestyle~ImageStyleConfig#options}
41
51
  */
42
- this.styles = styles.reduce( ( styles, style ) => {
43
- styles[ style.name ] = style;
44
-
52
+ this._styles = new Map( styles.map( style => {
45
53
  if ( style.isDefault ) {
46
- this.defaultStyle = style.name;
54
+ for ( const modelElementName of style.modelElements ) {
55
+ this._defaultStyles[ modelElementName ] = style.name;
56
+ }
47
57
  }
48
58
 
49
- return styles;
50
- }, {} );
59
+ return [ style.name, style ];
60
+ } ) );
51
61
  }
52
62
 
53
63
  /**
54
64
  * @inheritDoc
55
65
  */
56
66
  refresh() {
57
- const element = this.editor.model.document.selection.getSelectedElement();
67
+ const editor = this.editor;
68
+ const imageUtils = editor.plugins.get( 'ImageUtils' );
69
+ const element = imageUtils.getClosestSelectedImageElement( this.editor.model.document.selection );
58
70
 
59
- this.isEnabled = isImage( element );
71
+ this.isEnabled = !!element;
60
72
 
61
- if ( !element ) {
73
+ if ( !this.isEnabled ) {
62
74
  this.value = false;
63
75
  } else if ( element.hasAttribute( 'imageStyle' ) ) {
64
- const attributeValue = element.getAttribute( 'imageStyle' );
65
- this.value = this.styles[ attributeValue ] ? attributeValue : false;
76
+ this.value = element.getAttribute( 'imageStyle' );
66
77
  } else {
67
- this.value = this.defaultStyle;
78
+ this.value = this._defaultStyles[ element.name ];
68
79
  }
69
80
  }
70
81
 
71
82
  /**
72
- * Executes the command.
83
+ * Executes the command and applies the style to the currently selected image:
73
84
  *
74
85
  * editor.execute( 'imageStyle', { value: 'side' } );
75
86
  *
87
+ * **Note**: Executing this command may change the image model element if the desired style requires an image
88
+ * of a different type. Learn more about {@link module:image/imagestyle~ImageStyleOptionDefinition#modelElements model element}
89
+ * configuration for the style option.
90
+ *
76
91
  * @param {Object} options
77
- * @param {String} options.value The name of the style (based on the
78
- * {@link module:image/image~ImageConfig#styles `image.styles`} configuration option).
92
+ * @param {module:image/imagestyle~ImageStyleOptionDefinition#name} options.value The name of the style (as configured in
93
+ * {@link module:image/imagestyle~ImageStyleConfig#options}).
79
94
  * @fires execute
80
95
  */
81
- execute( options ) {
82
- const styleName = options.value;
83
-
84
- const model = this.editor.model;
85
- const imageElement = model.document.selection.getSelectedElement();
96
+ execute( options = {} ) {
97
+ const editor = this.editor;
98
+ const model = editor.model;
99
+ const imageUtils = editor.plugins.get( 'ImageUtils' );
86
100
 
87
101
  model.change( writer => {
102
+ const requestedStyle = options.value;
103
+
104
+ let imageElement = imageUtils.getClosestSelectedImageElement( model.document.selection );
105
+
106
+ // Change the image type if a style requires it.
107
+ if ( requestedStyle && this.shouldConvertImageType( requestedStyle, imageElement ) ) {
108
+ this.editor.execute( imageUtils.isBlockImage( imageElement ) ? 'imageTypeInline' : 'imageTypeBlock' );
109
+
110
+ // Update the imageElement to the newly created image.
111
+ imageElement = imageUtils.getClosestSelectedImageElement( model.document.selection );
112
+ }
113
+
88
114
  // Default style means that there is no `imageStyle` attribute in the model.
89
115
  // https://github.com/ckeditor/ckeditor5-image/issues/147
90
- if ( this.styles[ styleName ].isDefault ) {
116
+ if ( !requestedStyle || this._styles.get( requestedStyle ).isDefault ) {
91
117
  writer.removeAttribute( 'imageStyle', imageElement );
92
118
  } else {
93
- writer.setAttribute( 'imageStyle', styleName, imageElement );
119
+ writer.setAttribute( 'imageStyle', requestedStyle, imageElement );
94
120
  }
95
121
  } );
96
122
  }
123
+
124
+ /**
125
+ * Returns `true` if requested style change would trigger the image type change.
126
+ *
127
+ * @param {module:image/imagestyle~ImageStyleOptionDefinition} requestedStyle The name of the style (as configured in
128
+ * {@link module:image/imagestyle~ImageStyleConfig#options}).
129
+ * @param {module:engine/model/element~Element} imageElement The image model element.
130
+ * @returns {Boolean}
131
+ */
132
+ shouldConvertImageType( requestedStyle, imageElement ) {
133
+ const supportedTypes = this._styles.get( requestedStyle ).modelElements;
134
+
135
+ return !supportedTypes.includes( imageElement.name );
136
+ }
97
137
  }
@@ -9,8 +9,9 @@
9
9
 
10
10
  import { Plugin } from 'ckeditor5/src/core';
11
11
  import ImageStyleCommand from './imagestylecommand';
12
+ import ImageUtils from '../imageutils';
13
+ import utils from './utils';
12
14
  import { viewToModelStyleAttribute, modelToViewStyleAttribute } from './converters';
13
- import { normalizeImageStyles } from './utils';
14
15
 
15
16
  /**
16
17
  * The image style engine plugin. It sets the default configuration, creates converters and registers
@@ -26,69 +27,129 @@ export default class ImageStyleEditing extends Plugin {
26
27
  return 'ImageStyleEditing';
27
28
  }
28
29
 
30
+ /**
31
+ * @inheritDoc
32
+ */
33
+ static get requires() {
34
+ return [ ImageUtils ];
35
+ }
36
+
29
37
  /**
30
38
  * @inheritDoc
31
39
  */
32
40
  init() {
41
+ const { normalizeStyles, getDefaultStylesConfiguration } = utils;
42
+ const editor = this.editor;
43
+ const isBlockPluginLoaded = editor.plugins.has( 'ImageBlockEditing' );
44
+ const isInlinePluginLoaded = editor.plugins.has( 'ImageInlineEditing' );
45
+
46
+ editor.config.define( 'image.styles', getDefaultStylesConfiguration( isBlockPluginLoaded, isInlinePluginLoaded ) );
47
+
48
+ /**
49
+ * It contains a list of the normalized and validated style options.
50
+ *
51
+ * * Each option contains a complete icon markup.
52
+ * * The style options not supported by any of the loaded image editing plugins (
53
+ * {@link module:image/image/imageinlineediting~ImageInlineEditing `ImageInlineEditing`} or
54
+ * {@link module:image/image/imageblockediting~ImageBlockEditing `ImageBlockEditing`}) are filtered out.
55
+ *
56
+ * @protected
57
+ * @readonly
58
+ * @type {module:image/imagestyle~ImageStyleConfig}
59
+ */
60
+ this.normalizedStyles = normalizeStyles( {
61
+ configuredStyles: editor.config.get( 'image.styles' ),
62
+ isBlockPluginLoaded,
63
+ isInlinePluginLoaded
64
+ } );
65
+
66
+ this._setupConversion( isBlockPluginLoaded, isInlinePluginLoaded );
67
+ this._setupPostFixer();
68
+
69
+ // Register imageStyle command.
70
+ editor.commands.add( 'imageStyle', new ImageStyleCommand( editor, this.normalizedStyles ) );
71
+ }
72
+
73
+ /**
74
+ * Sets the editor conversion taking the presence of
75
+ * {@link module:image/image/imageinlineediting~ImageInlineEditing `ImageInlineEditing`}
76
+ * and {@link module:image/image/imageblockediting~ImageBlockEditing `ImageBlockEditing`} plugins into consideration.
77
+ *
78
+ * @private
79
+ * @param {Boolean} isBlockPluginLoaded
80
+ * @param {Boolean} isInlinePluginLoaded
81
+ */
82
+ _setupConversion( isBlockPluginLoaded, isInlinePluginLoaded ) {
33
83
  const editor = this.editor;
34
84
  const schema = editor.model.schema;
35
- const data = editor.data;
36
- const editing = editor.editing;
37
85
 
38
- // Define default configuration.
39
- editor.config.define( 'image.styles', [ 'full', 'side' ] );
86
+ const modelToViewConverter = modelToViewStyleAttribute( this.normalizedStyles );
87
+ const viewToModelConverter = viewToModelStyleAttribute( this.normalizedStyles );
40
88
 
41
- // Get configuration.
42
- const styles = normalizeImageStyles( editor.config.get( 'image.styles' ) );
89
+ editor.editing.downcastDispatcher.on( 'attribute:imageStyle', modelToViewConverter );
90
+ editor.data.downcastDispatcher.on( 'attribute:imageStyle', modelToViewConverter );
43
91
 
44
- // Allow imageStyle attribute in image.
92
+ // Allow imageStyle attribute in image and imageInline.
45
93
  // We could call it 'style' but https://github.com/ckeditor/ckeditor5-engine/issues/559.
46
- schema.extend( 'image', { allowAttributes: 'imageStyle' } );
94
+ if ( isBlockPluginLoaded ) {
95
+ schema.extend( 'imageBlock', { allowAttributes: 'imageStyle' } );
47
96
 
48
- // Converters for imageStyle attribute from model to view.
49
- const modelToViewConverter = modelToViewStyleAttribute( styles );
50
- editing.downcastDispatcher.on( 'attribute:imageStyle:image', modelToViewConverter );
51
- data.downcastDispatcher.on( 'attribute:imageStyle:image', modelToViewConverter );
97
+ // Converter for figure element from view to model.
98
+ editor.data.upcastDispatcher.on( 'element:figure', viewToModelConverter, { priority: 'low' } );
99
+ }
52
100
 
53
- // Converter for figure element from view to model.
54
- data.upcastDispatcher.on( 'element:figure', viewToModelStyleAttribute( styles ), { priority: 'low' } );
101
+ if ( isInlinePluginLoaded ) {
102
+ schema.extend( 'imageInline', { allowAttributes: 'imageStyle' } );
55
103
 
56
- // Register imageStyle command.
57
- editor.commands.add( 'imageStyle', new ImageStyleCommand( editor, styles ) );
104
+ // Converter for the img element from view to model.
105
+ editor.data.upcastDispatcher.on( 'element:img', viewToModelConverter, { priority: 'low' } );
106
+ }
58
107
  }
59
- }
60
108
 
61
- /**
62
- * The image style format descriptor.
63
- *
64
- * import fullSizeIcon from 'path/to/icon.svg';
65
- *
66
- * const imageStyleFormat = {
67
- * name: 'fullSize',
68
- * icon: fullSizeIcon,
69
- * title: 'Full size image',
70
- * className: 'image-full-size'
71
- * }
72
- *
73
- * @typedef {Object} module:image/imagestyle/imagestyleediting~ImageStyleFormat
74
- *
75
- * @property {String} name The unique name of the style. It will be used to:
76
- *
77
- * * Store the chosen style in the model by setting the `imageStyle` attribute of the `<image>` element.
78
- * * As a value of the {@link module:image/imagestyle/imagestylecommand~ImageStyleCommand#execute `imageStyle` command},
79
- * * when registering a button for each of the styles (`'imageStyle:{name}'`) in the
80
- * {@link module:ui/componentfactory~ComponentFactory UI components factory} (this functionality is provided by the
81
- * {@link module:image/imagestyle/imagestyleui~ImageStyleUI} plugin).
82
- *
83
- * @property {Boolean} [isDefault] When set, the style will be used as the default one.
84
- * A default style does not apply any CSS class to the view element.
85
- *
86
- * @property {String} icon One of the following to be used when creating the style's button:
87
- *
88
- * * An SVG icon source (as an XML string).
89
- * * One of {@link module:image/imagestyle/utils~defaultIcons} to use a default icon provided by the plugin.
90
- *
91
- * @property {String} title The style's title.
92
- *
93
- * @property {String} className The CSS class used to represent the style in the view.
94
- */
109
+ /**
110
+ * Registers a post-fixer that will make sure that the style attribute value is correct for a specific image type (block vs inline).
111
+ *
112
+ * @private
113
+ */
114
+ _setupPostFixer() {
115
+ const editor = this.editor;
116
+ const document = editor.model.document;
117
+
118
+ const imageUtils = editor.plugins.get( ImageUtils );
119
+ const stylesMap = new Map( this.normalizedStyles.map( style => [ style.name, style ] ) );
120
+
121
+ // Make sure that style attribute is valid for the image type.
122
+ document.registerPostFixer( writer => {
123
+ let changed = false;
124
+
125
+ for ( const change of document.differ.getChanges() ) {
126
+ if ( change.type == 'insert' || change.type == 'attribute' && change.attributeKey == 'imageStyle' ) {
127
+ let element = change.type == 'insert' ? change.position.nodeAfter : change.range.start.nodeAfter;
128
+
129
+ if ( element && element.is( 'element', 'paragraph' ) && element.childCount > 0 ) {
130
+ element = element.getChild( 0 );
131
+ }
132
+
133
+ if ( !imageUtils.isImage( element ) ) {
134
+ continue;
135
+ }
136
+
137
+ const imageStyle = element.getAttribute( 'imageStyle' );
138
+
139
+ if ( !imageStyle ) {
140
+ continue;
141
+ }
142
+
143
+ const imageStyleDefinition = stylesMap.get( imageStyle );
144
+
145
+ if ( !imageStyleDefinition || !imageStyleDefinition.modelElements.includes( element.name ) ) {
146
+ writer.removeAttribute( 'imageStyle', element );
147
+ changed = true;
148
+ }
149
+ }
150
+ }
151
+
152
+ return changed;
153
+ } );
154
+ }
155
+ }