@ckeditor/ckeditor5-table 0.0.0-nightly-next-20251209.0 → 0.0.0-nightly-20251210.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 (108) hide show
  1. package/build/table.js +2 -2
  2. package/build/translations/af.js +1 -1
  3. package/build/translations/ar.js +1 -1
  4. package/build/translations/ast.js +1 -1
  5. package/build/translations/az.js +1 -1
  6. package/build/translations/be.js +1 -1
  7. package/build/translations/bg.js +1 -1
  8. package/build/translations/bn.js +1 -1
  9. package/build/translations/bs.js +1 -1
  10. package/build/translations/ca.js +1 -1
  11. package/build/translations/cs.js +1 -1
  12. package/build/translations/da.js +1 -1
  13. package/build/translations/de-ch.js +1 -1
  14. package/build/translations/de.js +1 -1
  15. package/build/translations/el.js +1 -1
  16. package/build/translations/en-au.js +1 -1
  17. package/build/translations/en-gb.js +1 -1
  18. package/build/translations/eo.js +1 -1
  19. package/build/translations/es-co.js +1 -1
  20. package/build/translations/es.js +1 -1
  21. package/build/translations/et.js +1 -1
  22. package/build/translations/eu.js +1 -1
  23. package/build/translations/fa.js +1 -1
  24. package/build/translations/fi.js +1 -1
  25. package/build/translations/fr.js +1 -1
  26. package/build/translations/gl.js +1 -1
  27. package/build/translations/gu.js +1 -1
  28. package/build/translations/he.js +1 -1
  29. package/build/translations/hi.js +1 -1
  30. package/build/translations/hr.js +1 -1
  31. package/build/translations/hu.js +1 -1
  32. package/build/translations/hy.js +1 -1
  33. package/build/translations/id.js +1 -1
  34. package/build/translations/it.js +1 -1
  35. package/build/translations/ja.js +1 -1
  36. package/build/translations/jv.js +1 -1
  37. package/build/translations/kk.js +1 -1
  38. package/build/translations/km.js +1 -1
  39. package/build/translations/kn.js +1 -1
  40. package/build/translations/ko.js +1 -1
  41. package/build/translations/ku.js +1 -1
  42. package/build/translations/lt.js +1 -1
  43. package/build/translations/lv.js +1 -1
  44. package/build/translations/ms.js +1 -1
  45. package/build/translations/nb.js +1 -1
  46. package/build/translations/ne.js +1 -1
  47. package/build/translations/nl.js +1 -1
  48. package/build/translations/no.js +1 -1
  49. package/build/translations/oc.js +1 -1
  50. package/build/translations/pl.js +1 -1
  51. package/build/translations/pt-br.js +1 -1
  52. package/build/translations/pt.js +1 -1
  53. package/build/translations/ro.js +1 -1
  54. package/build/translations/ru.js +1 -1
  55. package/build/translations/si.js +1 -1
  56. package/build/translations/sk.js +1 -1
  57. package/build/translations/sl.js +1 -1
  58. package/build/translations/sq.js +1 -1
  59. package/build/translations/sr-latn.js +1 -1
  60. package/build/translations/sr.js +1 -1
  61. package/build/translations/sv.js +1 -1
  62. package/build/translations/th.js +1 -1
  63. package/build/translations/ti.js +1 -1
  64. package/build/translations/tk.js +1 -1
  65. package/build/translations/tr.js +1 -1
  66. package/build/translations/tt.js +1 -1
  67. package/build/translations/ug.js +1 -1
  68. package/build/translations/uk.js +1 -1
  69. package/build/translations/ur.js +1 -1
  70. package/build/translations/uz.js +1 -1
  71. package/build/translations/vi.js +1 -1
  72. package/build/translations/zh-cn.js +1 -1
  73. package/build/translations/zh.js +1 -1
  74. package/ckeditor5-metadata.json +1 -10
  75. package/dist/index-content.css +30 -30
  76. package/dist/index-editor.css +194 -120
  77. package/dist/index.css +265 -167
  78. package/dist/index.css.map +1 -1
  79. package/dist/index.js +2219 -148
  80. package/dist/index.js.map +1 -1
  81. package/lang/contexts.json +4 -0
  82. package/package.json +9 -9
  83. package/src/augmentation.d.ts +7 -0
  84. package/src/converters/downcast.js +12 -3
  85. package/src/index.d.ts +4 -0
  86. package/src/index.js +5 -0
  87. package/src/tablecellproperties/tablecellpropertiesuiexperimental.d.ts +128 -0
  88. package/src/tablecellproperties/tablecellpropertiesuiexperimental.js +386 -0
  89. package/src/tablecellproperties/ui/tablecellpropertiesview.d.ts +0 -8
  90. package/src/tablecellproperties/ui/tablecellpropertiesview.js +10 -30
  91. package/src/tablecellproperties/ui/tablecellpropertiesviewexperimental.d.ts +237 -0
  92. package/src/tablecellproperties/ui/tablecellpropertiesviewexperimental.js +633 -0
  93. package/src/tableconfig.d.ts +4 -4
  94. package/src/tableproperties/tablepropertiesediting.js +147 -14
  95. package/src/tableproperties/tablepropertiesuiexperimental.d.ts +136 -0
  96. package/src/tableproperties/tablepropertiesuiexperimental.js +375 -0
  97. package/src/tableproperties/ui/tablepropertiesview.d.ts +0 -8
  98. package/src/tableproperties/ui/tablepropertiesview.js +37 -59
  99. package/src/tableproperties/ui/tablepropertiesviewexperimental.d.ts +216 -0
  100. package/src/tableproperties/ui/tablepropertiesviewexperimental.js +544 -0
  101. package/src/utils/ui/table-propertiesexperimental.d.ts +215 -0
  102. package/src/utils/ui/table-propertiesexperimental.js +391 -0
  103. package/theme/formrow-experimental.css +15 -0
  104. package/theme/formrow.css +0 -2
  105. package/theme/tableform-experimental.css +73 -0
  106. package/theme/tableform.css +5 -1
  107. package/theme/tableproperties-experimental.css +78 -0
  108. package/theme/tableproperties.css +0 -60
