UNPKG

7.05 kBTypeScriptView Raw
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/converters/table-layout-post-fixer
7 */
8import type { Model } from 'ckeditor5/src/engine';
9/**
10 * Injects a table layout post-fixer into the model.
11 *
12 * The role of the table layout post-fixer is to ensure that the table rows have the correct structure
13 * after a {@link module:engine/model/model~Model#change `change()`} block was executed.
14 *
15 * The correct structure means that:
16 *
17 * * All table rows have the same size.
18 * * None of the table cells extend vertically beyond their section (either header or body).
19 * * A table cell has always at least one element as a child.
20 *
21 * If the table structure is not correct, the post-fixer will automatically correct it in two steps:
22 *
23 * 1. It will clip table cells that extend beyond their section.
24 * 2. It will add empty table cells to the rows that are narrower than the widest table row.
25 *
26 * ## Clipping overlapping table cells
27 *
28 * Such situation may occur when pasting a table (or a part of a table) to the editor from external sources.
29 *
30 * For example, see the following table which has a cell (FOO) with the rowspan attribute (2):
31 *
32 * ```xml
33 * <table headingRows="1">
34 * <tableRow>
35 * <tableCell rowspan="2"><paragraph>FOO</paragraph></tableCell>
36 * <tableCell colspan="2"><paragraph>BAR</paragraph></tableCell>
37 * </tableRow>
38 * <tableRow>
39 * <tableCell><paragraph>BAZ</paragraph></tableCell>
40 * <tableCell><paragraph>XYZ</paragraph></tableCell>
41 * </tableRow>
42 * </table>
43 * ```
44 *
45 * It will be rendered in the view as:
46 *
47 * ```xml
48 * <table>
49 * <thead>
50 * <tr>
51 * <td rowspan="2">FOO</td>
52 * <td colspan="2">BAR</td>
53 * </tr>
54 * </thead>
55 * <tbody>
56 * <tr>
57 * <td>BAZ</td>
58 * <td>XYZ</td>
59 * </tr>
60 * </tbody>
61 * </table>
62 * ```
63 *
64 * In the above example the table will be rendered as a table with two rows: one in the header and second one in the body.
65 * The table cell (FOO) cannot span over multiple rows as it would extend from the header to the body section.
66 * The `rowspan` attribute must be changed to (1). The value (1) is the default value of the `rowspan` attribute
67 * so the `rowspan` attribute will be removed from the model.
68 *
69 * The table cell with BAZ in the content will be in the first column of the table.
70 *
71 * ## Adding missing table cells
72 *
73 * The table post-fixer will insert empty table cells to equalize table row sizes (the number of columns).
74 * The size of a table row is calculated by counting column spans of table cells, both horizontal (from the same row) and
75 * vertical (from the rows above).
76 *
77 * In the above example, the table row in the body section of the table is narrower then the row from the header: it has two cells
78 * with the default colspan (1). The header row has one cell with colspan (1) and the second with colspan (2).
79 * The table cell (FOO) does not extend beyond the head section (and as such will be fixed in the first step of this post-fixer).
80 * The post-fixer will add a missing table cell to the row in the body section of the table.
81 *
82 * The table from the above example will be fixed and rendered to the view as below:
83 *
84 * ```xml
85 * <table>
86 * <thead>
87 * <tr>
88 * <td rowspan="2">FOO</td>
89 * <td colspan="2">BAR</td>
90 * </tr>
91 * </thead>
92 * <tbody>
93 * <tr>
94 * <td>BAZ</td>
95 * <td>XYZ</td>
96 * </tr>
97 * </tbody>
98 * </table>
99 * ```
100 *
101 * ## Collaboration and undo - Expectations vs post-fixer results
102 *
103 * The table post-fixer only ensures proper structure without a deeper analysis of the nature of the change. As such, it might lead
104 * to a structure which was not intended by the user. In particular, it will also fix undo steps (in conjunction with collaboration)
105 * in which the editor content might not return to the original state.
106 *
107 * This will usually happen when one or more users change the size of the table.
108 *
109 * As an example see the table below:
110 *
111 * ```xml
112 * <table>
113 * <tbody>
114 * <tr>
115 * <td>11</td>
116 * <td>12</td>
117 * </tr>
118 * <tr>
119 * <td>21</td>
120 * <td>22</td>
121 * </tr>
122 * </tbody>
123 * </table>
124 * ```
125 *
126 * and the user actions:
127 *
128 * 1. Both users have a table with two rows and two columns.
129 * 2. User A adds a column at the end of the table. This will insert empty table cells to two rows.
130 * 3. User B adds a row at the end of the table. This will insert a row with two empty table cells.
131 * 4. Both users will have a table as below:
132 *
133 * ```xml
134 * <table>
135 * <tbody>
136 * <tr>
137 * <td>11</td>
138 * <td>12</td>
139 * <td>(empty, inserted by A)</td>
140 * </tr>
141 * <tr>
142 * <td>21</td>
143 * <td>22</td>
144 * <td>(empty, inserted by A)</td>
145 * </tr>
146 * <tr>
147 * <td>(empty, inserted by B)</td>
148 * <td>(empty, inserted by B)</td>
149 * </tr>
150 * </tbody>
151 * </table>
152 * ```
153 *
154 * The last row is shorter then others so the table post-fixer will add an empty row to the last row:
155 *
156 * ```xml
157 * <table>
158 * <tbody>
159 * <tr>
160 * <td>11</td>
161 * <td>12</td>
162 * <td>(empty, inserted by A)</td>
163 * </tr>
164 * <tr>
165 * <td>21</td>
166 * <td>22</td>
167 * <td>(empty, inserted by A)</td>
168 * </tr>
169 * <tr>
170 * <td>(empty, inserted by B)</td>
171 * <td>(empty, inserted by B)</td>
172 * <td>(empty, inserted by the post-fixer)</td>
173 * </tr>
174 * </tbody>
175 * </table>
176 * ```
177 *
178 * Unfortunately undo does not know the nature of the changes and depending on which user applies the post-fixer changes, undoing them
179 * might lead to a broken table. If User B undoes inserting the column to the table, the undo engine will undo only the operations of
180 * inserting empty cells to rows from the initial table state (row 1 and 2) but the cell in the post-fixed row will remain:
181 *
182 * ```xml
183 * <table>
184 * <tbody>
185 * <tr>
186 * <td>11</td>
187 * <td>12</td>
188 * </tr>
189 * <tr>
190 * <td>21</td>
191 * <td>22</td>
192 * </tr>
193 * <tr>
194 * <td>(empty, inserted by B)</td>
195 * <td>(empty, inserted by B)</td>
196 * <td>(empty, inserted by a post-fixer)</td>
197 * </tr>
198 * </tbody>
199 * </table>
200 * ```
201 *
202 * After undo, the table post-fixer will detect that two rows are shorter than others and will fix the table to:
203 *
204 * ```xml
205 * <table>
206 * <tbody>
207 * <tr>
208 * <td>11</td>
209 * <td>12</td>
210 * <td>(empty, inserted by a post-fixer after undo)</td>
211 * </tr>
212 * <tr>
213 * <td>21</td>
214 * <td>22</td>
215 * <td>(empty, inserted by a post-fixer after undo)</td>
216 * </tr>
217 * <tr>
218 * <td>(empty, inserted by B)</td>
219 * <td>(empty, inserted by B)</td>
220 * <td>(empty, inserted by a post-fixer)</td>
221 * </tr>
222 * </tbody>
223 * </table>
224 * ```
225 */
226export default function injectTableLayoutPostFixer(model: Model): void;