@ckeditor/ckeditor5-table 0.0.0-nightly-20251125.0 → 0.0.0-nightly-20251126.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.
Files changed (37) hide show
  1. package/build/table.js +1 -1
  2. package/dist/index-content.css +30 -1
  3. package/dist/index-editor.css +181 -88
  4. package/dist/index.css +300 -158
  5. package/dist/index.css.map +1 -1
  6. package/dist/index.js +12442 -9941
  7. package/dist/index.js.map +1 -1
  8. package/lang/contexts.json +6 -0
  9. package/package.json +9 -9
  10. package/src/augmentation.d.ts +7 -0
  11. package/src/converters/downcast.d.ts +26 -1
  12. package/src/converters/downcast.js +129 -3
  13. package/src/converters/tableproperties.d.ts +43 -1
  14. package/src/converters/tableproperties.js +186 -0
  15. package/src/converters/upcasttable.js +2 -11
  16. package/src/index.d.ts +5 -1
  17. package/src/index.js +5 -0
  18. package/src/plaintableoutput.js +0 -91
  19. package/src/tablecellproperties/tablecellpropertiesuiexperimental.d.ts +128 -0
  20. package/src/tablecellproperties/tablecellpropertiesuiexperimental.js +386 -0
  21. package/src/tablecellproperties/ui/tablecellpropertiesviewexperimental.d.ts +237 -0
  22. package/src/tablecellproperties/ui/tablecellpropertiesviewexperimental.js +633 -0
  23. package/src/tableconfig.d.ts +187 -10
  24. package/src/tableediting.d.ts +5 -0
  25. package/src/tableediting.js +28 -1
  26. package/src/tableproperties/tablepropertiesediting.js +250 -5
  27. package/src/tableproperties/tablepropertiesuiexperimental.d.ts +136 -0
  28. package/src/tableproperties/tablepropertiesuiexperimental.js +375 -0
  29. package/src/tableproperties/ui/tablepropertiesviewexperimental.d.ts +216 -0
  30. package/src/tableproperties/ui/tablepropertiesviewexperimental.js +544 -0
  31. package/src/utils/structure.d.ts +5 -1
  32. package/src/utils/structure.js +10 -0
  33. package/src/utils/ui/table-propertiesexperimental.d.ts +215 -0
  34. package/src/utils/ui/table-propertiesexperimental.js +391 -0
  35. package/theme/formrow-experimental.css +15 -0
  36. package/theme/tableform-experimental.css +61 -0
  37. package/theme/tableproperties-experimental.css +78 -0
@@ -23,7 +23,7 @@ import type { ColorOption, ColorPickerConfig } from 'ckeditor5/src/ui.js';
23
23
  */
