@ckeditor/ckeditor5-link 36.0.1 → 37.0.0-alpha.1

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.
@@ -2,297 +2,244 @@
2
2
  * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
5
  /**
7
6
  * @module link/linkimageediting
8
7
  */
9
-
10
8
  import { Plugin } from 'ckeditor5/src/core';
11
9
  import { Matcher } from 'ckeditor5/src/engine';
12
10
  import { toMap } from 'ckeditor5/src/utils';
13
-
14
11
  import LinkEditing from './linkediting';
15
-
16
12
  /**
17
13
  * The link image engine feature.
18
14
  *
19
15
  * It accepts the `linkHref="url"` attribute in the model for the {@link module:image/image~Image `<imageBlock>`} element
20
16
  * which allows linking images.
21
- *
22
- * @extends module:core/plugin~Plugin
23
17
  */
24
18
  export default class LinkImageEditing extends Plugin {
25
- /**
26
- * @inheritDoc
27
- */
28
- static get requires() {
29
- return [ 'ImageEditing', 'ImageUtils', LinkEditing ];
30
- }
31
-
32
- /**
33
- * @inheritDoc
34
- */
35
- static get pluginName() {
36
- return 'LinkImageEditing';
37
- }
38
-
39
- init() {
40
- const editor = this.editor;
41
- const schema = editor.model.schema;
42
-
43
- if ( editor.plugins.has( 'ImageBlockEditing' ) ) {
44
- schema.extend( 'imageBlock', { allowAttributes: [ 'linkHref' ] } );
45
- }
46
-
47
- editor.conversion.for( 'upcast' ).add( upcastLink( editor ) );
48
- editor.conversion.for( 'downcast' ).add( downcastImageLink( editor ) );
49
-
50
- // Definitions for decorators are provided by the `link` command and the `LinkEditing` plugin.
51
- this._enableAutomaticDecorators();
52
- this._enableManualDecorators();
53
- }
54
-
55
- /**
56
- * Processes {@link module:link/link~LinkDecoratorAutomaticDefinition automatic decorators} definitions and
57
- * attaches proper converters that will work when linking an image.`
58
- *
59
- * @private
60
- */
61
- _enableAutomaticDecorators() {
62
- const editor = this.editor;
63
- const command = editor.commands.get( 'link' );
64
- const automaticDecorators = command.automaticDecorators;
65
-
66
- if ( automaticDecorators.length ) {
67
- editor.conversion.for( 'downcast' ).add( automaticDecorators.getDispatcherForLinkedImage() );
68
- }
69
- }
70
-
71
- /**
72
- * Processes transformed {@link module:link/utils~ManualDecorator} instances and attaches proper converters
73
- * that will work when linking an image.
74
- *
75
- * @private
76
- */
77
- _enableManualDecorators() {
78
- const editor = this.editor;
79
- const command = editor.commands.get( 'link' );
80
-
81
- for ( const decorator of command.manualDecorators ) {
82
- if ( editor.plugins.has( 'ImageBlockEditing' ) ) {
83
- editor.model.schema.extend( 'imageBlock', { allowAttributes: decorator.id } );
84
- }
85
-
86
- if ( editor.plugins.has( 'ImageInlineEditing' ) ) {
87
- editor.model.schema.extend( 'imageInline', { allowAttributes: decorator.id } );
88
- }
89
-
90
- editor.conversion.for( 'downcast' ).add( downcastImageLinkManualDecorator( decorator ) );
91
- editor.conversion.for( 'upcast' ).add( upcastImageLinkManualDecorator( editor, decorator ) );
92
- }
93
- }
19
+ /**
20
+ * @inheritDoc
21
+ */
22
+ static get requires() {
23
+ return ['ImageEditing', 'ImageUtils', LinkEditing];
24
+ }
25
+ /**
26
+ * @inheritDoc
27
+ */
28
+ static get pluginName() {
29
+ return 'LinkImageEditing';
30
+ }
31
+ /**
32
+ * @inheritDoc
33
+ */
34
+ init() {
35
+ const editor = this.editor;
36
+ const schema = editor.model.schema;
37
+ if (editor.plugins.has('ImageBlockEditing')) {
38
+ schema.extend('imageBlock', { allowAttributes: ['linkHref'] });
39
+ }
40
+ editor.conversion.for('upcast').add(upcastLink(editor));
41
+ editor.conversion.for('downcast').add(downcastImageLink(editor));
42
+ // Definitions for decorators are provided by the `link` command and the `LinkEditing` plugin.
43
+ this._enableAutomaticDecorators();
44
+ this._enableManualDecorators();
45
+ }
46
+ /**
47
+ * Processes {@link module:link/linkconfig~LinkDecoratorAutomaticDefinition automatic decorators} definitions and
48
+ * attaches proper converters that will work when linking an image.`
49
+ */
50
+ _enableAutomaticDecorators() {
51
+ const editor = this.editor;
52
+ const command = editor.commands.get('link');
53
+ const automaticDecorators = command.automaticDecorators;
54
+ if (automaticDecorators.length) {
55
+ editor.conversion.for('downcast').add(automaticDecorators.getDispatcherForLinkedImage());
56
+ }
57
+ }
58
+ /**
59
+ * Processes transformed {@link module:link/utils/manualdecorator~ManualDecorator} instances and attaches proper converters
60
+ * that will work when linking an image.
61
+ */
62
+ _enableManualDecorators() {
63
+ const editor = this.editor;
64
+ const command = editor.commands.get('link');
65
+ for (const decorator of command.manualDecorators) {
66
+ if (editor.plugins.has('ImageBlockEditing')) {
67
+ editor.model.schema.extend('imageBlock', { allowAttributes: decorator.id });
68
+ }
69
+ if (editor.plugins.has('ImageInlineEditing')) {
70
+ editor.model.schema.extend('imageInline', { allowAttributes: decorator.id });
71
+ }
72
+ editor.conversion.for('downcast').add(downcastImageLinkManualDecorator(decorator));
73
+ editor.conversion.for('upcast').add(upcastImageLinkManualDecorator(editor, decorator));
74
+ }
75
+ }
94
76
  }
