1 | import { Plugin } from '@ckeditor/ckeditor5-core';
|
2 | import { Element as ModelElement, Range as ModelRange } from '@ckeditor/ckeditor5-engine';
|
3 | import Writer from '@ckeditor/ckeditor5-engine/src/model/writer';
|
4 | import TableWalker from './tablewalker';
|
5 | import ModelSelection from '@ckeditor/ckeditor5-engine/src/model/selection';
|
6 |
|
7 | /**
|
8 | * The table utilities plugin.
|
9 | */
|
10 | export default class TableUtils extends Plugin {
|
11 | static readonly pluginName: 'TableUtils';
|
12 | init(): void;
|
13 |
|
14 | /**
|
15 | * Returns the table cell location as an object with table row and table column indexes.
|
16 | *
|
17 | * For instance, in the table below:
|
18 | *
|
19 | * 0 1 2 3
|
20 | * +---+---+---+---+
|
21 | * 0 | a | b | c |
|
22 | * + + +---+
|
23 | * 1 | | | d |
|
24 | * +---+---+ +---+
|
25 | * 2 | e | | f |
|
26 | * +---+---+---+---+
|
27 | *
|
28 | * the method will return:
|
29 | *
|
30 | * const cellA = table.getNodeByPath( [ 0, 0 ] );
|
31 | * editor.plugins.get( 'TableUtils' ).getCellLocation( cellA );
|
32 | * // will return { row: 0, column: 0 }
|
33 | *
|
34 | * const cellD = table.getNodeByPath( [ 1, 0 ] );
|
35 | * editor.plugins.get( 'TableUtils' ).getCellLocation( cellD );
|
36 | * // will return { row: 1, column: 3 }
|
37 | */
|
38 | getCellLocation(tableCell: ModelElement): { row: number; column: number } | void;
|
39 |
|
40 | /**
|
41 | * Creates an empty table with a proper structure. The table needs to be inserted into the model,
|
42 | * for example, by using the {@link module:engine/model/model~Model#insertContent} function.
|
43 | *
|
44 | * model.change( ( writer ) => {
|
45 | * // Create a table of 2 rows and 7 columns:
|
46 | * const table = tableUtils.createTable( writer, { rows: 2, columns: 7 } );
|
47 | *
|
48 | * // Insert a table to the model at the best position taking the current selection:
|
49 | * model.insertContent( table );
|
50 | * }
|
51 | */
|
52 | createTable(
|
53 | writer: Writer,
|
54 | options?: { rows?: number; columns?: number; headingRows?: number; headingColumns?: number },
|
55 | ): ModelElement;
|
56 |
|
57 | /**
|
58 | * Inserts rows into a table.
|
59 | *
|
60 | * editor.plugins.get( 'TableUtils' ).insertRows( table, { at: 1, rows: 2 } );
|
61 | *
|
62 | * Assuming the table on the left, the above code will transform it to the table on the right:
|
63 | *
|
64 | * row index
|
65 | * 0 +---+---+---+ `at` = 1, +---+---+---+ 0
|
66 | * | a | b | c | `rows` = 2, | a | b | c |
|
67 | * 1 + +---+---+ <-- insert here + +---+---+ 1
|
68 | * | | d | e | | | | |
|
69 | * 2 + +---+---+ will give: + +---+---+ 2
|
70 | * | | f | g | | | | |
|
71 | * 3 +---+---+---+ + +---+---+ 3
|
72 | * | | d | e |
|
73 | * + +---+---+ 4
|
74 | * + + f | g |
|
75 | * +---+---+---+ 5
|
76 | */
|
77 | insertRows(table: ModelElement, options?: { at?: number; rows?: number; copyStructureFromAbove?: boolean }): void;
|
78 |
|
79 | /**
|
80 | * Inserts columns into a table.
|
81 | *
|
82 | * editor.plugins.get( 'TableUtils' ).insertColumns( table, { at: 1, columns: 2 } );
|
83 | *
|
84 | * Assuming the table on the left, the above code will transform it to the table on the right:
|
85 | *
|
86 | * 0 1 2 3 0 1 2 3 4 5
|
87 | * +---+---+---+ +---+---+---+---+---+
|
88 | * | a | b | | a | b |
|
89 | * + +---+ + +---+
|
90 | * | | c | | | c |
|
91 | * +---+---+---+ will give: +---+---+---+---+---+
|
92 | * | d | e | f | | d | | | e | f |
|
93 | * +---+ +---+ +---+---+---+ +---+
|
94 | * | g | | h | | g | | | | h |
|
95 | * +---+---+---+ +---+---+---+---+---+
|
96 | * | i | | i |
|
97 | * +---+---+---+ +---+---+---+---+---+
|
98 | * ^---- insert here, `at` = 1, `columns` = 2
|
99 | */
|
100 | insertColumns(table: ModelElement, options?: { at?: number; columns?: number }): void;
|
101 |
|
102 | /**
|
103 | * Removes rows from the given `table`.
|
104 | *
|
105 | * This method re-calculates the table geometry including `rowspan` attribute of table cells overlapping removed rows
|
106 | * and table headings values.
|
107 | *
|
108 | * editor.plugins.get( 'TableUtils' ).removeRows( table, { at: 1, rows: 2 } );
|
109 | *
|
110 | * Executing the above code in the context of the table on the left will transform its structure as presented on the right:
|
111 | *
|
112 | * row index
|
113 | * ┌───┬───┬───┐ `at` = 1 ┌───┬───┬───┐
|
114 | * 0 │ a │ b │ c │ `rows` = 2 │ a │ b │ c │ 0
|
115 | * │ ├───┼───┤ │ ├───┼───┤
|
116 | * 1 │ │ d │ e │ <-- remove from here │ │ d │ g │ 1
|
117 | * │ │ ├───┤ will give: ├───┼───┼───┤
|
118 | * 2 │ │ │ f │ │ h │ i │ j │ 2
|
119 | * │ │ ├───┤ └───┴───┴───┘
|
120 | * 3 │ │ │ g │
|
121 | * ├───┼───┼───┤
|
122 | * 4 │ h │ i │ j │
|
123 | * └───┴───┴───┘
|
124 | */
|
125 | removeRows(table: ModelElement, options?: { at?: number; rows?: number }): void;
|
126 |
|
127 | /**
|
128 | * Removes columns from the given `table`.
|
129 | *
|
130 | * This method re-calculates the table geometry including the `colspan` attribute of table cells overlapping removed columns
|
131 | * and table headings values.
|
132 | *
|
133 | * editor.plugins.get( 'TableUtils' ).removeColumns( table, { at: 1, columns: 2 } );
|
134 | *
|
135 | * Executing the above code in the context of the table on the left will transform its structure as presented on the right:
|
136 | *
|
137 | * 0 1 2 3 4 0 1 2
|
138 | * ┌───────────────┬───┐ ┌───────┬───┐
|
139 | * │ a │ b │ │ a │ b │
|
140 | * │ ├───┤ │ ├───┤
|
141 | * │ │ c │ │ │ c │
|
142 | * ├───┬───┬───┬───┼───┤ will give: ├───┬───┼───┤
|
143 | * │ d │ e │ f │ g │ h │ │ d │ g │ h │
|
144 | * ├───┼───┼───┤ ├───┤ ├───┤ ├───┤
|
145 | * │ i │ j │ k │ │ l │ │ i │ │ l │
|
146 | * ├───┴───┴───┴───┴───┤ ├───┴───┴───┤
|
147 | * │ m │ │ m │
|
148 | * └───────────────────┘ └───────────┘
|
149 | * ^---- remove from here, `at` = 1, `columns` = 2
|
150 | */
|
151 | removeColumns(table: ModelElement, options?: { at?: number; columns?: number }): void;
|
152 |
|
153 | /**
|
154 | * Divides a table cell vertically into several ones.
|
155 | *
|
156 | * The cell will be visually split into more cells by updating colspans of other cells in a column
|
157 | * and inserting cells (columns) after that cell.
|
158 | *
|
159 | * In the table below, if cell "a" is split into 3 cells:
|
160 | *
|
161 | * +---+---+---+
|
162 | * | a | b | c |
|
163 | * +---+---+---+
|
164 | * | d | e | f |
|
165 | * +---+---+---+
|
166 | *
|
167 | * it will result in the table below:
|
168 | *
|
169 | * +---+---+---+---+---+
|
170 | * | a | | | b | c |
|
171 | * +---+---+---+---+---+
|
172 | * | d | e | f |
|
173 | * +---+---+---+---+---+
|
174 | *
|
175 | * So cell "d" will get its `colspan` updated to `3` and 2 cells will be added (2 columns will be created).
|
176 | *
|
177 | * Splitting a cell that already has a `colspan` attribute set will distribute the cell `colspan` evenly and the remainder
|
178 | * will be left to the original cell:
|
179 | *
|
180 | * +---+---+---+
|
181 | * | a |
|
182 | * +---+---+---+
|
183 | * | b | c | d |
|
184 | * +---+---+---+
|
185 | *
|
186 | * Splitting cell "a" with `colspan=3` into 2 cells will create 1 cell with a `colspan=a` and cell "a" that will have `colspan=2`:
|
187 | *
|
188 | * +---+---+---+
|
189 | * | a | |
|
190 | * +---+---+---+
|
191 | * | b | c | d |
|
192 | * +---+---+---+
|
193 | */
|
194 | splitCellVertically(tableCell: ModelElement, numberOfCells: number): void;
|
195 |
|
196 | /**
|
197 | * Divides a table cell horizontally into several ones.
|
198 | *
|
199 | * The cell will be visually split into more cells by updating rowspans of other cells in the row and inserting rows with a single cell
|
200 | * below.
|
201 | *
|
202 | * If in the table below cell "b" is split into 3 cells:
|
203 | *
|
204 | * +---+---+---+
|
205 | * | a | b | c |
|
206 | * +---+---+---+
|
207 | * | d | e | f |
|
208 | * +---+---+---+
|
209 | *
|
210 | * It will result in the table below:
|
211 | *
|
212 | * +---+---+---+
|
213 | * | a | b | c |
|
214 | * + +---+ +
|
215 | * | | | |
|
216 | * + +---+ +
|
217 | * | | | |
|
218 | * +---+---+---+
|
219 | * | d | e | f |
|
220 | * +---+---+---+
|
221 | *
|
222 | * So cells "a" and "b" will get their `rowspan` updated to `3` and 2 rows with a single cell will be added.
|
223 | *
|
224 | * Splitting a cell that already has a `rowspan` attribute set will distribute the cell `rowspan` evenly and the remainder
|
225 | * will be left to the original cell:
|
226 | *
|
227 | * +---+---+---+
|
228 | * | a | b | c |
|
229 | * + +---+---+
|
230 | * | | d | e |
|
231 | * + +---+---+
|
232 | * | | f | g |
|
233 | * + +---+---+
|
234 | * | | h | i |
|
235 | * +---+---+---+
|
236 | *
|
237 | * Splitting cell "a" with `rowspan=4` into 3 cells will create 2 cells with a `rowspan=1` and cell "a" will have `rowspan=2`:
|
238 | *
|
239 | * +---+---+---+
|
240 | * | a | b | c |
|
241 | * + +---+---+
|
242 | * | | d | e |
|
243 | * +---+---+---+
|
244 | * | | f | g |
|
245 | * +---+---+---+
|
246 | * | | h | i |
|
247 | * +---+---+---+
|
248 | */
|
249 | splitCellHorizontally(tableCell: ModelElement, numberOfCells?: number): void;
|
250 |
|
251 | /**
|
252 | * Returns the number of columns for a given table.
|
253 | *
|
254 | * editor.plugins.get( 'TableUtils' ).getColumns( table );
|
255 | */
|
256 | getColumns(table: ModelElement): number;
|
257 |
|
258 | /**
|
259 | * Returns the number of rows for a given table. Any other element present in the table model is omitted.
|
260 | *
|
261 | * editor.plugins.get( 'TableUtils' ).getRows( table );
|
262 | */
|
263 | getRows(table: ModelElement): number;
|
264 |
|
265 | /**
|
266 | * Creates an instance of the table walker.
|
267 | *
|
268 | * The table walker iterates internally by traversing the table from row index = 0 and column index = 0.
|
269 | * It walks row by row and column by column in order to output values defined in the options.
|
270 | * By default it will output only the locations that are occupied by a cell. To include also spanned rows and columns,
|
271 | * pass the `includeAllSlots` option.
|
272 | */
|
273 | createTableWalker(
|
274 | table: ModelElement,
|
275 | options?: {
|
276 | row?: number;
|
277 | startRow?: number;
|
278 | endRow?: number;
|
279 | column?: number;
|
280 | startColumn?: number;
|
281 | endColumn?: number;
|
282 | includeAllSlots?: boolean;
|
283 | },
|
284 | ): TableWalker;
|
285 |
|
286 | /**
|
287 | * Returns all model table cells that are fully selected (from the outside)
|
288 | * within the provided model selection's ranges.
|
289 | *
|
290 | * To obtain the cells selected from the inside, use
|
291 | * {@link #getTableCellsContainingSelection}.
|
292 | */
|
293 | getSelectedTableCells(selection: ModelSelection): ModelElement[];
|
294 |
|
295 | /**
|
296 | * Returns all model table cells that the provided model selection's ranges
|
297 | * {@link module:engine/model/range~Range#start} inside.
|
298 | *
|
299 | * To obtain the cells selected from the outside, use
|
300 | * {@link #getSelectedTableCells}.
|
301 | */
|
302 | getTableCellsContainingSelection(selection: ModelSelection): ModelElement[];
|
303 |
|
304 | /**
|
305 | * Returns all model table cells that are either completely selected
|
306 | * by selection ranges or host selection range
|
307 | * {@link module:engine/model/range~Range#start start positions} inside them.
|
308 | *
|
309 | * Combines {@link #getTableCellsContainingSelection} and
|
310 | * {@link #getSelectedTableCells}.
|
311 | */
|
312 | getSelectionAffectedTableCells(selection: ModelSelection): ModelElement[];
|
313 |
|
314 | /**
|
315 | * Returns an object with the `first` and `last` row index contained in the given `tableCells`.
|
316 | *
|
317 | * const selectedTableCells = getSelectedTableCells( editor.model.document.selection );
|
318 | *
|
319 | * const { first, last } = getRowIndexes( selectedTableCells );
|
320 | *
|
321 | * console.log( `Selected rows: ${ first } to ${ last }` );
|
322 | */
|
323 | getRowIndexes(tableCells: ModelElement[]): { first: number; last: number };
|
324 |
|
325 | /**
|
326 | * Returns an object with the `first` and `last` column index contained in the given `tableCells`.
|
327 | *
|
328 | * const selectedTableCells = getSelectedTableCells( editor.model.document.selection );
|
329 | *
|
330 | * const { first, last } = getColumnIndexes( selectedTableCells );
|
331 | *
|
332 | * console.log( `Selected columns: ${ first } to ${ last }` );
|
333 | */
|
334 | getColumnIndexes(tableCells: ModelElement[]): { first: number; last: number };
|
335 |
|
336 | /**
|
337 | * Checks if the selection contains cells that do not exceed rectangular selection.
|
338 | *
|
339 | * In a table below:
|
340 | *
|
341 | * ┌───┬───┬───┬───┐
|
342 | * │ a │ b │ c │ d │
|
343 | * ├───┴───┼───┤ │
|
344 | * │ e │ f │ │
|
345 | * │ ├───┼───┤
|
346 | * │ │ g │ h │
|
347 | * └───────┴───┴───┘
|
348 | *
|
349 | * Valid selections are these which create a solid rectangle (without gaps), such as:
|
350 | * - a, b (two horizontal cells)
|
351 | * - c, f (two vertical cells)
|
352 | * - a, b, e (cell "e" spans over four cells)
|
353 | * - c, d, f (cell d spans over a cell in the row below)
|
354 | *
|
355 | * While an invalid selection would be:
|
356 | * - a, c (the unselected cell "b" creates a gap)
|
357 | * - f, g, h (cell "d" spans over a cell from the row of "f" cell - thus creates a gap)
|
358 | */
|
359 | isSelectionRectangular(selectedTableCells: ModelElement[]): boolean;
|
360 |
|
361 | /**
|
362 | * Returns array of sorted ranges.
|
363 | */
|
364 | sortRanges(ranges: Iterable<ModelRange>): ModelRange[];
|
365 | }
|
366 |
|
367 | declare module '@ckeditor/ckeditor5-core/src/plugincollection' {
|
368 | interface Plugins {
|
369 | TableUtils: TableUtils;
|
370 | }
|
371 | }
|