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 link/ui/linkformview
|
7 | */
|
8 | import { ButtonView, FocusCycler, LabeledFieldView, SwitchButtonView, View, ViewCollection, createLabeledInputText, submitHandler } from 'ckeditor5/src/ui';
|
9 | import { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils';
|
10 | import { icons } from 'ckeditor5/src/core';
|
11 | // See: #8833.
|
12 | // eslint-disable-next-line ckeditor5-rules/ckeditor-imports
|
13 | import '@ckeditor/ckeditor5-ui/theme/components/responsive-form/responsiveform.css';
|
14 | import '../../theme/linkform.css';
|
15 | /**
|
16 | * The link form view controller class.
|
17 | *
|
18 | * See {@link module:link/ui/linkformview~LinkFormView}.
|
19 | */
|
20 | export default class LinkFormView extends View {
|
21 | /**
|
22 | * Creates an instance of the {@link module:link/ui/linkformview~LinkFormView} class.
|
23 | *
|
24 | * Also see {@link #render}.
|
25 | *
|
26 | * @param locale The localization services instance.
|
27 | * @param linkCommand Reference to {@link module:link/linkcommand~LinkCommand}.
|
28 | */
|
29 | constructor(locale, linkCommand) {
|
30 | super(locale);
|
31 | /**
|
32 | * Tracks information about DOM focus in the form.
|
33 | */
|
34 | this.focusTracker = new FocusTracker();
|
35 | /**
|
36 | * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.
|
37 | */
|
38 | this.keystrokes = new KeystrokeHandler();
|
39 | /**
|
40 | * A collection of views that can be focused in the form.
|
41 | */
|
42 | this._focusables = new ViewCollection();
|
43 | const t = locale.t;
|
44 | this.urlInputView = this._createUrlInput();
|
45 | this.saveButtonView = this._createButton(t('Save'), icons.check, 'ck-button-save');
|
46 | this.saveButtonView.type = 'submit';
|
47 | this.cancelButtonView = this._createButton(t('Cancel'), icons.cancel, 'ck-button-cancel', 'cancel');
|
48 | this._manualDecoratorSwitches = this._createManualDecoratorSwitches(linkCommand);
|
49 | this.children = this._createFormChildren(linkCommand.manualDecorators);
|
50 | this._focusCycler = new FocusCycler({
|
51 | focusables: this._focusables,
|
52 | focusTracker: this.focusTracker,
|
53 | keystrokeHandler: this.keystrokes,
|
54 | actions: {
|
55 | // Navigate form fields backwards using the Shift + Tab keystroke.
|
56 | focusPrevious: 'shift + tab',
|
57 | // Navigate form fields forwards using the Tab key.
|
58 | focusNext: 'tab'
|
59 | }
|
60 | });
|
61 | const classList = ['ck', 'ck-link-form', 'ck-responsive-form'];
|
62 | if (linkCommand.manualDecorators.length) {
|
63 | classList.push('ck-link-form_layout-vertical', 'ck-vertical-form');
|
64 | }
|
65 | this.setTemplate({
|
66 | tag: 'form',
|
67 | attributes: {
|
68 | class: classList,
|
69 | // https://github.com/ckeditor/ckeditor5-link/issues/90
|
70 | tabindex: '-1'
|
71 | },
|
72 | children: this.children
|
73 | });
|
74 | }
|
75 | /**
|
76 | * Obtains the state of the {@link module:ui/button/switchbuttonview~SwitchButtonView switch buttons} representing
|
77 | * {@link module:link/linkcommand~LinkCommand#manualDecorators manual link decorators}
|
78 | * in the {@link module:link/ui/linkformview~LinkFormView}.
|
79 | *
|
80 | * @returns Key-value pairs, where the key is the name of the decorator and the value is its state.
|
81 | */
|
82 | getDecoratorSwitchesState() {
|
83 | return Array
|
84 | .from(this._manualDecoratorSwitches)
|
85 | .reduce((accumulator, switchButton) => {
|
86 | accumulator[switchButton.name] = switchButton.isOn;
|
87 | return accumulator;
|
88 | }, {});
|
89 | }
|
90 | /**
|
91 | * @inheritDoc
|
92 | */
|
93 | render() {
|
94 | super.render();
|
95 | submitHandler({
|
96 | view: this
|
97 | });
|
98 | const childViews = [
|
99 | this.urlInputView,
|
100 | ...this._manualDecoratorSwitches,
|
101 | this.saveButtonView,
|
102 | this.cancelButtonView
|
103 | ];
|
104 | childViews.forEach(v => {
|
105 | // Register the view as focusable.
|
106 | this._focusables.add(v);
|
107 | // Register the view in the focus tracker.
|
108 | this.focusTracker.add(v.element);
|
109 | });
|
110 | // Start listening for the keystrokes coming from #element.
|
111 | this.keystrokes.listenTo(this.element);
|
112 | }
|
113 | /**
|
114 | * @inheritDoc
|
115 | */
|
116 | destroy() {
|
117 | super.destroy();
|
118 | this.focusTracker.destroy();
|
119 | this.keystrokes.destroy();
|
120 | }
|
121 | /**
|
122 | * Focuses the fist {@link #_focusables} in the form.
|
123 | */
|
124 | focus() {
|
125 | this._focusCycler.focusFirst();
|
126 | }
|
127 | /**
|
128 | * Creates a labeled input view.
|
129 | *
|
130 | * @returns Labeled field view instance.
|
131 | */
|
132 | _createUrlInput() {
|
133 | const t = this.locale.t;
|
134 | const labeledInput = new LabeledFieldView(this.locale, createLabeledInputText);
|
135 | labeledInput.label = t('Link URL');
|
136 | return labeledInput;
|
137 | }
|
138 | /**
|
139 | * Creates a button view.
|
140 | *
|
141 | * @param label The button label.
|
142 | * @param icon The button icon.
|
143 | * @param className The additional button CSS class name.
|
144 | * @param eventName An event name that the `ButtonView#execute` event will be delegated to.
|
145 | * @returns The button view instance.
|
146 | */
|
147 | _createButton(label, icon, className, eventName) {
|
148 | const button = new ButtonView(this.locale);
|
149 | button.set({
|
150 | label,
|
151 | icon,
|
152 | tooltip: true
|
153 | });
|
154 | button.extendTemplate({
|
155 | attributes: {
|
156 | class: className
|
157 | }
|
158 | });
|
159 | if (eventName) {
|
160 | button.delegate('execute').to(this, eventName);
|
161 | }
|
162 | return button;
|
163 | }
|
164 | /**
|
165 | * Populates {@link module:ui/viewcollection~ViewCollection} of {@link module:ui/button/switchbuttonview~SwitchButtonView}
|
166 | * made based on {@link module:link/linkcommand~LinkCommand#manualDecorators}.
|
167 | *
|
168 | * @param linkCommand A reference to the link command.
|
169 | * @returns ViewCollection of switch buttons.
|
170 | */
|
171 | _createManualDecoratorSwitches(linkCommand) {
|
172 | const switches = this.createCollection();
|
173 | for (const manualDecorator of linkCommand.manualDecorators) {
|
174 | const switchButton = new SwitchButtonView(this.locale);
|
175 | switchButton.set({
|
176 | name: manualDecorator.id,
|
177 | label: manualDecorator.label,
|
178 | withText: true
|
179 | });
|
180 | switchButton.bind('isOn').toMany([manualDecorator, linkCommand], 'value', (decoratorValue, commandValue) => {
|
181 | return commandValue === undefined && decoratorValue === undefined ? !!manualDecorator.defaultValue : !!decoratorValue;
|
182 | });
|
183 | switchButton.on('execute', () => {
|
184 | manualDecorator.set('value', !switchButton.isOn);
|
185 | });
|
186 | switches.add(switchButton);
|
187 | }
|
188 | return switches;
|
189 | }
|
190 | /**
|
191 | * Populates the {@link #children} collection of the form.
|
192 | *
|
193 | * If {@link module:link/linkcommand~LinkCommand#manualDecorators manual decorators} are configured in the editor, it creates an
|
194 | * additional `View` wrapping all {@link #_manualDecoratorSwitches} switch buttons corresponding
|
195 | * to these decorators.
|
196 | *
|
197 | * @param manualDecorators A reference to
|
198 | * the collection of manual decorators stored in the link command.
|
199 | * @returns The children of link form view.
|
200 | */
|
201 | _createFormChildren(manualDecorators) {
|
202 | const children = this.createCollection();
|
203 | children.add(this.urlInputView);
|
204 | if (manualDecorators.length) {
|
205 | const additionalButtonsView = new View();
|
206 | additionalButtonsView.setTemplate({
|
207 | tag: 'ul',
|
208 | children: this._manualDecoratorSwitches.map(switchButton => ({
|
209 | tag: 'li',
|
210 | children: [switchButton],
|
211 | attributes: {
|
212 | class: [
|
213 | 'ck',
|
214 | 'ck-list__item'
|
215 | ]
|
216 | }
|
217 | })),
|
218 | attributes: {
|
219 | class: [
|
220 | 'ck',
|
221 | 'ck-reset',
|
222 | 'ck-list'
|
223 | ]
|
224 | }
|
225 | });
|
226 | children.add(additionalButtonsView);
|
227 | }
|
228 | children.add(this.saveButtonView);
|
229 | children.add(this.cancelButtonView);
|
230 | return children;
|
231 | }
|
232 | }
|