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/imagestyle/imagestylecommand
|
8 | */
|
9 |
|
10 | import { Command } from 'ckeditor5/src/core';
|
11 |
|
12 | /**
|
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.
|
18 | *
|
19 | * @extends module:core/command~Command
|
20 | */
|
21 | export default class ImageStyleCommand extends Command {
|
22 | /**
|
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.
|
25 | *
|
26 | * @param {module:core/editor/editor~Editor} editor The editor instance.
|
27 | * @param {Array.<module:image/imagestyle~ImageStyleOptionDefinition>} styles
|
28 | * The style options that this command supports.
|
29 | */
|
30 | constructor( editor, styles ) {
|
31 | super( editor );
|
32 |
|
33 | /**
|
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`.
|
37 | *
|
38 | * @private
|
39 | * @type {Object.<String,module:image/imagestyle~ImageStyleOptionDefinition#name>}
|
40 | */
|
41 | this._defaultStyles = {
|
42 | imageBlock: false,
|
43 | imageInline: false
|
44 | };
|
45 |
|
46 | /**
|
47 | * The styles handled by this command.
|
48 | *
|
49 | * @private
|
50 | * @type {module:image/imagestyle~ImageStyleConfig#options}
|
51 | */
|
52 | this._styles = new Map( styles.map( style => {
|
53 | if ( style.isDefault ) {
|
54 | for ( const modelElementName of style.modelElements ) {
|
55 | this._defaultStyles[ modelElementName ] = style.name;
|
56 | }
|
57 | }
|
58 |
|
59 | return [ style.name, style ];
|
60 | } ) );
|
61 | }
|
62 |
|
63 | /**
|
64 | * @inheritDoc
|
65 | */
|
66 | refresh() {
|
67 | const editor = this.editor;
|
68 | const imageUtils = editor.plugins.get( 'ImageUtils' );
|
69 | const element = imageUtils.getClosestSelectedImageElement( this.editor.model.document.selection );
|
70 |
|
71 | this.isEnabled = !!element;
|
72 |
|
73 | if ( !this.isEnabled ) {
|
74 | this.value = false;
|
75 | } else if ( element.hasAttribute( 'imageStyle' ) ) {
|
76 | this.value = element.getAttribute( 'imageStyle' );
|
77 | } else {
|
78 | this.value = this._defaultStyles[ element.name ];
|
79 | }
|
80 | }
|
81 |
|
82 | /**
|
83 | * Executes the command and applies the style to the currently selected image:
|
84 | *
|
85 | * editor.execute( 'imageStyle', { value: 'side' } );
|
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 | *
|
91 | * @param {Object} options
|
92 | * @param {module:image/imagestyle~ImageStyleOptionDefinition#name} options.value The name of the style (as configured in
|
93 | * {@link module:image/imagestyle~ImageStyleConfig#options}).
|
94 | * @fires execute
|
95 | */
|
96 | execute( options = {} ) {
|
97 | const editor = this.editor;
|
98 | const model = editor.model;
|
99 | const imageUtils = editor.plugins.get( 'ImageUtils' );
|
100 |
|
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 |
|
114 | // Default style means that there is no `imageStyle` attribute in the model.
|
115 | // https://github.com/ckeditor/ckeditor5-image/issues/147
|
116 | if ( !requestedStyle || this._styles.get( requestedStyle ).isDefault ) {
|
117 | writer.removeAttribute( 'imageStyle', imageElement );
|
118 | } else {
|
119 | writer.setAttribute( 'imageStyle', requestedStyle, imageElement );
|
120 | }
|
121 | } );
|
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 | }
|
137 | }
|