@ckeditor/ckeditor5-table 27.1.0 → 29.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.
Files changed (156) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +3 -3
  3. package/build/table.js +1 -1
  4. package/build/translations/ar.js +1 -0
  5. package/build/translations/az.js +1 -0
  6. package/build/translations/bg.js +1 -0
  7. package/build/translations/cs.js +1 -0
  8. package/build/translations/da.js +1 -0
  9. package/build/translations/de-ch.js +1 -0
  10. package/build/translations/de.js +1 -0
  11. package/build/translations/en-au.js +1 -0
  12. package/build/translations/en-gb.js +1 -0
  13. package/build/translations/es.js +1 -0
  14. package/build/translations/et.js +1 -0
  15. package/build/translations/fa.js +1 -0
  16. package/build/translations/fi.js +1 -0
  17. package/build/translations/fr.js +1 -0
  18. package/build/translations/gl.js +1 -0
  19. package/build/translations/hi.js +1 -0
  20. package/build/translations/hr.js +1 -0
  21. package/build/translations/hu.js +1 -0
  22. package/build/translations/id.js +1 -0
  23. package/build/translations/it.js +1 -0
  24. package/build/translations/ja.js +1 -0
  25. package/build/translations/ko.js +1 -0
  26. package/build/translations/ku.js +1 -0
  27. package/build/translations/lt.js +1 -0
  28. package/build/translations/lv.js +1 -0
  29. package/build/translations/nb.js +1 -0
  30. package/build/translations/ne.js +1 -0
  31. package/build/translations/nl.js +1 -0
  32. package/build/translations/no.js +1 -0
  33. package/build/translations/pl.js +1 -0
  34. package/build/translations/pt-br.js +1 -0
  35. package/build/translations/ro.js +1 -0
  36. package/build/translations/ru.js +1 -0
  37. package/build/translations/sk.js +1 -0
  38. package/build/translations/sq.js +1 -0
  39. package/build/translations/sr-latn.js +1 -0
  40. package/build/translations/sr.js +1 -0
  41. package/build/translations/sv.js +1 -0
  42. package/build/translations/th.js +1 -0
  43. package/build/translations/tk.js +1 -0
  44. package/build/translations/tr.js +1 -0
  45. package/build/translations/ug.js +1 -0
  46. package/build/translations/uk.js +1 -0
  47. package/build/translations/vi.js +1 -0
  48. package/build/translations/zh-cn.js +1 -0
  49. package/build/translations/zh.js +1 -0
  50. package/ckeditor5-metadata.json +174 -0
  51. package/lang/contexts.json +4 -1
  52. package/lang/translations/ar.po +12 -0
  53. package/lang/translations/az.po +12 -0
  54. package/lang/translations/bg.po +12 -0
  55. package/lang/translations/cs.po +12 -0
  56. package/lang/translations/da.po +12 -0
  57. package/lang/translations/de-ch.po +12 -0
  58. package/lang/translations/de.po +12 -0
  59. package/lang/translations/en-au.po +12 -0
  60. package/lang/translations/en-gb.po +12 -0
  61. package/lang/translations/en.po +12 -0
  62. package/lang/translations/es.po +12 -0
  63. package/lang/translations/et.po +12 -0
  64. package/lang/translations/fa.po +12 -0
  65. package/lang/translations/fi.po +12 -0
  66. package/lang/translations/fr.po +12 -0
  67. package/lang/translations/gl.po +12 -0
  68. package/lang/translations/hi.po +12 -0
  69. package/lang/translations/hr.po +12 -0
  70. package/lang/translations/hu.po +23 -11
  71. package/lang/translations/id.po +23 -11
  72. package/lang/translations/it.po +12 -0
  73. package/lang/translations/ja.po +12 -0
  74. package/lang/translations/ko.po +12 -0
  75. package/lang/translations/ku.po +12 -0
  76. package/lang/translations/lt.po +12 -0
  77. package/lang/translations/lv.po +12 -0
  78. package/lang/translations/nb.po +12 -0
  79. package/lang/translations/ne.po +12 -0
  80. package/lang/translations/nl.po +12 -0
  81. package/lang/translations/no.po +12 -0
  82. package/lang/translations/pl.po +12 -0
  83. package/lang/translations/pt-br.po +12 -0
  84. package/lang/translations/ro.po +51 -39
  85. package/lang/translations/ru.po +12 -0
  86. package/lang/translations/sk.po +12 -0
  87. package/lang/translations/sq.po +12 -0
  88. package/lang/translations/sr-latn.po +12 -0
  89. package/lang/translations/sr.po +12 -0
  90. package/lang/translations/sv.po +12 -0
  91. package/lang/translations/th.po +12 -0
  92. package/lang/translations/tk.po +12 -0
  93. package/lang/translations/tr.po +12 -0
  94. package/lang/translations/ug.po +12 -0
  95. package/lang/translations/uk.po +12 -0
  96. package/lang/translations/vi.po +12 -0
  97. package/lang/translations/zh-cn.po +12 -0
  98. package/lang/translations/zh.po +12 -0
  99. package/package.json +25 -23
  100. package/src/commands/insertcolumncommand.js +2 -3
  101. package/src/commands/insertrowcommand.js +2 -3
  102. package/src/commands/inserttablecommand.js +22 -7
  103. package/src/commands/mergecellcommand.js +5 -3
  104. package/src/commands/removerowcommand.js +8 -5
  105. package/src/converters/downcast.js +4 -5
  106. package/src/converters/table-caption-post-fixer.js +69 -0
  107. package/src/converters/table-cell-paragraph-post-fixer.js +3 -1
  108. package/src/converters/table-layout-post-fixer.js +13 -8
  109. package/src/converters/tableproperties.js +82 -23
  110. package/src/converters/upcasttable.js +63 -0
  111. package/src/index.js +18 -33
  112. package/src/table.js +17 -0
  113. package/src/tablecaption/tablecaptionediting.js +153 -0
  114. package/src/tablecaption/tablecaptionui.js +71 -0
  115. package/src/tablecaption/toggletablecaptioncommand.js +120 -0
  116. package/src/tablecaption/utils.js +93 -0
  117. package/src/tablecaption.js +35 -0
  118. package/src/tablecellproperties/commands/tablecellbackgroundcolorcommand.js +3 -2
  119. package/src/tablecellproperties/commands/tablecellbordercolorcommand.js +10 -3
  120. package/src/tablecellproperties/commands/tablecellborderstylecommand.js +10 -3
  121. package/src/tablecellproperties/commands/tablecellborderwidthcommand.js +17 -4
  122. package/src/tablecellproperties/commands/tablecellheightcommand.js +10 -3
  123. package/src/tablecellproperties/commands/tablecellhorizontalalignmentcommand.js +3 -2
  124. package/src/tablecellproperties/commands/tablecellpaddingcommand.js +17 -4
  125. package/src/tablecellproperties/commands/tablecellpropertycommand.js +28 -2
  126. package/src/tablecellproperties/commands/tablecellverticalalignmentcommand.js +3 -2
  127. package/src/tablecellproperties/commands/tablecellwidthcommand.js +10 -3
  128. package/src/tablecellproperties/tablecellpropertiesediting.js +164 -65
  129. package/src/tablecellproperties/tablecellpropertiesui.js +76 -16
  130. package/src/tablecellproperties/ui/tablecellpropertiesview.js +39 -13
  131. package/src/tablecellproperties.js +42 -2
  132. package/src/tableediting.js +76 -6
  133. package/src/tablekeyboard.js +3 -2
  134. package/src/tableproperties/commands/tablealignmentcommand.js +3 -2
  135. package/src/tableproperties/commands/tablebackgroundcolorcommand.js +3 -2
  136. package/src/tableproperties/commands/tablebordercolorcommand.js +10 -3
  137. package/src/tableproperties/commands/tableborderstylecommand.js +10 -3
  138. package/src/tableproperties/commands/tableborderwidthcommand.js +17 -4
  139. package/src/tableproperties/commands/tableheightcommand.js +10 -3
  140. package/src/tableproperties/commands/tablepropertycommand.js +28 -2
  141. package/src/tableproperties/commands/tablewidthcommand.js +10 -3
  142. package/src/tableproperties/tablepropertiesediting.js +104 -47
  143. package/src/tableproperties/tablepropertiesui.js +68 -15
  144. package/src/tableproperties/ui/tablepropertiesview.js +26 -11
  145. package/src/tableproperties.js +38 -2
  146. package/src/tableui.js +10 -1
  147. package/src/tableutils.js +41 -5
  148. package/src/tablewalker.js +36 -1
  149. package/src/ui/colorinputview.js +11 -7
  150. package/src/utils/structure.js +4 -3
  151. package/src/utils/table-properties.js +41 -0
  152. package/src/utils/ui/table-properties.js +29 -7
  153. package/src/utils/ui/widget.js +7 -15
  154. package/theme/table.css +17 -1
  155. package/theme/tablecaption.css +53 -0
  156. package/build/table.js.map +0 -1
