@ckeditor/ckeditor5-table 0.0.0-nightly-20251215.0 → 0.0.0-nightly-20251216.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/dist/index-editor.css +76 -85
- package/dist/index.css +102 -111
- package/dist/index.css.map +1 -1
- package/dist/index.js +830 -125
- package/dist/index.js.map +1 -1
- package/lang/contexts.json +3 -0
- package/package.json +9 -9
- package/src/augmentation.d.ts +10 -1
- package/src/commands/setheadercolumncommand.js +2 -2
- package/src/commands/setheaderrowcommand.js +1 -2
- package/src/converters/downcast.d.ts +3 -1
- package/src/converters/downcast.js +18 -6
- package/src/converters/upcasttable.js +12 -5
- package/src/index.d.ts +2 -1
- package/src/index.js +2 -1
- package/src/tablecellproperties/commands/tablecellpropertycommand.d.ts +19 -1
- package/src/tablecellproperties/commands/tablecellpropertycommand.js +8 -0
- package/src/tablecellproperties/commands/tablecelltypecommand.d.ts +53 -0
- package/src/tablecellproperties/commands/tablecelltypecommand.js +167 -0
- package/src/tablecellproperties/tablecellpropertiesediting.d.ts +0 -3
- package/src/tablecellproperties/tablecellpropertiesediting.js +113 -0
- package/src/tablecellproperties/tablecellpropertiesuiexperimental.js +33 -11
- package/src/tablecellproperties/ui/tablecellpropertiesviewexperimental.d.ts +32 -3
- package/src/tablecellproperties/ui/tablecellpropertiesviewexperimental.js +129 -18
- package/src/tableediting.js +13 -3
- package/src/tableutils.d.ts +38 -0
- package/src/tableutils.js +219 -13
- package/src/utils/common.d.ts +23 -0
- package/src/utils/common.js +42 -0
- package/theme/tablecellproperties-experimental.css +4 -0
- package/theme/tableform-experimental.css +0 -12
- package/theme/tableform.css +5 -6
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* @module table/tablecellproperties/tablecellpropertiesediting
|
|
7
7
|
*/
|
|
8
|
+
import { priorities } from 'ckeditor5/src/utils.js';
|
|
8
9
|
import { Plugin } from 'ckeditor5/src/core.js';
|
|
9
10
|
import { addBorderStylesRules, addPaddingStylesRules, addBackgroundStylesRules } from 'ckeditor5/src/engine.js';
|
|
10
11
|
import { downcastAttributeToStyle, getDefaultValueAdjusted, upcastBorderStyles } from '../converters/tableproperties.js';
|
|
@@ -18,8 +19,11 @@ import { TableCellHorizontalAlignmentCommand } from './commands/tablecellhorizon
|
|
|
18
19
|
import { TableCellBorderStyleCommand } from './commands/tablecellborderstylecommand.js';
|
|
19
20
|
import { TableCellBorderColorCommand } from './commands/tablecellbordercolorcommand.js';
|
|
20
21
|
import { TableCellBorderWidthCommand } from './commands/tablecellborderwidthcommand.js';
|
|
22
|
+
import { TableCellTypeCommand, updateTablesHeadingAttributes } from './commands/tablecelltypecommand.js';
|
|
21
23
|
import { getNormalizedDefaultCellProperties } from '../utils/table-properties.js';
|
|
22
24
|
import { enableProperty } from '../utils/common.js';
|
|
25
|
+
import { TableUtils } from '../tableutils.js';
|
|
26
|
+
import { TableWalker } from '../tablewalker.js';
|
|
23
27
|
const VALIGN_VALUES_REG_EXP = /^(top|middle|bottom)$/;
|
|
24
28
|
const ALIGN_VALUES_REG_EXP = /^(left|center|right|justify)$/;
|
|
25
29
|
/**
|
|
@@ -125,6 +129,10 @@ export class TableCellPropertiesEditing extends Plugin {
|
|
|
125
129
|
editor.commands.add('tableCellHorizontalAlignment', new TableCellHorizontalAlignmentCommand(editor, defaultTableCellProperties.horizontalAlignment));
|
|
126
130
|
enableVerticalAlignmentProperty(schema, conversion, defaultTableCellProperties.verticalAlignment);
|
|
127
131
|
editor.commands.add('tableCellVerticalAlignment', new TableCellVerticalAlignmentCommand(editor, defaultTableCellProperties.verticalAlignment));
|
|
132
|
+
if (editor.config.get('experimentalFlags.tableCellTypeSupport')) {
|
|
133
|
+
enableCellTypeProperty(editor);
|
|
134
|
+
editor.commands.add('tableCellType', new TableCellTypeCommand(editor));
|
|
135
|
+
}
|
|
128
136
|
}
|
|
129
137
|
}
|
|
130
138
|
/**
|
|
@@ -290,3 +298,108 @@ function enableVerticalAlignmentProperty(schema, conversion, defaultValue) {
|
|
|
290
298
|
}
|
|
291
299
|
});
|
|
292
300
|
}
|
|
301
|
+
/**
|
|
302
|
+
* Enables the `tableCellType` attribute for table cells.
|
|
303
|
+
*/
|
|
304
|
+
function enableCellTypeProperty(editor) {
|
|
305
|
+
const { model, conversion, editing } = editor;
|
|
306
|
+
const { schema } = model;
|
|
307
|
+
const tableUtils = editor.plugins.get(TableUtils);
|
|
308
|
+
schema.extend('tableCell', {
|
|
309
|
+
allowAttributes: ['tableCellType']
|
|
310
|
+
});
|
|
311
|
+
schema.setAttributeProperties('tableCellType', {
|
|
312
|
+
isFormatting: true
|
|
313
|
+
});
|
|
314
|
+
// Upcast conversion for td/th elements.
|
|
315
|
+
conversion.for('upcast').add(dispatcher => {
|
|
316
|
+
dispatcher.on('element:th', (evt, data, conversionApi) => {
|
|
317
|
+
const { writer } = conversionApi;
|
|
318
|
+
const { modelRange } = data;
|
|
319
|
+
const modelElement = modelRange?.start.nodeAfter;
|
|
320
|
+
if (modelElement?.is('element', 'tableCell')) {
|
|
321
|
+
writer.setAttribute('tableCellType', 'header', modelElement);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
// Table type is examined after all other cell converters, on low priority, so
|
|
325
|
+
// we double check if there is any `th` left in the table. If so, the table is converted to a content table.
|
|
326
|
+
dispatcher.on('element:table', (evt, data, conversionApi) => {
|
|
327
|
+
const { writer } = conversionApi;
|
|
328
|
+
const { modelRange } = data;
|
|
329
|
+
const modelElement = modelRange?.start.nodeAfter;
|
|
330
|
+
if (modelElement?.is('element', 'table') && modelElement.getAttribute('tableType') === 'layout') {
|
|
331
|
+
for (const { cell } of new TableWalker(modelElement)) {
|
|
332
|
+
if (cell.getAttribute('tableCellType') === 'header') {
|
|
333
|
+
writer.setAttribute('tableType', 'content', modelElement);
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}, { priority: priorities.low - 1 });
|
|
339
|
+
});
|
|
340
|
+
// Registers a post-fixer that ensures the `headingRows` and `headingColumns` attributes
|
|
341
|
+
// are consistent with the `tableCellType` attribute of the cells. `tableCellType` has priority
|
|
342
|
+
// over `headingRows` and `headingColumns` and we use it to adjust the heading sections of the table.
|
|
343
|
+
model.document.registerPostFixer(writer => {
|
|
344
|
+
// 1. Collect all tables that need to be checked.
|
|
345
|
+
const changes = model.document.differ.getChanges();
|
|
346
|
+
const tablesToCheck = new Set();
|
|
347
|
+
for (const change of changes) {
|
|
348
|
+
// Check if headingRows or headingColumns changed.
|
|
349
|
+
if (change.type === 'attribute' && (change.attributeKey === 'headingRows' || change.attributeKey === 'headingColumns')) {
|
|
350
|
+
const table = change.range.start.nodeAfter;
|
|
351
|
+
if (table?.is('element', 'table') && table.root.rootName !== '$graveyard') {
|
|
352
|
+
tablesToCheck.add(table);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// Check if tableCellType changed.
|
|
356
|
+
if (change.type === 'attribute' && change.attributeKey === 'tableCellType') {
|
|
357
|
+
const cell = change.range.start.nodeAfter;
|
|
358
|
+
if (cell?.is('element', 'tableCell') && cell.root.rootName !== '$graveyard') {
|
|
359
|
+
const table = cell.findAncestor('table');
|
|
360
|
+
if (table) {
|
|
361
|
+
tablesToCheck.add(table);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
// Check if new headers were inserted.
|
|
366
|
+
if (change.type === 'insert' && change.position.nodeAfter) {
|
|
367
|
+
for (const { item } of model.createRangeOn(change.position.nodeAfter)) {
|
|
368
|
+
if (item.is('element', 'tableCell') &&
|
|
369
|
+
item.getAttribute('tableCellType') &&
|
|
370
|
+
item.root.rootName !== '$graveyard') {
|
|
371
|
+
const table = item.findAncestor('table');
|
|
372
|
+
if (table) {
|
|
373
|
+
tablesToCheck.add(table);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// 2. Update the attributes of the collected tables.
|
|
380
|
+
return updateTablesHeadingAttributes(tableUtils, writer, tablesToCheck);
|
|
381
|
+
});
|
|
382
|
+
// Refresh the table cells in the editing view when their `tableCellType` attribute changes.
|
|
383
|
+
model.document.on('change:data', () => {
|
|
384
|
+
const { differ } = model.document;
|
|
385
|
+
const cellsToReconvert = new Set();
|
|
386
|
+
for (const change of differ.getChanges()) {
|
|
387
|
+
// If the `tableCellType` attribute changed, the entire cell needs to be re-rendered.
|
|
388
|
+
if (change.type === 'attribute' && change.attributeKey === 'tableCellType') {
|
|
389
|
+
const tableCell = change.range.start.nodeAfter;
|
|
390
|
+
if (tableCell.is('element', 'tableCell')) {
|
|
391
|
+
cellsToReconvert.add(tableCell);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
// Reconvert table cells that had their `tableCellType` attribute changed.
|
|
396
|
+
for (const tableCell of cellsToReconvert) {
|
|
397
|
+
const viewElement = editing.mapper.toViewElement(tableCell);
|
|
398
|
+
const cellType = tableCell.getAttribute('tableCellType');
|
|
399
|
+
const expectedElementName = cellType === 'header' ? 'th' : 'td';
|
|
400
|
+
if (viewElement?.name !== expectedElementName) {
|
|
401
|
+
editing.reconvertItem(tableCell);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
}
|
|
@@ -26,7 +26,8 @@ const propertyToCommandMap = {
|
|
|
26
26
|
padding: 'tableCellPadding',
|
|
27
27
|
backgroundColor: 'tableCellBackgroundColor',
|
|
28
28
|
horizontalAlignment: 'tableCellHorizontalAlignment',
|
|
29
|
-
verticalAlignment: 'tableCellVerticalAlignment'
|
|
29
|
+
verticalAlignment: 'tableCellVerticalAlignment',
|
|
30
|
+
cellType: 'tableCellType'
|
|
30
31
|
};
|
|
31
32
|
/**
|
|
32
33
|
* The table cell properties UI plugin. It introduces the `'tableCellProperties'` button
|
|
@@ -125,8 +126,10 @@ export class TableCellPropertiesUIExperimental extends Plugin {
|
|
|
125
126
|
tooltip: true
|
|
126
127
|
});
|
|
127
128
|
this.listenTo(view, 'execute', () => this._showView());
|
|
128
|
-
const commands = Object
|
|
129
|
-
.
|
|
129
|
+
const commands = (Object
|
|
130
|
+
.values(propertyToCommandMap)
|
|
131
|
+
.map(commandName => editor.commands.get(commandName))
|
|
132
|
+
.filter(val => !!val));
|
|
130
133
|
view.bind('isEnabled').toMany(commands, 'isEnabled', (...areEnabled) => (areEnabled.some(isCommandEnabled => isCommandEnabled)));
|
|
131
134
|
return view;
|
|
132
135
|
});
|
|
@@ -155,11 +158,13 @@ export class TableCellPropertiesUIExperimental extends Plugin {
|
|
|
155
158
|
const backgroundColorsConfig = normalizeColorOptions(config.backgroundColors);
|
|
156
159
|
const localizedBackgroundColors = getLocalizedColorOptions(editor.locale, backgroundColorsConfig);
|
|
157
160
|
const hasColorPicker = config.colorPicker !== false;
|
|
161
|
+
const isTableCellTypeSupported = !!editor.config.get('experimentalFlags.tableCellTypeSupport');
|
|
158
162
|
const view = new TableCellPropertiesViewExperimental(editor.locale, {
|
|
159
163
|
borderColors: localizedBorderColors,
|
|
160
164
|
backgroundColors: localizedBackgroundColors,
|
|
161
165
|
defaultTableCellProperties,
|
|
162
|
-
colorPickerConfig: hasColorPicker ? (config.colorPicker || {}) : false
|
|
166
|
+
colorPickerConfig: hasColorPicker ? (config.colorPicker || {}) : false,
|
|
167
|
+
isTableCellTypeSupported
|
|
163
168
|
});
|
|
164
169
|
const t = editor.t;
|
|
165
170
|
// Render the view so its #element is available for the clickOutsideHandler.
|
|
@@ -232,6 +237,11 @@ export class TableCellPropertiesUIExperimental extends Plugin {
|
|
|
232
237
|
}));
|
|
233
238
|
view.on('change:horizontalAlignment', this._getPropertyChangeCallback('tableCellHorizontalAlignment'));
|
|
234
239
|
view.on('change:verticalAlignment', this._getPropertyChangeCallback('tableCellVerticalAlignment'));
|
|
240
|
+
const cellTypeCommand = editor.commands.get('tableCellType');
|
|
241
|
+
if (cellTypeCommand) {
|
|
242
|
+
view.cellTypeDropdown.bind('isEnabled').to(cellTypeCommand, 'isEnabled');
|
|
243
|
+
view.on('change:cellType', this._getPropertyChangeCallback('tableCellType'));
|
|
244
|
+
}
|
|
235
245
|
return view;
|
|
236
246
|
}
|
|
237
247
|
/**
|
|
@@ -245,16 +255,28 @@ export class TableCellPropertiesUIExperimental extends Plugin {
|
|
|
245
255
|
_fillViewFormFromCommandValues() {
|
|
246
256
|
const commands = this.editor.commands;
|
|
247
257
|
const borderStyleCommand = commands.get('tableCellBorderStyle');
|
|
248
|
-
Object
|
|
249
|
-
.
|
|
258
|
+
Object
|
|
259
|
+
.entries(propertyToCommandMap)
|
|
260
|
+
.flatMap(([property, commandName]) => {
|
|
261
|
+
const command = commands.get(commandName);
|
|
262
|
+
if (!command) {
|
|
263
|
+
return [];
|
|
264
|
+
}
|
|
250
265
|
const propertyKey = property;
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
266
|
+
let defaultValue;
|
|
267
|
+
if (propertyKey === 'cellType') {
|
|
268
|
+
defaultValue = '';
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
defaultValue = this.view === this._viewWithContentTableDefaults ?
|
|
272
|
+
this._defaultContentTableCellProperties[propertyKey] || '' :
|
|
273
|
+
this._defaultLayoutTableCellProperties[propertyKey] || '';
|
|
274
|
+
}
|
|
275
|
+
const entry = [
|
|
255
276
|
property,
|
|
256
|
-
|
|
277
|
+
command.value || defaultValue
|
|
257
278
|
];
|
|
279
|
+
return [entry];
|
|
258
280
|
})
|
|
259
281
|
.forEach(([property, value]) => {
|
|
260
282
|
// Do not set the `border-color` and `border-width` fields if `border-style:none`.
|
|
@@ -10,14 +10,15 @@ import { KeystrokeHandler, FocusTracker, type Locale } from 'ckeditor5/src/utils
|
|
|
10
10
|
import { type ColorInputView } from '../../ui/colorinputview.js';
|
|
11
11
|
import type { TableCellPropertiesOptions } from '../../tableconfig.js';
|
|
12
12
|
import '@ckeditor/ckeditor5-ui/theme/components/form/form.css';
|
|
13
|
-
import '../../../theme/formrow.css';
|
|
14
|
-
import '../../../theme/tableform.css';
|
|
15
|
-
import '../../../theme/tablecellproperties.css';
|
|
13
|
+
import '../../../theme/formrow-experimental.css';
|
|
14
|
+
import '../../../theme/tableform-experimental.css';
|
|
15
|
+
import '../../../theme/tablecellproperties-experimental.css';
|
|
16
16
|
export interface TableCellPropertiesViewOptionsExperimental {
|
|
17
17
|
borderColors: Array<NormalizedColorOption>;
|
|
18
18
|
backgroundColors: Array<NormalizedColorOption>;
|
|
19
19
|
defaultTableCellProperties: TableCellPropertiesOptions;
|
|
20
20
|
colorPickerConfig: false | ColorPickerConfig;
|
|
21
|
+
isTableCellTypeSupported: boolean;
|
|
21
22
|
}
|
|
22
23
|
/**
|
|
23
24
|
* The class representing a table cell properties form, allowing users to customize
|
|
@@ -87,6 +88,13 @@ export declare class TableCellPropertiesViewExperimental extends View {
|
|
|
87
88
|
* @default ''
|
|
88
89
|
*/
|
|
89
90
|
verticalAlignment: string;
|
|
91
|
+
/**
|
|
92
|
+
* The type of the table cell ('data' or 'header').
|
|
93
|
+
*
|
|
94
|
+
* @observable
|
|
95
|
+
* @default ''
|
|
96
|
+
*/
|
|
97
|
+
cellType: string;
|
|
90
98
|
/**
|
|
91
99
|
* Options passed to the view. See {@link #constructor} to learn more.
|
|
92
100
|
*/
|
|
@@ -119,6 +127,10 @@ export declare class TableCellPropertiesViewExperimental extends View {
|
|
|
119
127
|
* An input that allows specifying the table cell background color.
|
|
120
128
|
*/
|
|
121
129
|
readonly backgroundInput: LabeledFieldView<ColorInputView>;
|
|
130
|
+
/**
|
|
131
|
+
* A dropdown that allows selecting the type of the table cell (data or header).
|
|
132
|
+
*/
|
|
133
|
+
readonly cellTypeDropdown: LabeledFieldView<FocusableView>;
|
|
122
134
|
/**
|
|
123
135
|
* An input that allows specifying the table cell padding.
|
|
124
136
|
*/
|
|
@@ -167,6 +179,7 @@ export declare class TableCellPropertiesViewExperimental extends View {
|
|
|
167
179
|
* @param options.backgroundColors A configuration of the background color palette used by the
|
|
168
180
|
* {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView#backgroundInput}.
|
|
169
181
|
* @param options.defaultTableCellProperties The default table cell properties.
|
|
182
|
+
* @param options.isTableCellTypeSupported A flag indicating whether the table cell type is supported.
|
|
170
183
|
*/
|
|
171
184
|
constructor(locale: Locale, options: TableCellPropertiesViewOptionsExperimental);
|
|
172
185
|
/**
|
|
@@ -195,6 +208,14 @@ export declare class TableCellPropertiesViewExperimental extends View {
|
|
|
195
208
|
* * {@link #backgroundInput}.
|
|
196
209
|
*/
|
|
197
210
|
private _createBackgroundFields;
|
|
211
|
+
/**
|
|
212
|
+
* Create cell type field.
|
|
213
|
+
*
|
|
214
|
+
* * {@link #cellTypeDropdown}.
|
|
215
|
+
*
|
|
216
|
+
* @internal
|
|
217
|
+
*/
|
|
218
|
+
private _createCellTypeField;
|
|
198
219
|
/**
|
|
199
220
|
* Creates the following form fields:
|
|
200
221
|
*
|
|
@@ -226,6 +247,10 @@ export declare class TableCellPropertiesViewExperimental extends View {
|
|
|
226
247
|
* Creates a back button view that cancels the form.
|
|
227
248
|
*/
|
|
228
249
|
private _createBackButton;
|
|
250
|
+
/**
|
|
251
|
+
* Creates the cell type dropdown definitions.
|
|
252
|
+
*/
|
|
253
|
+
private _getCellTypeDefinitions;
|
|
229
254
|
/**
|
|
230
255
|
* Provides localized labels for {@link #horizontalAlignmentToolbar} buttons.
|
|
231
256
|
*/
|
|
@@ -234,4 +259,8 @@ export declare class TableCellPropertiesViewExperimental extends View {
|
|
|
234
259
|
* Provides localized labels for {@link #verticalAlignmentToolbar} buttons.
|
|
235
260
|
*/
|
|
236
261
|
private get _verticalAlignmentLabels();
|
|
262
|
+
/**
|
|
263
|
+
* Provides localized labels for {@link #cellTypeDropdown}.
|
|
264
|
+
*/
|
|
265
|
+
private get _cellTypeLabels();
|
|
237
266
|
}
|
|
@@ -6,15 +6,15 @@
|
|
|
6
6
|
* @module table/tablecellproperties/ui/tablecellpropertiesviewexperimental
|
|
7
7
|
*/
|
|
8
8
|
/* istanbul ignore file -- @preserve */
|
|
9
|
-
import { addListToDropdown, ButtonView, createLabeledDropdown, createLabeledInputText, FocusCycler, FormRowView, FormHeaderView, LabeledFieldView, LabelView, submitHandler, ToolbarView, View, ViewCollection } from 'ckeditor5/src/ui.js';
|
|
10
|
-
import { KeystrokeHandler, FocusTracker } from 'ckeditor5/src/utils.js';
|
|
9
|
+
import { addListToDropdown, ButtonView, createLabeledDropdown, createLabeledInputText, FocusCycler, FormRowView, FormHeaderView, LabeledFieldView, LabelView, submitHandler, ToolbarView, UIModel, View, ViewCollection } from 'ckeditor5/src/ui.js';
|
|
10
|
+
import { Collection, KeystrokeHandler, FocusTracker } from 'ckeditor5/src/utils.js';
|
|
11
11
|
import { IconAlignBottom, IconAlignCenter, IconAlignJustify, IconAlignLeft, IconAlignMiddle, IconAlignRight, IconAlignTop, IconPreviousArrow } from 'ckeditor5/src/icons.js';
|
|
12
12
|
import { fillToolbar, getBorderStyleDefinitions, getBorderStyleLabels, getLabeledColorInputCreator } from '../../utils/ui/table-propertiesexperimental.js';
|
|
13
13
|
// eslint-disable-next-line ckeditor5-rules/ckeditor-imports
|
|
14
14
|
import '@ckeditor/ckeditor5-ui/theme/components/form/form.css';
|
|
15
|
-
import '../../../theme/formrow.css';
|
|
16
|
-
import '../../../theme/tableform.css';
|
|
17
|
-
import '../../../theme/tablecellproperties.css';
|
|
15
|
+
import '../../../theme/formrow-experimental.css';
|
|
16
|
+
import '../../../theme/tableform-experimental.css';
|
|
17
|
+
import '../../../theme/tablecellproperties-experimental.css';
|
|
18
18
|
/**
|
|
19
19
|
* The class representing a table cell properties form, allowing users to customize
|
|
20
20
|
* certain style aspects of a table cell, for instance, border, padding, text alignment, etc..
|
|
@@ -52,6 +52,10 @@ export class TableCellPropertiesViewExperimental extends View {
|
|
|
52
52
|
* An input that allows specifying the table cell background color.
|
|
53
53
|
*/
|
|
54
54
|
backgroundInput;
|
|
55
|
+
/**
|
|
56
|
+
* A dropdown that allows selecting the type of the table cell (data or header).
|
|
57
|
+
*/
|
|
58
|
+
cellTypeDropdown;
|
|
55
59
|
/**
|
|
56
60
|
* An input that allows specifying the table cell padding.
|
|
57
61
|
*/
|
|
@@ -100,6 +104,7 @@ export class TableCellPropertiesViewExperimental extends View {
|
|
|
100
104
|
* @param options.backgroundColors A configuration of the background color palette used by the
|
|
101
105
|
* {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView#backgroundInput}.
|
|
102
106
|
* @param options.defaultTableCellProperties The default table cell properties.
|
|
107
|
+
* @param options.isTableCellTypeSupported A flag indicating whether the table cell type is supported.
|
|
103
108
|
*/
|
|
104
109
|
constructor(locale, options) {
|
|
105
110
|
super(locale);
|
|
@@ -112,11 +117,13 @@ export class TableCellPropertiesViewExperimental extends View {
|
|
|
112
117
|
width: '',
|
|
113
118
|
height: '',
|
|
114
119
|
horizontalAlignment: '',
|
|
115
|
-
verticalAlignment: ''
|
|
120
|
+
verticalAlignment: '',
|
|
121
|
+
cellType: ''
|
|
116
122
|
});
|
|
117
123
|
this.options = options;
|
|
118
124
|
const { borderStyleDropdown, borderWidthInput, borderColorInput, borderRowLabel } = this._createBorderFields();
|
|
119
125
|
const { backgroundRowLabel, backgroundInput } = this._createBackgroundFields();
|
|
126
|
+
const { cellTypeRowLabel, cellTypeDropdown } = this._createCellTypeField();
|
|
120
127
|
const { widthInput, operatorLabel, heightInput, dimensionsLabel } = this._createDimensionFields();
|
|
121
128
|
const { horizontalAlignmentToolbar, verticalAlignmentToolbar, alignmentLabel } = this._createAlignmentFields();
|
|
122
129
|
this.focusTracker = new FocusTracker();
|
|
@@ -126,6 +133,7 @@ export class TableCellPropertiesViewExperimental extends View {
|
|
|
126
133
|
this.borderWidthInput = borderWidthInput;
|
|
127
134
|
this.borderColorInput = borderColorInput;
|
|
128
135
|
this.backgroundInput = backgroundInput;
|
|
136
|
+
this.cellTypeDropdown = cellTypeDropdown;
|
|
129
137
|
this.paddingInput = this._createPaddingField();
|
|
130
138
|
this.widthInput = widthInput;
|
|
131
139
|
this.heightInput = heightInput;
|
|
@@ -159,22 +167,48 @@ export class TableCellPropertiesViewExperimental extends View {
|
|
|
159
167
|
// Border row.
|
|
160
168
|
this.children.add(new FormRowView(locale, {
|
|
161
169
|
labelView: borderRowLabel,
|
|
162
|
-
children: [
|
|
170
|
+
children: this.options.isTableCellTypeSupported ? [
|
|
171
|
+
borderRowLabel,
|
|
172
|
+
borderStyleDropdown,
|
|
173
|
+
borderWidthInput,
|
|
174
|
+
borderColorInput
|
|
175
|
+
] : [
|
|
163
176
|
borderRowLabel,
|
|
164
177
|
borderStyleDropdown,
|
|
165
178
|
borderColorInput,
|
|
166
179
|
borderWidthInput
|
|
167
180
|
],
|
|
168
|
-
class:
|
|
181
|
+
class: `ck-table-form__border-row${this.options.isTableCellTypeSupported ? ' ck-table-form__border-row_experimental' : ''}`
|
|
169
182
|
}));
|
|
170
|
-
// Background.
|
|
183
|
+
// Background and cell type.
|
|
171
184
|
this.children.add(new FormRowView(locale, {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
185
|
+
children: this.options.isTableCellTypeSupported ? [
|
|
186
|
+
new FormRowView(locale, {
|
|
187
|
+
labelView: cellTypeRowLabel,
|
|
188
|
+
children: [
|
|
189
|
+
cellTypeRowLabel,
|
|
190
|
+
cellTypeDropdown
|
|
191
|
+
],
|
|
192
|
+
class: 'ck-table-form__cell-type-row'
|
|
193
|
+
}),
|
|
194
|
+
new FormRowView(locale, {
|
|
195
|
+
labelView: backgroundRowLabel,
|
|
196
|
+
children: [
|
|
197
|
+
backgroundRowLabel,
|
|
198
|
+
backgroundInput
|
|
199
|
+
],
|
|
200
|
+
class: 'ck-table-form__background-row'
|
|
201
|
+
})
|
|
202
|
+
] : [
|
|
203
|
+
new FormRowView(locale, {
|
|
204
|
+
labelView: backgroundRowLabel,
|
|
205
|
+
children: [
|
|
206
|
+
backgroundRowLabel,
|
|
207
|
+
backgroundInput
|
|
208
|
+
],
|
|
209
|
+
class: 'ck-table-form__background-row'
|
|
210
|
+
})
|
|
211
|
+
]
|
|
178
212
|
}));
|
|
179
213
|
// Dimensions row and padding.
|
|
180
214
|
this.children.add(new FormRowView(locale, {
|
|
@@ -224,7 +258,9 @@ export class TableCellPropertiesViewExperimental extends View {
|
|
|
224
258
|
'ck',
|
|
225
259
|
'ck-form',
|
|
226
260
|
'ck-table-form',
|
|
227
|
-
'ck-table-cell-properties-form'
|
|
261
|
+
'ck-table-cell-properties-form',
|
|
262
|
+
'ck-table-cell-properties-form_experimental',
|
|
263
|
+
this.options.isTableCellTypeSupported ? 'ck-table-cell-properties-form_experimental-no-cell-type' : ''
|
|
228
264
|
],
|
|
229
265
|
// https://github.com/ckeditor/ckeditor5-link/issues/90
|
|
230
266
|
tabindex: '-1'
|
|
@@ -250,6 +286,7 @@ export class TableCellPropertiesViewExperimental extends View {
|
|
|
250
286
|
this.borderStyleDropdown,
|
|
251
287
|
this.borderColorInput,
|
|
252
288
|
this.borderWidthInput,
|
|
289
|
+
this.cellTypeDropdown,
|
|
253
290
|
this.backgroundInput,
|
|
254
291
|
this.widthInput,
|
|
255
292
|
this.heightInput,
|
|
@@ -408,6 +445,47 @@ export class TableCellPropertiesViewExperimental extends View {
|
|
|
408
445
|
backgroundInput
|
|
409
446
|
};
|
|
410
447
|
}
|
|
448
|
+
/**
|
|
449
|
+
* Create cell type field.
|
|
450
|
+
*
|
|
451
|
+
* * {@link #cellTypeDropdown}.
|
|
452
|
+
*
|
|
453
|
+
* @internal
|
|
454
|
+
*/
|
|
455
|
+
_createCellTypeField() {
|
|
456
|
+
const locale = this.locale;
|
|
457
|
+
const t = this.t;
|
|
458
|
+
const cellTypeRowLabel = new LabelView(locale);
|
|
459
|
+
cellTypeRowLabel.text = t('Cell type');
|
|
460
|
+
const cellTypeLabels = this._cellTypeLabels;
|
|
461
|
+
const cellTypeDropdown = new LabeledFieldView(locale, createLabeledDropdown);
|
|
462
|
+
cellTypeDropdown.set({
|
|
463
|
+
label: t('Cell type'),
|
|
464
|
+
class: 'ck-table-cell-properties-form__cell-type'
|
|
465
|
+
});
|
|
466
|
+
cellTypeDropdown.fieldView.buttonView.set({
|
|
467
|
+
ariaLabel: t('Cell type'),
|
|
468
|
+
ariaLabelledBy: undefined,
|
|
469
|
+
isOn: false,
|
|
470
|
+
withText: true,
|
|
471
|
+
tooltip: t('Cell type')
|
|
472
|
+
});
|
|
473
|
+
cellTypeDropdown.fieldView.buttonView.bind('label').to(this, 'cellType', value => {
|
|
474
|
+
return cellTypeLabels[value || 'data'];
|
|
475
|
+
});
|
|
476
|
+
cellTypeDropdown.fieldView.on('execute', evt => {
|
|
477
|
+
this.cellType = evt.source._cellTypeValue;
|
|
478
|
+
});
|
|
479
|
+
cellTypeDropdown.bind('isEmpty').to(this, 'cellType', value => !value);
|
|
480
|
+
addListToDropdown(cellTypeDropdown.fieldView, this._getCellTypeDefinitions(), {
|
|
481
|
+
role: 'menu',
|
|
482
|
+
ariaLabel: t('Cell type')
|
|
483
|
+
});
|
|
484
|
+
return {
|
|
485
|
+
cellTypeRowLabel,
|
|
486
|
+
cellTypeDropdown
|
|
487
|
+
};
|
|
488
|
+
}
|
|
411
489
|
/**
|
|
412
490
|
* Creates the following form fields:
|
|
413
491
|
*
|
|
@@ -505,7 +583,8 @@ export class TableCellPropertiesViewExperimental extends View {
|
|
|
505
583
|
horizontalAlignmentToolbar.set({
|
|
506
584
|
isCompact: true,
|
|
507
585
|
role: 'radiogroup',
|
|
508
|
-
ariaLabel: t('Horizontal text alignment toolbar')
|
|
586
|
+
ariaLabel: t('Horizontal text alignment toolbar'),
|
|
587
|
+
class: 'ck-table-cell-properties-form__horizontal-alignment-toolbar'
|
|
509
588
|
});
|
|
510
589
|
fillToolbar({
|
|
511
590
|
view: this,
|
|
@@ -532,7 +611,8 @@ export class TableCellPropertiesViewExperimental extends View {
|
|
|
532
611
|
verticalAlignmentToolbar.set({
|
|
533
612
|
isCompact: true,
|
|
534
613
|
role: 'radiogroup',
|
|
535
|
-
ariaLabel: t('Vertical text alignment toolbar')
|
|
614
|
+
ariaLabel: t('Vertical text alignment toolbar'),
|
|
615
|
+
class: 'ck-table-cell-properties-form__vertical-alignment-toolbar'
|
|
536
616
|
});
|
|
537
617
|
fillToolbar({
|
|
538
618
|
view: this,
|
|
@@ -598,6 +678,27 @@ export class TableCellPropertiesViewExperimental extends View {
|
|
|
598
678
|
backButton.delegate('execute').to(this, 'cancel');
|
|
599
679
|
return backButton;
|
|
600
680
|
}
|
|
681
|
+
/**
|
|
682
|
+
* Creates the cell type dropdown definitions.
|
|
683
|
+
*/
|
|
684
|
+
_getCellTypeDefinitions() {
|
|
685
|
+
const itemDefinitions = new Collection();
|
|
686
|
+
const cellTypeLabels = this._cellTypeLabels;
|
|
687
|
+
for (const type of ['data', 'header']) {
|
|
688
|
+
const definition = {
|
|
689
|
+
type: 'button',
|
|
690
|
+
model: new UIModel({
|
|
691
|
+
_cellTypeValue: type,
|
|
692
|
+
label: cellTypeLabels[type],
|
|
693
|
+
role: 'menuitemradio',
|
|
694
|
+
withText: true
|
|
695
|
+
})
|
|
696
|
+
};
|
|
697
|
+
definition.model.bind('isOn').to(this, 'cellType', value => value === type);
|
|
698
|
+
itemDefinitions.add(definition);
|
|
699
|
+
}
|
|
700
|
+
return itemDefinitions;
|
|
701
|
+
}
|
|
601
702
|
/**
|
|
602
703
|
* Provides localized labels for {@link #horizontalAlignmentToolbar} buttons.
|
|
603
704
|
*/
|
|
@@ -627,6 +728,16 @@ export class TableCellPropertiesViewExperimental extends View {
|
|
|
627
728
|
bottom: t('Align cell text to the bottom')
|
|
628
729
|
};
|
|
629
730
|
}
|
|
731
|
+
/**
|
|
732
|
+
* Provides localized labels for {@link #cellTypeDropdown}.
|
|
733
|
+
*/
|
|
734
|
+
get _cellTypeLabels() {
|
|
735
|
+
const t = this.t;
|
|
736
|
+
return {
|
|
737
|
+
data: t('Data cell'),
|
|
738
|
+
header: t('Header cell')
|
|
739
|
+
};
|
|
740
|
+
}
|
|
630
741
|
}
|
|
631
742
|
function isBorderStyleSet(value) {
|
|
632
743
|
return value !== 'none';
|
package/src/tableediting.js
CHANGED
|
@@ -25,6 +25,7 @@ import { injectTableLayoutPostFixer } from './converters/table-layout-post-fixer
|
|
|
25
25
|
import { injectTableCellParagraphPostFixer } from './converters/table-cell-paragraph-post-fixer.js';
|
|
26
26
|
import { tableHeadingsRefreshHandler } from './converters/table-headings-refresh-handler.js';
|
|
27
27
|
import { tableCellRefreshHandler } from './converters/table-cell-refresh-handler.js';
|
|
28
|
+
import { isTableCellTypeEnabled } from './utils/common.js';
|
|
28
29
|
import '../theme/tableediting.css';
|
|
29
30
|
/**
|
|
30
31
|
* The table editing feature.
|
|
@@ -120,11 +121,16 @@ export class TableEditing extends Plugin {
|
|
|
120
121
|
conversion.for('upcast').add(ensureParagraphInTableCell('th'));
|
|
121
122
|
conversion.for('editingDowncast').elementToElement({
|
|
122
123
|
model: 'tableCell',
|
|
123
|
-
view: downcastCell({
|
|
124
|
+
view: downcastCell({
|
|
125
|
+
asWidget: true,
|
|
126
|
+
cellTypeEnabled: () => isTableCellTypeEnabled(this.editor)
|
|
127
|
+
})
|
|
124
128
|
});
|
|
125
129
|
conversion.for('dataDowncast').elementToElement({
|
|
126
130
|
model: 'tableCell',
|
|
127
|
-
view: downcastCell(
|
|
131
|
+
view: downcastCell({
|
|
132
|
+
cellTypeEnabled: () => isTableCellTypeEnabled(this.editor)
|
|
133
|
+
})
|
|
128
134
|
});
|
|
129
135
|
// Duplicates code - needed to properly refresh paragraph inside a table cell.
|
|
130
136
|
conversion.for('editingDowncast').elementToElement({
|
|
@@ -175,7 +181,11 @@ export class TableEditing extends Plugin {
|
|
|
175
181
|
injectTableLayoutPostFixer(model);
|
|
176
182
|
injectTableCellParagraphPostFixer(model);
|
|
177
183
|
this.listenTo(model.document, 'change:data', () => {
|
|
178
|
-
|
|
184
|
+
// It's no longer needed to refresh table headings on every data change if table cell type feature is enabled.
|
|
185
|
+
// It's because headings rows / columns are updated based on cell types which triggers their own refresh handler.
|
|
186
|
+
if (!isTableCellTypeEnabled(editor)) {
|
|
187
|
+
tableHeadingsRefreshHandler(model, editor.editing);
|
|
188
|
+
}
|
|
179
189
|
tableCellRefreshHandler(model, editor.editing);
|
|
180
190
|
});
|
|
181
191
|
}
|
package/src/tableutils.d.ts
CHANGED
|
@@ -350,6 +350,44 @@ export declare class TableUtils extends Plugin {
|
|
|
350
350
|
* {@link #getTableCellsContainingSelection}.
|
|
351
351
|
*/
|
|
352
352
|
getSelectedTableCells(selection: ModelSelection | ModelDocumentSelection): Array<ModelElement>;
|
|
353
|
+
/**
|
|
354
|
+
* Sets the number of heading rows for the given `table`.
|
|
355
|
+
*
|
|
356
|
+
* @param writer The model writer.
|
|
357
|
+
* @param table The table model element.
|
|
358
|
+
* @param headingRows The number of heading rows to set.
|
|
359
|
+
* @param options Additional options.
|
|
360
|
+
* @param options.shallow If set to `true` it will only update the `headingRows` attribute
|
|
361
|
+
* without updating the cell types in the table. Default is `false`.
|
|
362
|
+
* @param options.resetFormerHeadingCells If set to `true`, it will check if the rows that are no longer in the heading section
|
|
363
|
+
* should be updated to body cells. Default is `true`.
|
|
364
|
+
* @param options.autoExpand If set to `true`, it will check if the following rows look like a header and expand the heading section.
|
|
365
|
+
* Default is `true`.
|
|
366
|
+
*/
|
|
367
|
+
setHeadingRowsCount(writer: ModelWriter, table: ModelElement, headingRows: number, options?: {
|
|
368
|
+
shallow?: boolean;
|
|
369
|
+
resetFormerHeadingCells?: boolean;
|
|
370
|
+
autoExpand?: boolean;
|
|
371
|
+
}): void;
|
|
372
|
+
/**
|
|
373
|
+
* Sets the number of heading columns for the given `table`.
|
|
374
|
+
*
|
|
375
|
+
* @param writer The model writer to use.
|
|
376
|
+
* @param table The table model element.
|
|
377
|
+
* @param headingColumns The number of heading columns to set.
|
|
378
|
+
* @param options Additional options.
|
|
379
|
+
* @param options.shallow If set to `true` it will only update the `headingColumns` attribute
|
|
380
|
+
* without updating the cell types in the table. Default is `false`.
|
|
381
|
+
* @param options.resetFormerHeadingCells If set to `true`, it will check if the columns that are no longer in the heading section
|
|
382
|
+
* should be updated to body cells. Default is `true`.
|
|
383
|
+
* @param options.autoExpand If set to `true`, it will check if the following columns look like a header and expand the heading section.
|
|
384
|
+
* Default is `true`.
|
|
385
|
+
*/
|
|
386
|
+
setHeadingColumnsCount(writer: ModelWriter, table: ModelElement, headingColumns: number, options?: {
|
|
387
|
+
shallow?: boolean;
|
|
388
|
+
resetFormerHeadingCells?: boolean;
|
|
389
|
+
autoExpand?: boolean;
|
|
390
|
+
}): void;
|
|
353
391
|
/**
|
|
354
392
|
* Returns all model table cells that the provided model selection's ranges
|
|
355
393
|
* {@link module:engine/model/range~ModelRange#start} inside.
|