@ckeditor/ckeditor5-table 40.0.0 → 40.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/CHANGELOG.md +15 -15
  2. package/LICENSE.md +3 -3
  3. package/build/table.js +1 -1
  4. package/build/translations/fi.js +1 -1
  5. package/lang/translations/fi.po +3 -3
  6. package/package.json +2 -2
  7. package/src/augmentation.d.ts +76 -76
  8. package/src/augmentation.js +5 -5
  9. package/src/commands/insertcolumncommand.d.ts +55 -55
  10. package/src/commands/insertcolumncommand.js +67 -67
  11. package/src/commands/insertrowcommand.d.ts +54 -54
  12. package/src/commands/insertrowcommand.js +66 -66
  13. package/src/commands/inserttablecommand.d.ts +44 -44
  14. package/src/commands/inserttablecommand.js +69 -69
  15. package/src/commands/mergecellcommand.d.ts +68 -68
  16. package/src/commands/mergecellcommand.js +198 -198
  17. package/src/commands/mergecellscommand.d.ts +28 -28
  18. package/src/commands/mergecellscommand.js +94 -94
  19. package/src/commands/removecolumncommand.d.ts +29 -29
  20. package/src/commands/removecolumncommand.js +109 -109
  21. package/src/commands/removerowcommand.d.ts +29 -29
  22. package/src/commands/removerowcommand.js +82 -82
  23. package/src/commands/selectcolumncommand.d.ts +33 -33
  24. package/src/commands/selectcolumncommand.js +60 -60
  25. package/src/commands/selectrowcommand.d.ts +33 -33
  26. package/src/commands/selectrowcommand.js +56 -56
  27. package/src/commands/setheadercolumncommand.d.ts +50 -50
  28. package/src/commands/setheadercolumncommand.js +71 -71
  29. package/src/commands/setheaderrowcommand.d.ts +53 -53
  30. package/src/commands/setheaderrowcommand.js +79 -79
  31. package/src/commands/splitcellcommand.d.ts +43 -43
  32. package/src/commands/splitcellcommand.js +54 -54
  33. package/src/converters/downcast.d.ts +63 -63
  34. package/src/converters/downcast.js +146 -146
  35. package/src/converters/table-caption-post-fixer.d.ts +20 -20
  36. package/src/converters/table-caption-post-fixer.js +53 -53
  37. package/src/converters/table-cell-paragraph-post-fixer.d.ts +32 -32
  38. package/src/converters/table-cell-paragraph-post-fixer.js +107 -107
  39. package/src/converters/table-cell-refresh-handler.d.ts +18 -18
  40. package/src/converters/table-cell-refresh-handler.js +45 -45
  41. package/src/converters/table-headings-refresh-handler.d.ts +17 -17
  42. package/src/converters/table-headings-refresh-handler.js +49 -49
  43. package/src/converters/table-layout-post-fixer.d.ts +226 -226
  44. package/src/converters/table-layout-post-fixer.js +367 -367
  45. package/src/converters/tableproperties.d.ts +54 -54
  46. package/src/converters/tableproperties.js +159 -159
  47. package/src/converters/upcasttable.d.ts +49 -49
  48. package/src/converters/upcasttable.js +243 -243
  49. package/src/index.d.ts +60 -60
  50. package/src/index.js +30 -30
  51. package/src/plaintableoutput.d.ts +26 -26
  52. package/src/plaintableoutput.js +123 -123
  53. package/src/table.d.ts +40 -40
  54. package/src/table.js +44 -44
  55. package/src/tablecaption/tablecaptionediting.d.ts +63 -63
  56. package/src/tablecaption/tablecaptionediting.js +122 -122
  57. package/src/tablecaption/tablecaptionui.d.ts +21 -21
  58. package/src/tablecaption/tablecaptionui.js +57 -57
  59. package/src/tablecaption/toggletablecaptioncommand.d.ts +68 -68
  60. package/src/tablecaption/toggletablecaptioncommand.js +105 -104
  61. package/src/tablecaption/utils.d.ts +38 -42
  62. package/src/tablecaption/utils.js +57 -67
  63. package/src/tablecaption.d.ts +24 -24
  64. package/src/tablecaption.js +28 -28
  65. package/src/tablecellproperties/commands/tablecellbackgroundcolorcommand.d.ts +32 -32
  66. package/src/tablecellproperties/commands/tablecellbackgroundcolorcommand.js +30 -30
  67. package/src/tablecellproperties/commands/tablecellbordercolorcommand.d.ts +37 -37
  68. package/src/tablecellproperties/commands/tablecellbordercolorcommand.js +44 -44
  69. package/src/tablecellproperties/commands/tablecellborderstylecommand.d.ts +37 -37
  70. package/src/tablecellproperties/commands/tablecellborderstylecommand.js +44 -44
  71. package/src/tablecellproperties/commands/tablecellborderwidthcommand.d.ts +51 -51
  72. package/src/tablecellproperties/commands/tablecellborderwidthcommand.js +64 -64
  73. package/src/tablecellproperties/commands/tablecellheightcommand.d.ts +46 -46
  74. package/src/tablecellproperties/commands/tablecellheightcommand.js +51 -51
  75. package/src/tablecellproperties/commands/tablecellhorizontalalignmentcommand.d.ts +32 -32
  76. package/src/tablecellproperties/commands/tablecellhorizontalalignmentcommand.js +30 -30
  77. package/src/tablecellproperties/commands/tablecellpaddingcommand.d.ts +51 -51
  78. package/src/tablecellproperties/commands/tablecellpaddingcommand.js +64 -64
  79. package/src/tablecellproperties/commands/tablecellpropertycommand.d.ts +62 -62
  80. package/src/tablecellproperties/commands/tablecellpropertycommand.js +92 -92
  81. package/src/tablecellproperties/commands/tablecellverticalalignmentcommand.d.ts +40 -40
  82. package/src/tablecellproperties/commands/tablecellverticalalignmentcommand.js +38 -38
  83. package/src/tablecellproperties/tablecellpropertiesediting.d.ts +43 -43
  84. package/src/tablecellproperties/tablecellpropertiesediting.js +241 -241
  85. package/src/tablecellproperties/tablecellpropertiesui.d.ts +112 -112
  86. package/src/tablecellproperties/tablecellpropertiesui.js +330 -330
  87. package/src/tablecellproperties/ui/tablecellpropertiesview.d.ts +228 -228
  88. package/src/tablecellproperties/ui/tablecellpropertiesview.js +548 -548
  89. package/src/tablecellproperties.d.ts +30 -30
  90. package/src/tablecellproperties.js +34 -34
  91. package/src/tablecellwidth/commands/tablecellwidthcommand.d.ts +46 -46
  92. package/src/tablecellwidth/commands/tablecellwidthcommand.js +51 -51
  93. package/src/tablecellwidth/tablecellwidthediting.d.ts +29 -29
  94. package/src/tablecellwidth/tablecellwidthediting.js +45 -45
  95. package/src/tableclipboard.d.ts +65 -65
  96. package/src/tableclipboard.js +450 -450
  97. package/src/tablecolumnresize/constants.d.ts +20 -20
  98. package/src/tablecolumnresize/constants.js +20 -20
  99. package/src/tablecolumnresize/converters.d.ts +18 -18
  100. package/src/tablecolumnresize/converters.js +46 -46
  101. package/src/tablecolumnresize/tablecolumnresizeediting.d.ts +139 -139
  102. package/src/tablecolumnresize/tablecolumnresizeediting.js +583 -583
  103. package/src/tablecolumnresize/tablewidthscommand.d.ts +38 -38
  104. package/src/tablecolumnresize/tablewidthscommand.js +61 -61
  105. package/src/tablecolumnresize/utils.d.ts +148 -148
  106. package/src/tablecolumnresize/utils.js +358 -358
  107. package/src/tablecolumnresize.d.ts +26 -26
  108. package/src/tablecolumnresize.js +30 -30
  109. package/src/tableconfig.d.ts +343 -343
  110. package/src/tableconfig.js +5 -5
  111. package/src/tableediting.d.ts +98 -98
  112. package/src/tableediting.js +191 -191
  113. package/src/tablekeyboard.d.ts +68 -68
  114. package/src/tablekeyboard.js +279 -279
  115. package/src/tablemouse/mouseeventsobserver.d.ts +62 -62
  116. package/src/tablemouse/mouseeventsobserver.js +35 -35
  117. package/src/tablemouse.d.ts +48 -48
  118. package/src/tablemouse.js +172 -172
  119. package/src/tableproperties/commands/tablealignmentcommand.d.ts +32 -32
  120. package/src/tableproperties/commands/tablealignmentcommand.js +30 -30
  121. package/src/tableproperties/commands/tablebackgroundcolorcommand.d.ts +32 -32
  122. package/src/tableproperties/commands/tablebackgroundcolorcommand.js +30 -30
  123. package/src/tableproperties/commands/tablebordercolorcommand.d.ts +37 -37
  124. package/src/tableproperties/commands/tablebordercolorcommand.js +44 -44
  125. package/src/tableproperties/commands/tableborderstylecommand.d.ts +37 -37
  126. package/src/tableproperties/commands/tableborderstylecommand.js +44 -44
  127. package/src/tableproperties/commands/tableborderwidthcommand.d.ts +51 -51
  128. package/src/tableproperties/commands/tableborderwidthcommand.js +64 -64
  129. package/src/tableproperties/commands/tableheightcommand.d.ts +46 -46
  130. package/src/tableproperties/commands/tableheightcommand.js +54 -54
  131. package/src/tableproperties/commands/tablepropertycommand.d.ts +61 -61
  132. package/src/tableproperties/commands/tablepropertycommand.js +81 -80
  133. package/src/tableproperties/commands/tablewidthcommand.d.ts +46 -46
  134. package/src/tableproperties/commands/tablewidthcommand.js +54 -54
  135. package/src/tableproperties/tablepropertiesediting.d.ts +40 -40
  136. package/src/tableproperties/tablepropertiesediting.js +206 -206
  137. package/src/tableproperties/tablepropertiesui.d.ts +114 -114
  138. package/src/tableproperties/tablepropertiesui.js +321 -321
  139. package/src/tableproperties/ui/tablepropertiesview.d.ts +207 -207
  140. package/src/tableproperties/ui/tablepropertiesview.js +466 -466
  141. package/src/tableproperties.d.ts +30 -30
  142. package/src/tableproperties.js +34 -34
  143. package/src/tableselection.d.ts +107 -107
  144. package/src/tableselection.js +297 -297
  145. package/src/tabletoolbar.d.ts +32 -32
  146. package/src/tabletoolbar.js +57 -57
  147. package/src/tableui.d.ts +53 -53
  148. package/src/tableui.js +309 -309
  149. package/src/tableutils.d.ts +448 -448
  150. package/src/tableutils.js +1055 -1055
  151. package/src/tablewalker.d.ts +362 -362
  152. package/src/tablewalker.js +393 -393
  153. package/src/ui/colorinputview.d.ts +140 -140
  154. package/src/ui/colorinputview.js +271 -271
  155. package/src/ui/formrowview.d.ts +61 -61
  156. package/src/ui/formrowview.js +57 -57
  157. package/src/ui/inserttableview.d.ts +77 -77
  158. package/src/ui/inserttableview.js +169 -169
  159. package/src/utils/common.d.ts +46 -42
  160. package/src/utils/common.js +68 -57
  161. package/src/utils/structure.d.ts +245 -245
  162. package/src/utils/structure.js +426 -426
  163. package/src/utils/table-properties.d.ts +67 -67
  164. package/src/utils/table-properties.js +86 -86
  165. package/src/utils/ui/contextualballoon.d.ts +34 -34
  166. package/src/utils/ui/contextualballoon.js +110 -106
  167. package/src/utils/ui/table-properties.d.ts +195 -195
  168. package/src/utils/ui/table-properties.js +362 -362
  169. package/src/utils/ui/widget.d.ts +20 -16
  170. package/src/utils/ui/widget.js +48 -38
  171. package/build/table.js.map +0 -1
