UNPKG

3.35 kBJavaScriptView Raw
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/image/imagetypecommand
8 */
9
10import { Command } from 'ckeditor5/src/core';
11
12/**
13 * The image type command. It changes the type of a selected image, depending on the configuration.
14 *
15 * @extends module:core/command~Command
16 */
17export default class ImageTypeCommand extends Command {
18 /**
19 * @inheritDoc
20 *
21 * @param {module:core/editor/editor~Editor} editor
22 * @param {'imageBlock'|'imageInline'} modelElementName Model element name the command converts to.
23 */
24 constructor( editor, modelElementName ) {
25 super( editor );
26
27 /**
28 * Model element name the command converts to.
29 *
30 * @readonly
31 * @private
32 * @member {'imageBlock'|'imageInline'}
33 */
34 this._modelElementName = modelElementName;
35 }
36
37 /**
38 * @inheritDoc
39 */
40 refresh() {
41 const editor = this.editor;
42 const imageUtils = editor.plugins.get( 'ImageUtils' );
43 const element = imageUtils.getClosestSelectedImageElement( this.editor.model.document.selection );
44
45 if ( this._modelElementName === 'imageBlock' ) {
46 this.isEnabled = imageUtils.isInlineImage( element );
47 } else {
48 this.isEnabled = imageUtils.isBlockImage( element );
49 }
50 }
51
52 /**
53 * Executes the command and changes the type of a selected image.
54 *
55 * @fires execute
56 * @returns {Object|null} An object containing references to old and new model image elements
57 * (for before and after the change) so external integrations can hook into the decorated
58 * `execute` event and handle this change. `null` if the type change failed.
59 */
60 execute() {
61 const editor = this.editor;
62 const model = this.editor.model;
63 const imageUtils = editor.plugins.get( 'ImageUtils' );
64 const oldElement = imageUtils.getClosestSelectedImageElement( model.document.selection );
65 const attributes = Object.fromEntries( oldElement.getAttributes() );
66
67 // Don't change image type if "src" is missing (a broken image), unless there's "uploadId" set.
68 // This state may happen during image upload (before it finishes) and it should be possible to change type
69 // of the image in the meantime.
70 if ( !attributes.src && !attributes.uploadId ) {
71 return null;
72 }
73
74 return model.change( writer => {
75 // Get all markers that contain the old image element.
76 const markers = Array.from( model.markers )
77 .filter( marker => marker.getRange().containsItem( oldElement ) );
78
79 const newElement = imageUtils.insertImage( attributes, model.createSelection( oldElement, 'on' ), this._modelElementName );
80
81 if ( !newElement ) {
82 return null;
83 }
84
85 const newElementRange = writer.createRangeOn( newElement );
86
87 // Expand the previously intersecting markers' ranges to include the new image element.
88 for ( const marker of markers ) {
89 const markerRange = marker.getRange();
90
91 // Join the survived part of the old marker range with the new element range
92 // (loosely because there could be some new paragraph or the existing one might got split).
93 const range = markerRange.root.rootName != '$graveyard' ?
94 markerRange.getJoined( newElementRange, true ) : newElementRange;
95
96 writer.updateMarker( marker, { range } );
97 }
98
99 return {
100 oldElement,
101 newElement
102 };
103 } );
104 }
105}