95
-
96
- // Returns a converter for linked block images that consumes the "href" attribute
97
- // if a link contains an image.
98
- //
99
- // @private
100
- // @param {module:core/editor/editor~Editor} editor The editor instance.
101
- // @returns {Function}
102
- function upcastLink( editor ) {
103
- const isImageInlinePluginLoaded = editor.plugins.has( 'ImageInlineEditing' );
104
- const imageUtils = editor.plugins.get( 'ImageUtils' );
105
-
106
- return dispatcher => {
107
- dispatcher.on( 'element:a', ( evt, data, conversionApi ) => {
108
- const viewLink = data.viewItem;
109
- const imageInLink = imageUtils.findViewImgElement( viewLink );
110
-
111
- if ( !imageInLink ) {
112
- return;
113
- }
114
-
115
- const blockImageView = imageInLink.findAncestor( element => imageUtils.isBlockImageView( element ) );
116
-
117
- // There are four possible cases to consider here
118
- //
119
- // 1. A "root > ... > figure.image > a > img" structure.
120
- // 2. A "root > ... > figure.image > a > picture > img" structure.
121
- // 3. A "root > ... > block > a > img" structure.
122
- // 4. A "root > ... > block > a > picture > img" structure.
123
- //
124
- // but the last 2 cases should only be considered by this converter when the inline image plugin
125
- // is NOT loaded in the editor (because otherwise, that would be a plain, linked inline image).
126
- if ( isImageInlinePluginLoaded && !blockImageView ) {
127
- return;
128
- }
129
-
130
- // There's an image inside an <a> element - we consume it so it won't be picked up by the Link plugin.
131
- const consumableAttributes = { attributes: [ 'href' ] };
132
-
133
- // Consume the `href` attribute so the default one will not convert it to $text attribute.
134
- if ( !conversionApi.consumable.consume( viewLink, consumableAttributes ) ) {
135
- // Might be consumed by something else - i.e. other converter with priority=highest - a standard check.
136
- return;
137
- }
138
-
139
- const linkHref = viewLink.getAttribute( 'href' );
140
-
141
- // Missing the 'href' attribute.
142
- if ( !linkHref ) {
143
- return;
144
- }
145
-
146
- // A full definition of the image feature.
147
- // figure > a > img: parent of the view link element is an image element (figure).
148
- let modelElement = data.modelCursor.parent;
149
-
150
- if ( !modelElement.is( 'element', 'imageBlock' ) ) {
151
- // a > img: parent of the view link is not the image (figure) element. We need to convert it manually.
152
- const conversionResult = conversionApi.convertItem( imageInLink, data.modelCursor );
153
-
154
- // Set image range as conversion result.
155
- data.modelRange = conversionResult.modelRange;
156
-
157
- // Continue conversion where image conversion ends.
158
- data.modelCursor = conversionResult.modelCursor;
159
-
160
- modelElement = data.modelCursor.nodeBefore;
161
- }
162
-
163
- if ( modelElement && modelElement.is( 'element', 'imageBlock' ) ) {
164
- // Set the linkHref attribute from link element on model image element.
165
- conversionApi.writer.setAttribute( 'linkHref', linkHref, modelElement );
166
- }
167
- }, { priority: 'high' } );
168
- // Using the same priority that `upcastImageLinkManualDecorator()` converter guarantees
169
- // that manual decorators will decorate the proper element.
170
- };
77
+ /**
78
+ * Returns a converter for linked block images that consumes the "href" attribute
79
+ * if a link contains an image.
80
+ *
81
+ * @param editor The editor instance.
82
+ */
83
+ function upcastLink(editor) {
84
+ const isImageInlinePluginLoaded = editor.plugins.has('ImageInlineEditing');
85
+ const imageUtils = editor.plugins.get('ImageUtils');
86
+ return dispatcher => {
87
+ dispatcher.on('element:a', (evt, data, conversionApi) => {
88
+ const viewLink = data.viewItem;
89
+ const imageInLink = imageUtils.findViewImgElement(viewLink);
90
+ if (!imageInLink) {
91
+ return;
92
+ }
93
+ const blockImageView = imageInLink.findAncestor(element => imageUtils.isBlockImageView(element));
94
+ // There are four possible cases to consider here
95
+ //
96
+ // 1. A "root > ... > figure.image > a > img" structure.
97
+ // 2. A "root > ... > figure.image > a > picture > img" structure.
98
+ // 3. A "root > ... > block > a > img" structure.
99
+ // 4. A "root > ... > block > a > picture > img" structure.
100
+ //
101
+ // but the last 2 cases should only be considered by this converter when the inline image plugin
102
+ // is NOT loaded in the editor (because otherwise, that would be a plain, linked inline image).
103
+ if (isImageInlinePluginLoaded && !blockImageView) {
104
+ return;
105
+ }
106
+ // There's an image inside an <a> element - we consume it so it won't be picked up by the Link plugin.
107
+ const consumableAttributes = { attributes: ['href'] };
108
+ // Consume the `href` attribute so the default one will not convert it to $text attribute.
109
+ if (!conversionApi.consumable.consume(viewLink, consumableAttributes)) {
110
+ // Might be consumed by something else - i.e. other converter with priority=highest - a standard check.
111
+ return;
112
+ }
113
+ const linkHref = viewLink.getAttribute('href');
114
+ // Missing the 'href' attribute.
115
+ if (!linkHref) {
116
+ return;
117
+ }
118
+ // A full definition of the image feature.
119
+ // figure > a > img: parent of the view link element is an image element (figure).
120
+ let modelElement = data.modelCursor.parent;
121
+ if (!modelElement.is('element', 'imageBlock')) {
122
+ // a > img: parent of the view link is not the image (figure) element. We need to convert it manually.
123
+ const conversionResult = conversionApi.convertItem(imageInLink, data.modelCursor);
124
+ // Set image range as conversion result.
125
+ data.modelRange = conversionResult.modelRange;
126
+ // Continue conversion where image conversion ends.
127
+ data.modelCursor = conversionResult.modelCursor;
128
+ modelElement = data.modelCursor.nodeBefore;
129
+ }
130
+ if (modelElement && modelElement.is('element', 'imageBlock')) {
131
+ // Set the linkHref attribute from link element on model image element.
132
+ conversionApi.writer.setAttribute('linkHref', linkHref, modelElement);
133
+ }
134
+ }, { priority: 'high' });
135
+ // Using the same priority that `upcastImageLinkManualDecorator()` converter guarantees
136
+ // that manual decorators will decorate the proper element.
137
+ };
171
138
  }
172
-
173
- // Creates a converter that adds `<a>` to linked block image view elements.
174
- //
175
- // @private
176
- function downcastImageLink( editor ) {
177
- const imageUtils = editor.plugins.get( 'ImageUtils' );
178
-
179
- return dispatcher => {
180
- dispatcher.on( 'attribute:linkHref:imageBlock', ( evt, data, conversionApi ) => {
181
- if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
182
- return;
183
- }
184
-
185
- // The image will be already converted - so it will be present in the view.
186
- const viewFigure = conversionApi.mapper.toViewElement( data.item );
187
- const writer = conversionApi.writer;
188
-
189
- // But we need to check whether the link element exists.
190
- const linkInImage = Array.from( viewFigure.getChildren() ).find( child => child.name === 'a' );
191
- const viewImage = imageUtils.findViewImgElement( viewFigure );
192
- // <picture>...<img/></picture> or <img/>
193
- const viewImgOrPicture = viewImage.parent.is( 'element', 'picture' ) ? viewImage.parent : viewImage;
194
-
195
- // If so, update the attribute if it's defined or remove the entire link if the attribute is empty.
196
- if ( linkInImage ) {
197
- if ( data.attributeNewValue ) {
198
- writer.setAttribute( 'href', data.attributeNewValue, linkInImage );
199
- } else {
200
- writer.move( writer.createRangeOn( viewImgOrPicture ), writer.createPositionAt( viewFigure, 0 ) );
201
- writer.remove( linkInImage );
202
- }
203
- } else {
204
- // But if it does not exist. Let's wrap already converted image by newly created link element.
205
- // 1. Create an empty link element.
206
- const linkElement = writer.createContainerElement( 'a', { href: data.attributeNewValue } );
207
-
208
- // 2. Insert link inside the associated image.
209
- writer.insert( writer.createPositionAt( viewFigure, 0 ), linkElement );
210
-
211
- // 3. Move the image to the link.
212
- writer.move( writer.createRangeOn( viewImgOrPicture ), writer.createPositionAt( linkElement, 0 ) );
213
- }
214
- }, { priority: 'high' } );
215
- };
139
+ /**
140
+ * Creates a converter that adds `<a>` to linked block image view elements.
141
+ */
142
+ function downcastImageLink(editor) {
143
+ const imageUtils = editor.plugins.get('ImageUtils');
144
+ return dispatcher => {
145
+ dispatcher.on('attribute:linkHref:imageBlock', (evt, data, conversionApi) => {
146
+ if (!conversionApi.consumable.consume(data.item, evt.name)) {
147
+ return;
148
+ }
149
+ // The image will be already converted - so it will be present in the view.
150
+ const viewFigure = conversionApi.mapper.toViewElement(data.item);
151
+ const writer = conversionApi.writer;
152
+ // But we need to check whether the link element exists.
153
+ const linkInImage = Array.from(viewFigure.getChildren())
154
+ .find((child) => child.is('element', 'a'));
155
+ const viewImage = imageUtils.findViewImgElement(viewFigure);
156
+ // <picture>...<img/></picture> or <img/>
157
+ const viewImgOrPicture = viewImage.parent.is('element', 'picture') ? viewImage.parent : viewImage;
158
+ // If so, update the attribute if it's defined or remove the entire link if the attribute is empty.
159
+ if (linkInImage) {
160
+ if (data.attributeNewValue) {
161
+ writer.setAttribute('href', data.attributeNewValue, linkInImage);
162
+ }
163
+ else {
164
+ writer.move(writer.createRangeOn(viewImgOrPicture), writer.createPositionAt(viewFigure, 0));
165
+ writer.remove(linkInImage);
166
+ }
167
+ }
168
+ else {
169
+ // But if it does not exist. Let's wrap already converted image by newly created link element.
170
+ // 1. Create an empty link element.
171
+ const linkElement = writer.createContainerElement('a', { href: data.attributeNewValue });
172
+ // 2. Insert link inside the associated image.
173
+ writer.insert(writer.createPositionAt(viewFigure, 0), linkElement);
174
+ // 3. Move the image to the link.
175
+ writer.move(writer.createRangeOn(viewImgOrPicture), writer.createPositionAt(linkElement, 0));
176
+ }
177
+ }, { priority: 'high' });
178
+ };
216
179
  }
217
-
218
- // Returns a converter that decorates the `<a>` element when the image is the link label.
219
- //
220
- // @private
221
- // @returns {Function}
222
- function downcastImageLinkManualDecorator( decorator ) {
223
- return dispatcher => {
224
- dispatcher.on( `attribute:${ decorator.id }:imageBlock`, ( evt, data, conversionApi ) => {
225
- const viewFigure = conversionApi.mapper.toViewElement( data.item );
226
- const linkInImage = Array.from( viewFigure.getChildren() ).find( child => child.name === 'a' );
227
-
228
- // The <a> element was removed by the time this converter is executed.
229
- // It may happen when the base `linkHref` and decorator attributes are removed
230
- // at the same time (see #8401).
231
- if ( !linkInImage ) {
232
- return;
233
- }
234
-
235
- for ( const [ key, val ] of toMap( decorator.attributes ) ) {
236
- conversionApi.writer.setAttribute( key, val, linkInImage );
237
- }
238
-
239
- if ( decorator.classes ) {
240
- conversionApi.writer.addClass( decorator.classes, linkInImage );
241
- }
242
-
243
- for ( const key in decorator.styles ) {
244
- conversionApi.writer.setStyle( key, decorator.styles[ key ], linkInImage );
245
- }
246
- } );
247
- };
180
+ /**
181
+ * Returns a converter that decorates the `<a>` element when the image is the link label.
182
+ */
183
+ function downcastImageLinkManualDecorator(decorator) {
184
+ return dispatcher => {
185
+ dispatcher.on(`attribute:${decorator.id}:imageBlock`, (evt, data, conversionApi) => {
186
+ const viewFigure = conversionApi.mapper.toViewElement(data.item);
187
+ const linkInImage = Array.from(viewFigure.getChildren())
188
+ .find((child) => child.is('element', 'a'));
189
+ // The <a> element was removed by the time this converter is executed.
190
+ // It may happen when the base `linkHref` and decorator attributes are removed
191
+ // at the same time (see #8401).
192
+ if (!linkInImage) {
193
+ return;
194
+ }
195
+ for (const [key, val] of toMap(decorator.attributes)) {
196
+ conversionApi.writer.setAttribute(key, val, linkInImage);
197
+ }
198
+ if (decorator.classes) {
199
+ conversionApi.writer.addClass(decorator.classes, linkInImage);
200
+ }
201
+ for (const key in decorator.styles) {
202
+ conversionApi.writer.setStyle(key, decorator.styles[key], linkInImage);
203
+ }
204
+ });
205
+ };
248
206
  }
249
-
250
- // Returns a converter that checks whether manual decorators should be applied to the link.
251
- //
252
- // @private
253
- // @returns {Function}
254
- function upcastImageLinkManualDecorator( editor, decorator ) {
255
- const isImageInlinePluginLoaded = editor.plugins.has( 'ImageInlineEditing' );
256
- const imageUtils = editor.plugins.get( 'ImageUtils' );
257
-
258
- return dispatcher => {
259
- dispatcher.on( 'element:a', ( evt, data, conversionApi ) => {
260
- const viewLink = data.viewItem;
261
- const imageInLink = imageUtils.findViewImgElement( viewLink );
262
-
263
- // We need to check whether an image is inside a link because the converter handles
264
- // only manual decorators for linked images. See #7975.
265
- if ( !imageInLink ) {
266
- return;
267
- }
268
-
269
- const blockImageView = imageInLink.findAncestor( element => imageUtils.isBlockImageView( element ) );
270
-
271
- if ( isImageInlinePluginLoaded && !blockImageView ) {
272
- return;
273
- }
274
-
275
- const matcher = new Matcher( decorator._createPattern() );
276
- const result = matcher.match( viewLink );
277
-
278
- // The link element does not have required attributes or/and proper values.
279
- if ( !result ) {
280
- return;
281
- }
282
-
283
- // Check whether we can consume those attributes.
284
- if ( !conversionApi.consumable.consume( viewLink, result.match ) ) {
285
- return;
286
- }
287
-
288
- // At this stage we can assume that we have the `<imageBlock>` element.
289
- // `nodeBefore` comes after conversion: `<a><img></a>`.
290
- // `parent` comes with full image definition: `<figure><a><img></a></figure>.
291
- // See the body of the `upcastLink()` function.
292
- const modelElement = data.modelCursor.nodeBefore || data.modelCursor.parent;
293
-
294
- conversionApi.writer.setAttribute( decorator.id, true, modelElement );
295
- }, { priority: 'high' } );
296
- // Using the same priority that `upcastLink()` converter guarantees that the linked image was properly converted.
297
- };
207
+ /**
208
+ * Returns a converter that checks whether manual decorators should be applied to the link.
209
+ */
210
+ function upcastImageLinkManualDecorator(editor, decorator) {
211
+ const isImageInlinePluginLoaded = editor.plugins.has('ImageInlineEditing');
212
+ const imageUtils = editor.plugins.get('ImageUtils');
213
+ return dispatcher => {
214
+ dispatcher.on('element:a', (evt, data, conversionApi) => {
215
+ const viewLink = data.viewItem;
216
+ const imageInLink = imageUtils.findViewImgElement(viewLink);
217
+ // We need to check whether an image is inside a link because the converter handles
218
+ // only manual decorators for linked images. See #7975.
219
+ if (!imageInLink) {
220
+ return;
221
+ }
222
+ const blockImageView = imageInLink.findAncestor(element => imageUtils.isBlockImageView(element));
223
+ if (isImageInlinePluginLoaded && !blockImageView) {
224
+ return;
225
+ }
226
+ const matcher = new Matcher(decorator._createPattern());
227
+ const result = matcher.match(viewLink);
228
+ // The link element does not have required attributes or/and proper values.
229
+ if (!result) {
230
+ return;
231
+ }
232
+ // Check whether we can consume those attributes.
233
+ if (!conversionApi.consumable.consume(viewLink, result.match)) {
234
+ return;
235
+ }
236
+ // At this stage we can assume that we have the `<imageBlock>` element.
237
+ // `nodeBefore` comes after conversion: `<a><img></a>`.
238
+ // `parent` comes with full image definition: `<figure><a><img></a></figure>.
239
+ // See the body of the `upcastLink()` function.
240
+ const modelElement = data.modelCursor.nodeBefore || data.modelCursor.parent;
241
+ conversionApi.writer.setAttribute(decorator.id, true, modelElement);
242
+ }, { priority: 'high' });
243
+ // Using the same priority that `upcastLink()` converter guarantees that the linked image was properly converted.
244
+ };
298
245
  }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ import { Plugin, type PluginDependencies } from 'ckeditor5/src/core';
6
+ /**
7
+ * The link image UI plugin.
8
+ *
9
+ * This plugin provides the `'linkImage'` button that can be displayed in the {@link module:image/imagetoolbar~ImageToolbar}.
10
+ * It can be used to wrap images in links.
11
+ */
12
+ export default class LinkImageUI extends Plugin {
13
+ /**
14
+ * @inheritDoc
15
+ */
16
+ static get requires(): PluginDependencies;
17
+ /**
18
+ * @inheritDoc
19
+ */
20
+ static get pluginName(): 'LinkImageUI';
21
+ /**
22
+ * @inheritDoc
23
+ */
24
+ init(): void;
25
+ /**
26
+ * Creates a `LinkImageUI` button view.
27
+ *
28
+ * Clicking this button shows a {@link module:link/linkui~LinkUI#_balloon} attached to the selection.
29
+ * When an image is already linked, the view shows {@link module:link/linkui~LinkUI#actionsView} or
30
+ * {@link module:link/linkui~LinkUI#formView} if it is not.
31
+ */
32
+ private _createToolbarLinkImageButton;
33
+ /**
34
+ * Returns true if a linked image (either block or inline) is the only selected element
35
+ * in the model document.
36
+ */
37
+ private _isSelectedLinkedImage;
38
+ }