@@ -33,6 +33,7 @@
33
33
  "Dimensions": "The label describing a group of form fields that allows setting dimensions of a table or a table cell.",
34
34
  "Table cell text alignment": "The label for the group of toolbars that allows configuring the text alignment in a table cell.",
35
35
  "Table Alignment": "The label for the toolbar that allows configuring the alignment of a table.",
36
+ "Alignment": "The label for the toolbar that allows configuring the alignment of a table.",
36
37
  "Horizontal text alignment toolbar": "The label used by assistive technologies describing a toolbar that allows configuring the horizontal text alignment in a table cell.",
37
38
  "Vertical text alignment toolbar": "The label used by assistive technologies describing a toolbar that allows configuring the vertical text alignment in a table cell.",
38
39
  "Table alignment toolbar": "The label used by assistive technologies describing a toolbar that allows configuring the alignment of a table.",
@@ -57,6 +58,9 @@
57
58
  "Align table to the right with text wrapping": "The label used by assistive technologies describing a button that aligns the table to the right as an inline element, allowing text to wrap around it.",
58
59
  "Align table to the left with no text wrapping": "The label used by assistive technologies describing a button that aligns the table to the left as a block element with no text wrapping.",
59
60
  "Align table to the right with no text wrapping": "The label used by assistive technologies describing a button that aligns the table to the right as a block element with no text wrapping.",
61
+ "Align table to the left": "The label used by assistive technologies describing a button that aligns the table to the left.",
62
+ "Center table": "The label used by assistive technologies describing a button that centers the table.",
63
+ "Align table to the right": "The label used by assistive technologies describing a button that aligns the table to the right.",
60
64
  "The color is invalid. Try \"#FF0000\" or \"rgb(255,0,0)\" or \"red\".": "The localized error string that can be displayed next to color (background, border) fields that have an invalid value",
61
65
  "The value is invalid. Try \"10px\" or \"2em\" or simply \"2\".": "The localized error string that can be displayed next to length (padding, border width) fields that have an invalid value.",
62
66
  "Enter table caption": "The placeholder text for the table caption displayed when the caption is empty.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckeditor/ckeditor5-table",
3
- "version": "0.0.0-nightly-next-20251209.0",
3
+ "version": "0.0.0-nightly-20251210.0",
4
4
  "description": "Table feature for CKEditor 5.",
