@ckeditor/ckeditor5-table 39.0.1 → 40.0.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 (229) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +3 -3
  3. package/build/table.js +1 -1
  4. package/build/table.js.map +1 -0
  5. package/build/translations/hy.js +1 -0
  6. package/lang/translations/ar.po +1 -0
  7. package/lang/translations/az.po +1 -0
  8. package/lang/translations/bg.po +1 -0
  9. package/lang/translations/bn.po +1 -0
  10. package/lang/translations/ca.po +1 -0
  11. package/lang/translations/cs.po +1 -0
  12. package/lang/translations/da.po +1 -0
  13. package/lang/translations/de-ch.po +1 -0
  14. package/lang/translations/de.po +1 -0
  15. package/lang/translations/el.po +1 -0
  16. package/lang/translations/en-au.po +1 -0
  17. package/lang/translations/en-gb.po +1 -0
  18. package/lang/translations/en.po +1 -0
  19. package/lang/translations/es.po +1 -0
  20. package/lang/translations/et.po +1 -0
  21. package/lang/translations/fa.po +1 -0
  22. package/lang/translations/fi.po +1 -0
  23. package/lang/translations/fr.po +1 -0
  24. package/lang/translations/gl.po +1 -0
  25. package/lang/translations/he.po +1 -0
  26. package/lang/translations/hi.po +1 -0
  27. package/lang/translations/hr.po +1 -0
  28. package/lang/translations/hu.po +1 -0
  29. package/lang/translations/hy.po +262 -0
  30. package/lang/translations/id.po +1 -0
  31. package/lang/translations/it.po +1 -0
  32. package/lang/translations/ja.po +1 -0
  33. package/lang/translations/ko.po +1 -0
  34. package/lang/translations/ku.po +1 -0
  35. package/lang/translations/lt.po +1 -0
  36. package/lang/translations/lv.po +1 -0
  37. package/lang/translations/ms.po +1 -0
  38. package/lang/translations/nb.po +1 -0
  39. package/lang/translations/ne.po +1 -0
  40. package/lang/translations/nl.po +1 -0
  41. package/lang/translations/no.po +1 -0
  42. package/lang/translations/pl.po +1 -0
  43. package/lang/translations/pt-br.po +1 -0
  44. package/lang/translations/pt.po +1 -0
  45. package/lang/translations/ro.po +1 -0
  46. package/lang/translations/ru.po +1 -0
  47. package/lang/translations/sk.po +1 -0
  48. package/lang/translations/sl.po +1 -0
  49. package/lang/translations/sq.po +1 -0
  50. package/lang/translations/sr-latn.po +1 -0
  51. package/lang/translations/sr.po +1 -0
  52. package/lang/translations/sv.po +1 -0
  53. package/lang/translations/th.po +1 -0
  54. package/lang/translations/tk.po +1 -0
  55. package/lang/translations/tr.po +1 -0
  56. package/lang/translations/tt.po +1 -0
  57. package/lang/translations/ug.po +1 -0
  58. package/lang/translations/uk.po +1 -0
  59. package/lang/translations/ur.po +1 -0
  60. package/lang/translations/uz.po +1 -0
  61. package/lang/translations/vi.po +1 -0
  62. package/lang/translations/zh-cn.po +1 -0
  63. package/lang/translations/zh.po +1 -0
  64. package/package.json +2 -6
  65. package/src/augmentation.d.ts +76 -76
  66. package/src/augmentation.js +5 -5
  67. package/src/commands/insertcolumncommand.d.ts +55 -55
  68. package/src/commands/insertcolumncommand.js +67 -67
  69. package/src/commands/insertrowcommand.d.ts +54 -54
  70. package/src/commands/insertrowcommand.js +66 -66
  71. package/src/commands/inserttablecommand.d.ts +44 -44
  72. package/src/commands/inserttablecommand.js +69 -69
  73. package/src/commands/mergecellcommand.d.ts +68 -68
  74. package/src/commands/mergecellcommand.js +198 -198
  75. package/src/commands/mergecellscommand.d.ts +28 -28
  76. package/src/commands/mergecellscommand.js +94 -94
  77. package/src/commands/removecolumncommand.d.ts +29 -29
  78. package/src/commands/removecolumncommand.js +109 -109
  79. package/src/commands/removerowcommand.d.ts +29 -29
  80. package/src/commands/removerowcommand.js +82 -82
  81. package/src/commands/selectcolumncommand.d.ts +33 -33
  82. package/src/commands/selectcolumncommand.js +60 -60
  83. package/src/commands/selectrowcommand.d.ts +33 -33
  84. package/src/commands/selectrowcommand.js +56 -56
  85. package/src/commands/setheadercolumncommand.d.ts +50 -50
  86. package/src/commands/setheadercolumncommand.js +71 -71
  87. package/src/commands/setheaderrowcommand.d.ts +53 -53
  88. package/src/commands/setheaderrowcommand.js +79 -79
  89. package/src/commands/splitcellcommand.d.ts +43 -43
  90. package/src/commands/splitcellcommand.js +54 -54
  91. package/src/converters/downcast.d.ts +63 -63
  92. package/src/converters/downcast.js +146 -146
  93. package/src/converters/table-caption-post-fixer.d.ts +20 -20
  94. package/src/converters/table-caption-post-fixer.js +53 -53
  95. package/src/converters/table-cell-paragraph-post-fixer.d.ts +32 -32
  96. package/src/converters/table-cell-paragraph-post-fixer.js +107 -107
  97. package/src/converters/table-cell-refresh-handler.d.ts +18 -18
  98. package/src/converters/table-cell-refresh-handler.js +45 -45
  99. package/src/converters/table-headings-refresh-handler.d.ts +17 -17
  100. package/src/converters/table-headings-refresh-handler.js +49 -49
  101. package/src/converters/table-layout-post-fixer.d.ts +226 -226
  102. package/src/converters/table-layout-post-fixer.js +367 -367
  103. package/src/converters/tableproperties.d.ts +54 -54
  104. package/src/converters/tableproperties.js +159 -159
  105. package/src/converters/upcasttable.d.ts +49 -49
  106. package/src/converters/upcasttable.js +243 -243
  107. package/src/index.d.ts +60 -60
  108. package/src/index.js +30 -30
  109. package/src/plaintableoutput.d.ts +26 -26
  110. package/src/plaintableoutput.js +123 -123
  111. package/src/table.d.ts +40 -40
  112. package/src/table.js +44 -44
  113. package/src/tablecaption/tablecaptionediting.d.ts +63 -63
  114. package/src/tablecaption/tablecaptionediting.js +122 -122
  115. package/src/tablecaption/tablecaptionui.d.ts +21 -21
  116. package/src/tablecaption/tablecaptionui.js +57 -57
  117. package/src/tablecaption/toggletablecaptioncommand.d.ts +68 -68
  118. package/src/tablecaption/toggletablecaptioncommand.js +104 -104
  119. package/src/tablecaption/utils.d.ts +42 -42
  120. package/src/tablecaption/utils.js +67 -67
  121. package/src/tablecaption.d.ts +24 -24
  122. package/src/tablecaption.js +28 -28
  123. package/src/tablecellproperties/commands/tablecellbackgroundcolorcommand.d.ts +32 -32
  124. package/src/tablecellproperties/commands/tablecellbackgroundcolorcommand.js +30 -30
  125. package/src/tablecellproperties/commands/tablecellbordercolorcommand.d.ts +37 -37
  126. package/src/tablecellproperties/commands/tablecellbordercolorcommand.js +44 -44
  127. package/src/tablecellproperties/commands/tablecellborderstylecommand.d.ts +37 -37
  128. package/src/tablecellproperties/commands/tablecellborderstylecommand.js +44 -44
  129. package/src/tablecellproperties/commands/tablecellborderwidthcommand.d.ts +51 -51
  130. package/src/tablecellproperties/commands/tablecellborderwidthcommand.js +64 -64
  131. package/src/tablecellproperties/commands/tablecellheightcommand.d.ts +46 -46
  132. package/src/tablecellproperties/commands/tablecellheightcommand.js +51 -51
  133. package/src/tablecellproperties/commands/tablecellhorizontalalignmentcommand.d.ts +32 -32
  134. package/src/tablecellproperties/commands/tablecellhorizontalalignmentcommand.js +30 -30
  135. package/src/tablecellproperties/commands/tablecellpaddingcommand.d.ts +51 -51
  136. package/src/tablecellproperties/commands/tablecellpaddingcommand.js +64 -64
  137. package/src/tablecellproperties/commands/tablecellpropertycommand.d.ts +62 -62
  138. package/src/tablecellproperties/commands/tablecellpropertycommand.js +92 -92
  139. package/src/tablecellproperties/commands/tablecellverticalalignmentcommand.d.ts +40 -40
  140. package/src/tablecellproperties/commands/tablecellverticalalignmentcommand.js +38 -38
  141. package/src/tablecellproperties/tablecellpropertiesediting.d.ts +43 -43
  142. package/src/tablecellproperties/tablecellpropertiesediting.js +241 -241
  143. package/src/tablecellproperties/tablecellpropertiesui.d.ts +112 -112
  144. package/src/tablecellproperties/tablecellpropertiesui.js +330 -330
  145. package/src/tablecellproperties/ui/tablecellpropertiesview.d.ts +228 -228
  146. package/src/tablecellproperties/ui/tablecellpropertiesview.js +548 -539
  147. package/src/tablecellproperties.d.ts +30 -30
  148. package/src/tablecellproperties.js +34 -34
  149. package/src/tablecellwidth/commands/tablecellwidthcommand.d.ts +46 -46
  150. package/src/tablecellwidth/commands/tablecellwidthcommand.js +51 -51
  151. package/src/tablecellwidth/tablecellwidthediting.d.ts +29 -29
  152. package/src/tablecellwidth/tablecellwidthediting.js +45 -45
  153. package/src/tableclipboard.d.ts +65 -65
  154. package/src/tableclipboard.js +450 -450
  155. package/src/tablecolumnresize/constants.d.ts +20 -20
  156. package/src/tablecolumnresize/constants.js +20 -20
  157. package/src/tablecolumnresize/converters.d.ts +18 -18
  158. package/src/tablecolumnresize/converters.js +46 -45
  159. package/src/tablecolumnresize/tablecolumnresizeediting.d.ts +139 -139
  160. package/src/tablecolumnresize/tablecolumnresizeediting.js +583 -571
  161. package/src/tablecolumnresize/tablewidthscommand.d.ts +38 -38
  162. package/src/tablecolumnresize/tablewidthscommand.js +61 -61
  163. package/src/tablecolumnresize/utils.d.ts +148 -141
  164. package/src/tablecolumnresize/utils.js +358 -330
  165. package/src/tablecolumnresize.d.ts +26 -26
  166. package/src/tablecolumnresize.js +30 -30
  167. package/src/tableconfig.d.ts +343 -343
  168. package/src/tableconfig.js +5 -5
  169. package/src/tableediting.d.ts +98 -98
  170. package/src/tableediting.js +191 -191
  171. package/src/tablekeyboard.d.ts +68 -68
  172. package/src/tablekeyboard.js +279 -279
  173. package/src/tablemouse/mouseeventsobserver.d.ts +62 -62
  174. package/src/tablemouse/mouseeventsobserver.js +35 -35
  175. package/src/tablemouse.d.ts +48 -48
  176. package/src/tablemouse.js +172 -172
  177. package/src/tableproperties/commands/tablealignmentcommand.d.ts +32 -32
  178. package/src/tableproperties/commands/tablealignmentcommand.js +30 -30
  179. package/src/tableproperties/commands/tablebackgroundcolorcommand.d.ts +32 -32
  180. package/src/tableproperties/commands/tablebackgroundcolorcommand.js +30 -30
  181. package/src/tableproperties/commands/tablebordercolorcommand.d.ts +37 -37
  182. package/src/tableproperties/commands/tablebordercolorcommand.js +44 -44
  183. package/src/tableproperties/commands/tableborderstylecommand.d.ts +37 -37
  184. package/src/tableproperties/commands/tableborderstylecommand.js +44 -44
  185. package/src/tableproperties/commands/tableborderwidthcommand.d.ts +51 -51
  186. package/src/tableproperties/commands/tableborderwidthcommand.js +64 -64
  187. package/src/tableproperties/commands/tableheightcommand.d.ts +46 -46
  188. package/src/tableproperties/commands/tableheightcommand.js +54 -54
  189. package/src/tableproperties/commands/tablepropertycommand.d.ts +61 -61
  190. package/src/tableproperties/commands/tablepropertycommand.js +80 -80
  191. package/src/tableproperties/commands/tablewidthcommand.d.ts +46 -46
  192. package/src/tableproperties/commands/tablewidthcommand.js +54 -54
  193. package/src/tableproperties/tablepropertiesediting.d.ts +40 -40
  194. package/src/tableproperties/tablepropertiesediting.js +206 -206
  195. package/src/tableproperties/tablepropertiesui.d.ts +114 -114
  196. package/src/tableproperties/tablepropertiesui.js +321 -321
  197. package/src/tableproperties/ui/tablepropertiesview.d.ts +207 -207
  198. package/src/tableproperties/ui/tablepropertiesview.js +466 -457
  199. package/src/tableproperties.d.ts +30 -30
  200. package/src/tableproperties.js +34 -34
  201. package/src/tableselection.d.ts +107 -107
  202. package/src/tableselection.js +297 -297
  203. package/src/tabletoolbar.d.ts +32 -32
  204. package/src/tabletoolbar.js +57 -57
  205. package/src/tableui.d.ts +53 -53
  206. package/src/tableui.js +309 -309
  207. package/src/tableutils.d.ts +448 -448
  208. package/src/tableutils.js +1055 -1041
  209. package/src/tablewalker.d.ts +362 -323
  210. package/src/tablewalker.js +393 -333
  211. package/src/ui/colorinputview.d.ts +140 -140
  212. package/src/ui/colorinputview.js +271 -265
  213. package/src/ui/formrowview.d.ts +61 -61
  214. package/src/ui/formrowview.js +57 -57
  215. package/src/ui/inserttableview.d.ts +77 -77
  216. package/src/ui/inserttableview.js +169 -169
  217. package/src/utils/common.d.ts +42 -42
  218. package/src/utils/common.js +57 -57
  219. package/src/utils/structure.d.ts +245 -245
  220. package/src/utils/structure.js +426 -426
  221. package/src/utils/table-properties.d.ts +67 -67
  222. package/src/utils/table-properties.js +86 -86
  223. package/src/utils/ui/contextualballoon.d.ts +34 -34
  224. package/src/utils/ui/contextualballoon.js +106 -106
  225. package/src/utils/ui/table-properties.d.ts +195 -195
  226. package/src/utils/ui/table-properties.js +362 -362
  227. package/src/utils/ui/widget.d.ts +16 -16
  228. package/src/utils/ui/widget.js +38 -38
  229. package/theme/tablecolumnresize.css +8 -6
