@ckeditor/ckeditor5-table 38.1.1 → 38.2.0-alpha.1

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 (169) hide show
  1. package/build/table.js +1 -1
  2. package/package.json +3 -2
  3. package/src/augmentation.d.ts +76 -76
  4. package/src/augmentation.js +5 -5
  5. package/src/commands/insertcolumncommand.d.ts +55 -55
  6. package/src/commands/insertcolumncommand.js +67 -67
  7. package/src/commands/insertrowcommand.d.ts +54 -54
  8. package/src/commands/insertrowcommand.js +66 -66
  9. package/src/commands/inserttablecommand.d.ts +44 -44
  10. package/src/commands/inserttablecommand.js +69 -69
  11. package/src/commands/mergecellcommand.d.ts +68 -68
  12. package/src/commands/mergecellcommand.js +198 -198
  13. package/src/commands/mergecellscommand.d.ts +28 -28
  14. package/src/commands/mergecellscommand.js +94 -94
  15. package/src/commands/removecolumncommand.d.ts +29 -29
  16. package/src/commands/removecolumncommand.js +109 -109
  17. package/src/commands/removerowcommand.d.ts +29 -29
  18. package/src/commands/removerowcommand.js +82 -82
  19. package/src/commands/selectcolumncommand.d.ts +33 -33
  20. package/src/commands/selectcolumncommand.js +60 -60
  21. package/src/commands/selectrowcommand.d.ts +33 -33
  22. package/src/commands/selectrowcommand.js +56 -56
  23. package/src/commands/setheadercolumncommand.d.ts +50 -50
  24. package/src/commands/setheadercolumncommand.js +71 -71
  25. package/src/commands/setheaderrowcommand.d.ts +53 -53
  26. package/src/commands/setheaderrowcommand.js +79 -79
  27. package/src/commands/splitcellcommand.d.ts +43 -43
  28. package/src/commands/splitcellcommand.js +54 -54
  29. package/src/converters/downcast.d.ts +63 -63
  30. package/src/converters/downcast.js +146 -146
  31. package/src/converters/table-caption-post-fixer.d.ts +20 -20
  32. package/src/converters/table-caption-post-fixer.js +53 -53
  33. package/src/converters/table-cell-paragraph-post-fixer.d.ts +32 -32
  34. package/src/converters/table-cell-paragraph-post-fixer.js +107 -107
  35. package/src/converters/table-cell-refresh-handler.d.ts +18 -18
  36. package/src/converters/table-cell-refresh-handler.js +45 -45
  37. package/src/converters/table-headings-refresh-handler.d.ts +17 -17
  38. package/src/converters/table-headings-refresh-handler.js +49 -49
  39. package/src/converters/table-layout-post-fixer.d.ts +226 -226
  40. package/src/converters/table-layout-post-fixer.js +367 -367
  41. package/src/converters/tableproperties.d.ts +54 -54
  42. package/src/converters/tableproperties.js +159 -159
  43. package/src/converters/upcasttable.d.ts +49 -49
  44. package/src/converters/upcasttable.js +243 -243
  45. package/src/index.d.ts +60 -60
  46. package/src/index.js +30 -30
  47. package/src/plaintableoutput.d.ts +26 -26
  48. package/src/plaintableoutput.js +123 -123
  49. package/src/table.d.ts +40 -40
  50. package/src/table.js +44 -44
  51. package/src/tablecaption/tablecaptionediting.d.ts +63 -63
  52. package/src/tablecaption/tablecaptionediting.js +122 -122
  53. package/src/tablecaption/tablecaptionui.d.ts +21 -21
  54. package/src/tablecaption/tablecaptionui.js +57 -57
  55. package/src/tablecaption/toggletablecaptioncommand.d.ts +68 -68
  56. package/src/tablecaption/toggletablecaptioncommand.js +104 -104
  57. package/src/tablecaption/utils.d.ts +42 -42
  58. package/src/tablecaption/utils.js +67 -67
  59. package/src/tablecaption.d.ts +24 -24
  60. package/src/tablecaption.js +28 -28
  61. package/src/tablecellproperties/commands/tablecellbackgroundcolorcommand.d.ts +32 -32
  62. package/src/tablecellproperties/commands/tablecellbackgroundcolorcommand.js +30 -30
  63. package/src/tablecellproperties/commands/tablecellbordercolorcommand.d.ts +37 -37
  64. package/src/tablecellproperties/commands/tablecellbordercolorcommand.js +44 -44
  65. package/src/tablecellproperties/commands/tablecellborderstylecommand.d.ts +37 -37
  66. package/src/tablecellproperties/commands/tablecellborderstylecommand.js +44 -44
  67. package/src/tablecellproperties/commands/tablecellborderwidthcommand.d.ts +51 -51
  68. package/src/tablecellproperties/commands/tablecellborderwidthcommand.js +64 -64
  69. package/src/tablecellproperties/commands/tablecellheightcommand.d.ts +46 -46
  70. package/src/tablecellproperties/commands/tablecellheightcommand.js +51 -51
  71. package/src/tablecellproperties/commands/tablecellhorizontalalignmentcommand.d.ts +32 -32
  72. package/src/tablecellproperties/commands/tablecellhorizontalalignmentcommand.js +30 -30
  73. package/src/tablecellproperties/commands/tablecellpaddingcommand.d.ts +51 -51
  74. package/src/tablecellproperties/commands/tablecellpaddingcommand.js +64 -64
  75. package/src/tablecellproperties/commands/tablecellpropertycommand.d.ts +62 -62
  76. package/src/tablecellproperties/commands/tablecellpropertycommand.js +92 -92
  77. package/src/tablecellproperties/commands/tablecellverticalalignmentcommand.d.ts +40 -40
  78. package/src/tablecellproperties/commands/tablecellverticalalignmentcommand.js +38 -38
  79. package/src/tablecellproperties/tablecellpropertiesediting.d.ts +43 -43
  80. package/src/tablecellproperties/tablecellpropertiesediting.js +241 -241
  81. package/src/tablecellproperties/tablecellpropertiesui.d.ts +112 -112
  82. package/src/tablecellproperties/tablecellpropertiesui.js +330 -328
  83. package/src/tablecellproperties/ui/tablecellpropertiesview.d.ts +228 -227
  84. package/src/tablecellproperties/ui/tablecellpropertiesview.js +539 -537
  85. package/src/tablecellproperties.d.ts +30 -30
  86. package/src/tablecellproperties.js +34 -34
  87. package/src/tablecellwidth/commands/tablecellwidthcommand.d.ts +46 -46
  88. package/src/tablecellwidth/commands/tablecellwidthcommand.js +51 -51
  89. package/src/tablecellwidth/tablecellwidthediting.d.ts +29 -29
  90. package/src/tablecellwidth/tablecellwidthediting.js +45 -45
  91. package/src/tableclipboard.d.ts +65 -65
  92. package/src/tableclipboard.js +450 -450
  93. package/src/tablecolumnresize/constants.d.ts +20 -20
  94. package/src/tablecolumnresize/constants.js +20 -20
  95. package/src/tablecolumnresize/converters.d.ts +18 -18
  96. package/src/tablecolumnresize/converters.js +45 -45
  97. package/src/tablecolumnresize/tablecolumnresizeediting.d.ts +139 -139
  98. package/src/tablecolumnresize/tablecolumnresizeediting.js +571 -571
  99. package/src/tablecolumnresize/tablewidthscommand.d.ts +38 -38
  100. package/src/tablecolumnresize/tablewidthscommand.js +61 -61
  101. package/src/tablecolumnresize/utils.d.ts +141 -141
  102. package/src/tablecolumnresize/utils.js +330 -330
  103. package/src/tablecolumnresize.d.ts +26 -26
  104. package/src/tablecolumnresize.js +30 -30
  105. package/src/tableconfig.d.ts +343 -331
  106. package/src/tableconfig.js +5 -5
  107. package/src/tableediting.d.ts +98 -98
  108. package/src/tableediting.js +191 -191
  109. package/src/tablekeyboard.d.ts +68 -68
  110. package/src/tablekeyboard.js +279 -279
  111. package/src/tablemouse/mouseeventsobserver.d.ts +62 -62
  112. package/src/tablemouse/mouseeventsobserver.js +35 -35
  113. package/src/tablemouse.d.ts +48 -48
  114. package/src/tablemouse.js +172 -172
  115. package/src/tableproperties/commands/tablealignmentcommand.d.ts +32 -32
  116. package/src/tableproperties/commands/tablealignmentcommand.js +30 -30
  117. package/src/tableproperties/commands/tablebackgroundcolorcommand.d.ts +32 -32
  118. package/src/tableproperties/commands/tablebackgroundcolorcommand.js +30 -30
  119. package/src/tableproperties/commands/tablebordercolorcommand.d.ts +37 -37
  120. package/src/tableproperties/commands/tablebordercolorcommand.js +44 -44
  121. package/src/tableproperties/commands/tableborderstylecommand.d.ts +37 -37
  122. package/src/tableproperties/commands/tableborderstylecommand.js +44 -44
  123. package/src/tableproperties/commands/tableborderwidthcommand.d.ts +51 -51
  124. package/src/tableproperties/commands/tableborderwidthcommand.js +64 -64
  125. package/src/tableproperties/commands/tableheightcommand.d.ts +46 -46
  126. package/src/tableproperties/commands/tableheightcommand.js +54 -54
  127. package/src/tableproperties/commands/tablepropertycommand.d.ts +61 -61
  128. package/src/tableproperties/commands/tablepropertycommand.js +80 -80
  129. package/src/tableproperties/commands/tablewidthcommand.d.ts +46 -46
  130. package/src/tableproperties/commands/tablewidthcommand.js +54 -54
  131. package/src/tableproperties/tablepropertiesediting.d.ts +40 -40
  132. package/src/tableproperties/tablepropertiesediting.js +206 -206
  133. package/src/tableproperties/tablepropertiesui.d.ts +114 -114
  134. package/src/tableproperties/tablepropertiesui.js +321 -319
  135. package/src/tableproperties/ui/tablepropertiesview.d.ts +207 -203
  136. package/src/tableproperties/ui/tablepropertiesview.js +457 -455
  137. package/src/tableproperties.d.ts +30 -30
  138. package/src/tableproperties.js +34 -34
  139. package/src/tableselection.d.ts +107 -107
  140. package/src/tableselection.js +297 -297
  141. package/src/tabletoolbar.d.ts +32 -32
  142. package/src/tabletoolbar.js +57 -57
  143. package/src/tableui.d.ts +53 -53
  144. package/src/tableui.js +309 -309
  145. package/src/tableutils.d.ts +448 -448
  146. package/src/tableutils.js +1041 -1041
  147. package/src/tablewalker.d.ts +323 -323
  148. package/src/tablewalker.js +333 -333
  149. package/src/ui/colorinputview.d.ts +140 -143
  150. package/src/ui/colorinputview.js +265 -248
  151. package/src/ui/formrowview.d.ts +61 -61
  152. package/src/ui/formrowview.js +57 -57
  153. package/src/ui/inserttableview.d.ts +77 -77
  154. package/src/ui/inserttableview.js +169 -169
  155. package/src/utils/common.d.ts +42 -42
  156. package/src/utils/common.js +57 -57
  157. package/src/utils/structure.d.ts +245 -245
  158. package/src/utils/structure.js +426 -426
  159. package/src/utils/table-properties.d.ts +67 -67
  160. package/src/utils/table-properties.js +86 -86
  161. package/src/utils/ui/contextualballoon.d.ts +34 -34
  162. package/src/utils/ui/contextualballoon.js +106 -106
  163. package/src/utils/ui/table-properties.d.ts +195 -193
  164. package/src/utils/ui/table-properties.js +362 -360
  165. package/src/utils/ui/widget.d.ts +16 -16
  166. package/src/utils/ui/widget.js +38 -38
  167. package/theme/tablecaption.css +7 -7
  168. package/theme/tablecolumnresize.css +2 -2
  169. package/build/table.js.map +0 -1