5
5
  "keywords": [
6
6
  "ckeditor",
@@ -13,14 +13,14 @@
13
13
  "type": "module",
14
14
  "main": "src/index.js",
15
15
  "dependencies": {
16
- "ckeditor5": "0.0.0-nightly-next-20251209.0",
17
- "@ckeditor/ckeditor5-clipboard": "0.0.0-nightly-next-20251209.0",
18
- "@ckeditor/ckeditor5-core": "0.0.0-nightly-next-20251209.0",
19
- "@ckeditor/ckeditor5-engine": "0.0.0-nightly-next-20251209.0",
20
- "@ckeditor/ckeditor5-icons": "0.0.0-nightly-next-20251209.0",
21
- "@ckeditor/ckeditor5-ui": "0.0.0-nightly-next-20251209.0",
22
- "@ckeditor/ckeditor5-utils": "0.0.0-nightly-next-20251209.0",
23
- "@ckeditor/ckeditor5-widget": "0.0.0-nightly-next-20251209.0",
16
+ "ckeditor5": "0.0.0-nightly-20251210.0",
17
+ "@ckeditor/ckeditor5-clipboard": "0.0.0-nightly-20251210.0",
18
+ "@ckeditor/ckeditor5-core": "0.0.0-nightly-20251210.0",
19
+ "@ckeditor/ckeditor5-engine": "0.0.0-nightly-20251210.0",
20
+ "@ckeditor/ckeditor5-icons": "0.0.0-nightly-20251210.0",
21
+ "@ckeditor/ckeditor5-ui": "0.0.0-nightly-20251210.0",
22
+ "@ckeditor/ckeditor5-utils": "0.0.0-nightly-20251210.0",
23
+ "@ckeditor/ckeditor5-widget": "0.0.0-nightly-20251210.0",
24
24
  "es-toolkit": "1.39.5"
25
25
  },
26
26
  "author": "CKSource (http://cksource.com/)",
@@ -15,6 +15,13 @@ declare module '@ckeditor/ckeditor5-engine' {
15
15
  * This will be enabled by default in the future CKEditor 5 releases.
16
16
  */
17
17
  upcastTableBorderZeroAttributes?: boolean;
18
+ /**
19
+ * When enabled, the the {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing table properties feature}
20
+ * will support extended alignment options for tables, i.e. `blockLeft` and `blockRight`, using CSS `margin` property.
21
+ *
22
+ * This will be enabled by default in the future CKEditor 5 releases.
23
+ */
24
+ useExtendedTableBlockAlignment?: boolean;
18
25
  }
19
26
  }