@@ -1,330 +1,358 @@
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 { global } from 'ckeditor5/src/utils';
6
- import { COLUMN_WIDTH_PRECISION, COLUMN_MIN_WIDTH_AS_PERCENTAGE, COLUMN_MIN_WIDTH_IN_PIXELS } from './constants';
7
- /**
8
- * Returns all the inserted or changed table model elements in a given change set. Only the tables
9
- * with 'columnsWidth' attribute are taken into account. The returned set may be empty.
10
- *
11
- * Most notably if an entire table is removed it will not be included in returned set.
12
- *
13
- * @param model The model to collect the affected elements from.
14
- * @returns A set of table model elements.
15
- */
16
- export function getChangedResizedTables(model) {
17
- const affectedTables = new Set();
18
- for (const change of model.document.differ.getChanges()) {
19
- let referencePosition = null;
20
- // Checks if the particular change from the differ is:
21
- // - an insertion or removal of a table, a row or a cell,
22
- // - an attribute change on a table, a row or a cell.
23
- switch (change.type) {
24
- case 'insert':
25
- referencePosition = ['table', 'tableRow', 'tableCell'].includes(change.name) ?
26
- change.position :
27
- null;
28
- break;
29
- case 'remove':
30
- // If the whole table is removed, there's no need to update its column widths (#12201).
31
- referencePosition = ['tableRow', 'tableCell'].includes(change.name) ?
32
- change.position :
33
- null;
34
- break;
35
- case 'attribute':
36
- if (change.range.start.nodeAfter) {
37
- referencePosition = ['table', 'tableRow', 'tableCell'].includes(change.range.start.nodeAfter.name) ?
38
- change.range.start :
39
- null;
40
- }
41
- break;
42
- }
43
- if (!referencePosition) {
44
- continue;
45
- }
46
- const tableNode = (referencePosition.nodeAfter && referencePosition.nodeAfter.is('element', 'table')) ?
47
- referencePosition.nodeAfter : referencePosition.findAncestor('table');
48
- // We iterate over the whole table looking for the nested tables that are also affected.
49
- for (const node of model.createRangeOn(tableNode).getItems()) {
50
- if (!node.is('element', 'table')) {
51
- continue;
52
- }
53
- if (!getColumnGroupElement(node)) {
54
- continue;
55
- }
56
- affectedTables.add(node);
57
- }
58
- }
59
- return affectedTables;
60
- }
61
- /**
62
- * Calculates the percentage of the minimum column width given in pixels for a given table.
63
- *
64
- * @param modelTable A table model element.
65
- * @param editor The editor instance.
66
- * @returns The minimal column width in percentage.
67
- */
68
- export function getColumnMinWidthAsPercentage(modelTable, editor) {
69
- return COLUMN_MIN_WIDTH_IN_PIXELS * 100 / getTableWidthInPixels(modelTable, editor);
70
- }
71
- /**
72
- * Calculates the table width in pixels.
73
- *
74
- * @param modelTable A table model element.
75
- * @param editor The editor instance.
76
- * @returns The width of the table in pixels.
77
- */
78
- export function getTableWidthInPixels(modelTable, editor) {
79
- // It is possible for a table to not have a <tbody> element - see #11878.
80
- const referenceElement = getChildrenViewElement(modelTable, 'tbody', editor) || getChildrenViewElement(modelTable, 'thead', editor);
81
- const domReferenceElement = editor.editing.view.domConverter.mapViewToDom(referenceElement);
82
- return getElementWidthInPixels(domReferenceElement);
83
- }
84
- /**
85
- * Returns the a view element with a given name that is nested directly in a `<table>` element
86
- * related to a given `modelTable`.
87
- *
88
- * @param elementName Name of a view to be looked for, e.g. `'colgroup`', `'thead`'.
89
- * @returns Matched view or `undefined` otherwise.
90
- */
91
- function getChildrenViewElement(modelTable, elementName, editor) {
92
- const viewFigure = editor.editing.mapper.toViewElement(modelTable);
93
- const viewTable = [...viewFigure.getChildren()]
94
- .find((node) => node.is('element', 'table'));
95
- return [...viewTable.getChildren()]
96
- .find((node) => node.is('element', elementName));
97
- }
98
- /**
99
- * Returns the computed width (in pixels) of the DOM element without padding and borders.
100
- *
101
- * @param domElement A DOM element.
102
- * @returns The width of the DOM element in pixels.
103
- */
104
- export function getElementWidthInPixels(domElement) {
105
- const styles = global.window.getComputedStyle(domElement);
106
- // In the 'border-box' box sizing algorithm, the element's width
107
- // already includes the padding and border width (#12335).
108
- if (styles.boxSizing === 'border-box') {
109
- return parseFloat(styles.width) -
110
- parseFloat(styles.paddingLeft) -
111
- parseFloat(styles.paddingRight) -
112
- parseFloat(styles.borderLeftWidth) -
113
- parseFloat(styles.borderRightWidth);
114
- }
115
- else {
116
- return parseFloat(styles.width);
117
- }
118
- }
119
- /**
120
- * Returns the column indexes on the left and right edges of a cell. They differ if the cell spans
121
- * across multiple columns.
122
- *
123
- * @param cell A table cell model element.
124
- * @param tableUtils The Table Utils plugin instance.
125
- * @returns An object containing the indexes of the left and right edges of the cell.
126
- */
127
- export function getColumnEdgesIndexes(cell, tableUtils) {
128
- const cellColumnIndex = tableUtils.getCellLocation(cell).column;
129
- const cellWidth = cell.getAttribute('colspan') || 1;
130
- return {
131
- leftEdge: cellColumnIndex,
132
- rightEdge: cellColumnIndex + cellWidth - 1
133
- };
134
- }
135
- /**
136
- * Rounds the provided value to a fixed-point number with defined number of digits after the decimal point.
137
- *
138
- * @param value A number to be rounded.
139
- * @returns The rounded number.
140
- */
141
- export function toPrecision(value) {
142
- const multiplier = Math.pow(10, COLUMN_WIDTH_PRECISION);
143
- const number = typeof value === 'number' ? value : parseFloat(value);
144
- return Math.round(number * multiplier) / multiplier;
145
- }
146
- /**
147
- * Clamps the number within the inclusive lower (min) and upper (max) bounds. Returned number is rounded using the
148
- * {@link ~toPrecision `toPrecision()`} function.
149
- *
150
- * @param number A number to be clamped.
151
- * @param min A lower bound.
152
- * @param max An upper bound.
153
- * @returns The clamped number.
154
- */
155
- export function clamp(number, min, max) {
156
- if (number <= min) {
157
- return toPrecision(min);
158
- }
159
- if (number >= max) {
160
- return toPrecision(max);
161
- }
162
- return toPrecision(number);
163
- }
164
- /**
165
- * Creates an array with defined length and fills all elements with defined value.
166
- *
167
- * @param length The length of the array.
168
- * @param value The value to fill the array with.
169
- * @returns An array with defined length and filled with defined value.
170
- */
171
- export function createFilledArray(length, value) {
172
- return Array(length).fill(value);
173
- }
174
- /**
175
- * Sums all array values that can be parsed to a float.
176
- *
177
- * @param array An array of numbers.
178
- * @returns The sum of all array values.
179
- */
180
- export function sumArray(array) {
181
- return array
182
- .map(value => typeof value === 'number' ? value : parseFloat(value))
183
- .filter(value => !Number.isNaN(value))
184
- .reduce((result, item) => result + item, 0);
185
- }
186
- /**
187
- * Makes sure that the sum of the widths from all columns is 100%. If the sum of all the widths is not equal 100%, all the widths are
188
- * changed proportionally so that they all sum back to 100%. If there are columns without specified width, the amount remaining
189
- * after assigning the known widths will be distributed equally between them.
190
- *
191
- * Currently, only widths provided as percentage values are supported.
192
- *
193
- * @param columnWidths An array of column widths.
194
- * @returns An array of column widths guaranteed to sum up to 100%.
195
- */
196
- export function normalizeColumnWidths(columnWidths) {
197
- const widths = columnWidths.map(width => {
198
- // Possible values are 'auto' or string ending with '%'
199
- if (width === 'auto') {
200
- return width;
201
- }
202
- return parseFloat(width.replace('%', ''));
203
- });
204
- let normalizedWidths = calculateMissingColumnWidths(widths);
205
- const totalWidth = sumArray(normalizedWidths);
206
- if (totalWidth !== 100) {
207
- normalizedWidths = normalizedWidths
208
- // Adjust all the columns proportionally.
209
- .map(width => toPrecision(width * 100 / totalWidth))
210
- // Due to rounding of numbers it may happen that the sum of the widths of all columns will not be exactly 100%.
211
- // Therefore, the width of the last column is explicitly adjusted (narrowed or expanded), since all the columns
212
- // have been proportionally changed already.
213
- .map((columnWidth, columnIndex, width) => {
214
- const isLastColumn = columnIndex === width.length - 1;
215
- if (!isLastColumn) {
216
- return columnWidth;
217
- }
218
- const totalWidth = sumArray(width);
219
- return toPrecision(columnWidth + 100 - totalWidth);
220
- });
221
- }
222
- return normalizedWidths.map(width => width + '%');
223
- }
224
- /**
225
- * Initializes the column widths by parsing the attribute value and calculating the uninitialized column widths. The special value 'auto'
226
- * indicates that width for the column must be calculated. The width of such uninitialized column is calculated as follows:
227
- * - If there is enough free space in the table for all uninitialized columns to have at least the minimum allowed width for all of them,
228
- * then set this width equally for all uninitialized columns.
229
- * - Otherwise, just set the minimum allowed width for all uninitialized columns. The sum of all column widths will be greater than 100%,
230
- * but then it will be adjusted proportionally to 100% in {@link #normalizeColumnWidths `normalizeColumnWidths()`}.
231
- *
232
- * @param columnWidths An array of column widths.
233
- * @returns An array with 'auto' values replaced with calculated widths.
234
- */
235
- function calculateMissingColumnWidths(columnWidths) {
236
- const numberOfUninitializedColumns = columnWidths.filter(columnWidth => columnWidth === 'auto').length;
237
- if (numberOfUninitializedColumns === 0) {
238
- return columnWidths.map(columnWidth => toPrecision(columnWidth));
239
- }
240
- const totalWidthOfInitializedColumns = sumArray(columnWidths);
241
- const widthForUninitializedColumn = Math.max((100 - totalWidthOfInitializedColumns) / numberOfUninitializedColumns, COLUMN_MIN_WIDTH_AS_PERCENTAGE);
242
- return columnWidths
243
- .map(columnWidth => columnWidth === 'auto' ? widthForUninitializedColumn : columnWidth)
244
- .map(columnWidth => toPrecision(columnWidth));
245
- }
246
- /**
247
- * Calculates the total horizontal space taken by the cell. That includes:
248
- * * width,
249
- * * left and red padding,
250
- * * border width.
251
- *
252
- * @param domCell A DOM cell element.
253
- * @returns Width in pixels without `px` at the end.
254
- */
255
- export function getDomCellOuterWidth(domCell) {
256
- const styles = global.window.getComputedStyle(domCell);
257
- // In the 'border-box' box sizing algorithm, the element's width
258
- // already includes the padding and border width (#12335).
259
- if (styles.boxSizing === 'border-box') {
260
- return parseInt(styles.width);
261
- }
262
- else {
263
- return parseFloat(styles.width) +
264
- parseFloat(styles.paddingLeft) +
265
- parseFloat(styles.paddingRight) +
266
- parseFloat(styles.borderWidth);
267
- }
268
- }
269
- /**
270
- * Updates column elements to match columns widths.
271
- *
272
- * @param columns
273
- * @param tableColumnGroup
274
- * @param normalizedWidths
275
- * @param writer
276
- */
277
- export function updateColumnElements(columns, tableColumnGroup, normalizedWidths, writer) {
278
- for (let i = 0; i < Math.max(normalizedWidths.length, columns.length); i++) {
279
- const column = columns[i];
280
- const columnWidth = normalizedWidths[i];
281
- if (!columnWidth) {
282
- // Number of `<tableColumn>` elements exceeds actual number of columns.
283
- writer.remove(column);
284
- }
285
- else if (!column) {
286
- // There is fewer `<tableColumn>` elements than actual columns.
287
- writer.appendElement('tableColumn', { columnWidth }, tableColumnGroup);
288
- }
289
- else {
290
- // Update column width.
291
- writer.setAttribute('columnWidth', columnWidth, column);
292
- }
293
- }
294
- }
295
- /**
296
- * Returns a 'tableColumnGroup' element from the 'table'.
297
- *
298
- * @internal
299
- * @param element A 'table' or 'tableColumnGroup' element.
300
- * @returns A 'tableColumnGroup' element.
301
- */
302
- export function getColumnGroupElement(element) {
303
- if (element.is('element', 'tableColumnGroup')) {
304
- return element;
305
- }
306
- const children = element.getChildren();
307
- return Array
308
- .from(children)
309
- .find(element => element.is('element', 'tableColumnGroup'));
310
- }
311
- /**
312
- * Returns an array of 'tableColumn' elements.
313
- *
314
- * @internal
315
- * @param element A 'table' or 'tableColumnGroup' element.
316
- * @returns An array of 'tableColumn' elements.
317
- */
318
- export function getTableColumnElements(element) {
319
- return Array.from(getColumnGroupElement(element).getChildren());
320
- }
321
- /**
322
- * Returns an array of table column widths.
323
- *
324
- * @internal
325
- * @param element A 'table' or 'tableColumnGroup' element.
326
- * @returns An array of table column widths.
327
- */
328
- export function getTableColumnsWidths(element) {
329
- return getTableColumnElements(element).map(column => column.getAttribute('columnWidth'));
330
- }
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 { global } from 'ckeditor5/src/utils';
6
+ import { COLUMN_WIDTH_PRECISION, COLUMN_MIN_WIDTH_AS_PERCENTAGE, COLUMN_MIN_WIDTH_IN_PIXELS } from './constants';
7
+ /**
8
+ * Returns all the inserted or changed table model elements in a given change set. Only the tables
9
+ * with 'columnsWidth' attribute are taken into account. The returned set may be empty.
10
+ *
11
+ * Most notably if an entire table is removed it will not be included in returned set.
12
+ *
13
+ * @param model The model to collect the affected elements from.
14
+ * @returns A set of table model elements.
15
+ */
16
+ export function getChangedResizedTables(model) {
17
+ const affectedTables = new Set();
18
+ for (const change of model.document.differ.getChanges()) {
19
+ let referencePosition = null;
20
+ // Checks if the particular change from the differ is:
21
+ // - an insertion or removal of a table, a row or a cell,
22
+ // - an attribute change on a table, a row or a cell.
23
+ switch (change.type) {
24
+ case 'insert':
25
+ referencePosition = ['table', 'tableRow', 'tableCell'].includes(change.name) ?
26
+ change.position :
27
+ null;
28
+ break;
29
+ case 'remove':
30
+ // If the whole table is removed, there's no need to update its column widths (#12201).
31
+ referencePosition = ['tableRow', 'tableCell'].includes(change.name) ?
32
+ change.position :
33
+ null;
34
+ break;
35
+ case 'attribute':
36
+ if (change.range.start.nodeAfter) {
37
+ referencePosition = ['table', 'tableRow', 'tableCell'].includes(change.range.start.nodeAfter.name) ?
38
+ change.range.start :
39
+ null;
40
+ }
41
+ break;
42
+ }
43
+ if (!referencePosition) {
44
+ continue;
45
+ }
46
+ const tableNode = (referencePosition.nodeAfter && referencePosition.nodeAfter.is('element', 'table')) ?
47
+ referencePosition.nodeAfter : referencePosition.findAncestor('table');
48
+ // We iterate over the whole table looking for the nested tables that are also affected.
49
+ for (const node of model.createRangeOn(tableNode).getItems()) {
50
+ if (!node.is('element', 'table')) {
51
+ continue;
52
+ }
53
+ if (!getColumnGroupElement(node)) {
54
+ continue;
55
+ }
56
+ affectedTables.add(node);
57
+ }
58
+ }
59
+ return affectedTables;
60
+ }
61
+ /**
62
+ * Calculates the percentage of the minimum column width given in pixels for a given table.
63
+ *
64
+ * @param modelTable A table model element.
65
+ * @param editor The editor instance.
66
+ * @returns The minimal column width in percentage.
67
+ */
68
+ export function getColumnMinWidthAsPercentage(modelTable, editor) {
69
+ return COLUMN_MIN_WIDTH_IN_PIXELS * 100 / getTableWidthInPixels(modelTable, editor);
70
+ }
71
+ /**
72
+ * Calculates the table width in pixels.
73
+ *
74
+ * @param modelTable A table model element.
75
+ * @param editor The editor instance.
76
+ * @returns The width of the table in pixels.
77
+ */
78
+ export function getTableWidthInPixels(modelTable, editor) {
79
+ // It is possible for a table to not have a <tbody> element - see #11878.
80
+ const referenceElement = getChildrenViewElement(modelTable, 'tbody', editor) || getChildrenViewElement(modelTable, 'thead', editor);
81
+ const domReferenceElement = editor.editing.view.domConverter.mapViewToDom(referenceElement);
82
+ return getElementWidthInPixels(domReferenceElement);
83
+ }
84
+ /**
85
+ * Returns the a view element with a given name that is nested directly in a `<table>` element
86
+ * related to a given `modelTable`.
87
+ *
88
+ * @param elementName Name of a view to be looked for, e.g. `'colgroup`', `'thead`'.
89
+ * @returns Matched view or `undefined` otherwise.
90
+ */
91
+ function getChildrenViewElement(modelTable, elementName, editor) {
92
+ const viewFigure = editor.editing.mapper.toViewElement(modelTable);
93
+ const viewTable = [...viewFigure.getChildren()]
94
+ .find((node) => node.is('element', 'table'));
95
+ return [...viewTable.getChildren()]
96
+ .find((node) => node.is('element', elementName));
97
+ }
98
+ /**
99
+ * Returns the computed width (in pixels) of the DOM element without padding and borders.
100
+ *
101
+ * @param domElement A DOM element.
102
+ * @returns The width of the DOM element in pixels.
103
+ */
104
+ export function getElementWidthInPixels(domElement) {
105
+ const styles = global.window.getComputedStyle(domElement);
106
+ // In the 'border-box' box sizing algorithm, the element's width
107
+ // already includes the padding and border width (#12335).
108
+ if (styles.boxSizing === 'border-box') {
109
+ return parseFloat(styles.width) -
110
+ parseFloat(styles.paddingLeft) -
111
+ parseFloat(styles.paddingRight) -
112
+ parseFloat(styles.borderLeftWidth) -
113
+ parseFloat(styles.borderRightWidth);
114
+ }
115
+ else {
116
+ return parseFloat(styles.width);
117
+ }
118
+ }
119
+ /**
120
+ * Returns the column indexes on the left and right edges of a cell. They differ if the cell spans
121
+ * across multiple columns.
122
+ *
123
+ * @param cell A table cell model element.
124
+ * @param tableUtils The Table Utils plugin instance.
125
+ * @returns An object containing the indexes of the left and right edges of the cell.
126
+ */
127
+ export function getColumnEdgesIndexes(cell, tableUtils) {
128
+ const cellColumnIndex = tableUtils.getCellLocation(cell).column;
129
+ const cellWidth = cell.getAttribute('colspan') || 1;
130
+ return {
131
+ leftEdge: cellColumnIndex,
132
+ rightEdge: cellColumnIndex + cellWidth - 1
133
+ };
134
+ }
135
+ /**
136
+ * Rounds the provided value to a fixed-point number with defined number of digits after the decimal point.
137
+ *
138
+ * @param value A number to be rounded.
139
+ * @returns The rounded number.
140
+ */
141
+ export function toPrecision(value) {
142
+ const multiplier = Math.pow(10, COLUMN_WIDTH_PRECISION);
143
+ const number = typeof value === 'number' ? value : parseFloat(value);
144
+ return Math.round(number * multiplier) / multiplier;
145
+ }
146
+ /**
147
+ * Clamps the number within the inclusive lower (min) and upper (max) bounds. Returned number is rounded using the
148
+ * {@link ~toPrecision `toPrecision()`} function.
149
+ *
150
+ * @param number A number to be clamped.
151
+ * @param min A lower bound.
152
+ * @param max An upper bound.
153
+ * @returns The clamped number.
154
+ */
155
+ export function clamp(number, min, max) {
156
+ if (number <= min) {
157
+ return toPrecision(min);
158
+ }
159
+ if (number >= max) {
160
+ return toPrecision(max);
161
+ }
162
+ return toPrecision(number);
163
+ }
164
+ /**
165
+ * Creates an array with defined length and fills all elements with defined value.
166
+ *
167
+ * @param length The length of the array.
168
+ * @param value The value to fill the array with.
169
+ * @returns An array with defined length and filled with defined value.
170
+ */
171
+ export function createFilledArray(length, value) {
172
+ return Array(length).fill(value);
173
+ }
174
+ /**
175
+ * Sums all array values that can be parsed to a float.
176
+ *
177
+ * @param array An array of numbers.
178
+ * @returns The sum of all array values.
179
+ */
180
+ export function sumArray(array) {
181
+ return array
182
+ .map(value => typeof value === 'number' ? value : parseFloat(value))
183
+ .filter(value => !Number.isNaN(value))
184
+ .reduce((result, item) => result + item, 0);
185
+ }
186
+ /**
187
+ * Makes sure that the sum of the widths from all columns is 100%. If the sum of all the widths is not equal 100%, all the widths are
188
+ * changed proportionally so that they all sum back to 100%. If there are columns without specified width, the amount remaining
189
+ * after assigning the known widths will be distributed equally between them.
190
+ *
191
+ * @param columnWidths An array of column widths.
192
+ * @returns An array of column widths guaranteed to sum up to 100%.
193
+ */
194
+ export function normalizeColumnWidths(columnWidths) {
195
+ const widths = columnWidths.map(width => {
196
+ if (width === 'auto') {
197
+ return width;
198
+ }
199
+ return parseFloat(width.replace('%', ''));
200
+ });
201
+ let normalizedWidths = calculateMissingColumnWidths(widths);
202
+ const totalWidth = sumArray(normalizedWidths);
203
+ if (totalWidth !== 100) {
204
+ normalizedWidths = normalizedWidths
205
+ // Adjust all the columns proportionally.
206
+ .map(width => toPrecision(width * 100 / totalWidth))
207
+ // Due to rounding of numbers it may happen that the sum of the widths of all columns will not be exactly 100%.
208
+ // Therefore, the width of the last column is explicitly adjusted (narrowed or expanded), since all the columns
209
+ // have been proportionally changed already.
210
+ .map((columnWidth, columnIndex, width) => {
211
+ const isLastColumn = columnIndex === width.length - 1;
212
+ if (!isLastColumn) {
213
+ return columnWidth;
214
+ }
215
+ const totalWidth = sumArray(width);
216
+ return toPrecision(columnWidth + 100 - totalWidth);
217
+ });
218
+ }
219
+ return normalizedWidths.map(width => width + '%');
220
+ }
221
+ /**
222
+ * Initializes the column widths by parsing the attribute value and calculating the uninitialized column widths. The special value 'auto'
223
+ * indicates that width for the column must be calculated. The width of such uninitialized column is calculated as follows:
224
+ * - If there is enough free space in the table for all uninitialized columns to have at least the minimum allowed width for all of them,
225
+ * then set this width equally for all uninitialized columns.
226
+ * - Otherwise, just set the minimum allowed width for all uninitialized columns. The sum of all column widths will be greater than 100%,
227
+ * but then it will be adjusted proportionally to 100% in {@link #normalizeColumnWidths `normalizeColumnWidths()`}.
228
+ *
229
+ * @param columnWidths An array of column widths.
230
+ * @returns An array with 'auto' values replaced with calculated widths.
231
+ */
232
+ function calculateMissingColumnWidths(columnWidths) {
233
+ const numberOfUninitializedColumns = columnWidths.filter(columnWidth => columnWidth === 'auto').length;
234
+ if (numberOfUninitializedColumns === 0) {
235
+ return columnWidths.map(columnWidth => toPrecision(columnWidth));
236
+ }
237
+ const totalWidthOfInitializedColumns = sumArray(columnWidths);
238
+ const widthForUninitializedColumn = Math.max((100 - totalWidthOfInitializedColumns) / numberOfUninitializedColumns, COLUMN_MIN_WIDTH_AS_PERCENTAGE);
239
+ return columnWidths
240
+ .map(columnWidth => columnWidth === 'auto' ? widthForUninitializedColumn : columnWidth)
241
+ .map(columnWidth => toPrecision(columnWidth));
242
+ }
243
+ /**
244
+ * Calculates the total horizontal space taken by the cell. That includes:
245
+ * * width,
246
+ * * left and red padding,
247
+ * * border width.
248
+ *
249
+ * @param domCell A DOM cell element.
250
+ * @returns Width in pixels without `px` at the end.
251
+ */
252
+ export function getDomCellOuterWidth(domCell) {
253
+ const styles = global.window.getComputedStyle(domCell);
254
+ // In the 'border-box' box sizing algorithm, the element's width
255
+ // already includes the padding and border width (#12335).
256
+ if (styles.boxSizing === 'border-box') {
257
+ return parseInt(styles.width);
258
+ }
259
+ else {
260
+ return parseFloat(styles.width) +
261
+ parseFloat(styles.paddingLeft) +
262
+ parseFloat(styles.paddingRight) +
263
+ parseFloat(styles.borderWidth);
264
+ }
265
+ }
266
+ /**
267
+ * Updates column elements to match columns widths.
268
+ *
269
+ * @param columns
270
+ * @param tableColumnGroup
271
+ * @param normalizedWidths
272
+ * @param writer
273
+ */
274
+ export function updateColumnElements(columns, tableColumnGroup, normalizedWidths, writer) {
275
+ for (let i = 0; i < Math.max(normalizedWidths.length, columns.length); i++) {
276
+ const column = columns[i];
277
+ const columnWidth = normalizedWidths[i];
278
+ if (!columnWidth) {
279
+ // Number of `<tableColumn>` elements exceeds actual number of columns.
280
+ writer.remove(column);
281
+ }
282
+ else if (!column) {
283
+ // There is fewer `<tableColumn>` elements than actual columns.
284
+ writer.appendElement('tableColumn', { columnWidth }, tableColumnGroup);
285
+ }
286
+ else {
287
+ // Update column width.
288
+ writer.setAttribute('columnWidth', columnWidth, column);
289
+ }
290
+ }
291
+ }
292
+ /**
293
+ * Returns a 'tableColumnGroup' element from the 'table'.
294
+ *
295
+ * @internal
296
+ * @param element A 'table' or 'tableColumnGroup' element.
297
+ * @returns A 'tableColumnGroup' element.
298
+ */
299
+ export function getColumnGroupElement(element) {
300
+ if (element.is('element', 'tableColumnGroup')) {
301
+ return element;
302
+ }
303
+ const children = element.getChildren();
304
+ return Array
305
+ .from(children)
306
+ .find(element => element.is('element', 'tableColumnGroup'));
307
+ }
308
+ /**
309
+ * Returns an array of 'tableColumn' elements. It may be empty if there's no `tableColumnGroup` element.
310
+ *
311
+ * @internal
312
+ * @param element A 'table' or 'tableColumnGroup' element.
313
+ * @returns An array of 'tableColumn' elements.
314
+ */
315
+ export function getTableColumnElements(element) {
316
+ const columnGroupElement = getColumnGroupElement(element);
317
+ if (!columnGroupElement) {
318
+ return [];
319
+ }
320
+ return Array.from(columnGroupElement.getChildren());
321
+ }
322
+ /**
323
+ * Returns an array of table column widths.
324
+ *
325
+ * @internal
326
+ * @param element A 'table' or 'tableColumnGroup' element.
327
+ * @returns An array of table column widths.
328
+ */
329
+ export function getTableColumnsWidths(element) {
330
+ return getTableColumnElements(element).map(column => column.getAttribute('columnWidth'));
331
+ }
332
+ /**
333
+ * Translates the `colSpan` model attribute into additional column widths and returns the resulting array.
334
+ *
335
+ * @internal
336
+ * @param element A 'table' or 'tableColumnGroup' element.
337
+ * @param writer A writer instance.
338
+ * @returns An array of table column widths.
339
+ */
340
+ export function translateColSpanAttribute(element, writer) {
341
+ const tableColumnElements = getTableColumnElements(element);
342
+ return tableColumnElements.reduce((acc, element) => {
343
+ const columnWidth = element.getAttribute('columnWidth');
344
+ const colSpan = element.getAttribute('colSpan');
345
+ if (!colSpan) {
346
+ acc.push(columnWidth);
347
+ return acc;
348
+ }
349
+ // Translate the `colSpan` model attribute on to the proper number of column widths
350
+ // and remove it from the element.
351
+ // See https://github.com/ckeditor/ckeditor5/issues/14521#issuecomment-1662102889 for more details.
352
+ for (let i = 0; i < colSpan; i++) {
353
+ acc.push(columnWidth);
354
+ }
355
+ writer.removeAttribute('colSpan', element);
356
+ return acc;
357
+ }, []);
358
+ }