UNPKG

27.9 kBJavaScriptView 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/tablecolumnresize/tablecolumnresizeediting
7 */
8import { throttle, isEqual } from 'lodash-es';
9import { global, DomEmitterMixin } from 'ckeditor5/src/utils';
10import { Plugin } from 'ckeditor5/src/core';
11import MouseEventsObserver from '../../src/tablemouse/mouseeventsobserver';
12import TableEditing from '../tableediting';
13import TableUtils from '../tableutils';
14import TableWalker from '../tablewalker';
15import TableWidthsCommand from './tablewidthscommand';
16import { downcastTableResizedClass, upcastColgroupElement } from './converters';
17import { clamp, createFilledArray, sumArray, getColumnEdgesIndexes, getChangedResizedTables, getColumnMinWidthAsPercentage, getElementWidthInPixels, getTableWidthInPixels, normalizeColumnWidths, toPrecision, getDomCellOuterWidth, updateColumnElements, getColumnGroupElement, getTableColumnElements, getTableColumnsWidths } from './utils';
18import { COLUMN_MIN_WIDTH_IN_PIXELS } from './constants';
19/**
20 * The table column resize editing plugin.
21 */
22export default class TableColumnResizeEditing extends Plugin {
23 /**
24 * @inheritDoc
25 */
26 static get requires() {
27 return [TableEditing, TableUtils];
28 }
29 /**
30 * @inheritDoc
31 */
32 static get pluginName() {
33 return 'TableColumnResizeEditing';
34 }
35 /**
36 * @inheritDoc
37 */
38 constructor(editor) {
39 super(editor);
40 this._isResizingActive = false;
41 this.set('_isResizingAllowed', true);
42 this._resizingData = null;
43 this._domEmitter = new (DomEmitterMixin())();
44 this._tableUtilsPlugin = editor.plugins.get('TableUtils');
45 this.on('change:_isResizingAllowed', (evt, name, value) => {
46 // Toggling the `ck-column-resize_disabled` class shows and hides the resizers through CSS.
47 const classAction = value ? 'removeClass' : 'addClass';
48 editor.editing.view.change(writer => {
49 for (const root of editor.editing.view.document.roots) {
50 writer[classAction]('ck-column-resize_disabled', editor.editing.view.document.getRoot(root.rootName));
51 }
52 });
53 });
54 }
55 /**
56 * @inheritDoc
57 */
58 init() {
59 this._extendSchema();
60 this._registerPostFixer();
61 this._registerConverters();
62 this._registerResizingListeners();
63 this._registerResizerInserter();
64 const editor = this.editor;
65 const columnResizePlugin = editor.plugins.get('TableColumnResize');
66 const tableEditing = editor.plugins.get('TableEditing');
67 tableEditing.registerAdditionalSlot({
68 filter: element => element.is('element', 'tableColumnGroup'),
69 positionOffset: 0
70 });
71 const tableWidthsCommand = new TableWidthsCommand(editor);
72 // For backwards compatibility we have two commands that perform exactly the same operation.
73 editor.commands.add('resizeTableWidth', tableWidthsCommand);
74 editor.commands.add('resizeColumnWidths', tableWidthsCommand);
75 // Currently the states of column resize and table resize (which is actually the last column resize) features
76 // are bound together. They can be separated in the future by adding distinct listeners and applying
77 // different CSS classes (e.g. `ck-column-resize_disabled` and `ck-table-resize_disabled`) to the editor root.
78 // See #12148 for the details.
79 this.bind('_isResizingAllowed').to(editor, 'isReadOnly', columnResizePlugin, 'isEnabled', tableWidthsCommand, 'isEnabled', (isEditorReadOnly, isPluginEnabled, isTableWidthsCommandCommandEnabled) => !isEditorReadOnly && isPluginEnabled && isTableWidthsCommandCommandEnabled);
80 }
81 /**
82 * @inheritDoc
83 */
84 destroy() {
85 this._domEmitter.stopListening();
86 super.destroy();
87 }
88 /**
89 * Returns a 'tableColumnGroup' element from the 'table'.
90 *
91 * @param element A 'table' or 'tableColumnGroup' element.
92 * @returns A 'tableColumnGroup' element.
93 */
94 getColumnGroupElement(element) {
95 return getColumnGroupElement(element);
96 }
97 /**
98 * Returns an array of 'tableColumn' elements.
99 *
100 * @param element A 'table' or 'tableColumnGroup' element.
101 * @returns An array of 'tableColumn' elements.
102 */
103 getTableColumnElements(element) {
104 return getTableColumnElements(element);
105 }
106 /**
107 * Returns an array of table column widths.
108 *
109 * @param element A 'table' or 'tableColumnGroup' element.
110 * @returns An array of table column widths.
111 */
112 getTableColumnsWidths(element) {
113 return getTableColumnsWidths(element);
114 }
115 /**
116 * Registers new attributes for a table model element.
117 */
118 _extendSchema() {
119 this.editor.model.schema.extend('table', {
120 allowAttributes: ['tableWidth']
121 });
122 this.editor.model.schema.register('tableColumnGroup', {
123 allowIn: 'table',
124 isLimit: true
125 });
126 this.editor.model.schema.register('tableColumn', {
127 allowIn: 'tableColumnGroup',
128 allowAttributes: ['columnWidth'],
129 isLimit: true
130 });
131 }
132 /**
133 * Registers table column resize post-fixer.
134 *
135 * It checks if the change from the differ concerns a table-related element or attribute. For detected changes it:
136 * * Adjusts the `columnWidths` attribute to guarantee that the sum of the widths from all columns is 100%.
137 * * Checks if the `columnWidths` attribute gets updated accordingly after columns have been added or removed.
138 */
139 _registerPostFixer() {
140 const editor = this.editor;
141 const model = editor.model;
142 model.document.registerPostFixer(writer => {
143 let changed = false;
144 for (const table of getChangedResizedTables(model)) {
145 const tableColumnGroup = this.getColumnGroupElement(table);
146 const columns = this.getTableColumnElements(tableColumnGroup);
147 const columnWidths = this.getTableColumnsWidths(tableColumnGroup);
148 // Adjust the `columnWidths` attribute to guarantee that the sum of the widths from all columns is 100%.
149 let normalizedWidths = normalizeColumnWidths(columnWidths);
150 // If the number of columns has changed, then we need to adjust the widths of the affected columns.
151 normalizedWidths = adjustColumnWidths(normalizedWidths, table, this);
152 if (isEqual(columnWidths, normalizedWidths)) {
153 continue;
154 }
155 updateColumnElements(columns, tableColumnGroup, normalizedWidths, writer);
156 changed = true;
157 }
158 return changed;
159 });
160 /**
161 * Adjusts if necessary the `columnWidths` in case if the number of column has changed.
162 *
163 * @param columnWidths Note: this array **may be modified** by the function.
164 * @param table Table to be checked.
165 */
166 function adjustColumnWidths(columnWidths, table, plugin) {
167 const newTableColumnsCount = plugin._tableUtilsPlugin.getColumns(table);
168 const columnsCountDelta = newTableColumnsCount - columnWidths.length;
169 if (columnsCountDelta === 0) {
170 return columnWidths;
171 }
172 const widths = columnWidths.map(width => Number(width.replace('%', '')));
173 // Collect all cells that are affected by the change.
174 const cellSet = getAffectedCells(plugin.editor.model.document.differ, table);
175 for (const cell of cellSet) {
176 const currentColumnsDelta = newTableColumnsCount - widths.length;
177 if (currentColumnsDelta === 0) {
178 continue;
179 }
180 // If the column count in the table changed, adjust the widths of the affected columns.
181 const hasMoreColumns = currentColumnsDelta > 0;
182 const currentColumnIndex = plugin._tableUtilsPlugin.getCellLocation(cell).column;
183 if (hasMoreColumns) {
184 const columnMinWidthAsPercentage = getColumnMinWidthAsPercentage(table, plugin.editor);
185 const columnWidthsToInsert = createFilledArray(currentColumnsDelta, columnMinWidthAsPercentage);
186 widths.splice(currentColumnIndex, 0, ...columnWidthsToInsert);
187 }
188 else {
189 // Moves the widths of the removed columns to the preceding one.
190 // Other editors either reduce the width of the whole table or adjust the widths
191 // proportionally, so change of this behavior can be considered in the future.
192 const removedColumnWidths = widths.splice(currentColumnIndex, Math.abs(currentColumnsDelta));
193 widths[currentColumnIndex] += sumArray(removedColumnWidths);
194 }
195 }
196 return widths.map(width => width + '%');
197 }
198 /**
199 * Returns a set of cells that have been changed in a given table.
200 */
201 function getAffectedCells(differ, table) {
202 const cellSet = new Set();
203 for (const change of differ.getChanges()) {
204 if (change.type == 'insert' &&
205 change.position.nodeAfter &&
206 change.position.nodeAfter.name == 'tableCell' &&
207 change.position.nodeAfter.getAncestors().includes(table)) {
208 cellSet.add(change.position.nodeAfter);
209 }
210 else if (change.type == 'remove') {
211 // If the first cell was removed, use the node after the change position instead.
212 const referenceNode = (change.position.nodeBefore || change.position.nodeAfter);
213 if (referenceNode.name == 'tableCell' && referenceNode.getAncestors().includes(table)) {
214 cellSet.add(referenceNode);
215 }
216 }
217 }
218 return cellSet;
219 }
220 }
221 /**
222 * Registers table column resize converters.
223 */
224 _registerConverters() {
225 const editor = this.editor;
226 const conversion = editor.conversion;
227 // Table width style
228 conversion.for('upcast').attributeToAttribute({
229 view: {
230 name: 'figure',
231 key: 'style',
232 value: {
233 width: /[\s\S]+/
234 }
235 },
236 model: {
237 name: 'table',
238 key: 'tableWidth',
239 value: (viewElement) => viewElement.getStyle('width')
240 }
241 });
242 conversion.for('downcast').attributeToAttribute({
243 model: {
244 name: 'table',
245 key: 'tableWidth'
246 },
247 view: (width) => ({
248 name: 'figure',
249 key: 'style',
250 value: {
251 width
252 }
253 })
254 });
255 conversion.elementToElement({ model: 'tableColumnGroup', view: 'colgroup' });
256 conversion.elementToElement({ model: 'tableColumn', view: 'col' });
257 conversion.for('downcast').add(downcastTableResizedClass());
258 conversion.for('upcast').add(upcastColgroupElement(this._tableUtilsPlugin));
259 conversion.for('upcast').attributeToAttribute({
260 view: {
261 name: 'col',
262 styles: {
263 width: /.*/
264 }
265 },
266 model: {
267 key: 'columnWidth',
268 value: (viewElement) => {
269 const viewColWidth = viewElement.getStyle('width');
270 if (!viewColWidth || !viewColWidth.endsWith('%')) {
271 return 'auto';
272 }
273 return viewColWidth;
274 }
275 }
276 });
277 conversion.for('downcast').attributeToAttribute({
278 model: {
279 name: 'tableColumn',
280 key: 'columnWidth'
281 },
282 view: width => ({ key: 'style', value: { width } })
283 });
284 }
285 /**
286 * Registers listeners to handle resizing process.
287 */
288 _registerResizingListeners() {
289 const editingView = this.editor.editing.view;
290 editingView.addObserver(MouseEventsObserver);
291 editingView.document.on('mousedown', this._onMouseDownHandler.bind(this), { priority: 'high' });
292 this._domEmitter.listenTo(global.window.document, 'mousemove', throttle(this._onMouseMoveHandler.bind(this), 50));
293 this._domEmitter.listenTo(global.window.document, 'mouseup', this._onMouseUpHandler.bind(this));
294 }
295 /**
296 * Handles the `mousedown` event on column resizer element:
297 * * calculates the initial column pixel widths,
298 * * inserts the `<colgroup>` element if it is not present in the `<table>`,
299 * * puts the necessary data in the temporary storage,
300 * * applies the attributes to the `<table>` view element.
301 *
302 * @param eventInfo An object containing information about the fired event.
303 * @param domEventData The data related to the DOM event.
304 */
305 _onMouseDownHandler(eventInfo, domEventData) {
306 const target = domEventData.target;
307 if (!target.hasClass('ck-table-column-resizer')) {
308 return;
309 }
310 if (!this._isResizingAllowed) {
311 return;
312 }
313 const editor = this.editor;
314 const modelTable = editor.editing.mapper.toModelElement(target.findAncestor('figure'));
315 // Do not resize if table model is in non-editable place.
316 if (!editor.model.canEditAt(modelTable)) {
317 return;
318 }
319 domEventData.preventDefault();
320 eventInfo.stop();
321 // The column widths are calculated upon mousedown to allow lazy applying the `columnWidths` attribute on the table.
322 const columnWidthsInPx = _calculateDomColumnWidths(modelTable, this._tableUtilsPlugin, editor);
323 const viewTable = target.findAncestor('table');
324 const editingView = editor.editing.view;
325 // Insert colgroup for the table that is resized for the first time.
326 if (!Array.from(viewTable.getChildren()).find(viewCol => viewCol.is('element', 'colgroup'))) {
327 editingView.change(viewWriter => {
328 _insertColgroupElement(viewWriter, columnWidthsInPx, viewTable);
329 });
330 }
331 this._isResizingActive = true;
332 this._resizingData = this._getResizingData(domEventData, columnWidthsInPx);
333 // At this point we change only the editor view - we don't want other users to see our changes yet,
334 // so we can't apply them in the model.
335 editingView.change(writer => _applyResizingAttributesToTable(writer, viewTable, this._resizingData));
336 /**
337 * Calculates the DOM columns' widths. It is done by taking the width of the widest cell
338 * from each table column (we rely on the {@link module:table/tablewalker~TableWalker}
339 * to determine which column the cell belongs to).
340 *
341 * @param modelTable A table which columns should be measured.
342 * @param tableUtils The Table Utils plugin instance.
343 * @param editor The editor instance.
344 * @returns Columns' widths expressed in pixels (without unit).
345 */
346 function _calculateDomColumnWidths(modelTable, tableUtilsPlugin, editor) {
347 const columnWidthsInPx = Array(tableUtilsPlugin.getColumns(modelTable));
348 const tableWalker = new TableWalker(modelTable);
349 for (const cellSlot of tableWalker) {
350 const viewCell = editor.editing.mapper.toViewElement(cellSlot.cell);
351 const domCell = editor.editing.view.domConverter.mapViewToDom(viewCell);
352 const domCellWidth = getDomCellOuterWidth(domCell);
353 if (!columnWidthsInPx[cellSlot.column] || domCellWidth < columnWidthsInPx[cellSlot.column]) {
354 columnWidthsInPx[cellSlot.column] = toPrecision(domCellWidth);
355 }
356 }
357 return columnWidthsInPx;
358 }
359 /**
360 * Creates a `<colgroup>` element with `<col>`s and inserts it into a given view table.
361 *
362 * @param viewWriter A writer instance.
363 * @param columnWidthsInPx Column widths.
364 * @param viewTable A table view element.
365 */
366 function _insertColgroupElement(viewWriter, columnWidthsInPx, viewTable) {
367 const colgroup = viewWriter.createContainerElement('colgroup');
368 for (let i = 0; i < columnWidthsInPx.length; i++) {
369 const viewColElement = viewWriter.createEmptyElement('col');
370 const columnWidthInPc = `${toPrecision(columnWidthsInPx[i] / sumArray(columnWidthsInPx) * 100)}%`;
371 viewWriter.setStyle('width', columnWidthInPc, viewColElement);
372 viewWriter.insert(viewWriter.createPositionAt(colgroup, 'end'), viewColElement);
373 }
374 viewWriter.insert(viewWriter.createPositionAt(viewTable, 0), colgroup);
375 }
376 /**
377 * Applies the style and classes to the view table as the resizing begun.
378 *
379 * @param viewWriter A writer instance.
380 * @param viewTable A table containing the clicked resizer.
381 * @param resizingData Data related to the resizing.
382 */
383 function _applyResizingAttributesToTable(viewWriter, viewTable, resizingData) {
384 const figureInitialPcWidth = resizingData.widths.viewFigureWidth / resizingData.widths.viewFigureParentWidth;
385 viewWriter.addClass('ck-table-resized', viewTable);
386 viewWriter.addClass('ck-table-column-resizer__active', resizingData.elements.viewResizer);
387 viewWriter.setStyle('width', `${toPrecision(figureInitialPcWidth * 100)}%`, viewTable.findAncestor('figure'));
388 }
389 }
390 /**
391 * Handles the `mousemove` event.
392 * * If resizing process is not in progress, it does nothing.
393 * * If resizing is active but not allowed, it stops the resizing process instantly calling the `mousedown` event handler.
394 * * Otherwise it dynamically updates the widths of the resized columns.
395 *
396 * @param eventInfo An object containing information about the fired event.
397 * @param mouseEventData The native DOM event.
398 */
399 _onMouseMoveHandler(eventInfo, mouseEventData) {
400 if (!this._isResizingActive) {
401 return;
402 }
403 if (!this._isResizingAllowed) {
404 this._onMouseUpHandler();
405 return;
406 }
407 const { columnPosition, flags: { isRightEdge, isTableCentered, isLtrContent }, elements: { viewFigure, viewLeftColumn, viewRightColumn }, widths: { viewFigureParentWidth, tableWidth, leftColumnWidth, rightColumnWidth } } = this._resizingData;
408 const dxLowerBound = -leftColumnWidth + COLUMN_MIN_WIDTH_IN_PIXELS;
409 const dxUpperBound = isRightEdge ?
410 viewFigureParentWidth - tableWidth :
411 rightColumnWidth - COLUMN_MIN_WIDTH_IN_PIXELS;
412 // The multiplier is needed for calculating the proper movement offset:
413 // - it should negate the sign if content language direction is right-to-left,
414 // - it should double the offset if the table edge is resized and table is centered.
415 const multiplier = (isLtrContent ? 1 : -1) * (isRightEdge && isTableCentered ? 2 : 1);
416 const dx = clamp((mouseEventData.clientX - columnPosition) * multiplier, Math.min(dxLowerBound, 0), Math.max(dxUpperBound, 0));
417 if (dx === 0) {
418 return;
419 }
420 this.editor.editing.view.change(writer => {
421 const leftColumnWidthAsPercentage = toPrecision((leftColumnWidth + dx) * 100 / tableWidth);
422 writer.setStyle('width', `${leftColumnWidthAsPercentage}%`, viewLeftColumn);
423 if (isRightEdge) {
424 const tableWidthAsPercentage = toPrecision((tableWidth + dx) * 100 / viewFigureParentWidth);
425 writer.setStyle('width', `${tableWidthAsPercentage}%`, viewFigure);
426 }
427 else {
428 const rightColumnWidthAsPercentage = toPrecision((rightColumnWidth - dx) * 100 / tableWidth);
429 writer.setStyle('width', `${rightColumnWidthAsPercentage}%`, viewRightColumn);
430 }
431 });
432 }
433 /**
434 * Handles the `mouseup` event.
435 * * If resizing process is not in progress, it does nothing.
436 * * If resizing is active but not allowed, it cancels the resizing process restoring the original widths.
437 * * Otherwise it propagates the changes from view to the model by executing the adequate commands.
438 */
439 _onMouseUpHandler() {
440 if (!this._isResizingActive) {
441 return;
442 }
443 const { viewResizer, modelTable, viewFigure, viewColgroup } = this._resizingData.elements;
444 const editor = this.editor;
445 const editingView = editor.editing.view;
446 const tableColumnGroup = this.getColumnGroupElement(modelTable);
447 const viewColumns = Array
448 .from(viewColgroup.getChildren())
449 .filter((column) => column.is('view:element'));
450 const columnWidthsAttributeOld = tableColumnGroup ?
451 this.getTableColumnsWidths(tableColumnGroup) :
452 null;
453 const columnWidthsAttributeNew = viewColumns.map(column => column.getStyle('width'));
454 const isColumnWidthsAttributeChanged = !isEqual(columnWidthsAttributeOld, columnWidthsAttributeNew);
455 const tableWidthAttributeOld = modelTable.getAttribute('tableWidth');
456 const tableWidthAttributeNew = viewFigure.getStyle('width');
457 const isTableWidthAttributeChanged = tableWidthAttributeOld !== tableWidthAttributeNew;
458 if (isColumnWidthsAttributeChanged || isTableWidthAttributeChanged) {
459 if (this._isResizingAllowed) {
460 editor.execute('resizeTableWidth', {
461 table: modelTable,
462 tableWidth: `${toPrecision(tableWidthAttributeNew)}%`,
463 columnWidths: columnWidthsAttributeNew
464 });
465 }
466 else {
467 // In read-only mode revert all changes in the editing view. The model is not touched so it does not need to be restored.
468 // This case can occur if the read-only mode kicks in during the resizing process.
469 editingView.change(writer => {
470 // If table had resized columns before, restore the previous column widths.
471 // Otherwise clean up the view from the temporary column resizing markup.
472 if (columnWidthsAttributeOld) {
473 for (const viewCol of viewColumns) {
474 writer.setStyle('width', columnWidthsAttributeOld.shift(), viewCol);
475 }
476 }
477 else {
478 writer.remove(viewColgroup);
479 }
480 if (isTableWidthAttributeChanged) {
481 // If the whole table was already resized before, restore the previous table width.
482 // Otherwise clean up the view from the temporary table resizing markup.
483 if (tableWidthAttributeOld) {
484 writer.setStyle('width', tableWidthAttributeOld, viewFigure);
485 }
486 else {
487 writer.removeStyle('width', viewFigure);
488 }
489 }
490 // If a table and its columns weren't resized before,
491 // prune the remaining common resizing markup.
492 if (!columnWidthsAttributeOld && !tableWidthAttributeOld) {
493 writer.removeClass('ck-table-resized', [...viewFigure.getChildren()].find(element => element.name === 'table'));
494 }
495 });
496 }
497 }
498 editingView.change(writer => {
499 writer.removeClass('ck-table-column-resizer__active', viewResizer);
500 });
501 this._isResizingActive = false;
502 this._resizingData = null;
503 }
504 /**
505 * Retrieves and returns required data needed for the resizing process.
506 *
507 * @param domEventData The data of the `mousedown` event.
508 * @param columnWidths The current widths of the columns.
509 * @returns The data needed for the resizing process.
510 */
511 _getResizingData(domEventData, columnWidths) {
512 const editor = this.editor;
513 const columnPosition = domEventData.domEvent.clientX;
514 const viewResizer = domEventData.target;
515 const viewLeftCell = viewResizer.findAncestor('td') || viewResizer.findAncestor('th');
516 const modelLeftCell = editor.editing.mapper.toModelElement(viewLeftCell);
517 const modelTable = modelLeftCell.findAncestor('table');
518 const leftColumnIndex = getColumnEdgesIndexes(modelLeftCell, this._tableUtilsPlugin).rightEdge;
519 const lastColumnIndex = this._tableUtilsPlugin.getColumns(modelTable) - 1;
520 const isRightEdge = leftColumnIndex === lastColumnIndex;
521 const isTableCentered = !modelTable.hasAttribute('tableAlignment');
522 const isLtrContent = editor.locale.contentLanguageDirection !== 'rtl';
523 const viewTable = viewLeftCell.findAncestor('table');
524 const viewFigure = viewTable.findAncestor('figure');
525 const viewColgroup = [...viewTable.getChildren()]
526 .find(viewCol => viewCol.is('element', 'colgroup'));
527 const viewLeftColumn = viewColgroup.getChild(leftColumnIndex);
528 const viewRightColumn = isRightEdge ? undefined : viewColgroup.getChild(leftColumnIndex + 1);
529 const viewFigureParentWidth = getElementWidthInPixels(editor.editing.view.domConverter.mapViewToDom(viewFigure.parent));
530 const viewFigureWidth = getElementWidthInPixels(editor.editing.view.domConverter.mapViewToDom(viewFigure));
531 const tableWidth = getTableWidthInPixels(modelTable, editor);
532 const leftColumnWidth = columnWidths[leftColumnIndex];
533 const rightColumnWidth = isRightEdge ? undefined : columnWidths[leftColumnIndex + 1];
534 return {
535 columnPosition,
536 flags: {
537 isRightEdge,
538 isTableCentered,
539 isLtrContent
540 },
541 elements: {
542 viewResizer,
543 modelTable,
544 viewFigure,
545 viewColgroup,
546 viewLeftColumn,
547 viewRightColumn
548 },
549 widths: {
550 viewFigureParentWidth,
551 viewFigureWidth,
552 tableWidth,
553 leftColumnWidth,
554 rightColumnWidth
555 }
556 };
557 }
558 /**
559 * Registers a listener ensuring that each resizable cell have a resizer handle.
560 */
561 _registerResizerInserter() {
562 this.editor.conversion.for('editingDowncast').add(dispatcher => {
563 dispatcher.on('insert:tableCell', (evt, data, conversionApi) => {
564 const modelElement = data.item;
565 const viewElement = conversionApi.mapper.toViewElement(modelElement);
566 const viewWriter = conversionApi.writer;
567 viewWriter.insert(viewWriter.createPositionAt(viewElement, 'end'), viewWriter.createUIElement('div', { class: 'ck-table-column-resizer' }));
568 }, { priority: 'lowest' });
569 });
570 }
571}