UNPKG

6.09 kBJavaScriptView Raw
1/**
2 * @license Copyright (c) 2003-2023, 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 * @module image/imageinsert/ui/imageinsertpanelview
7 */
8import { icons } from 'ckeditor5/src/core';
9import { ButtonView, View, ViewCollection, submitHandler, FocusCycler } from 'ckeditor5/src/ui';
10import { Collection, FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils';
11import ImageInsertFormRowView from './imageinsertformrowview';
12import '../../../theme/imageinsert.css';
13/**
14 * The insert an image via URL view controller class.
15 *
16 * See {@link module:image/imageinsert/ui/imageinsertpanelview~ImageInsertPanelView}.
17 */
18export default class ImageInsertPanelView extends View {
19 /**
20 * Creates a view for the dropdown panel of {@link module:image/imageinsert/imageinsertui~ImageInsertUI}.
21 *
22 * @param locale The localization services instance.
23 * @param integrations An integrations object that contains components (or tokens for components) to be shown in the panel view.
24 */
25 constructor(locale, integrations = {}) {
26 super(locale);
27 const { insertButtonView, cancelButtonView } = this._createActionButtons(locale);
28 this.insertButtonView = insertButtonView;
29 this.cancelButtonView = cancelButtonView;
30 this.set('imageURLInputValue', '');
31 this.focusTracker = new FocusTracker();
32 this.keystrokes = new KeystrokeHandler();
33 this._focusables = new ViewCollection();
34 this._focusCycler = new FocusCycler({
35 focusables: this._focusables,
36 focusTracker: this.focusTracker,
37 keystrokeHandler: this.keystrokes,
38 actions: {
39 // Navigate form fields backwards using the Shift + Tab keystroke.
40 focusPrevious: 'shift + tab',
41 // Navigate form fields forwards using the Tab key.
42 focusNext: 'tab'
43 }
44 });
45 this.set('_integrations', new Collection());
46 for (const [integration, integrationView] of Object.entries(integrations)) {
47 if (integration === 'insertImageViaUrl') {
48 integrationView.fieldView
49 .bind('value').to(this, 'imageURLInputValue', (value) => value || '');
50 integrationView.fieldView.on('input', () => {
51 this.imageURLInputValue = integrationView.fieldView.element.value.trim();
52 });
53 }
54 integrationView.name = integration;
55 this._integrations.add(integrationView);
56 }
57 this.setTemplate({
58 tag: 'form',
59 attributes: {
60 class: [
61 'ck',
62 'ck-image-insert-form'
63 ],
64 tabindex: '-1'
65 },
66 children: [
67 ...this._integrations,
68 new ImageInsertFormRowView(locale, {
69 children: [
70 this.insertButtonView,
71 this.cancelButtonView
72 ],
73 class: 'ck-image-insert-form__action-row'
74 })
75 ]
76 });
77 }
78 /**
79 * @inheritDoc
80 */
81 render() {
82 super.render();
83 submitHandler({
84 view: this
85 });
86 const childViews = [
87 ...this._integrations,
88 this.insertButtonView,
89 this.cancelButtonView
90 ];
91 childViews.forEach(v => {
92 // Register the view as focusable.
93 this._focusables.add(v);
94 // Register the view in the focus tracker.
95 this.focusTracker.add(v.element);
96 });
97 // Start listening for the keystrokes coming from #element.
98 this.keystrokes.listenTo(this.element);
99 const stopPropagation = (data) => data.stopPropagation();
100 // Since the form is in the dropdown panel which is a child of the toolbar, the toolbar's
101 // keystroke handler would take over the key management in the URL input. We need to prevent
102 // this ASAP. Otherwise, the basic caret movement using the arrow keys will be impossible.
103 this.keystrokes.set('arrowright', stopPropagation);
104 this.keystrokes.set('arrowleft', stopPropagation);
105 this.keystrokes.set('arrowup', stopPropagation);
106 this.keystrokes.set('arrowdown', stopPropagation);
107 }
108 /**
109 * @inheritDoc
110 */
111 destroy() {
112 super.destroy();
113 this.focusTracker.destroy();
114 this.keystrokes.destroy();
115 }
116 /**
117 * Returns a view of the integration.
118 *
119 * @param name The name of the integration.
120 */
121 getIntegration(name) {
122 return this._integrations.find(integration => integration.name === name);
123 }
124 /**
125 * Creates the following form controls:
126 *
127 * * {@link #insertButtonView},
128 * * {@link #cancelButtonView}.
129 *
130 * @param locale The localization services instance.
131 */
132 _createActionButtons(locale) {
133 const t = locale.t;
134 const insertButtonView = new ButtonView(locale);
135 const cancelButtonView = new ButtonView(locale);
136 insertButtonView.set({
137 label: t('Insert'),
138 icon: icons.check,
139 class: 'ck-button-save',
140 type: 'submit',
141 withText: true,
142 isEnabled: this.imageURLInputValue
143 });
144 cancelButtonView.set({
145 label: t('Cancel'),
146 icon: icons.cancel,
147 class: 'ck-button-cancel',
148 withText: true
149 });
150 insertButtonView.bind('isEnabled').to(this, 'imageURLInputValue', value => !!value);
151 insertButtonView.delegate('execute').to(this, 'submit');
152 cancelButtonView.delegate('execute').to(this, 'cancel');
153 return { insertButtonView, cancelButtonView };
154 }
155 /**
156 * Focuses the first {@link #_focusables focusable} in the form.
157 */
158 focus() {
159 this._focusCycler.focusFirst();
160 }
161}