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/imagecaption/toggleimagecaptioncommand
|
8 | */
|
9 |
|
10 | import { Command } from 'ckeditor5/src/core';
|
11 |
|
12 | import ImageBlockEditing from '../image/imageblockediting';
|
13 |
|
14 | /**
|
15 | * The toggle image caption command.
|
16 | *
|
17 | * This command is registered by {@link module:image/imagecaption/imagecaptionediting~ImageCaptionEditing} as the
|
18 | * `'toggleImageCaption'` editor command.
|
19 | *
|
20 | * Executing this command:
|
21 | *
|
22 | * * either adds or removes the image caption of a selected image (depending on whether the caption is present or not),
|
23 | * * removes the image caption if the selection is anchored in one.
|
24 | *
|
25 | * // Toggle the presence of the caption.
|
26 | * editor.execute( 'toggleImageCaption' );
|
27 | *
|
28 | * **Note**: Upon executing this command, the selection will be set on the image if previously anchored in the caption element.
|
29 | *
|
30 | * **Note**: You can move the selection to the caption right away as it shows up upon executing this command by using
|
31 | * the `focusCaptionOnShow` option:
|
32 | *
|
33 | * editor.execute( 'toggleImageCaption', { focusCaptionOnShow: true } );
|
34 | *
|
35 | * @extends module:core/command~Command
|
36 | */
|
37 | export default class ToggleImageCaptionCommand extends Command {
|
38 | /**
|
39 | * @inheritDoc
|
40 | */
|
41 | refresh() {
|
42 | const editor = this.editor;
|
43 | const imageCaptionUtils = editor.plugins.get( 'ImageCaptionUtils' );
|
44 |
|
45 | // Only block images can get captions.
|
46 | if ( !editor.plugins.has( ImageBlockEditing ) ) {
|
47 | this.isEnabled = false;
|
48 | this.value = false;
|
49 |
|
50 | return;
|
51 | }
|
52 |
|
53 | const selection = editor.model.document.selection;
|
54 | const selectedElement = selection.getSelectedElement();
|
55 |
|
56 | if ( !selectedElement ) {
|
57 | const ancestorCaptionElement = imageCaptionUtils.getCaptionFromModelSelection( selection );
|
58 |
|
59 | this.isEnabled = !!ancestorCaptionElement;
|
60 | this.value = !!ancestorCaptionElement;
|
61 |
|
62 | return;
|
63 | }
|
64 |
|
65 | // Block images support captions by default but the command should also be enabled for inline
|
66 | // images because toggling the caption when one is selected should convert it into a block image.
|
67 | this.isEnabled = this.editor.plugins.get( 'ImageUtils' ).isImage( selectedElement );
|
68 |
|
69 | if ( !this.isEnabled ) {
|
70 | this.value = false;
|
71 | } else {
|
72 | this.value = !!imageCaptionUtils.getCaptionFromImageModelElement( selectedElement );
|
73 | }
|
74 | }
|
75 |
|
76 | /**
|
77 | * Executes the command.
|
78 | *
|
79 | * editor.execute( 'toggleImageCaption' );
|
80 | *
|
81 | * @param {Object} [options] Options for the executed command.
|
82 | * @param {String} [options.focusCaptionOnShow] When true and the caption shows up, the selection will be moved into it straight away.
|
83 | * @fires execute
|
84 | */
|
85 | execute( options = {} ) {
|
86 | const { focusCaptionOnShow } = options;
|
87 |
|
88 | this.editor.model.change( writer => {
|
89 | if ( this.value ) {
|
90 | this._hideImageCaption( writer );
|
91 | } else {
|
92 | this._showImageCaption( writer, focusCaptionOnShow );
|
93 | }
|
94 | } );
|
95 | }
|
96 |
|
97 | /**
|
98 | * Shows the caption of the `<imageBlock>` or `<imageInline>`. Also:
|
99 | *
|
100 | * * it converts `<imageInline>` to `<imageBlock>` to show the caption,
|
101 | * * it attempts to restore the caption content from the `ImageCaptionEditing` caption registry,
|
102 | * * it moves the selection to the caption right away, it the `focusCaptionOnShow` option was set.
|
103 | *
|
104 | * @private
|
105 | * @param {module:engine/model/writer~Writer} writer
|
106 | */
|
107 | _showImageCaption( writer, focusCaptionOnShow ) {
|
108 | const model = this.editor.model;
|
109 | const selection = model.document.selection;
|
110 | const imageCaptionEditing = this.editor.plugins.get( 'ImageCaptionEditing' );
|
111 |
|
112 | let selectedImage = selection.getSelectedElement();
|
113 |
|
114 | const savedCaption = imageCaptionEditing._getSavedCaption( selectedImage );
|
115 |
|
116 | // Convert imageInline -> image first.
|
117 | if ( this.editor.plugins.get( 'ImageUtils' ).isInlineImage( selectedImage ) ) {
|
118 | this.editor.execute( 'imageTypeBlock' );
|
119 |
|
120 | // Executing the command created a new model element. Let's pick it again.
|
121 | selectedImage = selection.getSelectedElement();
|
122 | }
|
123 |
|
124 | // Try restoring the caption from the ImageCaptionEditing plugin storage.
|
125 | const newCaptionElement = savedCaption || writer.createElement( 'caption' );
|
126 |
|
127 | writer.append( newCaptionElement, selectedImage );
|
128 |
|
129 | if ( focusCaptionOnShow ) {
|
130 | writer.setSelection( newCaptionElement, 'in' );
|
131 | }
|
132 | }
|
133 |
|
134 | /**
|
135 | * Hides the caption of a selected image (or an image caption the selection is anchored to).
|
136 | *
|
137 | * The content of the caption is stored in the `ImageCaptionEditing` caption registry to make this
|
138 | * a reversible action.
|
139 | *
|
140 | * @private
|
141 | * @param {module:engine/model/writer~Writer} writer
|
142 | */
|
143 | _hideImageCaption( writer ) {
|
144 | const editor = this.editor;
|
145 | const selection = editor.model.document.selection;
|
146 | const imageCaptionEditing = editor.plugins.get( 'ImageCaptionEditing' );
|
147 | const imageCaptionUtils = editor.plugins.get( 'ImageCaptionUtils' );
|
148 | let selectedImage = selection.getSelectedElement();
|
149 | let captionElement;
|
150 |
|
151 | if ( selectedImage ) {
|
152 | captionElement = imageCaptionUtils.getCaptionFromImageModelElement( selectedImage );
|
153 | } else {
|
154 | captionElement = imageCaptionUtils.getCaptionFromModelSelection( selection );
|
155 | selectedImage = captionElement.parent;
|
156 | }
|
157 |
|
158 | // Store the caption content so it can be restored quickly if the user changes their mind even if they toggle image<->imageInline.
|
159 | imageCaptionEditing._saveCaption( selectedImage, captionElement );
|
160 |
|
161 | writer.setSelection( selectedImage, 'on' );
|
162 | writer.remove( captionElement );
|
163 | }
|
164 | }
|