@@ -1,243 +1,243 @@
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
- import { createEmptyTableCell } from '../utils/common';
6
- import { first } from 'ckeditor5/src/utils';
7
- /**
8
- * Returns a function that converts the table view representation:
9
- *
10
- * ```xml
11
- * <figure class="table"><table>...</table></figure>
12
- * ```
13
- *
14
- * to the model representation:
15
- *
16
- * ```xml
17
- * <table></table>
18
- * ```
19
- */
20
- export function upcastTableFigure() {
21
- return (dispatcher) => {
22
- dispatcher.on('element:figure', (evt, data, conversionApi) => {
23
- // Do not convert if this is not a "table figure".
24
- if (!conversionApi.consumable.test(data.viewItem, { name: true, classes: 'table' })) {
25
- return;
26
- }
27
- // Find a table element inside the figure element.
28
- const viewTable = getViewTableFromFigure(data.viewItem);
29
- // Do not convert if table element is absent or was already converted.
30
- if (!viewTable || !conversionApi.consumable.test(viewTable, { name: true })) {
31
- return;
32
- }
33
- // Consume the figure to prevent other converters from processing it again.
34
- conversionApi.consumable.consume(data.viewItem, { name: true, classes: 'table' });
35
- // Convert view table to model table.
36
- const conversionResult = conversionApi.convertItem(viewTable, data.modelCursor);
37
- // Get table element from conversion result.
38
- const modelTable = first(conversionResult.modelRange.getItems());
39
- // When table wasn't successfully converted then finish conversion.
40
- if (!modelTable) {
41
- // Revert consumed figure so other features can convert it.
42
- conversionApi.consumable.revert(data.viewItem, { name: true, classes: 'table' });
43
- return;
44
- }
45
- conversionApi.convertChildren(data.viewItem, conversionApi.writer.createPositionAt(modelTable, 'end'));
46
- conversionApi.updateConversionResult(modelTable, data);
47
- });
48
- };
49
- }
50
- /**
51
- * View table element to model table element conversion helper.
52
- *
53
- * This conversion helper converts the table element as well as table rows.
54
- *
55
- * @returns Conversion helper.
56
- */
57
- export default function upcastTable() {
58
- return (dispatcher) => {
59
- dispatcher.on('element:table', (evt, data, conversionApi) => {
60
- const viewTable = data.viewItem;
61
- // When element was already consumed then skip it.
62
- if (!conversionApi.consumable.test(viewTable, { name: true })) {
63
- return;
64
- }
65
- const { rows, headingRows, headingColumns } = scanTable(viewTable);
66
- // Only set attributes if values is greater then 0.
67
- const attributes = {};
68
- if (headingColumns) {
69
- attributes.headingColumns = headingColumns;
70
- }
71
- if (headingRows) {
72
- attributes.headingRows = headingRows;
73
- }
74
- const table = conversionApi.writer.createElement('table', attributes);
75
- if (!conversionApi.safeInsert(table, data.modelCursor)) {
76
- return;
77
- }
78
- conversionApi.consumable.consume(viewTable, { name: true });
79
- // Upcast table rows in proper order (heading rows first).
80
- rows.forEach(row => conversionApi.convertItem(row, conversionApi.writer.createPositionAt(table, 'end')));
81
- // Convert everything else.
82
- conversionApi.convertChildren(viewTable, conversionApi.writer.createPositionAt(table, 'end'));
83
- // Create one row and one table cell for empty table.
84
- if (table.isEmpty) {
85
- const row = conversionApi.writer.createElement('tableRow');
86
- conversionApi.writer.insert(row, conversionApi.writer.createPositionAt(table, 'end'));
87
- createEmptyTableCell(conversionApi.writer, conversionApi.writer.createPositionAt(row, 'end'));
88
- }
89
- conversionApi.updateConversionResult(table, data);
90
- });
91
- };
92
- }
93
- /**
94
- * A conversion helper that skips empty <tr> elements from upcasting at the beginning of the table.
95
- *
96
- * An empty row is considered a table model error but when handling clipboard data there could be rows that contain only row-spanned cells
97
- * and empty TR-s are used to maintain the table structure (also {@link module:table/tablewalker~TableWalker} assumes that there are only
98
- * rows that have related `tableRow` elements).
99
- *
100
- * *Note:* Only the first empty rows are removed because they have no meaning and it solves the issue
101
- * of an improper table with all empty rows.
102
- *
103
- * @returns Conversion helper.
104
- */
105
- export function skipEmptyTableRow() {
106
- return (dispatcher) => {
107
- dispatcher.on('element:tr', (evt, data) => {
108
- if (data.viewItem.isEmpty && data.modelCursor.index == 0) {
109
- evt.stop();
110
- }
111
- }, { priority: 'high' });
112
- };
113
- }
114
- /**
115
- * A converter that ensures an empty paragraph is inserted in a table cell if no other content was converted.
116
- *
117
- * @returns Conversion helper.
118
- */
119
- export function ensureParagraphInTableCell(elementName) {
120
- return (dispatcher) => {
121
- dispatcher.on(`element:${elementName}`, (evt, data, { writer }) => {
122
- // The default converter will create a model range on converted table cell.
123
- if (!data.modelRange) {
124
- return;
125
- }
126
- const tableCell = data.modelRange.start.nodeAfter;
127
- const modelCursor = writer.createPositionAt(tableCell, 0);
128
- // Ensure a paragraph in the model for empty table cells for converted table cells.
129
- if (data.viewItem.isEmpty) {
130
- writer.insertElement('paragraph', modelCursor);
131
- return;
132
- }
133
- const childNodes = Array.from(tableCell.getChildren());
134
- // In case there are only markers inside the table cell then move them to the paragraph.
135
- if (childNodes.every(node => node.is('element', '$marker'))) {
136
- const paragraph = writer.createElement('paragraph');
137
- writer.insert(paragraph, writer.createPositionAt(tableCell, 0));
138
- for (const node of childNodes) {
139
- writer.move(writer.createRangeOn(node), writer.createPositionAt(paragraph, 'end'));
140
- }
141
- }
142
- }, { priority: 'low' });
143
- };
144
- }
145
- /**
146
- * Get view `<table>` element from the view widget (`<figure>`).
147
- */
148
- function getViewTableFromFigure(figureView) {
149
- for (const figureChild of figureView.getChildren()) {
150
- if (figureChild.is('element', 'table')) {
151
- return figureChild;
152
- }
153
- }
154
- }
155
- /**
156
- * Scans table rows and extracts required metadata from the table:
157
- *
158
- * headingRows - The number of rows that go as table headers.
159
- * headingColumns - The maximum number of row headings.
160
- * rows - Sorted `<tr>` elements as they should go into the model - ie. if `<thead>` is inserted after `<tbody>` in the view.
161
- */
162
- function scanTable(viewTable) {
163
- let headingRows = 0;
164
- let headingColumns = undefined;
165
- // The `<tbody>` and `<thead>` sections in the DOM do not have to be in order `<thead>` -> `<tbody>` and there might be more than one
166
- // of them.
167
- // As the model does not have these sections, rows from different sections must be sorted.
168
- // For example, below is a valid HTML table:
169
- //
170
- // <table>
171
- // <tbody><tr><td>2</td></tr></tbody>
172
- // <thead><tr><td>1</td></tr></thead>
173
- // <tbody><tr><td>3</td></tr></tbody>
174
- // </table>
175
- //
176
- // But browsers will render rows in order as: 1 as the heading and 2 and 3 as the body.
177
- const headRows = [];
178
- const bodyRows = [];
179
- // Currently the editor does not support more then one <thead> section.
180
- // Only the first <thead> from the view will be used as a heading row and the others will be converted to body rows.
181
- let firstTheadElement;
182
- for (const tableChild of Array.from(viewTable.getChildren())) {
183
- // Only `<thead>`, `<tbody>` & `<tfoot>` from allowed table children can have `<tr>`s.
184
- // The else is for future purposes (mainly `<caption>`).
185
- if (tableChild.name !== 'tbody' && tableChild.name !== 'thead' && tableChild.name !== 'tfoot') {
186
- continue;
187
- }
188
- // Save the first `<thead>` in the table as table header - all other ones will be converted to table body rows.
189
- if (tableChild.name === 'thead' && !firstTheadElement) {
190
- firstTheadElement = tableChild;
191
- }
192
- // There might be some extra empty text nodes between the `<tr>`s.
193
- // Make sure further code operates on `tr`s only. (#145)
194
- const trs = Array.from(tableChild.getChildren()).filter((el) => el.is('element', 'tr'));
195
- for (const tr of trs) {
196
- // This <tr> is a child of a first <thead> element.
197
- if ((firstTheadElement && tableChild === firstTheadElement) ||
198
- (tableChild.name === 'tbody' &&
199
- Array.from(tr.getChildren()).length &&
200
- Array.from(tr.getChildren()).every(e => e.is('element', 'th')))) {
201
- headingRows++;
202
- headRows.push(tr);
203
- }
204
- else {
205
- bodyRows.push(tr);
206
- // For other rows check how many column headings this row has.
207
- const headingCols = scanRowForHeadingColumns(tr);
208
- if (!headingColumns || headingCols < headingColumns) {
209
- headingColumns = headingCols;
210
- }
211
- }
212
- }
213
- }
214
- return {
215
- headingRows,
216
- headingColumns: headingColumns || 0,
217
- rows: [...headRows, ...bodyRows]
218
- };
219
- }
220
- /**
221
- * Scans a `<tr>` element and its children for metadata:
222
- * - For heading row:
223
- * - Adds this row to either the heading or the body rows.
224
- * - Updates the number of heading rows.
225
- * - For body rows:
226
- * - Calculates the number of column headings.
227
- */
228
- function scanRowForHeadingColumns(tr) {
229
- let headingColumns = 0;
230
- let index = 0;
231
- // Filter out empty text nodes from tr children.
232
- const children = Array.from(tr.getChildren())
233
- .filter(child => child.name === 'th' || child.name === 'td');
234
- // Count starting adjacent <th> elements of a <tr>.
235
- while (index < children.length && children[index].name === 'th') {
236
- const th = children[index];
237
- // Adjust columns calculation by the number of spanned columns.
238
- const colspan = parseInt(th.getAttribute('colspan') || '1');
239
- headingColumns = headingColumns + colspan;
240
- index++;
241
- }
242
- return headingColumns;
243
- }
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
+ import { createEmptyTableCell } from '../utils/common.js';
6
+ import { first } from 'ckeditor5/src/utils.js';
7
+ /**
8
+ * Returns a function that converts the table view representation:
9
+ *
10
+ * ```xml
11
+ * <figure class="table"><table>...</table></figure>
12
+ * ```
13
+ *
14
+ * to the model representation:
15
+ *
16
+ * ```xml
17
+ * <table></table>
18
+ * ```
19
+ */
20
+ export function upcastTableFigure() {
21
+ return (dispatcher) => {
22
+ dispatcher.on('element:figure', (evt, data, conversionApi) => {
23
+ // Do not convert if this is not a "table figure".
24
+ if (!conversionApi.consumable.test(data.viewItem, { name: true, classes: 'table' })) {
25
+ return;
26
+ }
27
+ // Find a table element inside the figure element.
28
+ const viewTable = getViewTableFromFigure(data.viewItem);
29
+ // Do not convert if table element is absent or was already converted.
30
+ if (!viewTable || !conversionApi.consumable.test(viewTable, { name: true })) {
31
+ return;
32
+ }
33
+ // Consume the figure to prevent other converters from processing it again.
34
+ conversionApi.consumable.consume(data.viewItem, { name: true, classes: 'table' });
35
+ // Convert view table to model table.
36
+ const conversionResult = conversionApi.convertItem(viewTable, data.modelCursor);
37
+ // Get table element from conversion result.
38
+ const modelTable = first(conversionResult.modelRange.getItems());
39
+ // When table wasn't successfully converted then finish conversion.
40
+ if (!modelTable) {
41
+ // Revert consumed figure so other features can convert it.
42
+ conversionApi.consumable.revert(data.viewItem, { name: true, classes: 'table' });
43
+ return;
44
+ }
45
+ conversionApi.convertChildren(data.viewItem, conversionApi.writer.createPositionAt(modelTable, 'end'));
46
+ conversionApi.updateConversionResult(modelTable, data);
47
+ });
48
+ };
49
+ }
50
+ /**
51
+ * View table element to model table element conversion helper.
52
+ *
53
+ * This conversion helper converts the table element as well as table rows.
54
+ *
55
+ * @returns Conversion helper.
56
+ */
57
+ export default function upcastTable() {
58
+ return (dispatcher) => {
59
+ dispatcher.on('element:table', (evt, data, conversionApi) => {
60
+ const viewTable = data.viewItem;
61
+ // When element was already consumed then skip it.
62
+ if (!conversionApi.consumable.test(viewTable, { name: true })) {
63
+ return;
64
+ }
65
+ const { rows, headingRows, headingColumns } = scanTable(viewTable);
66
+ // Only set attributes if values is greater then 0.
67
+ const attributes = {};
68
+ if (headingColumns) {
69
+ attributes.headingColumns = headingColumns;
70
+ }
71
+ if (headingRows) {
72
+ attributes.headingRows = headingRows;
73
+ }
74
+ const table = conversionApi.writer.createElement('table', attributes);
75
+ if (!conversionApi.safeInsert(table, data.modelCursor)) {
76
+ return;
77
+ }
78
+ conversionApi.consumable.consume(viewTable, { name: true });
79
+ // Upcast table rows in proper order (heading rows first).
80
+ rows.forEach(row => conversionApi.convertItem(row, conversionApi.writer.createPositionAt(table, 'end')));
81
+ // Convert everything else.
82
+ conversionApi.convertChildren(viewTable, conversionApi.writer.createPositionAt(table, 'end'));
83
+ // Create one row and one table cell for empty table.
84
+ if (table.isEmpty) {
85
+ const row = conversionApi.writer.createElement('tableRow');
86
+ conversionApi.writer.insert(row, conversionApi.writer.createPositionAt(table, 'end'));
87
+ createEmptyTableCell(conversionApi.writer, conversionApi.writer.createPositionAt(row, 'end'));
88
+ }
89
+ conversionApi.updateConversionResult(table, data);
90
+ });
91
+ };
92
+ }
93
+ /**
94
+ * A conversion helper that skips empty <tr> elements from upcasting at the beginning of the table.
95
+ *
96
+ * An empty row is considered a table model error but when handling clipboard data there could be rows that contain only row-spanned cells
97
+ * and empty TR-s are used to maintain the table structure (also {@link module:table/tablewalker~TableWalker} assumes that there are only
98
+ * rows that have related `tableRow` elements).
99
+ *
100
+ * *Note:* Only the first empty rows are removed because they have no meaning and it solves the issue
101
+ * of an improper table with all empty rows.
102
+ *
103
+ * @returns Conversion helper.
104
+ */
105
+ export function skipEmptyTableRow() {
106
+ return (dispatcher) => {
107
+ dispatcher.on('element:tr', (evt, data) => {
108
+ if (data.viewItem.isEmpty && data.modelCursor.index == 0) {
109
+ evt.stop();
110
+ }
111
+ }, { priority: 'high' });
112
+ };
113
+ }
114
+ /**
115
+ * A converter that ensures an empty paragraph is inserted in a table cell if no other content was converted.
116
+ *
117
+ * @returns Conversion helper.
118
+ */
119
+ export function ensureParagraphInTableCell(elementName) {
120
+ return (dispatcher) => {
121
+ dispatcher.on(`element:${elementName}`, (evt, data, { writer }) => {
122
+ // The default converter will create a model range on converted table cell.
123
+ if (!data.modelRange) {
124
+ return;
125
+ }
126
+ const tableCell = data.modelRange.start.nodeAfter;
127
+ const modelCursor = writer.createPositionAt(tableCell, 0);
128
+ // Ensure a paragraph in the model for empty table cells for converted table cells.
129
+ if (data.viewItem.isEmpty) {
130
+ writer.insertElement('paragraph', modelCursor);
131
+ return;
132
+ }
133
+ const childNodes = Array.from(tableCell.getChildren());
134
+ // In case there are only markers inside the table cell then move them to the paragraph.
135
+ if (childNodes.every(node => node.is('element', '$marker'))) {
136
+ const paragraph = writer.createElement('paragraph');
137
+ writer.insert(paragraph, writer.createPositionAt(tableCell, 0));
138
+ for (const node of childNodes) {
139
+ writer.move(writer.createRangeOn(node), writer.createPositionAt(paragraph, 'end'));
140
+ }
141
+ }
142
+ }, { priority: 'low' });
143
+ };
144
+ }
145
+ /**
146
+ * Get view `<table>` element from the view widget (`<figure>`).
147
+ */
148
+ function getViewTableFromFigure(figureView) {
149
+ for (const figureChild of figureView.getChildren()) {
150
+ if (figureChild.is('element', 'table')) {
151
+ return figureChild;
152
+ }
153
+ }
154
+ }
155
+ /**
156
+ * Scans table rows and extracts required metadata from the table:
157
+ *
158
+ * headingRows - The number of rows that go as table headers.
159
+ * headingColumns - The maximum number of row headings.
160
+ * rows - Sorted `<tr>` elements as they should go into the model - ie. if `<thead>` is inserted after `<tbody>` in the view.
161
+ */
162
+ function scanTable(viewTable) {
163
+ let headingRows = 0;
164
+ let headingColumns = undefined;
165
+ // The `<tbody>` and `<thead>` sections in the DOM do not have to be in order `<thead>` -> `<tbody>` and there might be more than one
166
+ // of them.
167
+ // As the model does not have these sections, rows from different sections must be sorted.
168
+ // For example, below is a valid HTML table:
169
+ //
170
+ // <table>
171
+ // <tbody><tr><td>2</td></tr></tbody>
172
+ // <thead><tr><td>1</td></tr></thead>
173
+ // <tbody><tr><td>3</td></tr></tbody>
174
+ // </table>
175
+ //
176
+ // But browsers will render rows in order as: 1 as the heading and 2 and 3 as the body.
177
+ const headRows = [];
178
+ const bodyRows = [];
179
+ // Currently the editor does not support more then one <thead> section.
180
+ // Only the first <thead> from the view will be used as a heading row and the others will be converted to body rows.
181
+ let firstTheadElement;
182
+ for (const tableChild of Array.from(viewTable.getChildren())) {
183
+ // Only `<thead>`, `<tbody>` & `<tfoot>` from allowed table children can have `<tr>`s.
184
+ // The else is for future purposes (mainly `<caption>`).
185
+ if (tableChild.name !== 'tbody' && tableChild.name !== 'thead' && tableChild.name !== 'tfoot') {
186
+ continue;
187
+ }
188
+ // Save the first `<thead>` in the table as table header - all other ones will be converted to table body rows.
189
+ if (tableChild.name === 'thead' && !firstTheadElement) {
190
+ firstTheadElement = tableChild;
191
+ }
192
+ // There might be some extra empty text nodes between the `<tr>`s.
193
+ // Make sure further code operates on `tr`s only. (#145)
194
+ const trs = Array.from(tableChild.getChildren()).filter((el) => el.is('element', 'tr'));
195
+ for (const tr of trs) {
196
+ // This <tr> is a child of a first <thead> element.
197
+ if ((firstTheadElement && tableChild === firstTheadElement) ||
198
+ (tableChild.name === 'tbody' &&
199
+ Array.from(tr.getChildren()).length &&
200
+ Array.from(tr.getChildren()).every(e => e.is('element', 'th')))) {
201
+ headingRows++;
202
+ headRows.push(tr);
203
+ }
204
+ else {
205
+ bodyRows.push(tr);
206
+ // For other rows check how many column headings this row has.
207
+ const headingCols = scanRowForHeadingColumns(tr);
208
+ if (!headingColumns || headingCols < headingColumns) {
209
+ headingColumns = headingCols;
210
+ }
211
+ }
212
+ }
213
+ }
214
+ return {
215
+ headingRows,
216
+ headingColumns: headingColumns || 0,
217
+ rows: [...headRows, ...bodyRows]
218
+ };
219
+ }
220
+ /**
221
+ * Scans a `<tr>` element and its children for metadata:
222
+ * - For heading row:
223
+ * - Adds this row to either the heading or the body rows.
224
+ * - Updates the number of heading rows.
225
+ * - For body rows:
226
+ * - Calculates the number of column headings.
227
+ */
228
+ function scanRowForHeadingColumns(tr) {
229
+ let headingColumns = 0;
230
+ let index = 0;
231
+ // Filter out empty text nodes from tr children.
232
+ const children = Array.from(tr.getChildren())
233
+ .filter(child => child.name === 'th' || child.name === 'td');
234
+ // Count starting adjacent <th> elements of a <tr>.
235
+ while (index < children.length && children[index].name === 'th') {
236
+ const th = children[index];
237
+ // Adjust columns calculation by the number of spanned columns.
238
+ const colspan = parseInt(th.getAttribute('colspan') || '1');
239
+ headingColumns = headingColumns + colspan;
240
+ index++;
241
+ }
242
+ return headingColumns;
243
+ }
package/src/index.d.ts CHANGED
@@ -1,60 +1,60 @@
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
7
- */
8
- export { default as PlainTableOutput } from './plaintableoutput';
9
- export { default as Table } from './table';
10
- export { default as TableEditing } from './tableediting';
11
- export { default as TableUI } from './tableui';
12
- export { default as TableToolbar } from './tabletoolbar';
13
- export { default as TableCellProperties } from './tablecellproperties';
14
- export { default as TableCellPropertiesEditing } from './tablecellproperties/tablecellpropertiesediting';
15
- export { default as TableCellPropertiesUI } from './tablecellproperties/tablecellpropertiesui';
16
- export { default as TableCellWidthEditing } from './tablecellwidth/tablecellwidthediting';
17
- export { default as TableProperties } from './tableproperties';
18
- export { default as TablePropertiesEditing } from './tableproperties/tablepropertiesediting';
19
- export { default as TablePropertiesUI } from './tableproperties/tablepropertiesui';
20
- export { default as TableCaption } from './tablecaption';
21
- export { default as TableCaptionEditing } from './tablecaption/tablecaptionediting';
22
- export { default as TableCaptionUI } from './tablecaption/tablecaptionui';
23
- export { default as TableClipboard } from './tableclipboard';
24
- export { default as TableMouse } from './tablemouse';
25
- export { default as TableKeyboard } from './tablekeyboard';
26
- export { default as TableSelection } from './tableselection';
27
- export { default as TableUtils } from './tableutils';
28
- export { default as TableColumnResize } from './tablecolumnresize';
29
- export { default as TableColumnResizeEditing } from './tablecolumnresize/tablecolumnresizeediting';
30
- export type { TableConfig } from './tableconfig';
31
- export type { default as InsertColumnCommand } from './commands/insertcolumncommand';
32
- export type { default as InsertRowCommand } from './commands/insertrowcommand';
33
- export type { default as InsertTableCommand } from './commands/inserttablecommand';
34
- export type { default as MergeCellCommand } from './commands/mergecellcommand';
35
- export type { default as MergeCellsCommand } from './commands/mergecellscommand';
36
- export type { default as RemoveColumnCommand } from './commands/removecolumncommand';
37
- export type { default as RemoveRowCommand } from './commands/removerowcommand';
38
- export type { default as SelectColumnCommand } from './commands/selectcolumncommand';
39
- export type { default as SelectRowCommand } from './commands/selectrowcommand';
40
- export type { default as SetHeaderColumnCommand } from './commands/setheadercolumncommand';
41
- export type { default as SetHeaderRowCommand } from './commands/setheaderrowcommand';
42
- export type { default as SplitCellCommand } from './commands/splitcellcommand';
43
- export type { default as ToggleTableCaptionCommand } from './tablecaption/toggletablecaptioncommand';
44
- export type { default as TableCellBackgroundColorCommand } from './tablecellproperties/commands/tablecellbackgroundcolorcommand';
45
- export type { default as TableCellBorderColorCommand } from './tablecellproperties/commands/tablecellbordercolorcommand';
46
- export type { default as TableCellBorderStyleCommand } from './tablecellproperties/commands/tablecellborderstylecommand';
47
- export type { default as TableCellBorderWidthCommand } from './tablecellproperties/commands/tablecellborderwidthcommand';
48
- export type { default as TableCellHeightCommand } from './tablecellproperties/commands/tablecellheightcommand';
49
- export type { default as TableCellHorizontalAlignmentCommand } from './tablecellproperties/commands/tablecellhorizontalalignmentcommand';
50
- export type { default as TableCellPaddingCommand } from './tablecellproperties/commands/tablecellpaddingcommand';
51
- export type { default as TableCellVerticalAlignmentCommand } from './tablecellproperties/commands/tablecellverticalalignmentcommand';
52
- export type { default as TableCellWidthCommand } from './tablecellwidth/commands/tablecellwidthcommand';
53
- export type { default as TableAlignmentCommand } from './tableproperties/commands/tablealignmentcommand';
54
- export type { default as TableBackgroundColorCommand } from './tableproperties/commands/tablebackgroundcolorcommand';
55
- export type { default as TableBorderColorCommand } from './tableproperties/commands/tablebordercolorcommand';
56
- export type { default as TableBorderStyleCommand } from './tableproperties/commands/tableborderstylecommand';
57
- export type { default as TableBorderWidthCommand } from './tableproperties/commands/tableborderwidthcommand';
58
- export type { default as TableHeightCommand } from './tableproperties/commands/tableheightcommand';
59
- export type { default as TableWidthCommand } from './tableproperties/commands/tablewidthcommand';
60
- import './augmentation';
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
7
+ */
8
+ export { default as PlainTableOutput } from './plaintableoutput.js';
9
+ export { default as Table } from './table.js';
10
+ export { default as TableEditing } from './tableediting.js';
11
+ export { default as TableUI } from './tableui.js';
12
+ export { default as TableToolbar } from './tabletoolbar.js';
13
+ export { default as TableCellProperties } from './tablecellproperties.js';
14
+ export { default as TableCellPropertiesEditing } from './tablecellproperties/tablecellpropertiesediting.js';
15
+ export { default as TableCellPropertiesUI } from './tablecellproperties/tablecellpropertiesui.js';
16
+ export { default as TableCellWidthEditing } from './tablecellwidth/tablecellwidthediting.js';
17
+ export { default as TableProperties } from './tableproperties.js';
18
+ export { default as TablePropertiesEditing } from './tableproperties/tablepropertiesediting.js';
19
+ export { default as TablePropertiesUI } from './tableproperties/tablepropertiesui.js';
20
+ export { default as TableCaption } from './tablecaption.js';
21
+ export { default as TableCaptionEditing } from './tablecaption/tablecaptionediting.js';
22
+ export { default as TableCaptionUI } from './tablecaption/tablecaptionui.js';
23
+ export { default as TableClipboard } from './tableclipboard.js';
24
+ export { default as TableMouse } from './tablemouse.js';
25
+ export { default as TableKeyboard } from './tablekeyboard.js';
26
+ export { default as TableSelection } from './tableselection.js';
27
+ export { default as TableUtils } from './tableutils.js';
28
+ export { default as TableColumnResize } from './tablecolumnresize.js';
29
+ export { default as TableColumnResizeEditing } from './tablecolumnresize/tablecolumnresizeediting.js';
30
+ export type { TableConfig } from './tableconfig.js';
31
+ export type { default as InsertColumnCommand } from './commands/insertcolumncommand.js';
32
+ export type { default as InsertRowCommand } from './commands/insertrowcommand.js';
33
+ export type { default as InsertTableCommand } from './commands/inserttablecommand.js';
34
+ export type { default as MergeCellCommand } from './commands/mergecellcommand.js';
35
+ export type { default as MergeCellsCommand } from './commands/mergecellscommand.js';
36
+ export type { default as RemoveColumnCommand } from './commands/removecolumncommand.js';
37
+ export type { default as RemoveRowCommand } from './commands/removerowcommand.js';
38
+ export type { default as SelectColumnCommand } from './commands/selectcolumncommand.js';
39
+ export type { default as SelectRowCommand } from './commands/selectrowcommand.js';
40
+ export type { default as SetHeaderColumnCommand } from './commands/setheadercolumncommand.js';
41
+ export type { default as SetHeaderRowCommand } from './commands/setheaderrowcommand.js';
42
+ export type { default as SplitCellCommand } from './commands/splitcellcommand.js';
43
+ export type { default as ToggleTableCaptionCommand } from './tablecaption/toggletablecaptioncommand.js';
44
+ export type { default as TableCellBackgroundColorCommand } from './tablecellproperties/commands/tablecellbackgroundcolorcommand.js';
45
+ export type { default as TableCellBorderColorCommand } from './tablecellproperties/commands/tablecellbordercolorcommand.js';
46
+ export type { default as TableCellBorderStyleCommand } from './tablecellproperties/commands/tablecellborderstylecommand.js';
47
+ export type { default as TableCellBorderWidthCommand } from './tablecellproperties/commands/tablecellborderwidthcommand.js';
48
+ export type { default as TableCellHeightCommand } from './tablecellproperties/commands/tablecellheightcommand.js';
49
+ export type { default as TableCellHorizontalAlignmentCommand } from './tablecellproperties/commands/tablecellhorizontalalignmentcommand.js';
50
+ export type { default as TableCellPaddingCommand } from './tablecellproperties/commands/tablecellpaddingcommand.js';
51
+ export type { default as TableCellVerticalAlignmentCommand } from './tablecellproperties/commands/tablecellverticalalignmentcommand.js';
52
+ export type { default as TableCellWidthCommand } from './tablecellwidth/commands/tablecellwidthcommand.js';
53
+ export type { default as TableAlignmentCommand } from './tableproperties/commands/tablealignmentcommand.js';
54
+ export type { default as TableBackgroundColorCommand } from './tableproperties/commands/tablebackgroundcolorcommand.js';
55
+ export type { default as TableBorderColorCommand } from './tableproperties/commands/tablebordercolorcommand.js';
56
+ export type { default as TableBorderStyleCommand } from './tableproperties/commands/tableborderstylecommand.js';
57
+ export type { default as TableBorderWidthCommand } from './tableproperties/commands/tableborderwidthcommand.js';
58
+ export type { default as TableHeightCommand } from './tableproperties/commands/tableheightcommand.js';
59
+ export type { default as TableWidthCommand } from './tableproperties/commands/tablewidthcommand.js';
60
+ import './augmentation.js';