20
27
  declare module '@ckeditor/ckeditor5-core' {
@@ -162,7 +162,10 @@ function hasAnyAttribute(element) {
162
162
  */
163
163
  export function convertPlainTable(editor) {
164
164
  return (table, conversionApi) => {
165
- if (!conversionApi.options.isClipboardPipeline && !editor.plugins.has('PlainTableOutput')) {
165
+ const hasPlainTableOutput = editor.plugins.has('PlainTableOutput');
166
+ const isClipboardPipeline = conversionApi.options.isClipboardPipeline;
167
+ const useExtendedAlignment = editor.config.get('experimentalFlags.useExtendedTableBlockAlignment');
168
+ if (!hasPlainTableOutput && !(useExtendedAlignment && isClipboardPipeline)) {
166
169
  return null;
167
170
  }
168
171
  return downcastPlainTable(table, conversionApi, editor);
@@ -173,7 +176,10 @@ export function convertPlainTable(editor) {
173
176
  */
174
177
  export function convertPlainTableCaption(editor) {
175
178
  return (modelElement, { writer, options }) => {
176
- if (!options.isClipboardPipeline && !editor.plugins.has('PlainTableOutput')) {
179
+ const hasPlainTableOutput = editor.plugins.has('PlainTableOutput');
180
+ const isClipboardPipeline = options.isClipboardPipeline;
181
+ const useExtendedAlignment = editor.config.get('experimentalFlags.useExtendedTableBlockAlignment');
182
+ if (!hasPlainTableOutput && !(useExtendedAlignment && isClipboardPipeline)) {
177
183
  return null;
178
184
  }
179
185
  if (modelElement.parent.name === 'table') {
@@ -258,7 +264,10 @@ export function downcastTableBorderAndBackgroundAttributes(editor) {
258
264
  return dispatcher.on(`attribute:${modelAttribute}:table`, (evt, data, conversionApi) => {
259
265
  const { item, attributeNewValue } = data;
260
266
  const { mapper, writer } = conversionApi;
261
- if (!conversionApi.options.isClipboardPipeline && !editor.plugins.has('PlainTableOutput')) {
267
+ const hasPlainTableOutput = editor.plugins.has('PlainTableOutput');
268
+ const isClipboardPipeline = conversionApi.options.isClipboardPipeline;
269
+ const useExtendedAlignment = editor.config.get('experimentalFlags.useExtendedTableBlockAlignment');
270
+ if (!hasPlainTableOutput && !(useExtendedAlignment && isClipboardPipeline)) {
262
271
  return;
263
272
  }
264
273
  if (!conversionApi.consumable.consume(item, evt.name)) {
package/src/index.d.ts CHANGED
@@ -34,6 +34,10 @@ export { TableUtils, type TableIndexesObject } from './tableutils.js';
34
34
  export { TableColumnResize } from './tablecolumnresize.js';
35
35
  export { TableColumnResizeEditing } from './tablecolumnresize/tablecolumnresizeediting.js';
36
36
  export { TableWidthsCommand, type TableWidthsCommandOptions } from './tablecolumnresize/tablewidthscommand.js';
37
+ export { TablePropertiesUIExperimental } from './tableproperties/tablepropertiesuiexperimental.js';
38
+ export { TablePropertiesViewExperimental, type TablePropertiesViewOptionsExperimental } from './tableproperties/ui/tablepropertiesviewexperimental.js';
39
+ export { TableCellPropertiesUIExperimental } from './tablecellproperties/tablecellpropertiesuiexperimental.js';
40
+ export { TableCellPropertiesViewExperimental, type TableCellPropertiesViewOptionsExperimental } from './tablecellproperties/ui/tablecellpropertiesviewexperimental.js';
37
41
  export { InsertColumnCommand } from './commands/insertcolumncommand.js';
38
42
  export { InsertRowCommand } from './commands/insertrowcommand.js';
39
43
  export { InsertTableCommand } from './commands/inserttablecommand.js';
package/src/index.js CHANGED
@@ -34,6 +34,11 @@ export { TableUtils } from './tableutils.js';
34
34
  export { TableColumnResize } from './tablecolumnresize.js';
35
35
  export { TableColumnResizeEditing } from './tablecolumnresize/tablecolumnresizeediting.js';
36
36
  export { TableWidthsCommand } from './tablecolumnresize/tablewidthscommand.js';
37
+ // [experimental] Remove in the v48.
38
+ export { TablePropertiesUIExperimental } from './tableproperties/tablepropertiesuiexperimental.js';
39
+ export { TablePropertiesViewExperimental } from './tableproperties/ui/tablepropertiesviewexperimental.js';
40
+ export { TableCellPropertiesUIExperimental } from './tablecellproperties/tablecellpropertiesuiexperimental.js';
41
+ export { TableCellPropertiesViewExperimental } from './tablecellproperties/ui/tablecellpropertiesviewexperimental.js';
37
42
  export { InsertColumnCommand } from './commands/insertcolumncommand.js';
38
43
  export { InsertRowCommand } from './commands/insertrowcommand.js';
39
44
  export { InsertTableCommand } from './commands/inserttablecommand.js';
@@ -0,0 +1,128 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
+ */
5
+ /**
6
+ * @module table/tablecellproperties/tablecellpropertiesuiexperimental
7
+ */
8
+ import { Plugin, type Editor } from 'ckeditor5/src/core.js';
9
+ import { ContextualBalloon } from 'ckeditor5/src/ui.js';
10
+ import { TableCellPropertiesViewExperimental } from './ui/tablecellpropertiesviewexperimental.js';
11
+ /**
12
+ * The table cell properties UI plugin. It introduces the `'tableCellProperties'` button
13
+ * that opens a form allowing to specify the visual styling of a table cell.
14
+ *
15
+ * It uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.
16
+ */
17
+ export declare class TableCellPropertiesUIExperimental extends Plugin {
18
+ /**
19
+ * The default table cell properties.
20
+ */
21
+ private _defaultContentTableCellProperties;
22
+ /**
23
+ * The default layout table cell properties.
24
+ */
25
+ private _defaultLayoutTableCellProperties;
26
+ /**
27
+ * The contextual balloon plugin instance.
28
+ */
29
+ private _balloon?;
30
+ /**
31
+ * The cell properties form view displayed inside the balloon.
32
+ */
33
+ view?: TableCellPropertiesViewExperimental | null;
34
+ /**
35
+ * The cell properties form view displayed inside the balloon (content table).
36
+ */
37
+ private _viewWithContentTableDefaults?;
38
+ /**
39
+ * The cell properties form view displayed inside the balloon (layout table).
40
+ */
41
+ private _viewWithLayoutTableDefaults?;
42
+ /**
43
+ * The batch used to undo all changes made by the form (which are live, as the user types)
44
+ * when "Cancel" was pressed. Each time the view is shown, a new batch is created.
45
+ */
46
+ private _undoStepBatch?;
47
+ /**
48
+ * Flag used to indicate whether view is ready to execute update commands
49
+ * (it finished loading initial data).
50
+ */
51
+ private _isReady?;
52
+ /**
53
+ * @inheritDoc
54
+ */
55
+ static get requires(): readonly [typeof ContextualBalloon];
56
+ /**
57
+ * @inheritDoc
58
+ */
59
+ static get pluginName(): "TableCellPropertiesUIExperimental";
60
+ /**
61
+ * @inheritDoc
62
+ */
63
+ static get isOfficialPlugin(): true;
64
+ /**
65
+ * @inheritDoc
66
+ */
67
+ constructor(editor: Editor);
68
+ /**
69
+ * @inheritDoc
70
+ */
71
+ init(): void;
72
+ /**
73
+ * @inheritDoc
74
+ */
75
+ destroy(): void;
76
+ /**
77
+ * Creates the {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView} instance.
78
+ *
79
+ * @returns The cell properties form view instance.
80
+ */
81
+ private _createPropertiesView;
82
+ /**
83
+ * In this method the "editor data -> UI" binding is happening.
84
+ *
85
+ * When executed, this method obtains selected cell property values from various table commands
86
+ * and passes them to the {@link #view}.
87
+ *
88
+ * This way, the UI stays up–to–date with the editor data.
89
+ */
90
+ private _fillViewFormFromCommandValues;
91
+ /**
92
+ * Shows the {@link #view} in the {@link #_balloon}.
93
+ *
94
+ * **Note**: Each time a view is shown, a new {@link #_undoStepBatch} is created. It contains
95
+ * all changes made to the document when the view is visible, allowing a single undo step
96
+ * for all of them.
97
+ */
98
+ protected _showView(): void;
99
+ /**
100
+ * Removes the {@link #view} from the {@link #_balloon}.
101
+ */
102
+ protected _hideView(): void;
103
+ /**
104
+ * Repositions the {@link #_balloon} or hides the {@link #view} if a table cell is no longer selected.
105
+ */
106
+ protected _updateView(): void;
107
+ /**
108
+ * Returns `true` when the {@link #view} is visible in the {@link #_balloon}.
109
+ */
110
+ private get _isViewVisible();
111
+ /**
112
+ * Returns `true` when the {@link #view} is in the {@link #_balloon}.
113
+ */
114
+ private get _isViewInBalloon();
115
+ /**
116
+ * Creates a callback that when executed upon the {@link #view view's} property change
117
+ * executes a related editor command with the new property value.
118
+ *
119
+ * @param commandName The default value of the command.
120
+ */
121
+ private _getPropertyChangeCallback;
122
+ /**
123
+ * Creates a callback that when executed upon the {@link #view view's} property change:
124
+ * * Executes a related editor command with the new property value if the value is valid,
125
+ * * Or sets the error text next to the invalid field, if the value did not pass the validation.
126
+ */
127
+ private _getValidatedPropertyChangeCallback;
128
+ }
@@ -0,0 +1,386 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
+ */
5
+ /**
6
+ * @module table/tablecellproperties/tablecellpropertiesuiexperimental
7
+ */
8
+ /* istanbul ignore file -- @preserve */
9
+ import { Plugin } from 'ckeditor5/src/core.js';
10
+ import { IconTableCellProperties } from 'ckeditor5/src/icons.js';
11
+ import { ButtonView, clickOutsideHandler, ContextualBalloon, getLocalizedColorOptions, normalizeColorOptions } from 'ckeditor5/src/ui.js';
12
+ import { TableCellPropertiesViewExperimental } from './ui/tablecellpropertiesviewexperimental.js';
13
+ import { colorFieldValidator, getLocalizedColorErrorText, getLocalizedLengthErrorText, defaultColors, lengthFieldValidator, lineWidthFieldValidator } from '../utils/ui/table-properties.js';
14
+ import { debounce } from 'es-toolkit/compat';
15
+ import { getSelectionAffectedTableWidget, getTableWidgetAncestor } from '../utils/ui/widget.js';
16
+ import { getBalloonCellPositionData, repositionContextualBalloon } from '../utils/ui/contextualballoon.js';
17
+ import { getNormalizedDefaultCellProperties, getNormalizedDefaultProperties } from '../utils/table-properties.js';
18
+ const ERROR_TEXT_TIMEOUT = 500;
19
+ // Map of view properties and related commands.
20
+ const propertyToCommandMap = {
21
+ borderStyle: 'tableCellBorderStyle',
22
+ borderColor: 'tableCellBorderColor',
23
+ borderWidth: 'tableCellBorderWidth',
24
+ height: 'tableCellHeight',
25
+ width: 'tableCellWidth',
26
+ padding: 'tableCellPadding',
27
+ backgroundColor: 'tableCellBackgroundColor',
28
+ horizontalAlignment: 'tableCellHorizontalAlignment',
29
+ verticalAlignment: 'tableCellVerticalAlignment'
30
+ };
31
+ /**
32
+ * The table cell properties UI plugin. It introduces the `'tableCellProperties'` button
33
+ * that opens a form allowing to specify the visual styling of a table cell.
34
+ *
35
+ * It uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.
36
+ */
37
+ export class TableCellPropertiesUIExperimental extends Plugin {
38
+ /**
39
+ * The default table cell properties.
40
+ */
41
+ _defaultContentTableCellProperties;
42
+ /**
43
+ * The default layout table cell properties.
44
+ */
45
+ _defaultLayoutTableCellProperties;
46
+ /**
47
+ * The contextual balloon plugin instance.
48
+ */
49
+ _balloon;
50
+ /**
51
+ * The cell properties form view displayed inside the balloon.
52
+ */
53
+ view;
54
+ /**
55
+ * The cell properties form view displayed inside the balloon (content table).
56
+ */
57
+ _viewWithContentTableDefaults;
58
+ /**
59
+ * The cell properties form view displayed inside the balloon (layout table).
60
+ */
61
+ _viewWithLayoutTableDefaults;
62
+ /**
63
+ * The batch used to undo all changes made by the form (which are live, as the user types)
64
+ * when "Cancel" was pressed. Each time the view is shown, a new batch is created.
65
+ */
66
+ _undoStepBatch;
67
+ /**
68
+ * Flag used to indicate whether view is ready to execute update commands
69
+ * (it finished loading initial data).
70
+ */
71
+ _isReady;
72
+ /**
73
+ * @inheritDoc
74
+ */
75
+ static get requires() {
76
+ return [ContextualBalloon];
77
+ }
78
+ /**
79
+ * @inheritDoc
80
+ */
81
+ static get pluginName() {
82
+ return 'TableCellPropertiesUIExperimental';
83
+ }
84
+ /**
85
+ * @inheritDoc
86
+ */
87
+ static get isOfficialPlugin() {
88
+ return true;
89
+ }
90
+ /**
91
+ * @inheritDoc
92
+ */
93
+ constructor(editor) {
94
+ super(editor);
95
+ editor.config.define('table.tableCellProperties', {
96
+ borderColors: defaultColors,
97
+ backgroundColors: defaultColors
98
+ });
99
+ }
100
+ /**
101
+ * @inheritDoc
102
+ */
103
+ init() {
104
+ const editor = this.editor;
105
+ const t = editor.t;
106
+ this._defaultContentTableCellProperties = getNormalizedDefaultCellProperties(editor.config.get('table.tableCellProperties.defaultProperties'), {
107
+ includeVerticalAlignmentProperty: true,
108
+ includeHorizontalAlignmentProperty: true,
109
+ includePaddingProperty: true,
110
+ isRightToLeftContent: editor.locale.contentLanguageDirection === 'rtl'
111
+ });
112
+ this._defaultLayoutTableCellProperties = getNormalizedDefaultProperties(undefined, {
113
+ includeVerticalAlignmentProperty: true,
114
+ includeHorizontalAlignmentProperty: true,
115
+ isRightToLeftContent: editor.locale.contentLanguageDirection === 'rtl'
116
+ });
117
+ this._balloon = editor.plugins.get(ContextualBalloon);
118
+ this.view = null;
119
+ this._isReady = false;
120
+ editor.ui.componentFactory.add('tableCellProperties', locale => {
121
+ const view = new ButtonView(locale);
122
+ view.set({
123
+ label: t('Cell properties'),
124
+ icon: IconTableCellProperties,
125
+ tooltip: true
126
+ });
127
+ this.listenTo(view, 'execute', () => this._showView());
128
+ const commands = Object.values(propertyToCommandMap)
129
+ .map(commandName => editor.commands.get(commandName));
130
+ view.bind('isEnabled').toMany(commands, 'isEnabled', (...areEnabled) => (areEnabled.some(isCommandEnabled => isCommandEnabled)));
131
+ return view;
132
+ });
133
+ }
134
+ /**
135
+ * @inheritDoc
136
+ */
137
+ destroy() {
138
+ super.destroy();
139
+ // Destroy created UI components as they are not automatically destroyed.
140
+ // See https://github.com/ckeditor/ckeditor5/issues/1341.
141
+ if (this.view) {
142
+ this.view.destroy();
143
+ }
144
+ }
145
+ /**
146
+ * Creates the {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView} instance.
147
+ *
148
+ * @returns The cell properties form view instance.
149
+ */
150
+ _createPropertiesView(defaultTableCellProperties) {
151
+ const editor = this.editor;
152
+ const config = editor.config.get('table.tableCellProperties');
153
+ const borderColorsConfig = normalizeColorOptions(config.borderColors);
154
+ const localizedBorderColors = getLocalizedColorOptions(editor.locale, borderColorsConfig);
155
+ const backgroundColorsConfig = normalizeColorOptions(config.backgroundColors);
156
+ const localizedBackgroundColors = getLocalizedColorOptions(editor.locale, backgroundColorsConfig);
157
+ const hasColorPicker = config.colorPicker !== false;
158
+ const view = new TableCellPropertiesViewExperimental(editor.locale, {
159
+ borderColors: localizedBorderColors,
160
+ backgroundColors: localizedBackgroundColors,
161
+ defaultTableCellProperties,
162
+ colorPickerConfig: hasColorPicker ? (config.colorPicker || {}) : false
163
+ });
164
+ const t = editor.t;
165
+ // Render the view so its #element is available for the clickOutsideHandler.
166
+ view.render();
167
+ this.listenTo(view, 'submit', () => {
168
+ this._hideView();
169
+ });
170
+ this.listenTo(view, 'cancel', () => {
171
+ // https://github.com/ckeditor/ckeditor5/issues/6180
172
+ if (this._undoStepBatch.operations.length) {
173
+ editor.execute('undo', this._undoStepBatch);
174
+ }
175
+ this._hideView();
176
+ });
177
+ // Close the balloon on Esc key press.
178
+ view.keystrokes.set('Esc', (data, cancel) => {
179
+ this._hideView();
180
+ cancel();
181
+ });
182
+ // Close on click outside of balloon panel element.
183
+ clickOutsideHandler({
184
+ emitter: view,
185
+ activator: () => this._isViewInBalloon,
186
+ contextElements: [this._balloon.view.element],
187
+ callback: () => this._hideView()
188
+ });
189
+ const colorErrorText = getLocalizedColorErrorText(t);
190
+ const lengthErrorText = getLocalizedLengthErrorText(t);
191
+ // Create the "UI -> editor data" binding.
192
+ // These listeners update the editor data (via table commands) when any observable
193
+ // property of the view has changed. They also validate the value and display errors in the UI
194
+ // when necessary. This makes the view live, which means the changes are
195
+ // visible in the editing as soon as the user types or changes fields' values.
196
+ view.on('change:borderStyle', this._getPropertyChangeCallback('tableCellBorderStyle'));
197
+ view.on('change:borderColor', this._getValidatedPropertyChangeCallback({
198
+ viewField: view.borderColorInput,
199
+ commandName: 'tableCellBorderColor',
200
+ errorText: colorErrorText,
201
+ validator: colorFieldValidator
202
+ }));
203
+ view.on('change:borderWidth', this._getValidatedPropertyChangeCallback({
204
+ viewField: view.borderWidthInput,
205
+ commandName: 'tableCellBorderWidth',
206
+ errorText: lengthErrorText,
207
+ validator: lineWidthFieldValidator
208
+ }));
209
+ view.on('change:padding', this._getValidatedPropertyChangeCallback({
210
+ viewField: view.paddingInput,
211
+ commandName: 'tableCellPadding',
212
+ errorText: lengthErrorText,
213
+ validator: lengthFieldValidator
214
+ }));
215
+ view.on('change:width', this._getValidatedPropertyChangeCallback({
216
+ viewField: view.widthInput,
217
+ commandName: 'tableCellWidth',
218
+ errorText: lengthErrorText,
219
+ validator: lengthFieldValidator
220
+ }));
221
+ view.on('change:height', this._getValidatedPropertyChangeCallback({
222
+ viewField: view.heightInput,
223
+ commandName: 'tableCellHeight',
224
+ errorText: lengthErrorText,
225
+ validator: lengthFieldValidator
226
+ }));
227
+ view.on('change:backgroundColor', this._getValidatedPropertyChangeCallback({
228
+ viewField: view.backgroundInput,
229
+ commandName: 'tableCellBackgroundColor',
230
+ errorText: colorErrorText,
231
+ validator: colorFieldValidator
232
+ }));
233
+ view.on('change:horizontalAlignment', this._getPropertyChangeCallback('tableCellHorizontalAlignment'));
234
+ view.on('change:verticalAlignment', this._getPropertyChangeCallback('tableCellVerticalAlignment'));
235
+ return view;
236
+ }
237
+ /**
238
+ * In this method the "editor data -> UI" binding is happening.
239
+ *
240
+ * When executed, this method obtains selected cell property values from various table commands
241
+ * and passes them to the {@link #view}.
242
+ *
243
+ * This way, the UI stays up–to–date with the editor data.
244
+ */
245
+ _fillViewFormFromCommandValues() {
246
+ const commands = this.editor.commands;
247
+ const borderStyleCommand = commands.get('tableCellBorderStyle');
248
+ Object.entries(propertyToCommandMap)
249
+ .map(([property, commandName]) => {
250
+ const propertyKey = property;
251
+ const defaultValue = this.view === this._viewWithContentTableDefaults ?
252
+ this._defaultContentTableCellProperties[propertyKey] || '' :
253
+ this._defaultLayoutTableCellProperties[propertyKey] || '';
254
+ return [
255
+ property,
256
+ commands.get(commandName).value || defaultValue
257
+ ];
258
+ })
259
+ .forEach(([property, value]) => {
260
+ // Do not set the `border-color` and `border-width` fields if `border-style:none`.
261
+ if ((property === 'borderColor' || property === 'borderWidth') && borderStyleCommand.value === 'none') {
262
+ return;
263
+ }
264
+ this.view.set(property, value);
265
+ });
266
+ this._isReady = true;
267
+ }
268
+ /**
269
+ * Shows the {@link #view} in the {@link #_balloon}.
270
+ *
271
+ * **Note**: Each time a view is shown, a new {@link #_undoStepBatch} is created. It contains
272
+ * all changes made to the document when the view is visible, allowing a single undo step
273
+ * for all of them.
274
+ */
275
+ _showView() {
276
+ const editor = this.editor;
277
+ const viewTable = getSelectionAffectedTableWidget(editor.editing.view.document.selection);
278
+ const modelTable = viewTable && editor.editing.mapper.toModelElement(viewTable);
279
+ const useDefaults = !modelTable || modelTable.getAttribute('tableType') !== 'layout';
280
+ if (useDefaults && !this._viewWithContentTableDefaults) {
281
+ this._viewWithContentTableDefaults = this._createPropertiesView(this._defaultContentTableCellProperties);
282
+ }
283
+ else if (!useDefaults && !this._viewWithLayoutTableDefaults) {
284
+ this._viewWithLayoutTableDefaults = this._createPropertiesView(this._defaultLayoutTableCellProperties);
285
+ }
286
+ this.view = useDefaults ? this._viewWithContentTableDefaults : this._viewWithLayoutTableDefaults;
287
+ this.listenTo(editor.ui, 'update', () => {
288
+ this._updateView();
289
+ });
290
+ // Update the view with the model values.
291
+ this._fillViewFormFromCommandValues();
292
+ this._balloon.add({
293
+ view: this.view,
294
+ position: getBalloonCellPositionData(editor)
295
+ });
296
+ // Create a new batch. Clicking "Cancel" will undo this batch.
297
+ this._undoStepBatch = editor.model.createBatch();
298
+ // Basic a11y.
299
+ this.view.focus();
300
+ }
301
+ /**
302
+ * Removes the {@link #view} from the {@link #_balloon}.
303
+ */
304
+ _hideView() {
305
+ const editor = this.editor;
306
+ this.stopListening(editor.ui, 'update');
307
+ this._isReady = false;
308
+ // Blur any input element before removing it from DOM to prevent issues in some browsers.
309
+ // See https://github.com/ckeditor/ckeditor5/issues/1501.
310
+ this.view.saveButtonView.focus();
311
+ this._balloon.remove(this.view);
312
+ // Make sure the focus is not lost in the process by putting it directly
313
+ // into the editing view.
314
+ this.editor.editing.view.focus();
315
+ }
316
+ /**
317
+ * Repositions the {@link #_balloon} or hides the {@link #view} if a table cell is no longer selected.
318
+ */
319
+ _updateView() {
320
+ const editor = this.editor;
321
+ const viewDocument = editor.editing.view.document;
322
+ if (!getTableWidgetAncestor(viewDocument.selection)) {
323
+ this._hideView();
324
+ }
325
+ else if (this._isViewVisible) {
326
+ repositionContextualBalloon(editor, 'cell');
327
+ }
328
+ }
329
+ /**
330
+ * Returns `true` when the {@link #view} is visible in the {@link #_balloon}.
331
+ */
332
+ get _isViewVisible() {
333
+ return !!this.view && this._balloon.visibleView === this.view;
334
+ }
335
+ /**
336
+ * Returns `true` when the {@link #view} is in the {@link #_balloon}.
337
+ */
338
+ get _isViewInBalloon() {
339
+ return !!this.view && this._balloon.hasView(this.view);
340
+ }
341
+ /**
342
+ * Creates a callback that when executed upon the {@link #view view's} property change
343
+ * executes a related editor command with the new property value.
344
+ *
345
+ * @param commandName The default value of the command.
346
+ */
347
+ _getPropertyChangeCallback(commandName) {
348
+ return (evt, propertyName, newValue) => {
349
+ if (!this._isReady) {
350
+ return;
351
+ }
352
+ this.editor.execute(commandName, {
353
+ value: newValue,
354
+ batch: this._undoStepBatch
355
+ });
356
+ };
357
+ }
358
+ /**
359
+ * Creates a callback that when executed upon the {@link #view view's} property change:
360
+ * * Executes a related editor command with the new property value if the value is valid,
361
+ * * Or sets the error text next to the invalid field, if the value did not pass the validation.
362
+ */
363
+ _getValidatedPropertyChangeCallback(options) {
364
+ const { commandName, viewField, validator, errorText } = options;
365
+ const setErrorTextDebounced = debounce(() => {
366
+ viewField.errorText = errorText;
367
+ }, ERROR_TEXT_TIMEOUT);
368
+ return (evt, propertyName, newValue) => {
369
+ setErrorTextDebounced.cancel();
370
+ // Do not execute the command on initial call (opening the table properties view).
371
+ if (!this._isReady) {
372
+ return;
373
+ }
374
+ if (validator(newValue)) {
375
+ this.editor.execute(commandName, {
376
+ value: newValue,
377
+ batch: this._undoStepBatch
378
+ });
379
+ viewField.errorText = null;
380
+ }
381
+ else {
382
+ setErrorTextDebounced();
383
+ }
384
+ };
385
+ }
386
+ }
@@ -147,10 +147,6 @@ export declare class TableCellPropertiesView extends View {
147
147
  * The "Cancel" button view.
148
148
  */
149
149
  cancelButtonView: ButtonView;
150
- /**
151
- * The "Back" button view.
152
- */
153
- backButtonView: ButtonView;
154
150
  /**
155
151
  * A collection of views that can be focused in the form.
156
152
  */
@@ -222,10 +218,6 @@ export declare class TableCellPropertiesView extends View {
222
218
  * * {@link #cancelButtonView}.
223
219
  */
224
220
  private _createActionButtons;
225
- /**
226
- * Creates a back button view that cancels the form.
227
- */
228
- private _createBackButton;
229
221
  /**
230
222
  * Provides localized labels for {@link #horizontalAlignmentToolbar} buttons.
231
223
  */