@ckeditor/ckeditor5-table 35.0.1 → 35.2.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.
- package/build/table.js +1 -1
- package/build/table.js.map +1 -0
- package/build/translations/ko.js +1 -1
- package/build/translations/tt.js +1 -0
- package/build/translations/ur.js +1 -1
- package/lang/translations/ko.po +1 -1
- package/lang/translations/tt.po +261 -0
- package/lang/translations/ur.po +9 -9
- package/package.json +26 -26
- package/src/index.js +1 -0
- package/src/tablecaption/tablecaptionui.js +2 -0
- package/src/tablecellproperties/tablecellpropertiesediting.js +4 -30
- package/src/tablecellproperties/tablecellpropertiesui.js +1 -1
- package/src/tablecellproperties/ui/tablecellpropertiesview.js +2 -0
- package/src/{tablecellproperties → tablecellwidth}/commands/tablecellwidthcommand.js +2 -3
- package/src/tablecellwidth/tablecellwidthediting.js +58 -0
- package/src/tablecolumnresize/constants.js +0 -2
- package/src/tablecolumnresize/converters.js +29 -28
- package/src/tablecolumnresize/tablecolumnresizeediting.js +399 -425
- package/src/tablecolumnresize/tablecolumnwidthscommand.js +55 -0
- package/src/tablecolumnresize/tablewidthresizecommand.js +60 -0
- package/src/tablecolumnresize/utils.js +131 -167
- package/src/tablecolumnresize.js +4 -3
- package/src/tableproperties/ui/tablepropertiesview.js +2 -0
- package/src/tableui.js +0 -6
- package/src/ui/colorinputview.js +88 -51
- package/src/ui/inserttableview.js +86 -50
- package/src/utils/common.js +24 -0
- package/src/utils/ui/table-properties.js +7 -7
- package/theme/tablecolumnresize.css +13 -10
|
@@ -7,16 +7,18 @@
|
|
|
7
7
|
* @module table/tablecolumnresize/tablecolumnresizeediting
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
/* istanbul ignore file */
|
|
11
|
-
|
|
12
10
|
import { throttle } from 'lodash-es';
|
|
13
11
|
import { global, DomEmitterMixin } from 'ckeditor5/src/utils';
|
|
14
12
|
import { Plugin } from 'ckeditor5/src/core';
|
|
15
13
|
|
|
16
14
|
import MouseEventsObserver from '../../src/tablemouse/mouseeventsobserver';
|
|
17
15
|
import TableEditing from '../tableediting';
|
|
16
|
+
import TableUtils from '../tableutils';
|
|
18
17
|
import TableWalker from '../tablewalker';
|
|
19
18
|
|
|
19
|
+
import TableWidthResizeCommand from './tablewidthresizecommand';
|
|
20
|
+
import TableColumnWidthsCommand from './tablecolumnwidthscommand';
|
|
21
|
+
|
|
20
22
|
import {
|
|
21
23
|
upcastColgroupElement,
|
|
22
24
|
downcastTableColumnWidthsAttribute
|
|
@@ -24,20 +26,17 @@ import {
|
|
|
24
26
|
|
|
25
27
|
import {
|
|
26
28
|
clamp,
|
|
27
|
-
|
|
29
|
+
createFilledArray,
|
|
28
30
|
sumArray,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
getColumnWidthsInPixels,
|
|
31
|
+
getColumnEdgesIndexes,
|
|
32
|
+
getChangedResizedTables,
|
|
32
33
|
getColumnMinWidthAsPercentage,
|
|
33
34
|
getElementWidthInPixels,
|
|
34
35
|
getTableWidthInPixels,
|
|
35
|
-
|
|
36
|
-
isTableRendered,
|
|
37
|
-
normalizeColumnWidthsAttribute,
|
|
36
|
+
normalizeColumnWidths,
|
|
38
37
|
toPrecision,
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
ensureColumnResizerElement,
|
|
39
|
+
getDomCellOuterWidth
|
|
41
40
|
} from './utils';
|
|
42
41
|
|
|
43
42
|
import { COLUMN_MIN_WIDTH_IN_PIXELS } from './constants';
|
|
@@ -52,7 +51,7 @@ export default class TableColumnResizeEditing extends Plugin {
|
|
|
52
51
|
* @inheritDoc
|
|
53
52
|
*/
|
|
54
53
|
static get requires() {
|
|
55
|
-
return [ TableEditing ];
|
|
54
|
+
return [ TableEditing, TableUtils ];
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
/**
|
|
@@ -77,13 +76,14 @@ export default class TableColumnResizeEditing extends Plugin {
|
|
|
77
76
|
this._isResizingActive = false;
|
|
78
77
|
|
|
79
78
|
/**
|
|
80
|
-
* A flag indicating if the column resizing is allowed. It is not allowed if the editor is in read-only
|
|
81
|
-
* `TableColumnResize` plugin is disabled.
|
|
79
|
+
* A flag indicating if the column resizing is allowed. It is not allowed if the editor is in read-only
|
|
80
|
+
* or comments-only mode or the `TableColumnResize` plugin is disabled.
|
|
82
81
|
*
|
|
83
82
|
* @private
|
|
83
|
+
* @observable
|
|
84
84
|
* @member {Boolean}
|
|
85
85
|
*/
|
|
86
|
-
this._isResizingAllowed
|
|
86
|
+
this.set( '_isResizingAllowed', true );
|
|
87
87
|
|
|
88
88
|
/**
|
|
89
89
|
* A temporary storage for the required data needed to correctly calculate the widths of the resized columns. This storage is
|
|
@@ -95,22 +95,27 @@ export default class TableColumnResizeEditing extends Plugin {
|
|
|
95
95
|
this._resizingData = null;
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
|
-
*
|
|
99
|
-
* recognize if the cell was inserted or deleted.
|
|
98
|
+
* DOM emitter.
|
|
100
99
|
*
|
|
101
100
|
* @private
|
|
102
|
-
* @member {
|
|
101
|
+
* @member {DomEmitterMixin}
|
|
103
102
|
*/
|
|
104
|
-
this.
|
|
103
|
+
this._domEmitter = Object.create( DomEmitterMixin );
|
|
105
104
|
|
|
106
105
|
/**
|
|
107
|
-
*
|
|
108
|
-
* in order to add/remove resizers based on operation performed (which is done on 'render').
|
|
106
|
+
* A local reference to the {@link module:table/tableutils~TableUtils} plugin.
|
|
109
107
|
*
|
|
110
108
|
* @private
|
|
111
|
-
* @member {
|
|
109
|
+
* @member {module:table/tableutils~TableUtils}
|
|
112
110
|
*/
|
|
113
|
-
this.
|
|
111
|
+
this._tableUtilsPlugin = editor.plugins.get( 'TableUtils' );
|
|
112
|
+
|
|
113
|
+
this.on( 'change:_isResizingAllowed', ( evt, name, value ) => {
|
|
114
|
+
// Toggling the `ck-column-resize_disabled` class shows and hides the resizers through CSS.
|
|
115
|
+
editor.editing.view.change( writer => {
|
|
116
|
+
writer[ value ? 'removeClass' : 'addClass' ]( 'ck-column-resize_disabled', editor.editing.view.document.getRoot() );
|
|
117
|
+
} );
|
|
118
|
+
} );
|
|
114
119
|
}
|
|
115
120
|
|
|
116
121
|
/**
|
|
@@ -118,362 +123,239 @@ export default class TableColumnResizeEditing extends Plugin {
|
|
|
118
123
|
*/
|
|
119
124
|
init() {
|
|
120
125
|
this._extendSchema();
|
|
121
|
-
this.
|
|
122
|
-
this.
|
|
123
|
-
this.
|
|
126
|
+
this._registerPostFixer();
|
|
127
|
+
this._registerConverters();
|
|
128
|
+
this._registerResizingListeners();
|
|
124
129
|
this._registerColgroupFixer();
|
|
125
130
|
this._registerResizerInserter();
|
|
126
131
|
|
|
127
132
|
const editor = this.editor;
|
|
128
133
|
const columnResizePlugin = editor.plugins.get( 'TableColumnResize' );
|
|
129
134
|
|
|
135
|
+
editor.commands.add( 'resizeTableWidth', new TableWidthResizeCommand( editor ) );
|
|
136
|
+
editor.commands.add( 'resizeColumnWidths', new TableColumnWidthsCommand( editor ) );
|
|
137
|
+
|
|
138
|
+
const resizeTableWidthCommand = editor.commands.get( 'resizeTableWidth' );
|
|
139
|
+
const resizeColumnWidthsCommand = editor.commands.get( 'resizeColumnWidths' );
|
|
140
|
+
|
|
141
|
+
// Currently the states of column resize and table resize (which is actually the last column resize) features
|
|
142
|
+
// are bound together. They can be separated in the future by adding distinct listeners and applying
|
|
143
|
+
// different CSS classes (e.g. `ck-column-resize_disabled` and `ck-table-resize_disabled`) to the editor root.
|
|
144
|
+
// See #12148 for the details.
|
|
130
145
|
this.bind( '_isResizingAllowed' ).to(
|
|
131
146
|
editor, 'isReadOnly',
|
|
132
147
|
columnResizePlugin, 'isEnabled',
|
|
133
|
-
|
|
148
|
+
resizeTableWidthCommand, 'isEnabled',
|
|
149
|
+
resizeColumnWidthsCommand, 'isEnabled',
|
|
150
|
+
( isEditorReadOnly, isPluginEnabled, isResizeTableWidthCommandEnabled, isResizeColumnWidthsCommandEnabled ) =>
|
|
151
|
+
!isEditorReadOnly && isPluginEnabled && isResizeTableWidthCommandEnabled && isResizeColumnWidthsCommandEnabled
|
|
134
152
|
);
|
|
135
153
|
}
|
|
136
154
|
|
|
137
155
|
/**
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
* @private
|
|
156
|
+
* @inheritDoc
|
|
141
157
|
*/
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
schema.extend( 'table', {
|
|
147
|
-
allowAttributes: [ 'tableWidth', 'columnWidths' ]
|
|
148
|
-
} );
|
|
158
|
+
destroy() {
|
|
159
|
+
this._domEmitter.stopListening();
|
|
160
|
+
super.destroy();
|
|
149
161
|
}
|
|
150
162
|
|
|
151
163
|
/**
|
|
152
|
-
* Registers table
|
|
164
|
+
* Registers new attributes for a table model element.
|
|
153
165
|
*
|
|
154
166
|
* @private
|
|
155
167
|
*/
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
conversion.for( 'upcast' ).attributeToAttribute( {
|
|
161
|
-
view: {
|
|
162
|
-
name: 'figure',
|
|
163
|
-
key: 'style',
|
|
164
|
-
value: {
|
|
165
|
-
width: /[\s\S]+/
|
|
166
|
-
}
|
|
167
|
-
},
|
|
168
|
-
model: {
|
|
169
|
-
name: 'table',
|
|
170
|
-
key: 'tableWidth',
|
|
171
|
-
value: viewElement => viewElement.getStyle( 'width' )
|
|
172
|
-
}
|
|
173
|
-
} );
|
|
174
|
-
|
|
175
|
-
conversion.for( 'downcast' ).attributeToAttribute( {
|
|
176
|
-
model: {
|
|
177
|
-
name: 'table',
|
|
178
|
-
key: 'tableWidth'
|
|
179
|
-
},
|
|
180
|
-
view: width => ( {
|
|
181
|
-
name: 'figure',
|
|
182
|
-
key: 'style',
|
|
183
|
-
value: {
|
|
184
|
-
width
|
|
185
|
-
}
|
|
186
|
-
} )
|
|
168
|
+
_extendSchema() {
|
|
169
|
+
this.editor.model.schema.extend( 'table', {
|
|
170
|
+
allowAttributes: [ 'tableWidth', 'columnWidths' ]
|
|
187
171
|
} );
|
|
188
|
-
|
|
189
|
-
conversion.for( 'upcast' ).add( upcastColgroupElement( editor ) );
|
|
190
|
-
conversion.for( 'downcast' ).add( downcastTableColumnWidthsAttribute() );
|
|
191
172
|
}
|
|
192
173
|
|
|
193
174
|
/**
|
|
194
|
-
* Registers table column
|
|
175
|
+
* Registers table column resize post-fixer.
|
|
195
176
|
*
|
|
196
|
-
* It checks if the change from the differ concerns a table-related element or
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
* (1.1) ...removing the `columnWidths` attribute from the table and all the cells from column index map, or
|
|
200
|
-
* (1.2) ...adding the `columnWidths` attribute to the table.
|
|
201
|
-
* (2) Adjusting the `columnWidths` attribute to guarantee that the sum of the widths from all columns is 100%.
|
|
202
|
-
* (2.1) Add all cells to column index map with its column index (to properly handle column insertion and deletion).
|
|
203
|
-
* (3) Checking if columns have been added or removed...
|
|
204
|
-
* (3.1) ... in the middle of the table, or
|
|
205
|
-
* (3.2) ... at the table end.
|
|
206
|
-
* (4) Checking if the inline cell width has been configured and transferring its value to the appropriate column, but currently only
|
|
207
|
-
* for a cell that is not spanned horizontally.
|
|
177
|
+
* It checks if the change from the differ concerns a table-related element or attribute. For detected changes it:
|
|
178
|
+
* * Adjusts the `columnWidths` attribute to guarantee that the sum of the widths from all columns is 100%.
|
|
179
|
+
* * Checks if the `columnWidths` attribute gets updated accordingly after columns have been added or removed.
|
|
208
180
|
*
|
|
209
181
|
* @private
|
|
210
182
|
*/
|
|
211
|
-
|
|
183
|
+
_registerPostFixer() {
|
|
212
184
|
const editor = this.editor;
|
|
213
|
-
const
|
|
214
|
-
const cellsModified = this._cellsModified;
|
|
215
|
-
|
|
216
|
-
editor.model.document.registerPostFixer( writer => {
|
|
217
|
-
const changes = editor.model.document.differ.getChanges();
|
|
185
|
+
const model = editor.model;
|
|
218
186
|
|
|
187
|
+
model.document.registerPostFixer( writer => {
|
|
219
188
|
let changed = false;
|
|
220
189
|
|
|
221
|
-
for ( const table of
|
|
222
|
-
// (1
|
|
223
|
-
|
|
224
|
-
if ( this.fire( 'disableResize', table ) ) {
|
|
225
|
-
if ( table.hasAttribute( 'columnWidths' ) ) {
|
|
226
|
-
writer.removeAttribute( 'columnWidths', table );
|
|
190
|
+
for ( const table of getChangedResizedTables( model ) ) {
|
|
191
|
+
// (1) Adjust the `columnWidths` attribute to guarantee that the sum of the widths from all columns is 100%.
|
|
192
|
+
const columnWidths = normalizeColumnWidths( table.getAttribute( 'columnWidths' ).split( ',' ) );
|
|
227
193
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
cellsModified.set( cell, 'remove' );
|
|
231
|
-
}
|
|
194
|
+
// (2) If the number of columns has changed, then we need to adjust the widths of the affected columns.
|
|
195
|
+
adjustColumnWidths( columnWidths, table, this );
|
|
232
196
|
|
|
233
|
-
|
|
234
|
-
}
|
|
197
|
+
const columnWidthsAttribute = columnWidths.map( width => `${ width }%` ).join( ',' );
|
|
235
198
|
|
|
199
|
+
if ( table.getAttribute( 'columnWidths' ) === columnWidthsAttribute ) {
|
|
236
200
|
continue;
|
|
237
201
|
}
|
|
238
202
|
|
|
239
|
-
|
|
240
|
-
// calculated proportionally to the whole table width.
|
|
241
|
-
const numberOfColumns = getNumberOfColumn( table, editor );
|
|
242
|
-
|
|
243
|
-
if ( !table.hasAttribute( 'columnWidths' ) ) {
|
|
244
|
-
const columnWidthsAttribute = fillArray( numberOfColumns, 'auto' ).join( ',' );
|
|
245
|
-
|
|
246
|
-
writer.setAttribute( 'columnWidths', columnWidthsAttribute, table );
|
|
247
|
-
|
|
248
|
-
changed = true;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// (2) Adjust the `columnWidths` attribute to guarantee that the sum of the widths from all columns is 100%.
|
|
252
|
-
const columnWidths = normalizeColumnWidthsAttribute( table.getAttribute( 'columnWidths' ) );
|
|
253
|
-
|
|
254
|
-
let removedColumnWidths = null;
|
|
255
|
-
let isColumnInsertionHandled = false;
|
|
256
|
-
let isColumnDeletionHandled = false;
|
|
257
|
-
|
|
258
|
-
for ( const { cell, cellWidth: cellColumnWidth, column } of new TableWalker( table ) ) {
|
|
259
|
-
// (2.1) Add all cells to column index map with its column index. Do not process the given cell anymore, because the
|
|
260
|
-
// `columnIndex` reference in the map is required to properly handle column insertion and deletion.
|
|
261
|
-
if ( !columnIndexMap.has( cell ) ) {
|
|
262
|
-
columnIndexMap.set( cell, column );
|
|
263
|
-
cellsModified.set( cell, 'insert' );
|
|
264
|
-
|
|
265
|
-
changed = true;
|
|
266
|
-
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const previousColumn = columnIndexMap.get( cell );
|
|
271
|
-
|
|
272
|
-
const isColumnInsertion = previousColumn < column;
|
|
273
|
-
const isColumnDeletion = previousColumn > column;
|
|
274
|
-
|
|
275
|
-
// (3.1) Handle column insertion and update the `columnIndex` references in column index map for affected cells.
|
|
276
|
-
if ( isColumnInsertion ) {
|
|
277
|
-
if ( !isColumnInsertionHandled ) {
|
|
278
|
-
const columnMinWidthAsPercentage = getColumnMinWidthAsPercentage( table, editor );
|
|
279
|
-
const isColumnSwapped = columnIndexMap.get( cell.previousSibling ) === column;
|
|
280
|
-
const columnWidthsToInsert = isColumnSwapped ?
|
|
281
|
-
removedColumnWidths :
|
|
282
|
-
fillArray( column - previousColumn, columnMinWidthAsPercentage );
|
|
283
|
-
|
|
284
|
-
columnWidths.splice( previousColumn, 0, ...columnWidthsToInsert );
|
|
285
|
-
|
|
286
|
-
isColumnInsertionHandled = true;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
columnIndexMap.set( cell, column );
|
|
290
|
-
cellsModified.set( cell, 'insert' );
|
|
291
|
-
|
|
292
|
-
changed = true;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// (3.1) Handle column deletion and update the `columnIndex` references in column index map for affected cells.
|
|
296
|
-
if ( isColumnDeletion ) {
|
|
297
|
-
if ( !isColumnDeletionHandled ) {
|
|
298
|
-
removedColumnWidths = columnWidths.splice( column, previousColumn - column );
|
|
299
|
-
|
|
300
|
-
const isColumnSwapped = cell.nextSibling && columnIndexMap.get( cell.nextSibling ) === column;
|
|
301
|
-
|
|
302
|
-
if ( !isColumnSwapped ) {
|
|
303
|
-
const columnToExpand = column > 0 ? column - 1 : column;
|
|
304
|
-
|
|
305
|
-
columnWidths[ columnToExpand ] += sumArray( removedColumnWidths );
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
isColumnDeletionHandled = true;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
columnIndexMap.set( cell, column );
|
|
312
|
-
cellsModified.set( cell, 'insert' );
|
|
313
|
-
|
|
314
|
-
changed = true;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// (4) Check if the inline cell width has been configured and transfer its value to the appropriate column.
|
|
318
|
-
if ( cell.hasAttribute( 'width' ) ) {
|
|
319
|
-
// Currently, only the inline width from the cells that are not horizontally spanned are supported.
|
|
320
|
-
if ( cellColumnWidth !== 1 ) {
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// It may happen that the table is not yet fully rendered in the editing view (i.e. it does not contain the
|
|
325
|
-
// `<colgroup>` yet), but the cell has an inline width set. In that case it is not possible to properly convert the
|
|
326
|
-
// inline cell width as a percentage value to the whole table width. Currently, we just ignore this case and
|
|
327
|
-
// initialize the table with all the default (equal) column widths.
|
|
328
|
-
if ( !isTableRendered( table, editor ) ) {
|
|
329
|
-
writer.removeAttribute( 'width', cell );
|
|
330
|
-
|
|
331
|
-
changed = true;
|
|
332
|
-
|
|
333
|
-
continue;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const tableWidthInPixels = getTableWidthInPixels( table, editor );
|
|
337
|
-
const columnWidthsInPixels = getColumnWidthsInPixels( table, editor );
|
|
338
|
-
const columnMinWidthAsPercentage = getColumnMinWidthAsPercentage( table, editor );
|
|
339
|
-
|
|
340
|
-
const cellWidth = parseFloat( cell.getAttribute( 'width' ) );
|
|
341
|
-
|
|
342
|
-
const isWidthInPixels = cell.getAttribute( 'width' ).endsWith( 'px' );
|
|
343
|
-
const isWidthAsPercentage = cell.getAttribute( 'width' ).endsWith( '%' );
|
|
344
|
-
|
|
345
|
-
// Currently, only inline width in pixels or as percentage is supported.
|
|
346
|
-
if ( !isWidthInPixels && !isWidthAsPercentage ) {
|
|
347
|
-
continue;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
const isRightEdge = !cell.nextSibling;
|
|
351
|
-
|
|
352
|
-
if ( isRightEdge ) {
|
|
353
|
-
const rootWidthInPixels = getElementWidthInPixels( editor.editing.view.getDomRoot() );
|
|
354
|
-
const lastColumnIndex = numberOfColumns - 1;
|
|
355
|
-
const lastColumnWidthInPixels = columnWidthsInPixels[ lastColumnIndex ];
|
|
356
|
-
|
|
357
|
-
let tableWidthNew;
|
|
358
|
-
|
|
359
|
-
if ( isWidthInPixels ) {
|
|
360
|
-
const cellWidthLowerBound = COLUMN_MIN_WIDTH_IN_PIXELS;
|
|
361
|
-
const cellWidthUpperBound = rootWidthInPixels - ( tableWidthInPixels - lastColumnWidthInPixels );
|
|
362
|
-
|
|
363
|
-
columnWidthsInPixels[ lastColumnIndex ] = clamp( cellWidth, cellWidthLowerBound, cellWidthUpperBound );
|
|
364
|
-
|
|
365
|
-
tableWidthNew = sumArray( columnWidthsInPixels );
|
|
366
|
-
|
|
367
|
-
// Update all the column widths.
|
|
368
|
-
for ( let columnIndex = 0; columnIndex <= lastColumnIndex; columnIndex++ ) {
|
|
369
|
-
columnWidths[ columnIndex ] = toPrecision( columnWidthsInPixels[ columnIndex ] * 100 / tableWidthNew );
|
|
370
|
-
}
|
|
371
|
-
} else {
|
|
372
|
-
const cellWidthLowerBound = columnMinWidthAsPercentage;
|
|
373
|
-
const cellWidthUpperBound = 100 - ( tableWidthInPixels - lastColumnWidthInPixels ) * 100 /
|
|
374
|
-
rootWidthInPixels;
|
|
375
|
-
|
|
376
|
-
columnWidths[ lastColumnIndex ] = clamp( cellWidth, cellWidthLowerBound, cellWidthUpperBound );
|
|
203
|
+
writer.setAttribute( 'columnWidths', columnWidthsAttribute, table );
|
|
377
204
|
|
|
378
|
-
|
|
379
|
-
|
|
205
|
+
changed = true;
|
|
206
|
+
}
|
|
380
207
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
columnWidths[ columnIndex ] = toPrecision( columnWidthsInPixels[ columnIndex ] * 100 / tableWidthNew );
|
|
384
|
-
}
|
|
385
|
-
}
|
|
208
|
+
return changed;
|
|
209
|
+
} );
|
|
386
210
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
211
|
+
// Adjusts if necessary the `columnWidths` in case if the number of column has changed.
|
|
212
|
+
//
|
|
213
|
+
// @private
|
|
214
|
+
// @param {Array.<Number>} columnWidths Note: this array **may be modified** by the function.
|
|
215
|
+
// @param {module:engine/model/element~Element} table Table to be checked.
|
|
216
|
+
// @param {module:table/tablecolumnresize/tablecolumnresizeediting~TableColumnResizeEditing} plugin
|
|
217
|
+
function adjustColumnWidths( columnWidths, table, plugin ) {
|
|
218
|
+
const newTableColumnsCount = plugin._tableUtilsPlugin.getColumns( table );
|
|
219
|
+
const columnsCountDelta = newTableColumnsCount - columnWidths.length;
|
|
220
|
+
|
|
221
|
+
if ( columnsCountDelta === 0 ) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
392
224
|
|
|
393
|
-
|
|
225
|
+
// Collect all cells that are affected by the change.
|
|
226
|
+
const cellSet = getAffectedCells( plugin.editor.model.document.differ, table );
|
|
394
227
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
cellWidth;
|
|
228
|
+
for ( const cell of cellSet ) {
|
|
229
|
+
const currentColumnsDelta = newTableColumnsCount - columnWidths.length;
|
|
398
230
|
|
|
399
|
-
|
|
231
|
+
if ( currentColumnsDelta === 0 ) {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
400
234
|
|
|
401
|
-
|
|
235
|
+
// If the column count in the table changed, adjust the widths of the affected columns.
|
|
236
|
+
const hasMoreColumns = currentColumnsDelta > 0;
|
|
237
|
+
const currentColumnIndex = plugin._tableUtilsPlugin.getCellLocation( cell ).column;
|
|
402
238
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
239
|
+
if ( hasMoreColumns ) {
|
|
240
|
+
const columnMinWidthAsPercentage = getColumnMinWidthAsPercentage( table, plugin.editor );
|
|
241
|
+
const columnWidthsToInsert = createFilledArray( currentColumnsDelta, columnMinWidthAsPercentage );
|
|
406
242
|
|
|
407
|
-
|
|
243
|
+
columnWidths.splice( currentColumnIndex, 0, ...columnWidthsToInsert );
|
|
244
|
+
} else {
|
|
245
|
+
// Moves the widths of the removed columns to the preceding one.
|
|
246
|
+
// Other editors either reduce the width of the whole table or adjust the widths
|
|
247
|
+
// proportionally, so change of this behavior can be considered in the future.
|
|
248
|
+
const removedColumnWidths = columnWidths.splice( currentColumnIndex, Math.abs( currentColumnsDelta ) );
|
|
408
249
|
|
|
409
|
-
|
|
410
|
-
}
|
|
250
|
+
columnWidths[ currentColumnIndex ] += sumArray( removedColumnWidths );
|
|
411
251
|
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
412
254
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
255
|
+
// Returns a set of cells that have been changed in a given table.
|
|
256
|
+
//
|
|
257
|
+
// @private
|
|
258
|
+
// @param {module:engine/model/differ~Differ} differ
|
|
259
|
+
// @param {module:engine/model/element~Element} table
|
|
260
|
+
// @returns {Set.<module:engine/model/element~Element>}
|
|
261
|
+
function getAffectedCells( differ, table ) {
|
|
262
|
+
const cellSet = new Set();
|
|
263
|
+
|
|
264
|
+
for ( const change of differ.getChanges() ) {
|
|
265
|
+
if (
|
|
266
|
+
change.type == 'insert' &&
|
|
267
|
+
change.position.nodeAfter &&
|
|
268
|
+
change.position.nodeAfter.name == 'tableCell' &&
|
|
269
|
+
change.position.nodeAfter.getAncestors().includes( table )
|
|
270
|
+
) {
|
|
271
|
+
cellSet.add( change.position.nodeAfter );
|
|
272
|
+
} else if ( change.type == 'remove' ) {
|
|
273
|
+
// If the first cell was removed, use the node after the change position instead.
|
|
274
|
+
const referenceNode = change.position.nodeBefore || change.position.nodeAfter;
|
|
275
|
+
|
|
276
|
+
if ( referenceNode.name == 'tableCell' && referenceNode.getAncestors().includes( table ) ) {
|
|
277
|
+
cellSet.add( referenceNode );
|
|
278
|
+
}
|
|
423
279
|
}
|
|
280
|
+
}
|
|
424
281
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
282
|
+
return cellSet;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
428
285
|
|
|
429
|
-
|
|
286
|
+
/**
|
|
287
|
+
* Registers table column resize converters.
|
|
288
|
+
*
|
|
289
|
+
* @private
|
|
290
|
+
*/
|
|
291
|
+
_registerConverters() {
|
|
292
|
+
const editor = this.editor;
|
|
293
|
+
const conversion = editor.conversion;
|
|
294
|
+
const widthStyleToTableWidthDefinition = {
|
|
295
|
+
view: {
|
|
296
|
+
name: 'figure',
|
|
297
|
+
key: 'style',
|
|
298
|
+
value: {
|
|
299
|
+
width: /[\s\S]+/
|
|
430
300
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
301
|
+
},
|
|
302
|
+
model: {
|
|
303
|
+
name: 'table',
|
|
304
|
+
key: 'tableWidth',
|
|
305
|
+
value: viewElement => viewElement.getStyle( 'width' )
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
const tableWidthToWidthStyleDefinition = {
|
|
309
|
+
model: {
|
|
310
|
+
name: 'table',
|
|
311
|
+
key: 'tableWidth'
|
|
312
|
+
},
|
|
313
|
+
view: width => ( {
|
|
314
|
+
name: 'figure',
|
|
315
|
+
key: 'style',
|
|
316
|
+
value: {
|
|
317
|
+
width
|
|
436
318
|
}
|
|
319
|
+
} )
|
|
320
|
+
};
|
|
437
321
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
changed = true;
|
|
441
|
-
}
|
|
322
|
+
conversion.for( 'upcast' ).attributeToAttribute( widthStyleToTableWidthDefinition );
|
|
323
|
+
conversion.for( 'upcast' ).add( upcastColgroupElement( this._tableUtilsPlugin ) );
|
|
442
324
|
|
|
443
|
-
|
|
444
|
-
|
|
325
|
+
conversion.for( 'downcast' ).attributeToAttribute( tableWidthToWidthStyleDefinition );
|
|
326
|
+
conversion.for( 'downcast' ).add( downcastTableColumnWidthsAttribute() );
|
|
445
327
|
}
|
|
446
328
|
|
|
447
329
|
/**
|
|
448
|
-
*
|
|
330
|
+
* Registers listeners to handle resizing process.
|
|
449
331
|
*
|
|
450
332
|
* @private
|
|
451
333
|
*/
|
|
452
|
-
|
|
453
|
-
const
|
|
454
|
-
const editingView = editor.editing.view;
|
|
334
|
+
_registerResizingListeners() {
|
|
335
|
+
const editingView = this.editor.editing.view;
|
|
455
336
|
|
|
456
337
|
editingView.addObserver( MouseEventsObserver );
|
|
457
338
|
editingView.document.on( 'mousedown', this._onMouseDownHandler.bind( this ), { priority: 'high' } );
|
|
458
339
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
domEmitter.listenTo( global.window.document, 'mouseup', this._onMouseUpHandler.bind( this ) );
|
|
462
|
-
domEmitter.listenTo( global.window.document, 'mousemove', throttle( this._onMouseMoveHandler.bind( this ), 50 ) );
|
|
340
|
+
this._domEmitter.listenTo( global.window.document, 'mousemove', throttle( this._onMouseMoveHandler.bind( this ), 50 ) );
|
|
341
|
+
this._domEmitter.listenTo( global.window.document, 'mouseup', this._onMouseUpHandler.bind( this ) );
|
|
463
342
|
}
|
|
464
343
|
|
|
465
344
|
/**
|
|
466
|
-
* Handles the `mousedown` event on column resizer element
|
|
345
|
+
* Handles the `mousedown` event on column resizer element:
|
|
346
|
+
* * calculates the initial column pixel widths,
|
|
347
|
+
* * inserts the `<colgroup>` element if it is not present in the `<table>`,
|
|
348
|
+
* * puts the necessary data in the temporary storage,
|
|
349
|
+
* * applies the attributes to the `<table>` view element.
|
|
467
350
|
*
|
|
468
351
|
* @private
|
|
469
|
-
* @param {module:utils/eventinfo~EventInfo} eventInfo
|
|
470
|
-
* @param {module:engine/view/observer/domeventdata~DomEventData} domEventData
|
|
352
|
+
* @param {module:utils/eventinfo~EventInfo} eventInfo An object containing information about the fired event.
|
|
353
|
+
* @param {module:engine/view/observer/domeventdata~DomEventData} domEventData The data related to the DOM event.
|
|
471
354
|
*/
|
|
472
355
|
_onMouseDownHandler( eventInfo, domEventData ) {
|
|
473
|
-
const
|
|
474
|
-
const editingView = editor.editing.view;
|
|
356
|
+
const target = domEventData.target;
|
|
475
357
|
|
|
476
|
-
if ( !
|
|
358
|
+
if ( !target.hasClass( 'ck-table-column-resizer' ) ) {
|
|
477
359
|
return;
|
|
478
360
|
}
|
|
479
361
|
|
|
@@ -484,101 +366,100 @@ export default class TableColumnResizeEditing extends Plugin {
|
|
|
484
366
|
domEventData.preventDefault();
|
|
485
367
|
eventInfo.stop();
|
|
486
368
|
|
|
487
|
-
this._isResizingActive = true;
|
|
488
|
-
this._resizingData = this._getResizingData( domEventData );
|
|
489
|
-
|
|
490
|
-
editingView.change( writer => {
|
|
491
|
-
writer.addClass( 'table-column-resizer__active', this._resizingData.elements.viewResizer );
|
|
492
|
-
} );
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
/**
|
|
496
|
-
* Handles the `mouseup` event if previously the `mousedown` event was triggered from the column resizer element.
|
|
497
|
-
*
|
|
498
|
-
* @private
|
|
499
|
-
* @param {module:utils/eventinfo~EventInfo} eventInfo
|
|
500
|
-
* @param {module:engine/view/observer/domeventdata~DomEventData} domEventData
|
|
501
|
-
*/
|
|
502
|
-
_onMouseUpHandler() {
|
|
503
369
|
const editor = this.editor;
|
|
370
|
+
const modelTable = editor.editing.mapper.toModelElement( target.findAncestor( 'figure' ) );
|
|
371
|
+
|
|
372
|
+
// The column widths are calculated upon mousedown to allow lazy applying the `columnWidths` attribute on the table.
|
|
373
|
+
const columnWidthsInPx = _calculateDomColumnWidths( modelTable, this._tableUtilsPlugin, editor );
|
|
374
|
+
const viewTable = target.findAncestor( 'table' );
|
|
504
375
|
const editingView = editor.editing.view;
|
|
505
376
|
|
|
506
|
-
|
|
507
|
-
|
|
377
|
+
// Insert colgroup for the table that is resized for the first time.
|
|
378
|
+
if ( ![ ...viewTable.getChildren() ].find( viewCol => viewCol.is( 'element', 'colgroup' ) ) ) {
|
|
379
|
+
editingView.change( viewWriter => {
|
|
380
|
+
_insertColgroupElement( viewWriter, columnWidthsInPx, viewTable );
|
|
381
|
+
} );
|
|
508
382
|
}
|
|
509
383
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
editor.
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
}
|
|
540
|
-
} );
|
|
541
|
-
} else {
|
|
542
|
-
// In read-only mode revert all changes in the editing view. The model is not touched so it does not need to be restored.
|
|
543
|
-
editingView.change( writer => {
|
|
544
|
-
if ( isColumnWidthsAttributeChanged ) {
|
|
545
|
-
const columnWidths = columnWidthsAttributeOld.split( ',' );
|
|
384
|
+
this._isResizingActive = true;
|
|
385
|
+
this._resizingData = this._getResizingData( domEventData, columnWidthsInPx );
|
|
386
|
+
|
|
387
|
+
// At this point we change only the editor view - we don't want other users to see our changes yet,
|
|
388
|
+
// so we can't apply them in the model.
|
|
389
|
+
editingView.change( writer => _applyResizingAttributesToTable( writer, viewTable, this._resizingData ) );
|
|
390
|
+
|
|
391
|
+
// Calculates the DOM columns' widths. It is done by taking the width of the widest cell
|
|
392
|
+
// from each table column (we rely on the {@link module:table/tablewalker~TableWalker}
|
|
393
|
+
// to determine which column the cell belongs to).
|
|
394
|
+
//
|
|
395
|
+
// @private
|
|
396
|
+
// @param {module:engine/model/element~Element} modelTable A table which columns should be measured.
|
|
397
|
+
// @param {module:table/tableutils~TableUtils} tableUtils The Table Utils plugin instance.
|
|
398
|
+
// @param {module:core/editor/editor~Editor} editor The editor instance.
|
|
399
|
+
// @returns {Array.<Number>} Columns' widths expressed in pixels (without unit).
|
|
400
|
+
function _calculateDomColumnWidths( modelTable, tableUtilsPlugin, editor ) {
|
|
401
|
+
const columnWidthsInPx = Array( tableUtilsPlugin.getColumns( modelTable ) );
|
|
402
|
+
const tableWalker = new TableWalker( modelTable );
|
|
403
|
+
|
|
404
|
+
for ( const cellSlot of tableWalker ) {
|
|
405
|
+
const viewCell = editor.editing.mapper.toViewElement( cellSlot.cell );
|
|
406
|
+
const domCell = editor.editing.view.domConverter.mapViewToDom( viewCell );
|
|
407
|
+
const domCellWidth = getDomCellOuterWidth( domCell );
|
|
408
|
+
|
|
409
|
+
if ( !columnWidthsInPx[ cellSlot.column ] || domCellWidth < columnWidthsInPx[ cellSlot.column ] ) {
|
|
410
|
+
columnWidthsInPx[ cellSlot.column ] = toPrecision( domCellWidth );
|
|
411
|
+
}
|
|
412
|
+
}
|
|
546
413
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
}
|
|
550
|
-
}
|
|
414
|
+
return columnWidthsInPx;
|
|
415
|
+
}
|
|
551
416
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
417
|
+
// Creates a `<colgroup>` element with `<col>`s and inserts it into a given view table.
|
|
418
|
+
//
|
|
419
|
+
// @private
|
|
420
|
+
// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter A writer instance.
|
|
421
|
+
// @param {Array.<Number>} columnWidthsInPx Column widths.
|
|
422
|
+
// @param {module:engine/view/element~Element} viewTable A table view element.
|
|
423
|
+
function _insertColgroupElement( viewWriter, columnWidthsInPx, viewTable ) {
|
|
424
|
+
const colgroup = viewWriter.createContainerElement( 'colgroup' );
|
|
425
|
+
|
|
426
|
+
for ( let i = 0; i < columnWidthsInPx.length; i++ ) {
|
|
427
|
+
const viewColElement = viewWriter.createEmptyElement( 'col' );
|
|
428
|
+
const columnWidthInPc = `${ toPrecision( columnWidthsInPx[ i ] / sumArray( columnWidthsInPx ) * 100 ) }%`;
|
|
429
|
+
|
|
430
|
+
viewWriter.setStyle( 'width', columnWidthInPc, viewColElement );
|
|
431
|
+
viewWriter.insert( viewWriter.createPositionAt( colgroup, 'end' ), viewColElement );
|
|
560
432
|
}
|
|
561
|
-
}
|
|
562
433
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
} );
|
|
434
|
+
viewWriter.insert( viewWriter.createPositionAt( viewTable, 'start' ), colgroup );
|
|
435
|
+
}
|
|
566
436
|
|
|
567
|
-
|
|
568
|
-
|
|
437
|
+
// Applies the style and classes to the view table as the resizing begun.
|
|
438
|
+
//
|
|
439
|
+
// @private
|
|
440
|
+
// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter A writer instance.
|
|
441
|
+
// @param {module:engine/view/element~Element} viewTable A table containing the clicked resizer.
|
|
442
|
+
// @param {Object} resizingData Data related to the resizing.
|
|
443
|
+
function _applyResizingAttributesToTable( viewWriter, viewTable, resizingData ) {
|
|
444
|
+
const figureInitialPcWidth = resizingData.widths.viewFigureWidth / resizingData.widths.viewFigureParentWidth;
|
|
445
|
+
|
|
446
|
+
viewWriter.addClass( 'ck-table-resized', viewTable );
|
|
447
|
+
viewWriter.addClass( 'ck-table-column-resizer__active', resizingData.elements.viewResizer );
|
|
448
|
+
viewWriter.setStyle( 'width', `${ toPrecision( figureInitialPcWidth * 100 ) }%`, viewTable.findAncestor( 'figure' ) );
|
|
449
|
+
}
|
|
569
450
|
}
|
|
570
451
|
|
|
571
452
|
/**
|
|
572
|
-
* Handles the `mousemove` event
|
|
453
|
+
* Handles the `mousemove` event.
|
|
454
|
+
* * If resizing process is not in progress, it does nothing.
|
|
455
|
+
* * If resizing is active but not allowed, it stops the resizing process instantly calling the `mousedown` event handler.
|
|
456
|
+
* * Otherwise it dynamically updates the widths of the resized columns.
|
|
573
457
|
*
|
|
574
458
|
* @private
|
|
575
|
-
* @param {module:utils/eventinfo~EventInfo} eventInfo
|
|
576
|
-
* @param {
|
|
459
|
+
* @param {module:utils/eventinfo~EventInfo} eventInfo An object containing information about the fired event.
|
|
460
|
+
* @param {Event} mouseEventData The native DOM event.
|
|
577
461
|
*/
|
|
578
|
-
_onMouseMoveHandler( eventInfo,
|
|
579
|
-
const editor = this.editor;
|
|
580
|
-
const editingView = editor.editing.view;
|
|
581
|
-
|
|
462
|
+
_onMouseMoveHandler( eventInfo, mouseEventData ) {
|
|
582
463
|
if ( !this._isResizingActive ) {
|
|
583
464
|
return;
|
|
584
465
|
}
|
|
@@ -593,19 +474,19 @@ export default class TableColumnResizeEditing extends Plugin {
|
|
|
593
474
|
columnPosition,
|
|
594
475
|
flags: {
|
|
595
476
|
isRightEdge,
|
|
596
|
-
|
|
597
|
-
|
|
477
|
+
isTableCentered,
|
|
478
|
+
isLtrContent
|
|
479
|
+
},
|
|
480
|
+
elements: {
|
|
481
|
+
viewFigure,
|
|
482
|
+
viewLeftColumn,
|
|
483
|
+
viewRightColumn
|
|
598
484
|
},
|
|
599
485
|
widths: {
|
|
600
486
|
viewFigureParentWidth,
|
|
601
487
|
tableWidth,
|
|
602
488
|
leftColumnWidth,
|
|
603
489
|
rightColumnWidth
|
|
604
|
-
},
|
|
605
|
-
elements: {
|
|
606
|
-
viewFigure,
|
|
607
|
-
viewLeftColumn,
|
|
608
|
-
viewRightColumn
|
|
609
490
|
}
|
|
610
491
|
} = this._resizingData;
|
|
611
492
|
|
|
@@ -621,7 +502,7 @@ export default class TableColumnResizeEditing extends Plugin {
|
|
|
621
502
|
const multiplier = ( isLtrContent ? 1 : -1 ) * ( isRightEdge && isTableCentered ? 2 : 1 );
|
|
622
503
|
|
|
623
504
|
const dx = clamp(
|
|
624
|
-
(
|
|
505
|
+
( mouseEventData.clientX - columnPosition ) * multiplier,
|
|
625
506
|
Math.min( dxLowerBound, 0 ),
|
|
626
507
|
Math.max( dxUpperBound, 0 )
|
|
627
508
|
);
|
|
@@ -630,7 +511,7 @@ export default class TableColumnResizeEditing extends Plugin {
|
|
|
630
511
|
return;
|
|
631
512
|
}
|
|
632
513
|
|
|
633
|
-
|
|
514
|
+
this.editor.editing.view.change( writer => {
|
|
634
515
|
const leftColumnWidthAsPercentage = toPrecision( ( leftColumnWidth + dx ) * 100 / tableWidth );
|
|
635
516
|
|
|
636
517
|
writer.setStyle( 'width', `${ leftColumnWidthAsPercentage }%`, viewLeftColumn );
|
|
@@ -648,13 +529,110 @@ export default class TableColumnResizeEditing extends Plugin {
|
|
|
648
529
|
}
|
|
649
530
|
|
|
650
531
|
/**
|
|
651
|
-
*
|
|
532
|
+
* Handles the `mouseup` event.
|
|
533
|
+
* * If resizing process is not in progress, it does nothing.
|
|
534
|
+
* * If resizing is active but not allowed, it cancels the resizing process restoring the original widths.
|
|
535
|
+
* * Otherwise it propagates the changes from view to the model by executing the adequate commands.
|
|
652
536
|
*
|
|
653
537
|
* @private
|
|
654
|
-
* @param {module:engine/view/observer/domeventdata~DomEventData} domEventData
|
|
655
|
-
* @returns {Object}
|
|
656
538
|
*/
|
|
657
|
-
|
|
539
|
+
_onMouseUpHandler() {
|
|
540
|
+
if ( !this._isResizingActive ) {
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
const {
|
|
545
|
+
viewResizer,
|
|
546
|
+
modelTable,
|
|
547
|
+
viewFigure,
|
|
548
|
+
viewColgroup
|
|
549
|
+
} = this._resizingData.elements;
|
|
550
|
+
|
|
551
|
+
const editor = this.editor;
|
|
552
|
+
const editingView = editor.editing.view;
|
|
553
|
+
|
|
554
|
+
const columnWidthsAttributeOld = modelTable.getAttribute( 'columnWidths' );
|
|
555
|
+
const columnWidthsAttributeNew = [ ...viewColgroup.getChildren() ]
|
|
556
|
+
.map( viewCol => viewCol.getStyle( 'width' ) )
|
|
557
|
+
.join( ',' );
|
|
558
|
+
|
|
559
|
+
const isColumnWidthsAttributeChanged = columnWidthsAttributeOld !== columnWidthsAttributeNew;
|
|
560
|
+
|
|
561
|
+
const tableWidthAttributeOld = modelTable.getAttribute( 'tableWidth' );
|
|
562
|
+
const tableWidthAttributeNew = viewFigure.getStyle( 'width' );
|
|
563
|
+
|
|
564
|
+
const isTableWidthAttributeChanged = tableWidthAttributeOld !== tableWidthAttributeNew;
|
|
565
|
+
|
|
566
|
+
if ( isColumnWidthsAttributeChanged || isTableWidthAttributeChanged ) {
|
|
567
|
+
if ( this._isResizingAllowed ) {
|
|
568
|
+
// Commit all changes to the model.
|
|
569
|
+
if ( isTableWidthAttributeChanged ) {
|
|
570
|
+
editor.execute(
|
|
571
|
+
'resizeTableWidth',
|
|
572
|
+
{
|
|
573
|
+
table: modelTable,
|
|
574
|
+
tableWidth: `${ toPrecision( tableWidthAttributeNew ) }%`,
|
|
575
|
+
columnWidths: columnWidthsAttributeNew
|
|
576
|
+
}
|
|
577
|
+
);
|
|
578
|
+
} else {
|
|
579
|
+
editor.execute( 'resizeColumnWidths', { columnWidths: columnWidthsAttributeNew, table: modelTable } );
|
|
580
|
+
}
|
|
581
|
+
} else {
|
|
582
|
+
// In read-only mode revert all changes in the editing view. The model is not touched so it does not need to be restored.
|
|
583
|
+
// This case can occur if the read-only mode kicks in during the resizing process.
|
|
584
|
+
editingView.change( writer => {
|
|
585
|
+
// If table had resized columns before, restore the previous column widths.
|
|
586
|
+
// Otherwise clean up the view from the temporary column resizing markup.
|
|
587
|
+
if ( columnWidthsAttributeOld ) {
|
|
588
|
+
const columnWidths = columnWidthsAttributeOld.split( ',' );
|
|
589
|
+
|
|
590
|
+
for ( const viewCol of viewColgroup.getChildren() ) {
|
|
591
|
+
writer.setStyle( 'width', columnWidths.shift(), viewCol );
|
|
592
|
+
}
|
|
593
|
+
} else {
|
|
594
|
+
writer.remove( viewColgroup );
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if ( isTableWidthAttributeChanged ) {
|
|
598
|
+
// If the whole table was already resized before, restore the previous table width.
|
|
599
|
+
// Otherwise clean up the view from the temporary table resizing markup.
|
|
600
|
+
if ( tableWidthAttributeOld ) {
|
|
601
|
+
writer.setStyle( 'width', tableWidthAttributeOld, viewFigure );
|
|
602
|
+
} else {
|
|
603
|
+
writer.removeStyle( 'width', viewFigure );
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// If a table and its columns weren't resized before,
|
|
608
|
+
// prune the remaining common resizing markup.
|
|
609
|
+
if ( !columnWidthsAttributeOld && !tableWidthAttributeOld ) {
|
|
610
|
+
writer.removeClass(
|
|
611
|
+
'ck-table-resized',
|
|
612
|
+
[ ...viewFigure.getChildren() ].find( element => element.name === 'table' )
|
|
613
|
+
);
|
|
614
|
+
}
|
|
615
|
+
} );
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
editingView.change( writer => {
|
|
620
|
+
writer.removeClass( 'ck-table-column-resizer__active', viewResizer );
|
|
621
|
+
} );
|
|
622
|
+
|
|
623
|
+
this._isResizingActive = false;
|
|
624
|
+
this._resizingData = null;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Retrieves and returns required data needed for the resizing process.
|
|
629
|
+
*
|
|
630
|
+
* @private
|
|
631
|
+
* @param {module:engine/view/observer/domeventdata~DomEventData} domEventData The data of the `mousedown` event.
|
|
632
|
+
* @param {Array.<Number>} columnWidths The current widths of the columns.
|
|
633
|
+
* @returns {Object} The data needed for the resizing process.
|
|
634
|
+
*/
|
|
635
|
+
_getResizingData( domEventData, columnWidths ) {
|
|
658
636
|
const editor = this.editor;
|
|
659
637
|
|
|
660
638
|
const columnPosition = domEventData.domEvent.clientX;
|
|
@@ -664,8 +642,8 @@ export default class TableColumnResizeEditing extends Plugin {
|
|
|
664
642
|
const modelLeftCell = editor.editing.mapper.toModelElement( viewLeftCell );
|
|
665
643
|
const modelTable = modelLeftCell.findAncestor( 'table' );
|
|
666
644
|
|
|
667
|
-
const leftColumnIndex =
|
|
668
|
-
const lastColumnIndex =
|
|
645
|
+
const leftColumnIndex = getColumnEdgesIndexes( modelLeftCell, this._tableUtilsPlugin ).rightEdge;
|
|
646
|
+
const lastColumnIndex = this._tableUtilsPlugin.getColumns( modelTable ) - 1;
|
|
669
647
|
|
|
670
648
|
const isRightEdge = leftColumnIndex === lastColumnIndex;
|
|
671
649
|
const isTableCentered = !modelTable.hasAttribute( 'tableAlignment' );
|
|
@@ -678,37 +656,38 @@ export default class TableColumnResizeEditing extends Plugin {
|
|
|
678
656
|
const viewRightColumn = isRightEdge ? undefined : viewColgroup.getChild( leftColumnIndex + 1 );
|
|
679
657
|
|
|
680
658
|
const viewFigureParentWidth = getElementWidthInPixels( editor.editing.view.domConverter.mapViewToDom( viewFigure.parent ) );
|
|
659
|
+
const viewFigureWidth = getElementWidthInPixels( editor.editing.view.domConverter.mapViewToDom( viewFigure ) );
|
|
681
660
|
const tableWidth = getTableWidthInPixels( modelTable, editor );
|
|
682
|
-
const columnWidths = getColumnWidthsInPixels( modelTable, editor );
|
|
683
661
|
const leftColumnWidth = columnWidths[ leftColumnIndex ];
|
|
684
662
|
const rightColumnWidth = isRightEdge ? undefined : columnWidths[ leftColumnIndex + 1 ];
|
|
685
663
|
|
|
686
664
|
return {
|
|
687
665
|
columnPosition,
|
|
666
|
+
flags: {
|
|
667
|
+
isRightEdge,
|
|
668
|
+
isTableCentered,
|
|
669
|
+
isLtrContent
|
|
670
|
+
},
|
|
688
671
|
elements: {
|
|
672
|
+
viewResizer,
|
|
689
673
|
modelTable,
|
|
690
674
|
viewFigure,
|
|
691
675
|
viewColgroup,
|
|
692
676
|
viewLeftColumn,
|
|
693
|
-
viewRightColumn
|
|
694
|
-
viewResizer
|
|
677
|
+
viewRightColumn
|
|
695
678
|
},
|
|
696
679
|
widths: {
|
|
697
680
|
viewFigureParentWidth,
|
|
681
|
+
viewFigureWidth,
|
|
698
682
|
tableWidth,
|
|
699
683
|
leftColumnWidth,
|
|
700
684
|
rightColumnWidth
|
|
701
|
-
},
|
|
702
|
-
flags: {
|
|
703
|
-
isRightEdge,
|
|
704
|
-
isTableCentered,
|
|
705
|
-
isLtrContent
|
|
706
685
|
}
|
|
707
686
|
};
|
|
708
687
|
}
|
|
709
688
|
|
|
710
689
|
/**
|
|
711
|
-
* Inserts colgroup if it is missing
|
|
690
|
+
* Inserts the `<colgroup>` element if it is missing in the view table (e.g. after table insertion into table).
|
|
712
691
|
*
|
|
713
692
|
* @private
|
|
714
693
|
*/
|
|
@@ -716,43 +695,38 @@ export default class TableColumnResizeEditing extends Plugin {
|
|
|
716
695
|
const editor = this.editor;
|
|
717
696
|
|
|
718
697
|
this.listenTo( editor.editing.view.document, 'layoutChanged', () => {
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
element => element.name === 'table'
|
|
698
|
+
const viewTable = editor.editing.view.document.selection.getFirstPosition().getAncestors().reverse().find(
|
|
699
|
+
viewElement => viewElement.name === 'table'
|
|
722
700
|
);
|
|
723
|
-
const
|
|
701
|
+
const viewTableContainsColgroup = viewTable && [ ...viewTable.getChildren() ].find(
|
|
724
702
|
viewElement => viewElement.is( 'element', 'colgroup' )
|
|
725
703
|
);
|
|
704
|
+
const modelTable = editor.model.document.selection.getFirstPosition().findAncestor( 'table' );
|
|
726
705
|
|
|
727
|
-
if (
|
|
728
|
-
editor.editing.reconvertItem(
|
|
706
|
+
if ( modelTable && modelTable.hasAttribute( 'columnWidths' ) && viewTable && !viewTableContainsColgroup ) {
|
|
707
|
+
editor.editing.reconvertItem( modelTable );
|
|
729
708
|
}
|
|
730
709
|
}, { priority: 'low' } );
|
|
731
710
|
}
|
|
732
711
|
|
|
733
712
|
/**
|
|
734
|
-
* Registers a
|
|
713
|
+
* Registers a listener ensuring that each resizable cell have a resizer handle.
|
|
735
714
|
*
|
|
736
715
|
* @private
|
|
737
716
|
*/
|
|
738
717
|
_registerResizerInserter() {
|
|
739
|
-
const
|
|
740
|
-
const view = editor.editing.view;
|
|
741
|
-
const cellsModified = this._cellsModified;
|
|
718
|
+
const view = this.editor.editing.view;
|
|
742
719
|
|
|
743
720
|
view.on( 'render', () => {
|
|
744
|
-
for ( const
|
|
745
|
-
|
|
721
|
+
for ( const item of view.createRangeIn( view.document.getRoot() ) ) {
|
|
722
|
+
if ( ![ 'td', 'th' ].includes( item.item.name ) ) {
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
746
725
|
|
|
747
726
|
view.change( viewWriter => {
|
|
748
|
-
|
|
749
|
-
insertColumnResizerElements( viewWriter, viewCell );
|
|
750
|
-
} else if ( operation === 'remove' ) {
|
|
751
|
-
removeColumnResizerElements( viewWriter, viewCell );
|
|
752
|
-
}
|
|
727
|
+
ensureColumnResizerElement( viewWriter, item.item );
|
|
753
728
|
} );
|
|
754
729
|
}
|
|
755
|
-
cellsModified.clear();
|
|
756
730
|
}, { priority: 'lowest' } );
|
|
757
731
|
}
|
|
758
732
|
}
|