@@ -24,6 +24,7 @@ import { getTableWidgetAncestor } from '../utils/ui/widget';
24
24
  import { getBalloonCellPositionData, repositionContextualBalloon } from '../utils/ui/contextualballoon';
25
25
 
26
26
  import tableCellProperties from './../../theme/icons/table-cell-properties.svg';
27
+ import { getNormalizedDefaultProperties } from '../utils/table-properties';
27
28
 
28
29
  const ERROR_TEXT_TIMEOUT = 500;
29
30
 
@@ -83,6 +84,22 @@ export default class TableCellPropertiesUI extends Plugin {
83
84
  const editor = this.editor;
84
85
  const t = editor.t;
85
86
 
87
+ /**
88
+ * The default table cell properties.
89
+ *
90
+ * @protected
91
+ * @member {module:table/tablecellproperties~TableCellPropertiesOptions}
92
+ */
93
+ this._defaultTableCellProperties = getNormalizedDefaultProperties(
94
+ editor.config.get( 'table.tableCellProperties.defaultProperties' ),
95
+ {
96
+ includeVerticalAlignmentProperty: true,
97
+ includeHorizontalAlignmentProperty: true,
98
+ includePaddingProperty: true,
99
+ isRightToLeftContent: editor.locale.contentLanguageDirection === 'rtl'
100
+ }
101
+ );
102
+
86
103
  /**
87
104
  * The contextual balloon plugin instance.
88
105
  *
@@ -157,7 +174,8 @@ export default class TableCellPropertiesUI extends Plugin {
157
174
  const localizedBackgroundColors = getLocalizedColorOptions( editor.locale, backgroundColorsConfig );
158
175
  const view = new TableCellPropertiesView( editor.locale, {
159
176
  borderColors: localizedBorderColors,
160
- backgroundColors: localizedBackgroundColors
177
+ backgroundColors: localizedBackgroundColors,
178
+ defaultTableCellProperties: this._defaultTableCellProperties
161
179
  } );
162
180
  const t = editor.t;
163
181
 
@@ -208,52 +226,67 @@ export default class TableCellPropertiesUI extends Plugin {
208
226
  // property of the view has changed. They also validate the value and display errors in the UI
209
227
  // when necessary. This makes the view live, which means the changes are
210
228
  // visible in the editing as soon as the user types or changes fields' values.
211
- view.on( 'change:borderStyle', this._getPropertyChangeCallback( 'tableCellBorderStyle' ) );
229
+ view.on(
230
+ 'change:borderStyle',
231
+ this._getPropertyChangeCallback( 'tableCellBorderStyle', this._defaultTableCellProperties.borderStyle )
232
+ );
212
233
 
213
234
  view.on( 'change:borderColor', this._getValidatedPropertyChangeCallback( {
214
235
  viewField: view.borderColorInput,
215
236
  commandName: 'tableCellBorderColor',
216
237
  errorText: colorErrorText,
217
- validator: colorFieldValidator
238
+ validator: colorFieldValidator,
239
+ defaultValue: this._defaultTableCellProperties.borderColor
218
240
  } ) );
219
241
 
220
242
  view.on( 'change:borderWidth', this._getValidatedPropertyChangeCallback( {
221
243
  viewField: view.borderWidthInput,
222
244
  commandName: 'tableCellBorderWidth',
223
245
  errorText: lengthErrorText,
224
- validator: lineWidthFieldValidator
246
+ validator: lineWidthFieldValidator,
247
+ defaultValue: this._defaultTableCellProperties.borderWidth
225
248
  } ) );
226
249
 
227
250
  view.on( 'change:padding', this._getValidatedPropertyChangeCallback( {
228
251
  viewField: view.paddingInput,
229
252
  commandName: 'tableCellPadding',
230
253
  errorText: lengthErrorText,
231
- validator: lengthFieldValidator
254
+ validator: lengthFieldValidator,
255
+ defaultValue: this._defaultTableCellProperties.padding
232
256
  } ) );
233
257
 
234
258
  view.on( 'change:width', this._getValidatedPropertyChangeCallback( {
235
259
  viewField: view.widthInput,
236
260
  commandName: 'tableCellWidth',
237
261
  errorText: lengthErrorText,
238
- validator: lengthFieldValidator
262
+ validator: lengthFieldValidator,
263
+ defaultValue: this._defaultTableCellProperties.width
239
264
  } ) );
240
265
 
241
266
  view.on( 'change:height', this._getValidatedPropertyChangeCallback( {
242
267
  viewField: view.heightInput,
243
268
  commandName: 'tableCellHeight',
244
269
  errorText: lengthErrorText,
245
- validator: lengthFieldValidator
270
+ validator: lengthFieldValidator,
271
+ defaultValue: this._defaultTableCellProperties.height
246
272
  } ) );
247
273
 
248
274
  view.on( 'change:backgroundColor', this._getValidatedPropertyChangeCallback( {
249
275
  viewField: view.backgroundInput,
250
276
  commandName: 'tableCellBackgroundColor',
251
277
  errorText: colorErrorText,
252
- validator: colorFieldValidator
278
+ validator: colorFieldValidator,
279
+ defaultValue: this._defaultTableCellProperties.backgroundColor
253
280
  } ) );
254
281
 
255
- view.on( 'change:horizontalAlignment', this._getPropertyChangeCallback( 'tableCellHorizontalAlignment' ) );
256
- view.on( 'change:verticalAlignment', this._getPropertyChangeCallback( 'tableCellVerticalAlignment' ) );
282
+ view.on(
283
+ 'change:horizontalAlignment',
284
+ this._getPropertyChangeCallback( 'tableCellHorizontalAlignment', this._defaultTableCellProperties.horizontalAlignment )
285
+ );
286
+ view.on(
287
+ 'change:verticalAlignment',
288
+ this._getPropertyChangeCallback( 'tableCellVerticalAlignment', this._defaultTableCellProperties.verticalAlignment )
289
+ );
257
290
 
258
291
  return view;
259
292
  }
@@ -270,10 +303,22 @@ export default class TableCellPropertiesUI extends Plugin {
270
303
  */
271
304
  _fillViewFormFromCommandValues() {
272
305
  const commands = this.editor.commands;
306
+ const borderStyleCommand = commands.get( 'tableCellBorderStyle' );
273
307
 
274
308
  Object.entries( propertyToCommandMap )
275
- .map( ( [ property, commandName ] ) => [ property, commands.get( commandName ).value || '' ] )
276
- .forEach( ( [ property, value ] ) => this.view.set( property, value ) );
309
+ .map( ( [ property, commandName ] ) => {
310
+ const defaultValue = this._defaultTableCellProperties[ property ] || '';
311
+
312
+ return [ property, commands.get( commandName ).value || defaultValue ];
313
+ } )
314
+ .forEach( ( [ property, value ] ) => {
315
+ // Do not set the `border-color` and `border-width` fields if `border-style:none`.
316
+ if ( ( property === 'borderColor' || property === 'borderWidth' ) && borderStyleCommand.value === 'none' ) {
317
+ return;
318
+ }
319
+
320
+ this.view.set( property, value );
321
+ } );
277
322
  }
278
323
 
279
324
  /**
@@ -354,10 +399,17 @@ export default class TableCellPropertiesUI extends Plugin {
354
399
  *
355
400
  * @private
356
401
  * @param {String} commandName
402
+ * @param {String} defaultValue The default value of the command.
357
403
  * @returns {Function}
358
404
  */
359
- _getPropertyChangeCallback( commandName ) {
360
- return ( evt, propertyName, newValue ) => {
405
+ _getPropertyChangeCallback( commandName, defaultValue ) {
406
+ return ( evt, propertyName, newValue, oldValue ) => {
407
+ // If the "oldValue" is missing and "newValue" is set to the default value, do not execute the command.
408
+ // It is an initial call (when opening the table properties view).
409
+ if ( !oldValue && defaultValue === newValue ) {
410
+ return;
411
+ }
412
+
361
413
  this.editor.execute( commandName, {
362
414
  value: newValue,
363
415
  batch: this._undoStepBatch
@@ -376,16 +428,24 @@ export default class TableCellPropertiesUI extends Plugin {
376
428
  * @param {module:ui/view~View} options.viewField
377
429
  * @param {Function} options.validator
378
430
  * @param {String} options.errorText
431
+ * @param {String} options.defaultValue
379
432
  * @returns {Function}
380
433
  */
381
- _getValidatedPropertyChangeCallback( { commandName, viewField, validator, errorText } ) {
434
+ _getValidatedPropertyChangeCallback( options ) {
435
+ const { commandName, viewField, validator, errorText, defaultValue } = options;
382
436
  const setErrorTextDebounced = debounce( () => {
383
437
  viewField.errorText = errorText;
384
438
  }, ERROR_TEXT_TIMEOUT );
385
439
 
386
- return ( evt, propertyName, newValue ) => {
440
+ return ( evt, propertyName, newValue, oldValue ) => {
387
441
  setErrorTextDebounced.cancel();
388
442
 
443
+ // If the "oldValue" is missing and "newValue" is set to the default value, do not execute the command.
444
+ // It is an initial call (when opening the table properties view).
445
+ if ( !oldValue && defaultValue === newValue ) {
446
+ return;
447
+ }
448
+
389
449
  if ( validator( newValue ) ) {
390
450
  this.editor.execute( commandName, {
391
451
  value: newValue,
@@ -62,6 +62,8 @@ export default class TableCellPropertiesView extends View {
62
62
  * @param {module:table/table~TableColorConfig} options.backgroundColors A configuration of the background
63
63
  * color palette used by the
64
64
  * {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView#backgroundInput}.
65
+ * @param {module:table/tablecellproperties~TableCellPropertiesOptions} options.defaultTableCellProperties The default
66
+ * table cell properties.
65
67
  */
66
68
  constructor( locale, options ) {
67
69
  super( locale );
@@ -446,9 +448,17 @@ export default class TableCellPropertiesView extends View {
446
448
  * @returns {Object.<String,module:ui/view~View>}
447
449
  */
448
450
  _createBorderFields() {
451
+ const defaultTableCellProperties = this.options.defaultTableCellProperties;
452
+ const defaultBorder = {
453
+ style: defaultTableCellProperties.borderStyle,
454
+ width: defaultTableCellProperties.borderWidth,
455
+ color: defaultTableCellProperties.borderColor
456
+ };
457
+
449
458
  const colorInputCreator = getLabeledColorInputCreator( {
450
459
  colorConfig: this.options.borderColors,
451
- columns: 5
460
+ columns: 5,
461
+ defaultColorValue: defaultBorder.color
452
462
  } );
453
463
  const locale = this.locale;
454
464
  const t = this.t;
@@ -483,7 +493,7 @@ export default class TableCellPropertiesView extends View {
483
493
 
484
494
  borderStyleDropdown.bind( 'isEmpty' ).to( this, 'borderStyle', value => !value );
485
495
 
486
- addListToDropdown( borderStyleDropdown.fieldView, getBorderStyleDefinitions( this ) );
496
+ addListToDropdown( borderStyleDropdown.fieldView, getBorderStyleDefinitions( this, defaultBorder.style ) );
487
497
 
488
498
  // -- Width ---------------------------------------------------
489
499
 
@@ -516,13 +526,20 @@ export default class TableCellPropertiesView extends View {
516
526
  this.borderColor = borderColorInput.fieldView.value;
517
527
  } );
518
528
 
519
- // Reset the border color and width fields when style is "none".
520
- // https://github.com/ckeditor/ckeditor5/issues/6227
521
- this.on( 'change:borderStyle', ( evt, name, value ) => {
522
- if ( !isBorderStyleSet( value ) ) {
529
+ // Reset the border color and width fields depending on the `border-style` value.
530
+ this.on( 'change:borderStyle', ( evt, name, newValue, oldValue ) => {
531
+ // When removing the border (`border-style:none`), clear the remaining `border-*` properties.
532
+ // See: https://github.com/ckeditor/ckeditor5/issues/6227.
533
+ if ( !isBorderStyleSet( newValue ) ) {
523
534
  this.borderColor = '';
524
535
  this.borderWidth = '';
525
536
  }
537
+
538
+ // When setting the `border-style` from `none`, set the default `border-color` and `border-width` properties.
539
+ if ( !isBorderStyleSet( oldValue ) ) {
540
+ this.borderColor = defaultBorder.color;
541
+ this.borderWidth = defaultBorder.width;
542
+ }
526
543
  } );
527
544
 
528
545
  return {
@@ -554,7 +571,8 @@ export default class TableCellPropertiesView extends View {
554
571
 
555
572
  const colorInputCreator = getLabeledColorInputCreator( {
556
573
  colorConfig: this.options.backgroundColors,
557
- columns: 5
574
+ columns: 5,
575
+ defaultColorValue: this.options.defaultTableCellProperties.backgroundColor
558
576
  } );
559
577
 
560
578
  const backgroundInput = new LabeledFieldView( locale, colorInputCreator );
@@ -705,8 +723,18 @@ export default class TableCellPropertiesView extends View {
705
723
  labels: this._horizontalAlignmentLabels,
706
724
  propertyName: 'horizontalAlignment',
707
725
  nameToValue: name => {
708
- return name === ( isContentRTL ? 'right' : 'left' ) ? '' : name;
709
- }
726
+ // For the RTL content, we want to swap the buttons "align to the left" and "align to the right".
727
+ if ( isContentRTL ) {
728
+ if ( name === 'left' ) {
729
+ return 'right';
730
+ } else if ( name === 'right' ) {
731
+ return 'left';
732
+ }
733
+ }
734
+
735
+ return name;
736
+ },
737
+ defaultValue: this.options.defaultTableCellProperties.horizontalAlignment
710
738
  } );
711
739
 
712
740
  // -- Vertical -----------------------------------------------------
@@ -724,9 +752,7 @@ export default class TableCellPropertiesView extends View {
724
752
  toolbar: verticalAlignmentToolbar,
725
753
  labels: this._verticalAlignmentLabels,
726
754
  propertyName: 'verticalAlignment',
727
- nameToValue: name => {
728
- return name === 'middle' ? '' : name;
729
- }
755
+ defaultValue: this.options.defaultTableCellProperties.verticalAlignment
730
756
  } );
731
757
 
732
758
  return {
@@ -825,5 +851,5 @@ export default class TableCellPropertiesView extends View {
825
851
  }
826
852
 
827
853
  function isBorderStyleSet( value ) {
828
- return !!value;
854
+ return value !== 'none';
829
855
  }
@@ -64,9 +64,24 @@ export default class TableCellProperties extends Plugin {
64
64
  * }
65
65
  * };
66
66
  *
67
- * **Note**: The configurations do not impact the data loaded into the editor,
67
+ * * The default styles for table cells (`tableCellProperties.defaultProperties`):
68
+ *
69
+ * const tableConfig = {
70
+ * tableCellProperties: {
71
+ * defaultProperties: {
72
+ * horizontalAlignment: 'right',
73
+ * verticalAlignment: 'bottom',
74
+ * padding: '5px'
75
+ * }
76
+ * }
77
+ * }
78
+ *
79
+ * {@link module:table/tableproperties~TablePropertiesOptions Read more about the supported properties.}
80
+ *
81
+ * **Note**: The `borderColors` and `backgroundColors` options do not impact the data loaded into the editor,
68
82
  * i.e. they do not limit or filter the colors in the data. They are used only in the user interface
69
- * allowing users to pick colors in a more convenient way.
83
+ * allowing users to pick colors in a more convenient way. The `defaultProperties` option does impact the data.
84
+ * Default values will not be kept in the editor model.
70
85
  *
71
86
  * The default color palettes for the cell background and the cell border are the same
72
87
  * ({@link module:table/utils/ui/table-properties~defaultColors check out their content}).
@@ -78,3 +93,28 @@ export default class TableCellProperties extends Plugin {
78
93
  *
79
94
  * @member {Object} module:table/table~TableConfig#tableCellProperties
80
95
  */
96
+
97
+ /**
98
+ * The configuration of the table cell default properties feature.
99
+ *
100
+ * @typedef {Object} module:table/tablecellproperties~TableCellPropertiesOptions
101
+ *
102
+ * @property {String} width The default `width` of the table cell.
103
+ *
104
+ * @property {String} height The default `height` of the table cell.
105
+ *
106
+ * @property {String} padding The default `padding` of the table cell.
107
+ *
108
+ * @property {String} backgroundColor The default `background-color` of the table cell.
109
+ *
110
+ * @property {String} borderColor The default `border-color` of the table cell.
111
+ *
112
+ * @property {String} borderWidth The default `border-width` of the table cell.
113
+ *
114
+ * @property {String} [borderStyle='none'] The default `border-style` of the table cell.
115
+ *
116
+ * @property {String} [horizontalAlignment='center'] The default `horizontalAlignment` of the table cell.
117
+ *
118
+ * @property {String} [verticalAlignment='middle'] The default `verticalAlignment` of the table cell.
119
+ */
120
+
@@ -9,7 +9,7 @@
9
9
 
10
10
  import { Plugin } from 'ckeditor5/src/core';
11
11
 
12
- import upcastTable, { ensureParagraphInTableCell, skipEmptyTableRow } from './converters/upcasttable';
12
+ import upcastTable, { ensureParagraphInTableCell, skipEmptyTableRow, upcastTableFigure } from './converters/upcasttable';
13
13
  import {
14
14
  convertParagraphInTableCell,
15
15
  downcastInsertCell,
@@ -76,13 +76,14 @@ export default class TableEditing extends Plugin {
76
76
 
77
77
  schema.register( 'tableCell', {
78
78
  allowIn: 'tableRow',
79
+ allowChildren: '$block',
79
80
  allowAttributes: [ 'colspan', 'rowspan' ],
80
81
  isLimit: true,
81
82
  isSelectable: true
82
83
  } );
83
84
 
84
- // Allow all $block content inside a table cell.
85
- schema.extend( '$block', { allowIn: 'tableCell' } );
85
+ // Figure conversion.
86
+ conversion.for( 'upcast' ).add( upcastTableFigure() );
86
87
 
87
88
  // Table conversion.
88
89
  conversion.for( 'upcast' ).add( upcastTable() );
@@ -106,19 +107,37 @@ export default class TableEditing extends Plugin {
106
107
  conversion.for( 'editingDowncast' ).add( downcastInsertCell() );
107
108
 
108
109
  // Duplicates code - needed to properly refresh paragraph inside a table cell.
109
- editor.conversion.for( 'editingDowncast' ).elementToElement( {
110
+ conversion.for( 'editingDowncast' ).elementToElement( {
110
111
  model: 'paragraph',
111
112
  view: convertParagraphInTableCell,
112
113
  converterPriority: 'high'
113
114
  } );
114
115
 
115
116
  // Table attributes conversion.
116
- conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
117
- conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
117
+ conversion.for( 'downcast' ).attributeToAttribute( { model: 'colspan', view: 'colspan' } );
118
+ conversion.for( 'upcast' ).attributeToAttribute( {
119
+ model: { key: 'colspan', value: upcastCellSpan( 'colspan' ) },
120
+ view: 'colspan'
121
+ } );
122
+
123
+ conversion.for( 'downcast' ).attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
124
+ conversion.for( 'upcast' ).attributeToAttribute( {
125
+ model: { key: 'rowspan', value: upcastCellSpan( 'rowspan' ) },
126
+ view: 'rowspan'
127
+ } );
118
128
 
119
129
  // Table heading columns conversion (a change of heading rows requires a reconversion of the whole table).
120
130
  conversion.for( 'editingDowncast' ).add( downcastTableHeadingColumnsChange() );
121
131
 
132
+ // Manually adjust model position mappings in a special case, when a table cell contains a paragraph, which is bound
133
+ // to its parent (to the table cell). This custom model-to-view position mapping is necessary in data pipeline only,
134
+ // because only during this conversion a paragraph can be bound to its parent.
135
+ editor.data.mapper.on( 'modelToViewPosition', mapTableCellModelPositionToView() );
136
+
137
+ // Define the config.
138
+ editor.config.define( 'table.defaultHeadings.rows', 0 );
139
+ editor.config.define( 'table.defaultHeadings.columns', 0 );
140
+
122
141
  // Define all the commands.
123
142
  editor.commands.add( 'insertTable', new InsertTableCommand( editor ) );
124
143
  editor.commands.add( 'insertTableRowAbove', new InsertRowCommand( editor, { order: 'above' } ) );
@@ -158,3 +177,54 @@ export default class TableEditing extends Plugin {
158
177
  return [ TableUtils ];
159
178
  }
160
179
  }
180
+
181
+ // Creates a mapper callback to adjust model position mappings in a table cell containing a paragraph, which is bound to its parent
182
+ // (to the table cell). Only positions after this paragraph have to be adjusted, because after binding this paragraph to the table cell,
183
+ // elements located after this paragraph would point either to a non-existent offset inside `tableCell` (if paragraph is empty), or after
184
+ // the first character of the paragraph's text. See https://github.com/ckeditor/ckeditor5/issues/10116.
185
+ //
186
+ // <tableCell><paragraph></paragraph>^</tableCell> -> <td>^&nbsp;</td>
187
+ //
188
+ // <tableCell><paragraph>foobar</paragraph>^</tableCell> -> <td>foobar^</td>
189
+ //
190
+ // @returns {Function}
191
+ function mapTableCellModelPositionToView() {
192
+ return ( evt, data ) => {
193
+ const modelParent = data.modelPosition.parent;
194
+ const modelNodeBefore = data.modelPosition.nodeBefore;
195
+
196
+ if ( !modelParent.is( 'element', 'tableCell' ) ) {
197
+ return;
198
+ }
199
+
200
+ if ( !modelNodeBefore || !modelNodeBefore.is( 'element', 'paragraph' ) ) {
201
+ return;
202
+ }
203
+
204
+ const viewNodeBefore = data.mapper.toViewElement( modelNodeBefore );
205
+ const viewParent = data.mapper.toViewElement( modelParent );
206
+
207
+ if ( viewNodeBefore === viewParent ) {
208
+ // Since the paragraph has already been bound to its parent, update the current position in the model with paragraph's
209
+ // max offset, so it points to the place which should normally (in all other cases) be the end position of this paragraph.
210
+ data.viewPosition = data.mapper.findPositionIn( viewParent, modelNodeBefore.maxOffset );
211
+ }
212
+ };
213
+ }
214
+
215
+ // Returns fixed colspan and rowspan attrbutes values.
216
+ //
217
+ // @private
218
+ // @param {String} type colspan or rowspan.
219
+ // @returns {Function} conversion value function.
220
+ function upcastCellSpan( type ) {
221
+ return cell => {
222
+ const span = parseInt( cell.getAttribute( type ) );
223
+
224
+ if ( Number.isNaN( span ) || span <= 0 ) {
225
+ return null;
226
+ }
227
+
228
+ return span;
229
+ };
230
+ }
@@ -115,15 +115,16 @@ export default class TableKeyboard extends Plugin {
115
115
  return;
116
116
  }
117
117
 
118
+ const tableUtils = this.editor.plugins.get( 'TableUtils' );
118
119
  const isLastCellInRow = currentCellIndex === tableRow.childCount - 1;
119
- const isLastRow = currentRowIndex === table.childCount - 1;
120
+ const isLastRow = currentRowIndex === tableUtils.getRows( table ) - 1;
120
121
 
121
122
  if ( isForward && isLastRow && isLastCellInRow ) {
122
123
  editor.execute( 'insertTableRowBelow' );
123
124
 
124
125
  // Check if the command actually added a row. If `insertTableRowBelow` execution didn't add a row (because it was disabled
125
126
  // or it got overwritten) set the selection over the whole table to mirror the first cell case.
126
- if ( currentRowIndex === table.childCount - 1 ) {
127
+ if ( currentRowIndex === tableUtils.getRows( table ) - 1 ) {
127
128
  editor.model.change( writer => {
128
129
  writer.setSelection( writer.createRangeOn( table ) );
129
130
  } );
@@ -28,8 +28,9 @@ export default class TableAlignmentCommand extends TablePropertyCommand {
28
28
  * Creates a new `TableAlignmentCommand` instance.
29
29
  *
30
30
  * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.
31
+ * @param {String} defaultValue The default value for the "alignment" attribute.
31
32
  */
32
- constructor( editor ) {
33
- super( editor, 'alignment' );
33
+ constructor( editor, defaultValue ) {
34
+ super( editor, 'alignment', defaultValue );
34
35
  }
35
36
  }
@@ -28,8 +28,9 @@ export default class TableBackgroundColorCommand extends TablePropertyCommand {
28
28
  * Creates a new `TableBackgroundColorCommand` instance.
29
29
  *
30
30
  * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.
31
+ * @param {String} defaultValue The default value of the attribute.
31
32
  */
32
- constructor( editor ) {
33
- super( editor, 'backgroundColor' );
33
+ constructor( editor, defaultValue ) {
34
+ super( editor, 'backgroundColor', defaultValue );
34
35
  }
35
36
  }
@@ -29,9 +29,10 @@ export default class TableBorderColorCommand extends TablePropertyCommand {
29
29
  * Creates a new `TableBorderColorCommand` instance.
30
30
  *
31
31
  * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.
32
+ * @param {String} defaultValue The default value of the attribute.
32
33
  */
33
- constructor( editor ) {
34
- super( editor, 'borderColor' );
34
+ constructor( editor, defaultValue ) {
35
+ super( editor, 'borderColor', defaultValue );
35
36
  }
36
37
 
37
38
  /**
@@ -42,6 +43,12 @@ export default class TableBorderColorCommand extends TablePropertyCommand {
42
43
  return;
43
44
  }
44
45
 
45
- return getSingleValue( table.getAttribute( this.attributeName ) );
46
+ const value = getSingleValue( table.getAttribute( this.attributeName ) );
47
+
48
+ if ( value === this._defaultValue ) {
49
+ return;
50
+ }
51
+
52
+ return value;
46
53
  }
47
54
  }
@@ -29,9 +29,10 @@ export default class TableBorderStyleCommand extends TablePropertyCommand {
29
29
  * Creates a new `TableBorderStyleCommand` instance.
30
30
  *
31
31
  * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.
32
+ * @param {String} defaultValue The default value of the attribute.
32
33
  */
33
- constructor( editor ) {
34
- super( editor, 'borderStyle' );
34
+ constructor( editor, defaultValue ) {
35
+ super( editor, 'borderStyle', defaultValue );
35
36
  }
36
37
 
37
38
  /**
@@ -42,6 +43,12 @@ export default class TableBorderStyleCommand extends TablePropertyCommand {
42
43
  return;
43
44
  }
44
45
 
45
- return getSingleValue( table.getAttribute( this.attributeName ) );
46
+ const value = getSingleValue( table.getAttribute( this.attributeName ) );
47
+
48
+ if ( value === this._defaultValue ) {
49
+ return;
50
+ }
51
+
52
+ return value;
46
53
  }
47
54
  }
@@ -37,9 +37,10 @@ export default class TableBorderWidthCommand extends TablePropertyCommand {
37
37
  * Creates a new `TableBorderWidthCommand` instance.
38
38
  *
39
39
  * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.
40
+ * @param {String} defaultValue The default value of the attribute.
40
41
  */
41
- constructor( editor ) {
42
- super( editor, 'borderWidth' );
42
+ constructor( editor, defaultValue ) {
43
+ super( editor, 'borderWidth', defaultValue );
43
44
  }
44
45
 
45
46
  /**
@@ -50,13 +51,25 @@ export default class TableBorderWidthCommand extends TablePropertyCommand {
50
51
  return;
51
52
  }
52
53
 
53
- return getSingleValue( table.getAttribute( this.attributeName ) );
54
+ const value = getSingleValue( table.getAttribute( this.attributeName ) );
55
+
56
+ if ( value === this._defaultValue ) {
57
+ return;
58
+ }
59
+
60
+ return value;
54
61
  }
55
62
 
56
63
  /**
57
64
  * @inheritDoc
58
65
  */
59
66
  _getValueToSet( value ) {
60
- return addDefaultUnitToNumericValue( value, 'px' );
67
+ value = addDefaultUnitToNumericValue( value, 'px' );
68
+
69
+ if ( value === this._defaultValue ) {
70
+ return;
71
+ }
72
+
73
+ return value;
61
74
  }
62
75
  }
@@ -37,15 +37,22 @@ export default class TableHeightCommand extends TablePropertyCommand {
37
37
  * Creates a new `TableHeightCommand` instance.
38
38
  *
39
39
  * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.
40
+ * @param {String} defaultValue The default value of the attribute.
40
41
  */
41
- constructor( editor ) {
42
- super( editor, 'height' );
42
+ constructor( editor, defaultValue ) {
43
+ super( editor, 'height', defaultValue );
43
44
  }
44
45
 
45
46
  /**
46
47
  * @inheritDoc
47
48
  */
48
49
  _getValueToSet( value ) {
49
- return addDefaultUnitToNumericValue( value, 'px' );
50
+ value = addDefaultUnitToNumericValue( value, 'px' );
51
+
52
+ if ( value === this._defaultValue ) {
53
+ return null;
54
+ }
55
+
56
+ return value;
50
57
  }
51
58
  }