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