UNPKG

5.38 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/imageinsert/imageinsertui
8 */
9
10import { Plugin } from 'ckeditor5/src/core';
11import ImageInsertPanelView from './ui/imageinsertpanelview';
12import { prepareIntegrations } from './utils';
13
14/**
15 * The image insert dropdown plugin.
16 *
17 * For a detailed overview, check the {@glink features/images/image-upload/image-upload Image upload feature}
18 * and {@glink features/images/image-upload/images-inserting#inserting-images-via-source-url Insert images via source URL} documentation.
19 *
20 * Adds the `'insertImage'` dropdown to the {@link module:ui/componentfactory~ComponentFactory UI component factory}
21 * and also the `imageInsert` dropdown as an alias for backward compatibility.
22 *
23 * @extends module:core/plugin~Plugin
24 */
25export default class ImageInsertUI extends Plugin {
26 /**
27 * @inheritDoc
28 */
29 static get pluginName() {
30 return 'ImageInsertUI';
31 }
32
33 /**
34 * @inheritDoc
35 */
36 init() {
37 const editor = this.editor;
38 const componentCreator = locale => {
39 return this._createDropdownView( locale );
40 };
41
42 // Register `insertImage` dropdown and add `imageInsert` dropdown as an alias for backward compatibility.
43 editor.ui.componentFactory.add( 'insertImage', componentCreator );
44 editor.ui.componentFactory.add( 'imageInsert', componentCreator );
45 }
46
47 /**
48 * Creates the dropdown view.
49 *
50 * @param {module:utils/locale~Locale} locale The localization services instance.
51 *
52 * @private
53 * @returns {module:ui/dropdown/dropdownview~DropdownView}
54 */
55 _createDropdownView( locale ) {
56 const editor = this.editor;
57 const imageInsertView = new ImageInsertPanelView( locale, prepareIntegrations( editor ) );
58 const command = editor.commands.get( 'uploadImage' );
59
60 const dropdownView = imageInsertView.dropdownView;
61 const splitButtonView = dropdownView.buttonView;
62
63 splitButtonView.actionView = editor.ui.componentFactory.create( 'uploadImage' );
64 // After we replaced action button with `uploadImage` component,
65 // we have lost a proper styling and some minor visual quirks have appeared.
66 // Brining back original split button classes helps fix the button styling
67 // See https://github.com/ckeditor/ckeditor5/issues/7986.
68 splitButtonView.actionView.extendTemplate( {
69 attributes: {
70 class: 'ck ck-button ck-splitbutton__action'
71 }
72 } );
73
74 return this._setUpDropdown( dropdownView, imageInsertView, command );
75 }
76
77 /**
78 * Sets up the dropdown view.
79 *
80 * @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView A dropdownView.
81 * @param {module:image/imageinsert/ui/imageinsertpanelview~ImageInsertPanelView} imageInsertView An imageInsertView.
82 * @param {module:core/command~Command} command An insertImage command
83 *
84 * @private
85 * @returns {module:ui/dropdown/dropdownview~DropdownView}
86 */
87 _setUpDropdown( dropdownView, imageInsertView, command ) {
88 const editor = this.editor;
89 const t = editor.t;
90 const insertButtonView = imageInsertView.insertButtonView;
91 const insertImageViaUrlForm = imageInsertView.getIntegration( 'insertImageViaUrl' );
92 const panelView = dropdownView.panelView;
93 const imageUtils = this.editor.plugins.get( 'ImageUtils' );
94
95 dropdownView.bind( 'isEnabled' ).to( command );
96
97 // Defer the children injection to improve initial performance.
98 // See https://github.com/ckeditor/ckeditor5/pull/8019#discussion_r484069652.
99 dropdownView.buttonView.once( 'open', () => {
100 panelView.children.add( imageInsertView );
101 } );
102
103 dropdownView.on( 'change:isOpen', () => {
104 const selectedElement = editor.model.document.selection.getSelectedElement();
105
106 if ( dropdownView.isOpen ) {
107 imageInsertView.focus();
108
109 if ( imageUtils.isImage( selectedElement ) ) {
110 imageInsertView.imageURLInputValue = selectedElement.getAttribute( 'src' );
111 insertButtonView.label = t( 'Update' );
112 insertImageViaUrlForm.label = t( 'Update image URL' );
113 } else {
114 imageInsertView.imageURLInputValue = '';
115 insertButtonView.label = t( 'Insert' );
116 insertImageViaUrlForm.label = t( 'Insert image via URL' );
117 }
118 }
119 // Note: Use the low priority to make sure the following listener starts working after the
120 // default action of the drop-down is executed (i.e. the panel showed up). Otherwise, the
121 // invisible form/input cannot be focused/selected.
122 }, { priority: 'low' } );
123
124 imageInsertView.delegate( 'submit', 'cancel' ).to( dropdownView );
125 this.delegate( 'cancel' ).to( dropdownView );
126
127 dropdownView.on( 'submit', () => {
128 closePanel();
129 onSubmit();
130 } );
131
132 dropdownView.on( 'cancel', () => {
133 closePanel();
134 } );
135
136 function onSubmit() {
137 const selectedElement = editor.model.document.selection.getSelectedElement();
138
139 if ( imageUtils.isImage( selectedElement ) ) {
140 editor.model.change( writer => {
141 writer.setAttribute( 'src', imageInsertView.imageURLInputValue, selectedElement );
142 writer.removeAttribute( 'srcset', selectedElement );
143 writer.removeAttribute( 'sizes', selectedElement );
144 } );
145 } else {
146 editor.execute( 'insertImage', { source: imageInsertView.imageURLInputValue } );
147 }
148 }
149
150 function closePanel() {
151 editor.editing.view.focus();
152 dropdownView.isOpen = false;
153 }
154
155 return dropdownView;
156 }
157}