@ckeditor/ckeditor5-image 32.0.0 → 34.1.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.
@@ -82,7 +82,7 @@ export function upcastImageFigure( imageUtils ) {
82
82
  * @returns {Function}
83
83
  */
84
84
  export function upcastPicture( imageUtils ) {
85
- const sourceAttributeNames = [ 'srcset', 'media', 'type' ];
85
+ const sourceAttributeNames = [ 'srcset', 'media', 'type', 'sizes' ];
86
86
 
87
87
  return dispatcher => {
88
88
  dispatcher.on( 'element:picture', converter );
@@ -235,13 +235,11 @@ export function downcastSourcesAttribute( imageUtils ) {
235
235
 
236
236
  if ( data.attributeNewValue && data.attributeNewValue.length ) {
237
237
  // Make sure <picture> does not break attribute elements, for instance <a> in linked images.
238
- const pictureElement = viewWriter.createContainerElement( 'picture', {}, { isAllowedInsideAttributeElement: true } );
239
-
240
- for ( const sourceAttributes of data.attributeNewValue ) {
241
- const sourceElement = viewWriter.createEmptyElement( 'source', sourceAttributes );
242
-
243
- viewWriter.insert( viewWriter.createPositionAt( pictureElement, 'end' ), sourceElement );
244
- }
238
+ const pictureElement = viewWriter.createContainerElement( 'picture', null,
239
+ data.attributeNewValue.map( sourceAttributes => {
240
+ return viewWriter.createEmptyElement( 'source', sourceAttributes );
241
+ } )
242
+ );
245
243
 
246
244
  // Collect all wrapping attribute elements.
247
245
  const attributeElements = [];
@@ -22,7 +22,7 @@ import ImageTypeCommand from './imagetypecommand';
22
22
  import ImageUtils from '../imageutils';
23
23
  import {
24
24
  getImgViewElementMatcher,
25
- createImageViewElement,
25
+ createBlockImageViewElement,
26
26
  determineImageTypeForInsertionAtSelection
27
27
  } from '../image/utils';
28
28
 
@@ -62,9 +62,7 @@ export default class ImageBlockEditing extends Plugin {
62
62
 
63
63
  // Converters 'alt' and 'srcset' are added in 'ImageEditing' plugin.
64
64
  schema.register( 'imageBlock', {
65
- isObject: true,
66
- isBlock: true,
67
- allowWhere: '$block',
65
+ inheritAllFrom: '$blockObject',
68
66
  allowAttributes: [ 'alt', 'src', 'srcset' ]
69
67
  } );
70
68
 
@@ -90,16 +88,16 @@ export default class ImageBlockEditing extends Plugin {
90
88
  const imageUtils = editor.plugins.get( 'ImageUtils' );
91
89
 
92
90
  conversion.for( 'dataDowncast' )
93
- .elementToElement( {
91
+ .elementToStructure( {
94
92
  model: 'imageBlock',
95
- view: ( modelElement, { writer } ) => createImageViewElement( writer, 'imageBlock' )
93
+ view: ( modelElement, { writer } ) => createBlockImageViewElement( writer )
96
94
  } );
97
95
 
98
96
  conversion.for( 'editingDowncast' )
99
- .elementToElement( {
97
+ .elementToStructure( {
100
98
  model: 'imageBlock',
101
99
  view: ( modelElement, { writer } ) => imageUtils.toImageWidget(
102
- createImageViewElement( writer, 'imageBlock' ), writer, t( 'image widget' )
100
+ createBlockImageViewElement( writer ), writer, t( 'image widget' )
103
101
  )
104
102
  } );
105
103
 
@@ -21,7 +21,7 @@ import ImageTypeCommand from './imagetypecommand';
21
21
  import ImageUtils from '../imageutils';
22
22
  import {
23
23
  getImgViewElementMatcher,
24
- createImageViewElement,
24
+ createInlineImageViewElement,
25
25
  determineImageTypeForInsertionAtSelection
26
26
  } from '../image/utils';
27
27
 
@@ -61,10 +61,7 @@ export default class ImageInlineEditing extends Plugin {
61
61
 
62
62
  // Converters 'alt' and 'srcset' are added in 'ImageEditing' plugin.
63
63
  schema.register( 'imageInline', {
64
- isObject: true,
65
- isInline: true,
66
- allowWhere: '$text',
67
- allowAttributesOf: '$text',
64
+ inheritAllFrom: '$inlineObject',
68
65
  allowAttributes: [ 'alt', 'src', 'srcset' ]
69
66
  } );
70
67
 
@@ -105,10 +102,10 @@ export default class ImageInlineEditing extends Plugin {
105
102
  } );
106
103
 
107
104
  conversion.for( 'editingDowncast' )
108
- .elementToElement( {
105
+ .elementToStructure( {
109
106
  model: 'imageInline',
110
107
  view: ( modelElement, { writer } ) => imageUtils.toImageWidget(
111
- createImageViewElement( writer, 'imageInline' ), writer, t( 'image widget' )
108
+ createInlineImageViewElement( writer ), writer, t( 'image widget' )
112
109
  )
113
110
  } );
114
111
 
@@ -10,33 +10,38 @@
10
10
  import { first } from 'ckeditor5/src/utils';
11
11
 
12
12
  /**
13
- * Creates a view element representing the image of provided image type.
13
+ * Creates a view element representing the inline image.
14
14
  *
15
- * An 'imageBlock' type (block image):
15
+ * <span class="image-inline"><img></img></span>
16
16
  *
17
- * <figure class="image"><img></img></figure>
17
+ * Note that `alt` and `src` attributes are converted separately, so they are not included.
18
18
  *
19
- * An 'imageInline' type (inline image):
19
+ * @protected
20
+ * @param {module:engine/view/downcastwriter~DowncastWriter} writer
21
+ * @returns {module:engine/view/containerelement~ContainerElement}
22
+ */
23
+ export function createInlineImageViewElement( writer ) {
24
+ return writer.createContainerElement( 'span', { class: 'image-inline' },
25
+ writer.createEmptyElement( 'img' )
26
+ );
27
+ }
28
+
29
+ /**
30
+ * Creates a view element representing the block image.
20
31
  *
21
- * <span class="image-inline"><img></img></span>
32
+ * <figure class="image"><img></img></figure>
22
33
  *
23
34
  * Note that `alt` and `src` attributes are converted separately, so they are not included.
24
35
  *
25
36
  * @protected
26
37
  * @param {module:engine/view/downcastwriter~DowncastWriter} writer
27
- * @param {'imageBlock'|'imageInline'} imageType The type of created image.
28
38
  * @returns {module:engine/view/containerelement~ContainerElement}
29
39
  */
30
- export function createImageViewElement( writer, imageType ) {
31
- const emptyElement = writer.createEmptyElement( 'img' );
32
-
33
- const container = imageType === 'imageBlock' ?
34
- writer.createContainerElement( 'figure', { class: 'image' } ) :
35
- writer.createContainerElement( 'span', { class: 'image-inline' }, { isAllowedInsideAttributeElement: true } );
36
-
37
- writer.insert( writer.createPositionAt( container, 0 ), emptyElement );
38
-
39
- return container;
40
+ export function createBlockImageViewElement( writer ) {
41
+ return writer.createContainerElement( 'figure', { class: 'image' }, [
42
+ writer.createEmptyElement( 'img' ),
43
+ writer.createSlot()
44
+ ] );
40
45
  }
41
46
 
42
47
  /**
@@ -48,18 +53,20 @@ export function createImageViewElement( writer, imageType ) {
48
53
  * @returns {module:engine/view/matcher~MatcherPattern}
49
54
  */
50
55
  export function getImgViewElementMatcher( editor, matchImageType ) {
51
- if ( editor.plugins.has( 'ImageInlineEditing' ) !== editor.plugins.has( 'ImageBlockEditing' ) ) {
52
- return { name: 'img' };
53
- }
54
-
55
56
  const imageUtils = editor.plugins.get( 'ImageUtils' );
57
+ const areBothImagePluginsLoaded = editor.plugins.has( 'ImageInlineEditing' ) && editor.plugins.has( 'ImageBlockEditing' );
56
58
 
57
59
  return element => {
58
- // Check if view element is an `img`.
60
+ // Check if the matched view element is an <img>.
59
61
  if ( !imageUtils.isInlineImageView( element ) ) {
60
62
  return null;
61
63
  }
62
64
 
65
+ // If just one of the plugins is loaded (block or inline), it will match all kinds of images.
66
+ if ( !areBothImagePluginsLoaded ) {
67
+ return getPositiveMatchPattern( element );
68
+ }
69
+
63
70
  // The <img> can be standalone, wrapped in <figure>...</figure> (ImageBlock plugin) or
64
71
  // wrapped in <figure><a>...</a></figure> (LinkImage plugin).
65
72
  const imageType = element.findAncestor( imageUtils.isBlockImageView ) ? 'imageBlock' : 'imageInline';
@@ -68,8 +75,21 @@ export function getImgViewElementMatcher( editor, matchImageType ) {
68
75
  return null;
69
76
  }
70
77
 
71
- return { name: true };
78
+ return getPositiveMatchPattern( element );
72
79
  };
80
+
81
+ function getPositiveMatchPattern( element ) {
82
+ const pattern = {
83
+ name: true
84
+ };
85
+
86
+ // This will trigger src consumption (See https://github.com/ckeditor/ckeditor5/issues/11530).
87
+ if ( element.hasAttribute( 'src' ) ) {
88
+ pattern.attributes = [ 'src' ];
89
+ }
90
+
91
+ return pattern;
92
+ }
73
93
  }
74
94
 
75
95
  /**
@@ -14,7 +14,7 @@ import { toWidgetEditable } from 'ckeditor5/src/widget';
14
14
  import ToggleImageCaptionCommand from './toggleimagecaptioncommand';
15
15
 
16
16
  import ImageUtils from '../imageutils';
17
- import { getCaptionFromImageModelElement, matchImageCaptionViewElement } from './utils';
17
+ import ImageCaptionUtils from './imagecaptionutils';
18
18
 
19
19
  /**
20
20
  * The image caption engine plugin. It is responsible for:
@@ -30,7 +30,7 @@ export default class ImageCaptionEditing extends Plugin {
30
30
  * @inheritDoc
31
31
  */
32
32
  static get requires() {
33
- return [ ImageUtils ];
33
+ return [ ImageUtils, ImageCaptionUtils ];
34
34
  }
35
35
 
36
36
  /**
@@ -93,11 +93,12 @@ export default class ImageCaptionEditing extends Plugin {
93
93
  const editor = this.editor;
94
94
  const view = editor.editing.view;
95
95
  const imageUtils = editor.plugins.get( 'ImageUtils' );
96
+ const imageCaptionUtils = editor.plugins.get( 'ImageCaptionUtils' );
96
97
  const t = editor.t;
97
98
 
98
99
  // View -> model converter for the data pipeline.
99
100
  editor.conversion.for( 'upcast' ).elementToElement( {
100
- view: element => matchImageCaptionViewElement( imageUtils, element ),
101
+ view: element => imageCaptionUtils.matchImageCaptionViewElement( element ),
101
102
  model: 'caption'
102
103
  } );
103
104
 
@@ -134,9 +135,6 @@ export default class ImageCaptionEditing extends Plugin {
134
135
  return toWidgetEditable( figcaptionElement, writer );
135
136
  }
136
137
  } );
137
-
138
- editor.editing.mapper.on( 'modelToViewPosition', mapModelPositionToView( view ) );
139
- editor.data.mapper.on( 'modelToViewPosition', mapModelPositionToView( view ) );
140
138
  }
141
139
 
142
140
  /**
@@ -149,6 +147,7 @@ export default class ImageCaptionEditing extends Plugin {
149
147
  _setupImageTypeCommandsIntegration() {
150
148
  const editor = this.editor;
151
149
  const imageUtils = editor.plugins.get( 'ImageUtils' );
150
+ const imageCaptionUtils = editor.plugins.get( 'ImageCaptionUtils' );
152
151
  const imageTypeInlineCommand = editor.commands.get( 'imageTypeInline' );
153
152
  const imageTypeBlockCommand = editor.commands.get( 'imageTypeBlock' );
154
153
 
@@ -166,7 +165,7 @@ export default class ImageCaptionEditing extends Plugin {
166
165
  }
167
166
 
168
167
  if ( imageUtils.isBlockImage( oldElement ) ) {
169
- const oldCaptionElement = getCaptionFromImageModelElement( oldElement );
168
+ const oldCaptionElement = imageCaptionUtils.getCaptionFromImageModelElement( oldElement );
170
169
 
171
170
  // If the old element was a captioned block image (the caption was visible),
172
171
  // simply save it so it can be restored.
@@ -244,28 +243,3 @@ export default class ImageCaptionEditing extends Plugin {
244
243
  this._savedCaptionsMap.set( imageModelElement, caption.toJSON() );
245
244
  }
246
245
  }
247
-
248
- // Creates a mapper callback that reverses the order of `<img>` and `<figcaption>` in the image.
249
- // Without it, `<figcaption>` would precede the `<img>` in the conversion.
250
- //
251
- // <imageBlock>^</imageBlock> -> <figure><img>^<caption></caption></figure>
252
- //
253
- // @private
254
- // @param {module:engine/view/view~View} editingView
255
- // @returns {Function}
256
- function mapModelPositionToView( editingView ) {
257
- return ( evt, data ) => {
258
- const modelPosition = data.modelPosition;
259
- const parent = modelPosition.parent;
260
-
261
- if ( !parent.is( 'element', 'imageBlock' ) ) {
262
- return;
263
- }
264
-
265
- const viewElement = data.mapper.toViewElement( parent );
266
-
267
- // The "img" element is inserted by ImageBlockEditing during the downcast conversion via
268
- // an explicit view position so the "0" position does not need any mapping.
269
- data.viewPosition = editingView.createPositionAt( viewElement, modelPosition.offset + 1 );
270
- };
271
- }
@@ -9,9 +9,7 @@
9
9
 
10
10
  import { Plugin, icons } from 'ckeditor5/src/core';
11
11
  import { ButtonView } from 'ckeditor5/src/ui';
12
- import ImageUtils from '../imageutils';
13
-
14
- import { getCaptionFromModelSelection } from './utils';
12
+ import ImageCaptionUtils from './imagecaptionutils';
15
13
 
16
14
  /**
17
15
  * The image caption UI plugin. It introduces the `'toggleImageCaption'` UI button.
@@ -23,7 +21,7 @@ export default class ImageCaptionUI extends Plugin {
23
21
  * @inheritDoc
24
22
  */
25
23
  static get requires() {
26
- return [ ImageUtils ];
24
+ return [ ImageCaptionUtils ];
27
25
  }
28
26
 
29
27
  /**
@@ -39,7 +37,7 @@ export default class ImageCaptionUI extends Plugin {
39
37
  init() {
40
38
  const editor = this.editor;
41
39
  const editingView = editor.editing.view;
42
- const imageUtils = editor.plugins.get( 'ImageUtils' );
40
+ const imageCaptionUtils = editor.plugins.get( 'ImageCaptionUtils' );
43
41
  const t = editor.t;
44
42
 
45
43
  editor.ui.componentFactory.add( 'toggleImageCaption', locale => {
@@ -59,7 +57,7 @@ export default class ImageCaptionUI extends Plugin {
59
57
  editor.execute( 'toggleImageCaption', { focusCaptionOnShow: true } );
60
58
 
61
59
  // Scroll to the selection and highlight the caption if the caption showed up.
62
- const modelCaptionElement = getCaptionFromModelSelection( imageUtils, editor.model.document.selection );
60
+ const modelCaptionElement = imageCaptionUtils.getCaptionFromModelSelection( editor.model.document.selection );
63
61
 
64
62
  if ( modelCaptionElement ) {
65
63
  const figcaptionElement = editor.editing.mapper.toViewElement( modelCaptionElement );
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ /**
7
+ * @module image/imagecaptionutils/utils
8
+ */
9
+
10
+ import { Plugin } from 'ckeditor5/src/core';
11
+
12
+ import ImageUtils from '../imageutils';
13
+
14
+ /**
15
+ * The image caption utilities plugin.
16
+ *
17
+ * @extends module:core/plugin~Plugin
18
+ */
19
+ export default class ImageCaptionUtils extends Plugin {
20
+ /**
21
+ * @inheritDoc
22
+ */
23
+ static get pluginName() {
24
+ return 'ImageCaptionUtils';
25
+ }
26
+
27
+ /**
28
+ * @inheritDoc
29
+ */
30
+ static get requires() {
31
+ return [ ImageUtils ];
32
+ }
33
+
34
+ /**
35
+ * Returns the caption model element from a given image element. Returns `null` if no caption is found.
36
+ *
37
+ * @param {module:engine/model/element~Element} imageModelElement
38
+ * @returns {module:engine/model/element~Element|null}
39
+ */
40
+ getCaptionFromImageModelElement( imageModelElement ) {
41
+ for ( const node of imageModelElement.getChildren() ) {
42
+ if ( !!node && node.is( 'element', 'caption' ) ) {
43
+ return node;
44
+ }
45
+ }
46
+
47
+ return null;
48
+ }
49
+
50
+ /**
51
+ * Returns the caption model element for a model selection. Returns `null` if the selection has no caption element ancestor.
52
+ *
53
+ * @param {module:engine/model/selection~Selection} selection
54
+ * @returns {module:engine/model/element~Element|null}
55
+ */
56
+ getCaptionFromModelSelection( selection ) {
57
+ const imageUtils = this.editor.plugins.get( 'ImageUtils' );
58
+ const captionElement = selection.getFirstPosition().findAncestor( 'caption' );
59
+
60
+ if ( !captionElement ) {
61
+ return null;
62
+ }
63
+
64
+ if ( imageUtils.isBlockImage( captionElement.parent ) ) {
65
+ return captionElement;
66
+ }
67
+
68
+ return null;
69
+ }
70
+
71
+ /**
72
+ * {@link module:engine/view/matcher~Matcher} pattern. Checks if a given element is a `<figcaption>` element that is placed
73
+ * inside the image `<figure>` element.
74
+ *
75
+ * @param {module:engine/view/element~Element} element
76
+ * @returns {Object|null} Returns the object accepted by {@link module:engine/view/matcher~Matcher} or `null` if the element
77
+ * cannot be matched.
78
+ */
79
+ matchImageCaptionViewElement( element ) {
80
+ const imageUtils = this.editor.plugins.get( 'ImageUtils' );
81
+
82
+ // Convert only captions for images.
83
+ if ( element.name == 'figcaption' && imageUtils.isBlockImageView( element.parent ) ) {
84
+ return { name: true };
85
+ }
86
+
87
+ return null;
88
+ }
89
+ }
@@ -10,7 +10,6 @@
10
10
  import { Command } from 'ckeditor5/src/core';
11
11
 
12
12
  import ImageBlockEditing from '../image/imageblockediting';
13
- import { getCaptionFromImageModelElement, getCaptionFromModelSelection } from './utils';
14
13
 
15
14
  /**
16
15
  * The toggle image caption command.
@@ -41,7 +40,7 @@ export default class ToggleImageCaptionCommand extends Command {
41
40
  */
42
41
  refresh() {
43
42
  const editor = this.editor;
44
- const imageUtils = editor.plugins.get( 'ImageUtils' );
43
+ const imageCaptionUtils = editor.plugins.get( 'ImageCaptionUtils' );
45
44
 
46
45
  // Only block images can get captions.
47
46
  if ( !editor.plugins.has( ImageBlockEditing ) ) {
@@ -55,7 +54,7 @@ export default class ToggleImageCaptionCommand extends Command {
55
54
  const selectedElement = selection.getSelectedElement();
56
55
 
57
56
  if ( !selectedElement ) {
58
- const ancestorCaptionElement = getCaptionFromModelSelection( imageUtils, selection );
57
+ const ancestorCaptionElement = imageCaptionUtils.getCaptionFromModelSelection( selection );
59
58
 
60
59
  this.isEnabled = !!ancestorCaptionElement;
61
60
  this.value = !!ancestorCaptionElement;
@@ -70,7 +69,7 @@ export default class ToggleImageCaptionCommand extends Command {
70
69
  if ( !this.isEnabled ) {
71
70
  this.value = false;
72
71
  } else {
73
- this.value = !!getCaptionFromImageModelElement( selectedElement );
72
+ this.value = !!imageCaptionUtils.getCaptionFromImageModelElement( selectedElement );
74
73
  }
75
74
  }
76
75
 
@@ -145,14 +144,14 @@ export default class ToggleImageCaptionCommand extends Command {
145
144
  const editor = this.editor;
146
145
  const selection = editor.model.document.selection;
147
146
  const imageCaptionEditing = editor.plugins.get( 'ImageCaptionEditing' );
148
- const imageUtils = editor.plugins.get( 'ImageUtils' );
147
+ const imageCaptionUtils = editor.plugins.get( 'ImageCaptionUtils' );
149
148
  let selectedImage = selection.getSelectedElement();
150
149
  let captionElement;
151
150
 
152
151
  if ( selectedImage ) {
153
- captionElement = getCaptionFromImageModelElement( selectedImage );
152
+ captionElement = imageCaptionUtils.getCaptionFromImageModelElement( selectedImage );
154
153
  } else {
155
- captionElement = getCaptionFromModelSelection( imageUtils, selection );
154
+ captionElement = imageCaptionUtils.getCaptionFromModelSelection( selection );
156
155
  selectedImage = captionElement.parent;
157
156
  }
158
157
 
@@ -40,75 +40,91 @@ const {
40
40
  */
41
41
  const DEFAULT_OPTIONS = {
42
42
  // This style represents an image placed in the line of text.
43
- inline: {
44
- name: 'inline',
45
- title: 'In line',
46
- icon: objectInline,
47
- modelElements: [ 'imageInline' ],
48
- isDefault: true
43
+ get inline() {
44
+ return {
45
+ name: 'inline',
46
+ title: 'In line',
47
+ icon: objectInline,
48
+ modelElements: [ 'imageInline' ],
49
+ isDefault: true
50
+ };
49
51
  },
50
52
 
51
53
  // This style represents an image aligned to the left and wrapped with text.
52
- alignLeft: {
53
- name: 'alignLeft',
54
- title: 'Left aligned image',
55
- icon: objectLeft,
56
- modelElements: [ 'imageBlock', 'imageInline' ],
57
- className: 'image-style-align-left'
54
+ get alignLeft() {
55
+ return {
56
+ name: 'alignLeft',
57
+ title: 'Left aligned image',
58
+ icon: objectLeft,
59
+ modelElements: [ 'imageBlock', 'imageInline' ],
60
+ className: 'image-style-align-left'
61
+ };
58
62
  },
59
63
 
60
64
  // This style represents an image aligned to the left.
61
- alignBlockLeft: {
62
- name: 'alignBlockLeft',
63
- title: 'Left aligned image',
64
- icon: objectBlockLeft,
65
- modelElements: [ 'imageBlock' ],
66
- className: 'image-style-block-align-left'
65
+ get alignBlockLeft() {
66
+ return {
67
+ name: 'alignBlockLeft',
68
+ title: 'Left aligned image',
69
+ icon: objectBlockLeft,
70
+ modelElements: [ 'imageBlock' ],
71
+ className: 'image-style-block-align-left'
72
+ };
67
73
  },
68
74
 
69
75
  // This style represents a centered image.
70
- alignCenter: {
71
- name: 'alignCenter',
72
- title: 'Centered image',
73
- icon: objectCenter,
74
- modelElements: [ 'imageBlock' ],
75
- className: 'image-style-align-center'
76
+ get alignCenter() {
77
+ return {
78
+ name: 'alignCenter',
79
+ title: 'Centered image',
80
+ icon: objectCenter,
81
+ modelElements: [ 'imageBlock' ],
82
+ className: 'image-style-align-center'
83
+ };
76
84
  },
77
85
 
78
86
  // This style represents an image aligned to the right and wrapped with text.
79
- alignRight: {
80
- name: 'alignRight',
81
- title: 'Right aligned image',
82
- icon: objectRight,
83
- modelElements: [ 'imageBlock', 'imageInline' ],
84
- className: 'image-style-align-right'
87
+ get alignRight() {
88
+ return {
89
+ name: 'alignRight',
90
+ title: 'Right aligned image',
91
+ icon: objectRight,
92
+ modelElements: [ 'imageBlock', 'imageInline' ],
93
+ className: 'image-style-align-right'
94
+ };
85
95
  },
86
96
 
87
97
  // This style represents an image aligned to the right.
88
- alignBlockRight: {
89
- name: 'alignBlockRight',
90
- title: 'Right aligned image',
91
- icon: objectBlockRight,
92
- modelElements: [ 'imageBlock' ],
93
- className: 'image-style-block-align-right'
98
+ get alignBlockRight() {
99
+ return {
100
+ name: 'alignBlockRight',
101
+ title: 'Right aligned image',
102
+ icon: objectBlockRight,
103
+ modelElements: [ 'imageBlock' ],
104
+ className: 'image-style-block-align-right'
105
+ };
94
106
  },
95
107
 
96
108
  // This option is equal to the situation when no style is applied.
97
- block: {
98
- name: 'block',
99
- title: 'Centered image',
100
- icon: objectCenter,
101
- modelElements: [ 'imageBlock' ],
102
- isDefault: true
109
+ get block() {
110
+ return {
111
+ name: 'block',
112
+ title: 'Centered image',
113
+ icon: objectCenter,
114
+ modelElements: [ 'imageBlock' ],
115
+ isDefault: true
116
+ };
103
117
  },
104
118
 
105
119
  // This represents a side image.
106
- side: {
107
- name: 'side',
108
- title: 'Side image',
109
- icon: objectRight,
110
- modelElements: [ 'imageBlock' ],
111
- className: 'image-style-side'
120
+ get side() {
121
+ return {
122
+ name: 'side',
123
+ title: 'Side image',
124
+ icon: objectRight,
125
+ modelElements: [ 'imageBlock' ],
126
+ className: 'image-style-side'
127
+ };
112
128
  }
113
129
  };
114
130
 
package/src/imageutils.js CHANGED
@@ -103,18 +103,15 @@ export default class ImageUtils extends Plugin {
103
103
  return model.change( writer => {
104
104
  const imageElement = writer.createElement( imageType, attributes );
105
105
 
106
- // If we want to insert a block image (for whatever reason) then we don't want to split text blocks.
107
- // This applies only when we don't have the selectable specified (i.e., we insert multiple block images at once).
108
- if ( !selectable && imageType != 'imageInline' ) {
109
- selectable = findOptimalInsertionRange( selection, model );
110
- }
111
-
112
- model.insertContent( imageElement, selectable );
106
+ model.insertObject( imageElement, selectable, null, {
107
+ setSelection: 'on',
108
+ // If we want to insert a block image (for whatever reason) then we don't want to split text blocks.
109
+ // This applies only when we don't have the selectable specified (i.e., we insert multiple block images at once).
110
+ findOptimalPosition: !selectable && imageType != 'imageInline'
111
+ } );
113
112
 
114
113
  // Inserting an image might've failed due to schema regulations.
115
114
  if ( imageElement.parent ) {
116
- writer.setSelection( imageElement, 'on' );
117
-
118
115
  return imageElement;
119
116
  }
120
117
 
package/src/index.js CHANGED
@@ -10,6 +10,7 @@
10
10
  export { default as AutoImage } from './autoimage';
11
11
  export { default as Image } from './image';
12
12
  export { default as ImageEditing } from './image/imageediting';
13
+ export { default as ImageCaptionUtils } from './imagecaption/imagecaptionutils';
13
14
  export { default as ImageCaption } from './imagecaption';
14
15
  export { default as ImageCaptionEditing } from './imagecaption/imagecaptionediting';
15
16
  export { default as ImageInsert } from './imageinsert';
@@ -29,3 +30,4 @@ export { default as ImageUpload } from './imageupload';
29
30
  export { default as ImageUploadEditing } from './imageupload/imageuploadediting';
30
31
  export { default as ImageUploadProgress } from './imageupload/imageuploadprogress';
31
32
  export { default as ImageUploadUI } from './imageupload/imageuploadui';
33
+ export { default as PictureEditing } from './pictureediting';