UNPKG

3.65 kBJavaScriptView Raw
1/**
2 * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4 */
5import { Command } from 'ckeditor5/src/core.js';
6/**
7 * The image type command. It changes the type of a selected image, depending on the configuration.
8 */
9export default class ImageTypeCommand extends Command {
10 /**
11 * @inheritDoc
12 *
13 * @param modelElementName Model element name the command converts to.
14 */
15 constructor(editor, modelElementName) {
16 super(editor);
17 this._modelElementName = modelElementName;
18 }
19 /**
20 * @inheritDoc
21 */
22 refresh() {
23 const editor = this.editor;
24 const imageUtils = editor.plugins.get('ImageUtils');
25 const element = imageUtils.getClosestSelectedImageElement(this.editor.model.document.selection);
26 if (this._modelElementName === 'imageBlock') {
27 this.isEnabled = imageUtils.isInlineImage(element);
28 }
29 else {
30 this.isEnabled = imageUtils.isBlockImage(element);
31 }
32 }
33 /**
34 * Executes the command and changes the type of a selected image.
35 *
36 * @fires execute
37 * @param options.setImageSizes Specifies whether the image `width` and `height` attributes should be set automatically.
38 * The default is `true`.
39 * @returns An object containing references to old and new model image elements
40 * (for before and after the change) so external integrations can hook into the decorated
41 * `execute` event and handle this change. `null` if the type change failed.
42 */
43 execute(options = {}) {
44 const editor = this.editor;
45 const model = this.editor.model;
46 const imageUtils = editor.plugins.get('ImageUtils');
47 const oldElement = imageUtils.getClosestSelectedImageElement(model.document.selection);
48 const attributes = Object.fromEntries(oldElement.getAttributes());
49 // Don't change image type if "src" is missing (a broken image), unless there's "uploadId" set.
50 // This state may happen during image upload (before it finishes) and it should be possible to change type
51 // of the image in the meantime.
52 if (!attributes.src && !attributes.uploadId) {
53 return null;
54 }
55 return model.change(writer => {
56 const { setImageSizes = true } = options;
57 // Get all markers that contain the old image element.
58 const markers = Array.from(model.markers)
59 .filter(marker => marker.getRange().containsItem(oldElement));
60 const newElement = imageUtils.insertImage(attributes, model.createSelection(oldElement, 'on'), this._modelElementName, { setImageSizes });
61 if (!newElement) {
62 return null;
63 }
64 const newElementRange = writer.createRangeOn(newElement);
65 // Expand the previously intersecting markers' ranges to include the new image element.
66 for (const marker of markers) {
67 const markerRange = marker.getRange();
68 // Join the survived part of the old marker range with the new element range
69 // (loosely because there could be some new paragraph or the existing one might got split).
70 const range = markerRange.root.rootName != '$graveyard' ?
71 markerRange.getJoined(newElementRange, true) : newElementRange;
72 writer.updateMarker(marker, { range });
73 }
74 return {
75 oldElement,
76 newElement
77 };
78 });
79 }
80}