@@ -1,321 +1,321 @@
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 table/tableproperties/tablepropertiesui
7
- */
8
- import { Plugin } from 'ckeditor5/src/core';
9
- import { ButtonView, ContextualBalloon, clickOutsideHandler, getLocalizedColorOptions, normalizeColorOptions } from 'ckeditor5/src/ui';
10
- import { debounce } from 'lodash-es';
11
- import TablePropertiesView from './ui/tablepropertiesview';
12
- import tableProperties from './../../theme/icons/table-properties.svg';
13
- import { colorFieldValidator, getLocalizedColorErrorText, getLocalizedLengthErrorText, lengthFieldValidator, lineWidthFieldValidator, defaultColors } from '../utils/ui/table-properties';
14
- import { getTableWidgetAncestor } from '../utils/ui/widget';
15
- import { getBalloonTablePositionData, repositionContextualBalloon } from '../utils/ui/contextualballoon';
16
- import { getNormalizedDefaultProperties } from '../utils/table-properties';
17
- const ERROR_TEXT_TIMEOUT = 500;
18
- // Map of view properties and related commands.
19
- const propertyToCommandMap = {
20
- borderStyle: 'tableBorderStyle',
21
- borderColor: 'tableBorderColor',
22
- borderWidth: 'tableBorderWidth',
23
- backgroundColor: 'tableBackgroundColor',
24
- width: 'tableWidth',
25
- height: 'tableHeight',
26
- alignment: 'tableAlignment'
27
- };
28
- /**
29
- * The table properties UI plugin. It introduces the `'tableProperties'` button
30
- * that opens a form allowing to specify visual styling of an entire table.
31
- *
32
- * It uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.
33
- */
34
- export default class TablePropertiesUI extends Plugin {
35
- /**
36
- * @inheritDoc
37
- */
38
- static get requires() {
39
- return [ContextualBalloon];
40
- }
41
- /**
42
- * @inheritDoc
43
- */
44
- static get pluginName() {
45
- return 'TablePropertiesUI';
46
- }
47
- /**
48
- * @inheritDoc
49
- */
50
- constructor(editor) {
51
- super(editor);
52
- /**
53
- * The properties form view displayed inside the balloon.
54
- */
55
- this.view = null;
56
- editor.config.define('table.tableProperties', {
57
- borderColors: defaultColors,
58
- backgroundColors: defaultColors
59
- });
60
- }
61
- /**
62
- * @inheritDoc
63
- */
64
- init() {
65
- const editor = this.editor;
66
- const t = editor.t;
67
- this._defaultTableProperties = getNormalizedDefaultProperties(editor.config.get('table.tableProperties.defaultProperties'), {
68
- includeAlignmentProperty: true
69
- });
70
- this._balloon = editor.plugins.get(ContextualBalloon);
71
- editor.ui.componentFactory.add('tableProperties', locale => {
72
- const view = new ButtonView(locale);
73
- view.set({
74
- label: t('Table properties'),
75
- icon: tableProperties,
76
- tooltip: true
77
- });
78
- this.listenTo(view, 'execute', () => this._showView());
79
- const commands = Object.values(propertyToCommandMap)
80
- .map(commandName => editor.commands.get(commandName));
81
- view.bind('isEnabled').toMany(commands, 'isEnabled', (...areEnabled) => (areEnabled.some(isCommandEnabled => isCommandEnabled)));
82
- return view;
83
- });
84
- }
85
- /**
86
- * @inheritDoc
87
- */
88
- destroy() {
89
- super.destroy();
90
- // Destroy created UI components as they are not automatically destroyed.
91
- // See https://github.com/ckeditor/ckeditor5/issues/1341.
92
- if (this.view) {
93
- this.view.destroy();
94
- }
95
- }
96
- /**
97
- * Creates the {@link module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView} instance.
98
- *
99
- * @returns The table properties form view instance.
100
- */
101
- _createPropertiesView() {
102
- const editor = this.editor;
103
- const config = editor.config.get('table.tableProperties');
104
- const borderColorsConfig = normalizeColorOptions(config.borderColors);
105
- const localizedBorderColors = getLocalizedColorOptions(editor.locale, borderColorsConfig);
106
- const backgroundColorsConfig = normalizeColorOptions(config.backgroundColors);
107
- const localizedBackgroundColors = getLocalizedColorOptions(editor.locale, backgroundColorsConfig);
108
- const hasColorPicker = config.colorPicker !== false;
109
- const view = new TablePropertiesView(editor.locale, {
110
- borderColors: localizedBorderColors,
111
- backgroundColors: localizedBackgroundColors,
112
- defaultTableProperties: this._defaultTableProperties,
113
- colorPickerConfig: hasColorPicker ? (config.colorPicker || {}) : false
114
- });
115
- const t = editor.t;
116
- // Render the view so its #element is available for the clickOutsideHandler.
117
- view.render();
118
- this.listenTo(view, 'submit', () => {
119
- this._hideView();
120
- });
121
- this.listenTo(view, 'cancel', () => {
122
- // https://github.com/ckeditor/ckeditor5/issues/6180
123
- if (this._undoStepBatch.operations.length) {
124
- editor.execute('undo', this._undoStepBatch);
125
- }
126
- this._hideView();
127
- });
128
- // Close the balloon on Esc key press.
129
- view.keystrokes.set('Esc', (data, cancel) => {
130
- this._hideView();
131
- cancel();
132
- });
133
- // Close on click outside of balloon panel element.
134
- clickOutsideHandler({
135
- emitter: view,
136
- activator: () => this._isViewInBalloon,
137
- contextElements: [this._balloon.view.element],
138
- callback: () => this._hideView()
139
- });
140
- const colorErrorText = getLocalizedColorErrorText(t);
141
- const lengthErrorText = getLocalizedLengthErrorText(t);
142
- // Create the "UI -> editor data" binding.
143
- // These listeners update the editor data (via table commands) when any observable
144
- // property of the view has changed. They also validate the value and display errors in the UI
145
- // when necessary. This makes the view live, which means the changes are
146
- // visible in the editing as soon as the user types or changes fields' values.
147
- view.on('change:borderStyle', this._getPropertyChangeCallback('tableBorderStyle'));
148
- view.on('change:borderColor', this._getValidatedPropertyChangeCallback({
149
- viewField: view.borderColorInput,
150
- commandName: 'tableBorderColor',
151
- errorText: colorErrorText,
152
- validator: colorFieldValidator
153
- }));
154
- view.on('change:borderWidth', this._getValidatedPropertyChangeCallback({
155
- viewField: view.borderWidthInput,
156
- commandName: 'tableBorderWidth',
157
- errorText: lengthErrorText,
158
- validator: lineWidthFieldValidator
159
- }));
160
- view.on('change:backgroundColor', this._getValidatedPropertyChangeCallback({
161
- viewField: view.backgroundInput,
162
- commandName: 'tableBackgroundColor',
163
- errorText: colorErrorText,
164
- validator: colorFieldValidator
165
- }));
166
- view.on('change:width', this._getValidatedPropertyChangeCallback({
167
- viewField: view.widthInput,
168
- commandName: 'tableWidth',
169
- errorText: lengthErrorText,
170
- validator: lengthFieldValidator
171
- }));
172
- view.on('change:height', this._getValidatedPropertyChangeCallback({
173
- viewField: view.heightInput,
174
- commandName: 'tableHeight',
175
- errorText: lengthErrorText,
176
- validator: lengthFieldValidator
177
- }));
178
- view.on('change:alignment', this._getPropertyChangeCallback('tableAlignment'));
179
- return view;
180
- }
181
- /**
182
- * In this method the "editor data -> UI" binding is happening.
183
- *
184
- * When executed, this method obtains selected table property values from various table commands
185
- * and passes them to the {@link #view}.
186
- *
187
- * This way, the UI stays up–to–date with the editor data.
188
- */
189
- _fillViewFormFromCommandValues() {
190
- const commands = this.editor.commands;
191
- const borderStyleCommand = commands.get('tableBorderStyle');
192
- Object.entries(propertyToCommandMap)
193
- .map(([property, commandName]) => {
194
- const propertyKey = property;
195
- const defaultValue = this._defaultTableProperties[propertyKey] || '';
196
- return [propertyKey, (commands.get(commandName).value || defaultValue)];
197
- })
198
- .forEach(([property, value]) => {
199
- // Do not set the `border-color` and `border-width` fields if `border-style:none`.
200
- if ((property === 'borderColor' || property === 'borderWidth') && borderStyleCommand.value === 'none') {
201
- return;
202
- }
203
- this.view.set(property, value);
204
- });
205
- this._isReady = true;
206
- }
207
- /**
208
- * Shows the {@link #view} in the {@link #_balloon}.
209
- *
210
- * **Note**: Each time a view is shown, the new {@link #_undoStepBatch} is created that contains
211
- * all changes made to the document when the view is visible, allowing a single undo step
212
- * for all of them.
213
- */
214
- _showView() {
215
- const editor = this.editor;
216
- if (!this.view) {
217
- this.view = this._createPropertiesView();
218
- }
219
- this.listenTo(editor.ui, 'update', () => {
220
- this._updateView();
221
- });
222
- // Update the view with the model values.
223
- this._fillViewFormFromCommandValues();
224
- this._balloon.add({
225
- view: this.view,
226
- position: getBalloonTablePositionData(editor)
227
- });
228
- // Create a new batch. Clicking "Cancel" will undo this batch.
229
- this._undoStepBatch = editor.model.createBatch();
230
- // Basic a11y.
231
- this.view.focus();
232
- }
233
- /**
234
- * Removes the {@link #view} from the {@link #_balloon}.
235
- */
236
- _hideView() {
237
- const editor = this.editor;
238
- this.stopListening(editor.ui, 'update');
239
- this._isReady = false;
240
- // Blur any input element before removing it from DOM to prevent issues in some browsers.
241
- // See https://github.com/ckeditor/ckeditor5/issues/1501.
242
- this.view.saveButtonView.focus();
243
- this._balloon.remove(this.view);
244
- // Make sure the focus is not lost in the process by putting it directly
245
- // into the editing view.
246
- this.editor.editing.view.focus();
247
- }
248
- /**
249
- * Repositions the {@link #_balloon} or hides the {@link #view} if a table is no longer selected.
250
- */
251
- _updateView() {
252
- const editor = this.editor;
253
- const viewDocument = editor.editing.view.document;
254
- if (!getTableWidgetAncestor(viewDocument.selection)) {
255
- this._hideView();
256
- }
257
- else if (this._isViewVisible) {
258
- repositionContextualBalloon(editor, 'table');
259
- }
260
- }
261
- /**
262
- * Returns `true` when the {@link #view} is the visible in the {@link #_balloon}.
263
- */
264
- get _isViewVisible() {
265
- return !!this.view && this._balloon.visibleView === this.view;
266
- }
267
- /**
268
- * Returns `true` when the {@link #view} is in the {@link #_balloon}.
269
- */
270
- get _isViewInBalloon() {
271
- return !!this.view && this._balloon.hasView(this.view);
272
- }
273
- /**
274
- * Creates a callback that when executed upon {@link #view view's} property change
275
- * executes a related editor command with the new property value.
276
- *
277
- * If new value will be set to the default value, the command will not be executed.
278
- *
279
- * @param commandName The command that will be executed.
280
- */
281
- _getPropertyChangeCallback(commandName) {
282
- return (evt, propertyName, newValue) => {
283
- // Do not execute the command on initial call (opening the table properties view).
284
- if (!this._isReady) {
285
- return;
286
- }
287
- this.editor.execute(commandName, {
288
- value: newValue,
289
- batch: this._undoStepBatch
290
- });
291
- };
292
- }
293
- /**
294
- * Creates a callback that when executed upon {@link #view view's} property change:
295
- * * executes a related editor command with the new property value if the value is valid,
296
- * * or sets the error text next to the invalid field, if the value did not pass the validation.
297
- */
298
- _getValidatedPropertyChangeCallback(options) {
299
- const { commandName, viewField, validator, errorText } = options;
300
- const setErrorTextDebounced = debounce(() => {
301
- viewField.errorText = errorText;
302
- }, ERROR_TEXT_TIMEOUT);
303
- return (evt, propertyName, newValue) => {
304
- setErrorTextDebounced.cancel();
305
- // Do not execute the command on initial call (opening the table properties view).
306
- if (!this._isReady) {
307
- return;
308
- }
309
- if (validator(newValue)) {
310
- this.editor.execute(commandName, {
311
- value: newValue,
312
- batch: this._undoStepBatch
313
- });
314
- viewField.errorText = null;
315
- }
316
- else {
317
- setErrorTextDebounced();
318
- }
319
- };
320
- }
321
- }
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 table/tableproperties/tablepropertiesui
7
+ */
8
+ import { Plugin } from 'ckeditor5/src/core';
9
+ import { ButtonView, ContextualBalloon, clickOutsideHandler, getLocalizedColorOptions, normalizeColorOptions } from 'ckeditor5/src/ui';
10
+ import { debounce } from 'lodash-es';
11
+ import TablePropertiesView from './ui/tablepropertiesview';
12
+ import tableProperties from './../../theme/icons/table-properties.svg';
13
+ import { colorFieldValidator, getLocalizedColorErrorText, getLocalizedLengthErrorText, lengthFieldValidator, lineWidthFieldValidator, defaultColors } from '../utils/ui/table-properties';
14
+ import { getSelectionAffectedTableWidget } from '../utils/ui/widget';
15
+ import { getBalloonTablePositionData, repositionContextualBalloon } from '../utils/ui/contextualballoon';
16
+ import { getNormalizedDefaultProperties } from '../utils/table-properties';
17
+ const ERROR_TEXT_TIMEOUT = 500;
18
+ // Map of view properties and related commands.
19
+ const propertyToCommandMap = {
20
+ borderStyle: 'tableBorderStyle',
21
+ borderColor: 'tableBorderColor',
22
+ borderWidth: 'tableBorderWidth',
23
+ backgroundColor: 'tableBackgroundColor',
24
+ width: 'tableWidth',
25
+ height: 'tableHeight',
26
+ alignment: 'tableAlignment'
27
+ };
28
+ /**
29
+ * The table properties UI plugin. It introduces the `'tableProperties'` button
30
+ * that opens a form allowing to specify visual styling of an entire table.
31
+ *
32
+ * It uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.
33
+ */
34
+ export default class TablePropertiesUI extends Plugin {
35
+ /**
36
+ * @inheritDoc
37
+ */
38
+ static get requires() {
39
+ return [ContextualBalloon];
40
+ }
41
+ /**
42
+ * @inheritDoc
43
+ */
44
+ static get pluginName() {
45
+ return 'TablePropertiesUI';
46
+ }
47
+ /**
48
+ * @inheritDoc
49
+ */
50
+ constructor(editor) {
51
+ super(editor);
52
+ /**
53
+ * The properties form view displayed inside the balloon.
54
+ */
55
+ this.view = null;
56
+ editor.config.define('table.tableProperties', {
57
+ borderColors: defaultColors,
58
+ backgroundColors: defaultColors
59
+ });
60
+ }
61
+ /**
62
+ * @inheritDoc
63
+ */
64
+ init() {
65
+ const editor = this.editor;
66
+ const t = editor.t;
67
+ this._defaultTableProperties = getNormalizedDefaultProperties(editor.config.get('table.tableProperties.defaultProperties'), {
68
+ includeAlignmentProperty: true
69
+ });
70
+ this._balloon = editor.plugins.get(ContextualBalloon);
71
+ editor.ui.componentFactory.add('tableProperties', locale => {
72
+ const view = new ButtonView(locale);
73
+ view.set({
74
+ label: t('Table properties'),
75
+ icon: tableProperties,
76
+ tooltip: true
77
+ });
78
+ this.listenTo(view, 'execute', () => this._showView());
79
+ const commands = Object.values(propertyToCommandMap)
80
+ .map(commandName => editor.commands.get(commandName));
81
+ view.bind('isEnabled').toMany(commands, 'isEnabled', (...areEnabled) => (areEnabled.some(isCommandEnabled => isCommandEnabled)));
82
+ return view;
83
+ });
84
+ }
85
+ /**
86
+ * @inheritDoc
87
+ */
88
+ destroy() {
89
+ super.destroy();
90
+ // Destroy created UI components as they are not automatically destroyed.
91
+ // See https://github.com/ckeditor/ckeditor5/issues/1341.
92
+ if (this.view) {
93
+ this.view.destroy();
94
+ }
95
+ }
96
+ /**
97
+ * Creates the {@link module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView} instance.
98
+ *
99
+ * @returns The table properties form view instance.
100
+ */
101
+ _createPropertiesView() {
102
+ const editor = this.editor;
103
+ const config = editor.config.get('table.tableProperties');
104
+ const borderColorsConfig = normalizeColorOptions(config.borderColors);
105
+ const localizedBorderColors = getLocalizedColorOptions(editor.locale, borderColorsConfig);
106
+ const backgroundColorsConfig = normalizeColorOptions(config.backgroundColors);
107
+ const localizedBackgroundColors = getLocalizedColorOptions(editor.locale, backgroundColorsConfig);
108
+ const hasColorPicker = config.colorPicker !== false;
109
+ const view = new TablePropertiesView(editor.locale, {
110
+ borderColors: localizedBorderColors,
111
+ backgroundColors: localizedBackgroundColors,
112
+ defaultTableProperties: this._defaultTableProperties,
113
+ colorPickerConfig: hasColorPicker ? (config.colorPicker || {}) : false
114
+ });
115
+ const t = editor.t;
116
+ // Render the view so its #element is available for the clickOutsideHandler.
117
+ view.render();
118
+ this.listenTo(view, 'submit', () => {
119
+ this._hideView();
120
+ });
121
+ this.listenTo(view, 'cancel', () => {
122
+ // https://github.com/ckeditor/ckeditor5/issues/6180
123
+ if (this._undoStepBatch.operations.length) {
124
+ editor.execute('undo', this._undoStepBatch);
125
+ }
126
+ this._hideView();
127
+ });
128
+ // Close the balloon on Esc key press.
129
+ view.keystrokes.set('Esc', (data, cancel) => {
130
+ this._hideView();
131
+ cancel();
132
+ });
133
+ // Close on click outside of balloon panel element.
134
+ clickOutsideHandler({
135
+ emitter: view,
136
+ activator: () => this._isViewInBalloon,
137
+ contextElements: [this._balloon.view.element],
138
+ callback: () => this._hideView()
139
+ });
140
+ const colorErrorText = getLocalizedColorErrorText(t);
141
+ const lengthErrorText = getLocalizedLengthErrorText(t);
142
+ // Create the "UI -> editor data" binding.
143
+ // These listeners update the editor data (via table commands) when any observable
144
+ // property of the view has changed. They also validate the value and display errors in the UI
145
+ // when necessary. This makes the view live, which means the changes are
146
+ // visible in the editing as soon as the user types or changes fields' values.
147
+ view.on('change:borderStyle', this._getPropertyChangeCallback('tableBorderStyle'));
148
+ view.on('change:borderColor', this._getValidatedPropertyChangeCallback({
149
+ viewField: view.borderColorInput,
150
+ commandName: 'tableBorderColor',
151
+ errorText: colorErrorText,
152
+ validator: colorFieldValidator
153
+ }));
154
+ view.on('change:borderWidth', this._getValidatedPropertyChangeCallback({
155
+ viewField: view.borderWidthInput,
156
+ commandName: 'tableBorderWidth',
157
+ errorText: lengthErrorText,
158
+ validator: lineWidthFieldValidator
159
+ }));
160
+ view.on('change:backgroundColor', this._getValidatedPropertyChangeCallback({
161
+ viewField: view.backgroundInput,
162
+ commandName: 'tableBackgroundColor',
163
+ errorText: colorErrorText,
164
+ validator: colorFieldValidator
165
+ }));
166
+ view.on('change:width', this._getValidatedPropertyChangeCallback({
167
+ viewField: view.widthInput,
168
+ commandName: 'tableWidth',
169
+ errorText: lengthErrorText,
170
+ validator: lengthFieldValidator
171
+ }));
172
+ view.on('change:height', this._getValidatedPropertyChangeCallback({
173
+ viewField: view.heightInput,
174
+ commandName: 'tableHeight',
175
+ errorText: lengthErrorText,
176
+ validator: lengthFieldValidator
177
+ }));
178
+ view.on('change:alignment', this._getPropertyChangeCallback('tableAlignment'));
179
+ return view;
180
+ }
181
+ /**
182
+ * In this method the "editor data -> UI" binding is happening.
183
+ *
184
+ * When executed, this method obtains selected table property values from various table commands
185
+ * and passes them to the {@link #view}.
186
+ *
187
+ * This way, the UI stays up–to–date with the editor data.
188
+ */
189
+ _fillViewFormFromCommandValues() {
190
+ const commands = this.editor.commands;
191
+ const borderStyleCommand = commands.get('tableBorderStyle');
192
+ Object.entries(propertyToCommandMap)
193
+ .map(([property, commandName]) => {
194
+ const propertyKey = property;
195
+ const defaultValue = this._defaultTableProperties[propertyKey] || '';
196
+ return [propertyKey, (commands.get(commandName).value || defaultValue)];
197
+ })
198
+ .forEach(([property, value]) => {
199
+ // Do not set the `border-color` and `border-width` fields if `border-style:none`.
200
+ if ((property === 'borderColor' || property === 'borderWidth') && borderStyleCommand.value === 'none') {
201
+ return;
202
+ }
203
+ this.view.set(property, value);
204
+ });
205
+ this._isReady = true;
206
+ }
207
+ /**
208
+ * Shows the {@link #view} in the {@link #_balloon}.
209
+ *
210
+ * **Note**: Each time a view is shown, the new {@link #_undoStepBatch} is created that contains
211
+ * all changes made to the document when the view is visible, allowing a single undo step
212
+ * for all of them.
213
+ */
214
+ _showView() {
215
+ const editor = this.editor;
216
+ if (!this.view) {
217
+ this.view = this._createPropertiesView();
218
+ }
219
+ this.listenTo(editor.ui, 'update', () => {
220
+ this._updateView();
221
+ });
222
+ // Update the view with the model values.
223
+ this._fillViewFormFromCommandValues();
224
+ this._balloon.add({
225
+ view: this.view,
226
+ position: getBalloonTablePositionData(editor)
227
+ });
228
+ // Create a new batch. Clicking "Cancel" will undo this batch.
229
+ this._undoStepBatch = editor.model.createBatch();
230
+ // Basic a11y.
231
+ this.view.focus();
232
+ }
233
+ /**
234
+ * Removes the {@link #view} from the {@link #_balloon}.
235
+ */
236
+ _hideView() {
237
+ const editor = this.editor;
238
+ this.stopListening(editor.ui, 'update');
239
+ this._isReady = false;
240
+ // Blur any input element before removing it from DOM to prevent issues in some browsers.
241
+ // See https://github.com/ckeditor/ckeditor5/issues/1501.
242
+ this.view.saveButtonView.focus();
243
+ this._balloon.remove(this.view);
244
+ // Make sure the focus is not lost in the process by putting it directly
245
+ // into the editing view.
246
+ this.editor.editing.view.focus();
247
+ }
248
+ /**
249
+ * Repositions the {@link #_balloon} or hides the {@link #view} if a table is no longer selected.
250
+ */
251
+ _updateView() {
252
+ const editor = this.editor;
253
+ const viewDocument = editor.editing.view.document;
254
+ if (!getSelectionAffectedTableWidget(viewDocument.selection)) {
255
+ this._hideView();
256
+ }
257
+ else if (this._isViewVisible) {
258
+ repositionContextualBalloon(editor, 'table');
259
+ }
260
+ }
261
+ /**
262
+ * Returns `true` when the {@link #view} is the visible in the {@link #_balloon}.
263
+ */
264
+ get _isViewVisible() {
265
+ return !!this.view && this._balloon.visibleView === this.view;
266
+ }
267
+ /**
268
+ * Returns `true` when the {@link #view} is in the {@link #_balloon}.
269
+ */
270
+ get _isViewInBalloon() {
271
+ return !!this.view && this._balloon.hasView(this.view);
272
+ }
273
+ /**
274
+ * Creates a callback that when executed upon {@link #view view's} property change
275
+ * executes a related editor command with the new property value.
276
+ *
277
+ * If new value will be set to the default value, the command will not be executed.
278
+ *
279
+ * @param commandName The command that will be executed.
280
+ */
281
+ _getPropertyChangeCallback(commandName) {
282
+ return (evt, propertyName, newValue) => {
283
+ // Do not execute the command on initial call (opening the table properties view).
284
+ if (!this._isReady) {
285
+ return;
286
+ }
287
+ this.editor.execute(commandName, {
288
+ value: newValue,
289
+ batch: this._undoStepBatch
290
+ });
291
+ };
292
+ }
293
+ /**
294
+ * Creates a callback that when executed upon {@link #view view's} property change:
295
+ * * executes a related editor command with the new property value if the value is valid,
296
+ * * or sets the error text next to the invalid field, if the value did not pass the validation.
297
+ */
298
+ _getValidatedPropertyChangeCallback(options) {
299
+ const { commandName, viewField, validator, errorText } = options;
300
+ const setErrorTextDebounced = debounce(() => {
301
+ viewField.errorText = errorText;
302
+ }, ERROR_TEXT_TIMEOUT);
303
+ return (evt, propertyName, newValue) => {
304
+ setErrorTextDebounced.cancel();
305
+ // Do not execute the command on initial call (opening the table properties view).
306
+ if (!this._isReady) {
307
+ return;
308
+ }
309
+ if (validator(newValue)) {
310
+ this.editor.execute(commandName, {
311
+ value: newValue,
312
+ batch: this._undoStepBatch
313
+ });
314
+ viewField.errorText = null;
315
+ }
316
+ else {
317
+ setErrorTextDebounced();
318
+ }
319
+ };
320
+ }
321
+ }