24
24
  export interface TableConfig {
25
25
  /**
26
- * Number of rows and columns to render by table heading when inserting new tables.
26
+ * Number of rows and columns to render by the table heading when inserting new tables.
27
27
  *
28
28
  * You can configure it like this:
29
29
  *
@@ -36,7 +36,7 @@ export interface TableConfig {
36
36
  * };
37
37
  * ```
38
38
  *
39
- * Both rows and columns properties are optional defaulting to 0 (no heading).
39
+ * Both rows and columns properties are optional, defaulting to 0 (no heading).
40
40
  */
41
41
  defaultHeadings?: {
42
42
  rows?: number;
@@ -86,7 +86,7 @@ export interface TableConfig {
86
86
  */
87
87
  tableToolbar?: Array<ToolbarConfigItem>;
88
88
  /**
89
- * The configuration of the table properties user interface (balloon). It allows to define:
89
+ * The configuration of the table properties user interface (balloon). It allows us to define:
90
90
  *
91
91
  * * The color palette for the table border color style field (`tableProperties.borderColors`),
92
92
  * * The color palette for the table background style field (`tableProperties.backgroundColors`).
@@ -130,9 +130,9 @@ export interface TableConfig {
130
130
  * {@link module:table/tableconfig~TablePropertiesOptions Read more about the supported properties.}
131
131
  *
132
132
  * **Note**: The `borderColors` and `backgroundColors` options do not impact the data loaded into the editor,
133
- * i.e. they do not limit or filter the colors in the data. They are used only in the user interface
134
- * allowing users to pick colors in a more convenient way. The `defaultProperties` option does impact the data.
135
- * Default values will not be kept in the editor model.
133
+ * i.e., they do not limit or filter the colors in the data. They are used only in the user interface,
134
+ * allowing users to pick colors more conveniently. The `defaultProperties` option does impact the data.
135
+ * The editor model will not keep the default values.
136
136
  *
137
137
  * The default color palettes for the table background and the table border are the same
138
138
  * ({@link module:table/utils/ui/table-properties#defaultColors check out their content}).
@@ -144,7 +144,7 @@ export interface TableConfig {
144
144
  */
145
145
  tableProperties?: TablePropertiesConfig;
146
146
  /**
147
- * The configuration of the table cell properties user interface (balloon). It allows to define:
147
+ * The configuration of the table cell properties user interface (balloon). It allows us to define:
148
148
  *
149
149
  * * The color palette for the cell border color style field (`tableCellProperties.borderColors`),
150
150
  * * The color palette for the cell background style field (`tableCellProperties.backgroundColors`).
@@ -187,11 +187,11 @@ export interface TableConfig {
187
187
  * {@link module:table/tableconfig~TablePropertiesOptions Read more about the supported properties.}
188
188
  *
189
189
  * **Note**: The `borderColors` and `backgroundColors` options do not impact the data loaded into the editor,
190
- * i.e. they do not limit or filter the colors in the data. They are used only in the user interface
190
+ * i.e., they do not limit or filter the colors in the data. They are used only in the user interface,
191
191
  * allowing users to pick colors in a more convenient way. The `defaultProperties` option does impact the data.
192
- * Default values will not be kept in the editor model.
192
+ * The editor model will not keep the default values.
193
193
  *
194
- * The default color palettes for the cell background and the cell border are the same
194
+ * The default color palettes for the cell background and the cell border are identical
195
195
  * ({@link module:table/utils/ui/table-properties#defaultColors check out their content}).
196
196
  *
197
197
  * Both color palette configurations must follow the
@@ -225,9 +225,99 @@ export interface TableConfig {
225
225
  * The configuration of the table properties user interface (balloon).
226
226
  */
227
227
  export interface TablePropertiesConfig {
228
+ /**
229
+ * The color palette for the table border color picker.
230
+ *
231
+ * ```ts
232
+ * const tableConfig = {
233
+ * tableProperties: {
234
+ * borderColors: [
235
+ * {
236
+ * color: 'hsl(0, 0%, 0%)',
237
+ * label: 'Black'
238
+ * },
239
+ * {
240
+ * color: 'hsl(0, 0%, 100%)',
241
+ * label: 'White',
242
+ * hasBorder: true
243
+ * }
244
+ * ]
245
+ * }
246
+ * };
247
+ * ```
248
+ *
249
+ * **Note**: This configuration only affects the UI. It does not limit or filter the colors in the data.
250
+ *
251
+ * Defaults to {@link module:table/utils/ui/table-properties#defaultColors}.
252
+ *
253
+ * @see {@link module:table/tableconfig~TableColorConfig}
254
+ */
228
255
  borderColors?: TableColorConfig;
256
+ /**
257
+ * The color palette for the table background color picker.
258
+ *
259
+ * ```ts
260
+ * const tableConfig = {
261
+ * tableProperties: {
262
+ * backgroundColors: [
263
+ * {
264
+ * color: 'hsl(0, 0%, 100%)',
265
+ * label: 'White',
266
+ * hasBorder: true
267
+ * },
268
+ * {
269
+ * color: 'hsl(120, 75%, 60%)',
270
+ * label: 'Green'
271
+ * }
272
+ * ]
273
+ * }
274
+ * };
275
+ * ```
276
+ *
277
+ * **Note**: This configuration only affects the UI. It does not limit or filter the colors in the data.
278
+ *
279
+ * Defaults to {@link module:table/utils/ui/table-properties#defaultColors}.
280
+ *
281
+ * @see {@link module:table/tableconfig~TableColorConfig}
282
+ */
229
283
  backgroundColors?: TableColorConfig;
284
+ /**
285
+ * Default styles for newly created tables.
286
+ *
287
+ * ```ts
288
+ * const tableConfig = {
289
+ * tableProperties: {
290
+ * defaultProperties: {
291
+ * borderStyle: 'dashed',
292
+ * borderColor: 'hsl(0, 0%, 90%)',
293
+ * borderWidth: '3px',
294
+ * alignment: 'left',
295
+ * width: '550px',
296
+ * height: '450px'
297
+ * }
298
+ * }
299
+ * }
300
+ * ```
301
+ *
302
+ * **Note**: The model does not store the default values. The editor will only keep values that differ from the defaults.
303
+ *
304
+ * See {@link module:table/tableconfig~TablePropertiesOptions} for the full list of properties.
305
+ */
230
306
  defaultProperties?: TablePropertiesOptions;
307
+ /**
308
+ * Configuration of the table alignment behavior in the editor output.
309
+ *
310
+ * ```ts
311
+ * const tableConfig = {
312
+ * tableProperties: {
313
+ * alignment: {
314
+ * useInlineStyles: false // Use CSS classes instead of inline styles
315
+ * }
316
+ * }
317
+ * };
318
+ * ```
319
+ */
320
+ alignment?: TableAlignmentConfig;
231
321
  /**
232
322
  * Configuration of the color picker in the table properties balloon.
233
323
  *
@@ -276,8 +366,84 @@ export interface TablePropertiesOptions {
276
366
  * The configuration of the table cell properties user interface (balloon).
277
367
  */
278
368
  export interface TableCellPropertiesConfig {
369
+ /**
370
+ * The color palette for the table cell border color picker.
371
+ *
372
+ * ```ts
373
+ * const tableConfig = {
374
+ * tableCellProperties: {
375
+ * borderColors: [
376
+ * {
377
+ * color: 'hsl(0, 0%, 0%)',
378
+ * label: 'Black'
379
+ * },
380
+ * {
381
+ * color: 'hsl(0, 0%, 100%)',
382
+ * label: 'White',
383
+ * hasBorder: true
384
+ * }
385
+ * ]
386
+ * }
387
+ * };
388
+ * ```
389
+ *
390
+ * **Note**: This configuration only affects the UI. It does not limit or filter the colors in the data.
391
+ *
392
+ * Defaults to {@link module:table/utils/ui/table-properties#defaultColors}.
393
+ *
394
+ * @see {@link module:table/tableconfig~TableColorConfig}
395
+ */
279
396
  borderColors?: TableColorConfig;
397
+ /**
398
+ * The color palette for the table cell background color picker.
399
+ *
400
+ * ```ts
401
+ * const tableConfig = {
402
+ * tableCellProperties: {
403
+ * backgroundColors: [
404
+ * {
405
+ * color: 'hsl(0, 0%, 100%)',
406
+ * label: 'White',
407
+ * hasBorder: true
408
+ * },
409
+ * {
410
+ * color: 'hsl(120, 75%, 60%)',
411
+ * label: 'Green'
412
+ * }
413
+ * ]
414
+ * }
415
+ * };
416
+ * ```
417
+ *
418
+ * **Note**: This configuration only affects the UI. It does not limit or filter the colors in the data.
419
+ *
420
+ * Defaults to {@link module:table/utils/ui/table-properties#defaultColors}.
421
+ *
422
+ * @see {@link module:table/tableconfig~TableColorConfig}
423
+ */
280
424
  backgroundColors?: TableColorConfig;
425
+ /**
426
+ * Default styles for newly created table cells.
427
+ *
428
+ * ```ts
429
+ * const tableConfig = {
430
+ * tableCellProperties: {
431
+ * defaultProperties: {
432
+ * borderStyle: 'dashed',
433
+ * borderColor: 'hsl(0, 0%, 90%)',
434
+ * borderWidth: '3px',
435
+ * horizontalAlignment: 'center',
436
+ * verticalAlignment: 'middle',
437
+ * padding: '10px'
438
+ * }
439
+ * }
440
+ * }
441
+ * ```
442
+ *
443
+ * **Note**: The model does not store the default values. The editor will only keep values that differ from the defaults.
444
+ *
445
+ * See {@link module:table/tableconfig~TableCellPropertiesOptions} for the full list of properties.
446
+ */
281
447
  defaultProperties?: TableCellPropertiesOptions;
282
448
  /**
283
449
  * Configuration of the color picker in the table cell properties balloon.
@@ -433,3 +599,14 @@ export interface TableCaptionConfig {
433
599
  * The type of the table.
434
600
  */
435
601
  export type TableType = 'content' | 'layout';
602
+ export interface TableAlignmentConfig {
603
+ /**
604
+ * Whether to use inline styles for table alignment in the editor output.
605
+ *
606
+ * * When `true` (default), the alignment is rendered as inline styles.
607
+ * * When `false`, the alignment is rendered as CSS classes.
608
+ *
609
+ * @default true
610
+ */
611
+ useInlineStyles?: boolean;
612
+ }
@@ -41,6 +41,11 @@ export declare class TableEditing extends Plugin {
41
41
  * Registers downcast handler for the additional table slot.
42
42
  */
43
43
  registerAdditionalSlot(slotHandler: TableConversionAdditionalSlot): void;
44
+ /**
45
+ * Adds converters for plain table output. These converters are used either when the `PlainTableOutput` plugin is loaded
46
+ * or when content is processed by the clipboard pipeline, ensuring that pasted tables are not wrapped in a <figure> element.
47
+ */
48
+ private _addPlainTableOutputConverters;
44
49
  }
45
50
  /**
46
51
  * By default, only the `tableRow` elements from the `table` model are downcast inside the `<table>` and
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import { Plugin } from 'ckeditor5/src/core.js';
9
9
  import { upcastTable, ensureParagraphInTableCell, skipEmptyTableRow, upcastTableFigure } from './converters/upcasttable.js';
10
- import { convertParagraphInTableCell, downcastCell, downcastRow, downcastTable } from './converters/downcast.js';
10
+ import { convertParagraphInTableCell, downcastCell, downcastRow, downcastTable, downcastTableBorderAndBackgroundAttributes, convertPlainTable, convertPlainTableCaption } from './converters/downcast.js';
11
11
  import { InsertTableCommand } from './commands/inserttablecommand.js';
12
12
  import { InsertRowCommand } from './commands/insertrowcommand.js';
13
13
  import { InsertColumnCommand } from './commands/insertcolumncommand.js';
@@ -148,6 +148,8 @@ export class TableEditing extends Plugin {
148
148
  model: { key: 'rowspan', value: upcastCellSpan('rowspan') },
149
149
  view: 'rowspan'
150
150
  });
151
+ // Plain table output converters (also used in the clipboard pipeline).
152
+ this._addPlainTableOutputConverters();
151
153
  // Define the config.
152
154
  editor.config.define('table.defaultHeadings.rows', 0);
153
155
  editor.config.define('table.defaultHeadings.columns', 0);
@@ -183,6 +185,31 @@ export class TableEditing extends Plugin {
183
185
  registerAdditionalSlot(slotHandler) {
184
186
  this._additionalSlots.push(slotHandler);
185
187
  }
188
+ /**
189
+ * Adds converters for plain table output. These converters are used either when the `PlainTableOutput` plugin is loaded
190
+ * or when content is processed by the clipboard pipeline, ensuring that pasted tables are not wrapped in a <figure> element.
191
+ */
192
+ _addPlainTableOutputConverters() {
193
+ const editor = this.editor;
194
+ // Override default table data downcast converter.
195
+ editor.conversion.for('dataDowncast').elementToStructure({
196
+ model: 'table',
197
+ view: convertPlainTable(editor),
198
+ converterPriority: 'high'
199
+ });
200
+ // Make sure table <caption> is downcasted into <caption> in the data pipeline when necessary.
201
+ if (editor.plugins.has('TableCaption')) {
202
+ editor.conversion.for('dataDowncast').elementToElement({
203
+ model: 'caption',
204
+ view: convertPlainTableCaption(editor),
205
+ converterPriority: 'high'
206
+ });
207
+ }
208
+ // Handle border-style, border-color, border-width and background-color table attributes.
209
+ if (editor.plugins.has('TableProperties')) {
210
+ downcastTableBorderAndBackgroundAttributes(editor);
211
+ }
212
+ }
186
213
  }
187
214
  /**
188
215
  * Returns fixed colspan and rowspan attrbutes values.
@@ -6,9 +6,10 @@
6
6
  * @module table/tableproperties/tablepropertiesediting
7
7
  */
8
8
  import { Plugin } from 'ckeditor5/src/core.js';
9
- import { addBackgroundStylesRules, addBorderStylesRules } from 'ckeditor5/src/engine.js';
9
+ import { addBackgroundStylesRules, addBorderStylesRules, addMarginStylesRules } from 'ckeditor5/src/engine.js';
10
+ import { first } from 'ckeditor5/src/utils.js';
10
11
  import { TableEditing } from '../tableediting.js';
11
- import { downcastAttributeToStyle, downcastTableAttribute, getDefaultValueAdjusted, upcastBorderStyles, upcastStyleToAttribute } from '../converters/tableproperties.js';
12
+ import { downcastAttributeToStyle, downcastTableAttribute, getDefaultValueAdjusted, upcastBorderStyles, upcastStyleToAttribute, upcastTableAlignmentConfig, DEFAULT_TABLE_ALIGNMENT_OPTIONS } from '../converters/tableproperties.js';
12
13
  import { TableBackgroundColorCommand } from './commands/tablebackgroundcolorcommand.js';
13
14
  import { TableBorderColorCommand } from './commands/tablebordercolorcommand.js';
14
15
  import { TableBorderStyleCommand } from './commands/tableborderstylecommand.js';
@@ -17,8 +18,7 @@ import { TableWidthCommand } from './commands/tablewidthcommand.js';
17
18
  import { TableHeightCommand } from './commands/tableheightcommand.js';
18
19
  import { TableAlignmentCommand } from './commands/tablealignmentcommand.js';
19
20
  import { getNormalizedDefaultTableProperties } from '../utils/table-properties.js';
20
- const ALIGN_VALUES_REG_EXP = /^(left|center|right)$/;
21
- const FLOAT_VALUES_REG_EXP = /^(left|none|right)$/;
21
+ import { getViewTableFromWrapper } from '../utils/structure.js';
22
22
  /**
23
23
  * The table properties editing feature.
24
24
  *
@@ -79,6 +79,8 @@ export class TablePropertiesEditing extends Plugin {
79
79
  const defaultTableProperties = getNormalizedDefaultTableProperties(editor.config.get('table.tableProperties.defaultProperties'), {
80
80
  includeAlignmentProperty: true
81
81
  });
82
+ const useInlineStyles = editor.config.get('table.tableProperties.alignment.useInlineStyles') !== false;
83
+ editor.data.addStyleProcessorRules(addMarginStylesRules);
82
84
  editor.data.addStyleProcessorRules(addBorderStylesRules);
83
85
  enableBorderProperties(editor, {
84
86
  color: defaultTableProperties.borderColor,
@@ -88,7 +90,12 @@ export class TablePropertiesEditing extends Plugin {
88
90
  editor.commands.add('tableBorderColor', new TableBorderColorCommand(editor, defaultTableProperties.borderColor));
89
91
  editor.commands.add('tableBorderStyle', new TableBorderStyleCommand(editor, defaultTableProperties.borderStyle));
90
92
  editor.commands.add('tableBorderWidth', new TableBorderWidthCommand(editor, defaultTableProperties.borderWidth));
91
- enableAlignmentProperty(schema, conversion, defaultTableProperties.alignment);
93
+ if (editor.config.get('experimentalFlags.useExtendedTableBlockAlignment')) {
94
+ enableExtendedAlignmentProperty(schema, conversion, defaultTableProperties.alignment, useInlineStyles);
95
+ }
96
+ else {
97
+ enableAlignmentProperty(schema, conversion, defaultTableProperties.alignment);
98
+ }
92
99
  editor.commands.add('tableAlignment', new TableAlignmentCommand(editor, defaultTableProperties.alignment));
93
100
  enableTableToFigureProperty(schema, conversion, {
94
101
  modelAttribute: 'tableWidth',
@@ -115,8 +122,50 @@ export class TablePropertiesEditing extends Plugin {
115
122
  defaultValue: defaultTableProperties.backgroundColor
116
123
  });
117
124
  editor.commands.add('tableBackgroundColor', new TableBackgroundColorCommand(editor, defaultTableProperties.backgroundColor));
125
+ if (editor.config.get('experimentalFlags.useExtendedTableBlockAlignment')) {
126
+ const viewDoc = editor.editing.view.document;
127
+ // Adjust clipboard output to wrap tables in divs if needed (for alignment).
128
+ this.listenTo(viewDoc, 'clipboardOutput', (evt, data) => {
129
+ editor.editing.view.change(writer => {
130
+ for (const { item } of writer.createRangeIn(data.content)) {
131
+ wrapInDivIfNeeded(item, writer);
132
+ }
133
+ data.dataTransfer.setData('text/html', this.editor.data.htmlProcessor.toData(data.content));
134
+ });
135
+ }, { priority: 'lowest' });
136
+ }
118
137
  }
119
138
  }
139
+ /**
140
+ * Checks whether the view element is a table and if it needs to be wrapped in a div for alignment purposes.
141
+ * If so, it wraps it in a div and inserts it into the data content.
142
+ */
143
+ function wrapInDivIfNeeded(viewItem, writer) {
144
+ if (!viewItem.is('element', 'table')) {
145
+ return;
146
+ }
147
+ const alignAttribute = viewItem.getAttribute('align');
148
+ const floatAttribute = viewItem.getStyle('float');
149
+ const marginLeft = viewItem.getStyle('margin-left');
150
+ const marginRight = viewItem.getStyle('margin-right');
151
+ if (
152
+ // Align center.
153
+ (alignAttribute && alignAttribute === 'center') ||
154
+ // Align right with text wrapping.
155
+ (floatAttribute && floatAttribute === 'right' && alignAttribute && alignAttribute === 'right')) {
156
+ insertWrapperWithAlignment(writer, alignAttribute, viewItem);
157
+ return;
158
+ }
159
+ // Align right with no text wrapping.
160
+ if (floatAttribute === undefined && marginLeft === 'auto' && marginRight === '0') {
161
+ insertWrapperWithAlignment(writer, 'right', viewItem);
162
+ }
163
+ }
164
+ function insertWrapperWithAlignment(writer, align, table) {
165
+ const position = writer.createPositionBefore(table);
166
+ const wrapper = writer.createContainerElement('div', { align }, table);
167
+ writer.insert(position, wrapper);
168
+ }
120
169
  /**
121
170
  * Enables `tableBorderStyle'`, `tableBorderColor'` and `tableBorderWidth'` attributes for table.
122
171
  *
@@ -144,12 +193,110 @@ function enableBorderProperties(editor, defaultBorder) {
144
193
  downcastTableAttribute(conversion, { modelAttribute: modelAttributes.style, styleName: 'border-style' });
145
194
  downcastTableAttribute(conversion, { modelAttribute: modelAttributes.width, styleName: 'border-width' });
146
195
  }
196
+ /**
197
+ * Enables the extended block`'alignment'` attribute for table.
198
+ *
199
+ * @param defaultValue The default alignment value.
200
+ */
201
+ function enableExtendedAlignmentProperty(schema, conversion, defaultValue, useInlineStyles) {
202
+ schema.extend('table', {
203
+ allowAttributes: ['tableAlignment']
204
+ });
205
+ schema.setAttributeProperties('tableAlignment', { isFormatting: true });
206
+ conversion.for('downcast')
207
+ .attributeToAttribute({
208
+ model: {
209
+ name: 'table',
210
+ key: 'tableAlignment',
211
+ values: ['left', 'center', 'right', 'blockLeft', 'blockRight']
212
+ },
213
+ view: {
214
+ left: useInlineStyles ? {
215
+ key: 'style',
216
+ value: {
217
+ float: 'left',
218
+ 'margin-right': 'var(--ck-content-table-style-spacing, 1.5em)'
219
+ }
220
+ } : {
221
+ key: 'class',
222
+ value: DEFAULT_TABLE_ALIGNMENT_OPTIONS.left.className
223
+ },
224
+ right: useInlineStyles ? {
225
+ key: 'style',
226
+ value: {
227
+ float: 'right',
228
+ 'margin-left': 'var(--ck-content-table-style-spacing, 1.5em)'
229
+ }
230
+ } : {
231
+ key: 'class',
232
+ value: DEFAULT_TABLE_ALIGNMENT_OPTIONS.right.className
233
+ },
234
+ center: useInlineStyles ? {
235
+ key: 'style',
236
+ value: {
237
+ 'margin-left': 'auto',
238
+ 'margin-right': 'auto'
239
+ }
240
+ } : {
241
+ key: 'class',
242
+ value: DEFAULT_TABLE_ALIGNMENT_OPTIONS.center.className
243
+ },
244
+ blockLeft: useInlineStyles ? {
245
+ key: 'style',
246
+ value: {
247
+ 'margin-left': '0',
248
+ 'margin-right': 'auto'
249
+ }
250
+ } : {
251
+ key: 'class',
252
+ value: DEFAULT_TABLE_ALIGNMENT_OPTIONS.blockLeft.className
253
+ },
254
+ blockRight: useInlineStyles ? {
255
+ key: 'style',
256
+ value: {
257
+ 'margin-left': 'auto',
258
+ 'margin-right': '0'
259
+ }
260
+ } : {
261
+ key: 'class',
262
+ value: DEFAULT_TABLE_ALIGNMENT_OPTIONS.blockRight.className
263
+ }
264
+ },
265
+ converterPriority: 'high'
266
+ });
267
+ /**
268
+ * Enables upcasting of the `tableAlignment` attribute.
269
+ */
270
+ upcastTableAlignmentConfig.forEach(config => {
271
+ conversion.for('upcast').attributeToAttribute({
272
+ view: config.view,
273
+ model: {
274
+ key: 'tableAlignment',
275
+ value: (viewElement, conversionApi, data) => {
276
+ if (isNonTableFigureElement(viewElement)) {
277
+ return;
278
+ }
279
+ const localDefaultValue = getDefaultValueAdjusted(defaultValue, '', data);
280
+ const align = config.getAlign(viewElement);
281
+ const consumables = config.getConsumables(viewElement);
282
+ conversionApi.consumable.consume(viewElement, consumables);
283
+ if (align !== localDefaultValue) {
284
+ return align;
285
+ }
286
+ }
287
+ }
288
+ });
289
+ });
290
+ conversion.for('upcast').add(upcastTableAlignedDiv(defaultValue));
291
+ }
147
292
  /**
148
293
  * Enables the `'alignment'` attribute for table.
149
294
  *
150
295
  * @param defaultValue The default alignment value.
151
296
  */
152
297
  function enableAlignmentProperty(schema, conversion, defaultValue) {
298
+ const ALIGN_VALUES_REG_EXP = /^(left|center|right)$/;
299
+ const FLOAT_VALUES_REG_EXP = /^(left|none|right)$/;
153
300
  schema.extend('table', {
154
301
  allowAttributes: ['tableAlignment']
155
302
  });
@@ -268,6 +415,98 @@ function enableAlignmentProperty(schema, conversion, defaultValue) {
268
415
  }
269
416
  });
270
417
  }
418
+ /**
419
+ * Returns a function that converts the table view representation:
420
+ *
421
+ * ```html
422
+ * <div align="right"><table>...</table></div>
423
+ * <!-- or -->
424
+ * <div align="center"><table>...</table></div>
425
+ * <!-- or -->
426
+ * <div align="left"><table>...</table></div>
427
+ * ```
428
+ *
429
+ * to the model representation:
430
+ *
431
+ * ```xml
432
+ * <table tableAlignment="right|center|left"></table>
433
+ * ```
434
+ *
435
+ * @internal
436
+ */
437
+ function upcastTableAlignedDiv(defaultValue) {
438
+ return (dispatcher) => {
439
+ dispatcher.on('element:div', (evt, data, conversionApi) => {
440
+ // Do not convert if this is not a "table wrapped in div with align attribute".
441
+ if (!conversionApi.consumable.test(data.viewItem, { name: true, attributes: 'align' })) {
442
+ return;
443
+ }
444
+ // Find a table element inside the div element.
445
+ const viewTable = getViewTableFromWrapper(data.viewItem);
446
+ // Do not convert if table element is absent or was already converted.
447
+ if (!viewTable || !conversionApi.consumable.test(viewTable, { name: true })) {
448
+ return;
449
+ }
450
+ // Consume the div to prevent other converters from processing it again.
451
+ conversionApi.consumable.consume(data.viewItem, { name: true, attributes: 'align' });
452
+ // Convert view table to model table.
453
+ const conversionResult = conversionApi.convertItem(viewTable, data.modelCursor);
454
+ // Get table element from conversion result.
455
+ const modelTable = first(conversionResult.modelRange.getItems());
456
+ // When table wasn't successfully converted then finish conversion.
457
+ if (!modelTable || !modelTable.is('element', 'table')) {
458
+ // Revert consumed div so other features can convert it.
459
+ conversionApi.consumable.revert(data.viewItem, { name: true, attributes: 'align' });
460
+ // If anyway some table content was converted, we have to pass the model range and cursor.
461
+ if (conversionResult.modelRange && !conversionResult.modelRange.isCollapsed) {
462
+ data.modelRange = conversionResult.modelRange;
463
+ data.modelCursor = conversionResult.modelCursor;
464
+ }
465
+ return;
466
+ }
467
+ const alignAttributeFromDiv = data.viewItem.getAttribute('align');
468
+ const alignAttributeFromTable = viewTable.getAttribute('align');
469
+ const localDefaultValue = getDefaultValueAdjusted(defaultValue, '', data);
470
+ const align = convertToTableAlignment(alignAttributeFromDiv, alignAttributeFromTable, localDefaultValue);
471
+ if (align) {
472
+ conversionApi.writer.setAttribute('tableAlignment', align, modelTable);
473
+ }
474
+ conversionApi.convertChildren(data.viewItem, conversionApi.writer.createPositionAt(modelTable, 'end'));
475
+ conversionApi.updateConversionResult(modelTable, data);
476
+ });
477
+ };
478
+ }
479
+ /**
480
+ * Converts div `align` and table `align` attributes to the model `tableAlignment` attribute.
481
+ *
482
+ * @param divAlign The value of the div `align` attribute.
483
+ * @param tableAlign The value of the table `align` attribute.
484
+ * @param defaultValue The default alignment value.
485
+ * @returns The model `tableAlignment` value or `undefined` if no conversion is needed.
486
+ */
487
+ function convertToTableAlignment(divAlign, tableAlign, defaultValue) {
488
+ if (divAlign) {
489
+ switch (divAlign) {
490
+ case 'right':
491
+ if (tableAlign === 'right') {
492
+ return 'right';
493
+ }
494
+ else if (tableAlign === 'left') {
495
+ return 'left';
496
+ }
497
+ else {
498
+ return 'blockRight';
499
+ }
500
+ case 'center':
501
+ return 'center';
502
+ case 'left':
503
+ return tableAlign === undefined ? 'blockLeft' : 'left';
504
+ default:
505
+ return defaultValue;
506
+ }
507
+ }
508
+ return undefined;
509
+ }
271
510
  /**
272
511
  * Enables conversion for an attribute for simple view-model mappings.
273
512
  *
@@ -299,3 +538,9 @@ function enableTableToFigureProperty(schema, conversion, options) {
299
538
  });
300
539
  downcastAttributeToStyle(conversion, { modelElement: 'table', ...options });
301
540
  }
541
+ /**
542
+ * Checks whether a given figure element should be ignored when upcasting table properties.
543
+ */
544
+ function isNonTableFigureElement(viewElement) {
545
+ return viewElement.name == 'figure' && !viewElement.hasClass('table');
546
+ }