1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | import { addListToDropdown, ButtonView, createLabeledDropdown, createLabeledInputText, FocusCycler, FormHeaderView, LabeledFieldView, LabelView, submitHandler, ToolbarView, View, ViewCollection } from 'ckeditor5/src/ui';
|
9 | import { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils';
|
10 | import { icons } from 'ckeditor5/src/core';
|
11 | import { fillToolbar, getBorderStyleDefinitions, getBorderStyleLabels, getLabeledColorInputCreator } from '../../utils/ui/table-properties';
|
12 | import FormRowView from '../../ui/formrowview';
|
13 | import '../../../theme/form.css';
|
14 | import '../../../theme/tableform.css';
|
15 | import '../../../theme/tableproperties.css';
|
16 | const ALIGNMENT_ICONS = {
|
17 | left: icons.objectLeft,
|
18 | center: icons.objectCenter,
|
19 | right: icons.objectRight
|
20 | };
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | export default class TablePropertiesView extends View {
|
26 | |
27 |
|
28 |
|
29 |
|
30 | constructor(locale, options) {
|
31 | super(locale);
|
32 | this.set({
|
33 | borderStyle: '',
|
34 | borderWidth: '',
|
35 | borderColor: '',
|
36 | backgroundColor: '',
|
37 | width: '',
|
38 | height: '',
|
39 | alignment: ''
|
40 | });
|
41 | this.options = options;
|
42 | const { borderStyleDropdown, borderWidthInput, borderColorInput, borderRowLabel } = this._createBorderFields();
|
43 | const { backgroundRowLabel, backgroundInput } = this._createBackgroundFields();
|
44 | const { widthInput, operatorLabel, heightInput, dimensionsLabel } = this._createDimensionFields();
|
45 | const { alignmentToolbar, alignmentLabel } = this._createAlignmentFields();
|
46 | this.focusTracker = new FocusTracker();
|
47 | this.keystrokes = new KeystrokeHandler();
|
48 | this.children = this.createCollection();
|
49 | this.borderStyleDropdown = borderStyleDropdown;
|
50 | this.borderWidthInput = borderWidthInput;
|
51 | this.borderColorInput = borderColorInput;
|
52 | this.backgroundInput = backgroundInput;
|
53 | this.widthInput = widthInput;
|
54 | this.heightInput = heightInput;
|
55 | this.alignmentToolbar = alignmentToolbar;
|
56 |
|
57 |
|
58 |
|
59 | const { saveButtonView, cancelButtonView } = this._createActionButtons();
|
60 | this.saveButtonView = saveButtonView;
|
61 | this.cancelButtonView = cancelButtonView;
|
62 | this._focusables = new ViewCollection();
|
63 | this._focusCycler = new FocusCycler({
|
64 | focusables: this._focusables,
|
65 | focusTracker: this.focusTracker,
|
66 | keystrokeHandler: this.keystrokes,
|
67 | actions: {
|
68 |
|
69 | focusPrevious: 'shift + tab',
|
70 |
|
71 | focusNext: 'tab'
|
72 | }
|
73 | });
|
74 |
|
75 | this.children.add(new FormHeaderView(locale, {
|
76 | label: this.t('Table properties')
|
77 | }));
|
78 |
|
79 | this.children.add(new FormRowView(locale, {
|
80 | labelView: borderRowLabel,
|
81 | children: [
|
82 | borderRowLabel,
|
83 | borderStyleDropdown,
|
84 | borderColorInput,
|
85 | borderWidthInput
|
86 | ],
|
87 | class: 'ck-table-form__border-row'
|
88 | }));
|
89 |
|
90 | this.children.add(new FormRowView(locale, {
|
91 | labelView: backgroundRowLabel,
|
92 | children: [
|
93 | backgroundRowLabel,
|
94 | backgroundInput
|
95 | ],
|
96 | class: 'ck-table-form__background-row'
|
97 | }));
|
98 | this.children.add(new FormRowView(locale, {
|
99 | children: [
|
100 |
|
101 | new FormRowView(locale, {
|
102 | labelView: dimensionsLabel,
|
103 | children: [
|
104 | dimensionsLabel,
|
105 | widthInput,
|
106 | operatorLabel,
|
107 | heightInput
|
108 | ],
|
109 | class: 'ck-table-form__dimensions-row'
|
110 | }),
|
111 |
|
112 | new FormRowView(locale, {
|
113 | labelView: alignmentLabel,
|
114 | children: [
|
115 | alignmentLabel,
|
116 | alignmentToolbar
|
117 | ],
|
118 | class: 'ck-table-properties-form__alignment-row'
|
119 | })
|
120 | ]
|
121 | }));
|
122 |
|
123 | this.children.add(new FormRowView(locale, {
|
124 | children: [
|
125 | this.saveButtonView,
|
126 | this.cancelButtonView
|
127 | ],
|
128 | class: 'ck-table-form__action-row'
|
129 | }));
|
130 | this.setTemplate({
|
131 | tag: 'form',
|
132 | attributes: {
|
133 | class: [
|
134 | 'ck',
|
135 | 'ck-form',
|
136 | 'ck-table-form',
|
137 | 'ck-table-properties-form'
|
138 | ],
|
139 |
|
140 | tabindex: '-1'
|
141 | },
|
142 | children: this.children
|
143 | });
|
144 | }
|
145 | |
146 |
|
147 |
|
148 | render() {
|
149 | super.render();
|
150 |
|
151 |
|
152 | submitHandler({
|
153 | view: this
|
154 | });
|
155 | [
|
156 | this.borderStyleDropdown,
|
157 | this.borderColorInput,
|
158 | this.borderColorInput.fieldView.dropdownView.buttonView,
|
159 | this.borderWidthInput,
|
160 | this.backgroundInput,
|
161 | this.backgroundInput.fieldView.dropdownView.buttonView,
|
162 | this.widthInput,
|
163 | this.heightInput,
|
164 | this.alignmentToolbar,
|
165 | this.saveButtonView,
|
166 | this.cancelButtonView
|
167 | ].forEach(view => {
|
168 |
|
169 | this._focusables.add(view);
|
170 |
|
171 | this.focusTracker.add(view.element);
|
172 | });
|
173 |
|
174 | this.keystrokes.listenTo(this.element);
|
175 | }
|
176 | |
177 |
|
178 |
|
179 | destroy() {
|
180 | super.destroy();
|
181 | this.focusTracker.destroy();
|
182 | this.keystrokes.destroy();
|
183 | }
|
184 | |
185 |
|
186 |
|
187 | focus() {
|
188 | this._focusCycler.focusFirst();
|
189 | }
|
190 | |
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 | _createBorderFields() {
|
198 | const defaultTableProperties = this.options.defaultTableProperties;
|
199 | const defaultBorder = {
|
200 | style: defaultTableProperties.borderStyle,
|
201 | width: defaultTableProperties.borderWidth,
|
202 | color: defaultTableProperties.borderColor
|
203 | };
|
204 | const colorInputCreator = getLabeledColorInputCreator({
|
205 | colorConfig: this.options.borderColors,
|
206 | columns: 5,
|
207 | defaultColorValue: defaultBorder.color
|
208 | });
|
209 | const locale = this.locale;
|
210 | const t = this.t;
|
211 | const accessibleLabel = t('Style');
|
212 |
|
213 | const borderRowLabel = new LabelView(locale);
|
214 | borderRowLabel.text = t('Border');
|
215 |
|
216 | const styleLabels = getBorderStyleLabels(t);
|
217 | const borderStyleDropdown = new LabeledFieldView(locale, createLabeledDropdown);
|
218 | borderStyleDropdown.set({
|
219 | label: accessibleLabel,
|
220 | class: 'ck-table-form__border-style'
|
221 | });
|
222 | borderStyleDropdown.fieldView.buttonView.set({
|
223 | ariaLabel: accessibleLabel,
|
224 | ariaLabelledBy: undefined,
|
225 | isOn: false,
|
226 | withText: true,
|
227 | tooltip: accessibleLabel
|
228 | });
|
229 | borderStyleDropdown.fieldView.buttonView.bind('label').to(this, 'borderStyle', value => {
|
230 | return styleLabels[value ? value : 'none'];
|
231 | });
|
232 | borderStyleDropdown.fieldView.on('execute', evt => {
|
233 | this.borderStyle = evt.source._borderStyleValue;
|
234 | });
|
235 | borderStyleDropdown.bind('isEmpty').to(this, 'borderStyle', value => !value);
|
236 | addListToDropdown(borderStyleDropdown.fieldView, getBorderStyleDefinitions(this, defaultBorder.style), {
|
237 | role: 'menu',
|
238 | ariaLabel: accessibleLabel
|
239 | });
|
240 |
|
241 | const borderWidthInput = new LabeledFieldView(locale, createLabeledInputText);
|
242 | borderWidthInput.set({
|
243 | label: t('Width'),
|
244 | class: 'ck-table-form__border-width'
|
245 | });
|
246 | borderWidthInput.fieldView.bind('value').to(this, 'borderWidth');
|
247 | borderWidthInput.bind('isEnabled').to(this, 'borderStyle', isBorderStyleSet);
|
248 | borderWidthInput.fieldView.on('input', () => {
|
249 | this.borderWidth = borderWidthInput.fieldView.element.value;
|
250 | });
|
251 |
|
252 | const borderColorInput = new LabeledFieldView(locale, colorInputCreator);
|
253 | borderColorInput.set({
|
254 | label: t('Color'),
|
255 | class: 'ck-table-form__border-color'
|
256 | });
|
257 | borderColorInput.fieldView.bind('value').to(this, 'borderColor');
|
258 | borderColorInput.bind('isEnabled').to(this, 'borderStyle', isBorderStyleSet);
|
259 | borderColorInput.fieldView.on('input', () => {
|
260 | this.borderColor = borderColorInput.fieldView.value;
|
261 | });
|
262 |
|
263 | this.on('change:borderStyle', (evt, name, newValue, oldValue) => {
|
264 |
|
265 |
|
266 | if (!isBorderStyleSet(newValue)) {
|
267 | this.borderColor = '';
|
268 | this.borderWidth = '';
|
269 | }
|
270 |
|
271 | if (!isBorderStyleSet(oldValue)) {
|
272 | this.borderColor = defaultBorder.color;
|
273 | this.borderWidth = defaultBorder.width;
|
274 | }
|
275 | });
|
276 | return {
|
277 | borderRowLabel,
|
278 | borderStyleDropdown,
|
279 | borderColorInput,
|
280 | borderWidthInput
|
281 | };
|
282 | }
|
283 | |
284 |
|
285 |
|
286 |
|
287 |
|
288 | _createBackgroundFields() {
|
289 | const locale = this.locale;
|
290 | const t = this.t;
|
291 |
|
292 | const backgroundRowLabel = new LabelView(locale);
|
293 | backgroundRowLabel.text = t('Background');
|
294 |
|
295 | const backgroundInputCreator = getLabeledColorInputCreator({
|
296 | colorConfig: this.options.backgroundColors,
|
297 | columns: 5,
|
298 | defaultColorValue: this.options.defaultTableProperties.backgroundColor
|
299 | });
|
300 | const backgroundInput = new LabeledFieldView(locale, backgroundInputCreator);
|
301 | backgroundInput.set({
|
302 | label: t('Color'),
|
303 | class: 'ck-table-properties-form__background'
|
304 | });
|
305 | backgroundInput.fieldView.bind('value').to(this, 'backgroundColor');
|
306 | backgroundInput.fieldView.on('input', () => {
|
307 | this.backgroundColor = backgroundInput.fieldView.value;
|
308 | });
|
309 | return {
|
310 | backgroundRowLabel,
|
311 | backgroundInput
|
312 | };
|
313 | }
|
314 | |
315 |
|
316 |
|
317 |
|
318 |
|
319 |
|
320 | _createDimensionFields() {
|
321 | const locale = this.locale;
|
322 | const t = this.t;
|
323 |
|
324 | const dimensionsLabel = new LabelView(locale);
|
325 | dimensionsLabel.text = t('Dimensions');
|
326 |
|
327 | const widthInput = new LabeledFieldView(locale, createLabeledInputText);
|
328 | widthInput.set({
|
329 | label: t('Width'),
|
330 | class: 'ck-table-form__dimensions-row__width'
|
331 | });
|
332 | widthInput.fieldView.bind('value').to(this, 'width');
|
333 | widthInput.fieldView.on('input', () => {
|
334 | this.width = widthInput.fieldView.element.value;
|
335 | });
|
336 |
|
337 | const operatorLabel = new View(locale);
|
338 | operatorLabel.setTemplate({
|
339 | tag: 'span',
|
340 | attributes: {
|
341 | class: [
|
342 | 'ck-table-form__dimension-operator'
|
343 | ]
|
344 | },
|
345 | children: [
|
346 | { text: '×' }
|
347 | ]
|
348 | });
|
349 |
|
350 | const heightInput = new LabeledFieldView(locale, createLabeledInputText);
|
351 | heightInput.set({
|
352 | label: t('Height'),
|
353 | class: 'ck-table-form__dimensions-row__height'
|
354 | });
|
355 | heightInput.fieldView.bind('value').to(this, 'height');
|
356 | heightInput.fieldView.on('input', () => {
|
357 | this.height = heightInput.fieldView.element.value;
|
358 | });
|
359 | return {
|
360 | dimensionsLabel,
|
361 | widthInput,
|
362 | operatorLabel,
|
363 | heightInput
|
364 | };
|
365 | }
|
366 | |
367 |
|
368 |
|
369 |
|
370 |
|
371 | _createAlignmentFields() {
|
372 | const locale = this.locale;
|
373 | const t = this.t;
|
374 |
|
375 | const alignmentLabel = new LabelView(locale);
|
376 | alignmentLabel.text = t('Alignment');
|
377 |
|
378 | const alignmentToolbar = new ToolbarView(locale);
|
379 | alignmentToolbar.set({
|
380 | isCompact: true,
|
381 | ariaLabel: t('Table alignment toolbar')
|
382 | });
|
383 | fillToolbar({
|
384 | view: this,
|
385 | icons: ALIGNMENT_ICONS,
|
386 | toolbar: alignmentToolbar,
|
387 | labels: this._alignmentLabels,
|
388 | propertyName: 'alignment',
|
389 | defaultValue: this.options.defaultTableProperties.alignment
|
390 | });
|
391 | return {
|
392 | alignmentLabel,
|
393 | alignmentToolbar
|
394 | };
|
395 | }
|
396 | |
397 |
|
398 |
|
399 |
|
400 |
|
401 |
|
402 | _createActionButtons() {
|
403 | const locale = this.locale;
|
404 | const t = this.t;
|
405 | const saveButtonView = new ButtonView(locale);
|
406 | const cancelButtonView = new ButtonView(locale);
|
407 | const fieldsThatShouldValidateToSave = [
|
408 | this.borderWidthInput,
|
409 | this.borderColorInput,
|
410 | this.backgroundInput,
|
411 | this.widthInput,
|
412 | this.heightInput
|
413 | ];
|
414 | saveButtonView.set({
|
415 | label: t('Save'),
|
416 | icon: icons.check,
|
417 | class: 'ck-button-save',
|
418 | type: 'submit',
|
419 | withText: true
|
420 | });
|
421 | saveButtonView.bind('isEnabled').toMany(fieldsThatShouldValidateToSave, 'errorText', (...errorTexts) => {
|
422 | return errorTexts.every(errorText => !errorText);
|
423 | });
|
424 | cancelButtonView.set({
|
425 | label: t('Cancel'),
|
426 | icon: icons.cancel,
|
427 | class: 'ck-button-cancel',
|
428 | withText: true
|
429 | });
|
430 | cancelButtonView.delegate('execute').to(this, 'cancel');
|
431 | return {
|
432 | saveButtonView, cancelButtonView
|
433 | };
|
434 | }
|
435 | |
436 |
|
437 |
|
438 | get _alignmentLabels() {
|
439 | const locale = this.locale;
|
440 | const t = this.t;
|
441 | const left = t('Align table to the left');
|
442 | const center = t('Center table');
|
443 | const right = t('Align table to the right');
|
444 |
|
445 | if (locale.uiLanguageDirection === 'rtl') {
|
446 | return { right, center, left };
|
447 | }
|
448 | else {
|
449 | return { left, center, right };
|
450 | }
|
451 | }
|
452 | }
|
453 | function isBorderStyleSet(value) {
|
454 | return value !== 'none';
|
455 | }
|