@ckeditor/ckeditor5-table 0.0.0-nightly-next-20251217.0 → 0.0.0-nightly-20251218.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 (112) hide show
  1. package/build/table.js +2 -2
  2. package/build/translations/af.js +1 -1
  3. package/build/translations/ar.js +1 -1
  4. package/build/translations/ast.js +1 -1
  5. package/build/translations/az.js +1 -1
  6. package/build/translations/be.js +1 -1
  7. package/build/translations/bg.js +1 -1
  8. package/build/translations/bn.js +1 -1
  9. package/build/translations/bs.js +1 -1
  10. package/build/translations/ca.js +1 -1
  11. package/build/translations/cs.js +1 -1
  12. package/build/translations/da.js +1 -1
  13. package/build/translations/de-ch.js +1 -1
  14. package/build/translations/de.js +1 -1
  15. package/build/translations/el.js +1 -1
  16. package/build/translations/en-au.js +1 -1
  17. package/build/translations/en-gb.js +1 -1
  18. package/build/translations/eo.js +1 -1
  19. package/build/translations/es-co.js +1 -1
  20. package/build/translations/es.js +1 -1
  21. package/build/translations/et.js +1 -1
  22. package/build/translations/eu.js +1 -1
  23. package/build/translations/fa.js +1 -1
  24. package/build/translations/fi.js +1 -1
  25. package/build/translations/fr.js +1 -1
  26. package/build/translations/gl.js +1 -1
  27. package/build/translations/gu.js +1 -1
  28. package/build/translations/he.js +1 -1
  29. package/build/translations/hi.js +1 -1
  30. package/build/translations/hr.js +1 -1
  31. package/build/translations/hu.js +1 -1
  32. package/build/translations/hy.js +1 -1
  33. package/build/translations/id.js +1 -1
  34. package/build/translations/it.js +1 -1
  35. package/build/translations/ja.js +1 -1
  36. package/build/translations/jv.js +1 -1
  37. package/build/translations/kk.js +1 -1
  38. package/build/translations/km.js +1 -1
  39. package/build/translations/kn.js +1 -1
  40. package/build/translations/ko.js +1 -1
  41. package/build/translations/ku.js +1 -1
  42. package/build/translations/lt.js +1 -1
  43. package/build/translations/lv.js +1 -1
  44. package/build/translations/ms.js +1 -1
  45. package/build/translations/nb.js +1 -1
  46. package/build/translations/ne.js +1 -1
  47. package/build/translations/nl.js +1 -1
  48. package/build/translations/no.js +1 -1
  49. package/build/translations/oc.js +1 -1
  50. package/build/translations/pl.js +1 -1
  51. package/build/translations/pt-br.js +1 -1
  52. package/build/translations/pt.js +1 -1
  53. package/build/translations/ro.js +1 -1
  54. package/build/translations/ru.js +1 -1
  55. package/build/translations/si.js +1 -1
  56. package/build/translations/sk.js +1 -1
  57. package/build/translations/sl.js +1 -1
  58. package/build/translations/sq.js +1 -1
  59. package/build/translations/sr-latn.js +1 -1
  60. package/build/translations/sr.js +1 -1
  61. package/build/translations/sv.js +1 -1
  62. package/build/translations/th.js +1 -1
  63. package/build/translations/ti.js +1 -1
  64. package/build/translations/tk.js +1 -1
  65. package/build/translations/tr.js +1 -1
  66. package/build/translations/tt.js +1 -1
  67. package/build/translations/ug.js +1 -1
  68. package/build/translations/uk.js +1 -1
  69. package/build/translations/ur.js +1 -1
  70. package/build/translations/uz.js +1 -1
  71. package/build/translations/vi.js +1 -1
  72. package/build/translations/zh-cn.js +1 -1
  73. package/build/translations/zh.js +1 -1
  74. package/ckeditor5-metadata.json +2 -11
  75. package/dist/index-content.css +30 -30
  76. package/dist/index-editor.css +170 -104
  77. package/dist/index.css +237 -147
  78. package/dist/index.css.map +1 -1
  79. package/dist/index.js +2399 -307
  80. package/dist/index.js.map +1 -1
  81. package/lang/contexts.json +4 -0
  82. package/package.json +9 -9
  83. package/src/augmentation.d.ts +15 -0
  84. package/src/converters/downcast.js +12 -3
  85. package/src/index.d.ts +4 -0
  86. package/src/index.js +5 -0
  87. package/src/tablecellproperties/tablecellpropertiesediting.js +4 -2
  88. package/src/tablecellproperties/tablecellpropertiesui.js +10 -30
  89. package/src/tablecellproperties/tablecellpropertiesuiexperimental.d.ts +128 -0
  90. package/src/tablecellproperties/tablecellpropertiesuiexperimental.js +408 -0
  91. package/src/tablecellproperties/ui/tablecellpropertiesview.d.ts +0 -35
  92. package/src/tablecellproperties/ui/tablecellpropertiesview.js +23 -137
  93. package/src/tablecellproperties/ui/tablecellpropertiesviewexperimental.d.ts +266 -0
  94. package/src/tablecellproperties/ui/tablecellpropertiesviewexperimental.js +744 -0
  95. package/src/tableconfig.d.ts +4 -4
  96. package/src/tableproperties/tablepropertiesediting.js +147 -14
  97. package/src/tableproperties/tablepropertiesuiexperimental.d.ts +136 -0
  98. package/src/tableproperties/tablepropertiesuiexperimental.js +375 -0
  99. package/src/tableproperties/ui/tablepropertiesview.d.ts +0 -8
  100. package/src/tableproperties/ui/tablepropertiesview.js +37 -59
  101. package/src/tableproperties/ui/tablepropertiesviewexperimental.d.ts +216 -0
  102. package/src/tableproperties/ui/tablepropertiesviewexperimental.js +544 -0
  103. package/src/utils/common.js +3 -2
  104. package/src/utils/ui/table-propertiesexperimental.d.ts +215 -0
  105. package/src/utils/ui/table-propertiesexperimental.js +391 -0
  106. package/theme/formrow-experimental.css +15 -0
  107. package/theme/formrow.css +0 -2
  108. package/theme/tablecellproperties-experimental.css +4 -0
  109. package/theme/tableform-experimental.css +61 -0
  110. package/theme/tableform.css +5 -1
  111. package/theme/tableproperties-experimental.css +78 -0
  112. package/theme/tableproperties.css +0 -60
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { Command, Plugin } from '@ckeditor/ckeditor5-core/dist/index.js';
6
6
  import { toWidgetEditable, toWidget, Widget, isWidget, WidgetToolbarRepository } from '@ckeditor/ckeditor5-widget/dist/index.js';
7
7
  import { first, global, CKEditorError, KeystrokeHandler, FocusTracker, Collection, getLocalizedArrowKeyCodeDirection, Rect, priorities, DomEmitterMixin, toUnit } from '@ckeditor/ckeditor5-utils/dist/index.js';
8
8
  import { isObject, debounce, isEqual, throttle } from 'es-toolkit/compat';
9
- import { IconTable, IconTableColumn, IconTableRow, IconTableMergeCell, IconPreviousArrow, IconAlignBottom, IconAlignMiddle, IconAlignTop, IconAlignJustify, IconAlignRight, IconAlignCenter, IconAlignLeft, IconTableCellProperties, IconTableLayout, IconTableProperties, IconObjectRight, IconObjectLeft, IconObjectInlineRight, IconObjectCenter, IconObjectInlineLeft, IconCaption } from '@ckeditor/ckeditor5-icons/dist/index.js';
9
+ import { IconTable, IconTableColumn, IconTableRow, IconTableMergeCell, IconCheck, IconCancel, IconAlignBottom, IconAlignMiddle, IconAlignTop, IconAlignJustify, IconAlignRight, IconAlignCenter, IconAlignLeft, IconTableCellProperties, IconTableLayout, IconTableProperties, IconObjectInlineRight, IconObjectCenter, IconObjectInlineLeft, IconCaption, IconPreviousArrow, IconObjectRight, IconObjectLeft } from '@ckeditor/ckeditor5-icons/dist/index.js';
10
10
  import { View, addKeyboardHandlingForGrid, ButtonView, createDropdown, MenuBarMenuView, SwitchButtonView, SplitButtonView, addListToDropdown, UIModel, ViewCollection, FocusCycler, InputTextView, ColorSelectorView, FormHeaderView, FormRowView, submitHandler, LabelView, LabeledFieldView, createLabeledDropdown, createLabeledInputText, ToolbarView, BalloonPanelView, ContextualBalloon, normalizeColorOptions, getLocalizedColorOptions, clickOutsideHandler, DropdownButtonView } from '@ckeditor/ckeditor5-ui/dist/index.js';
11
11
  import { ClipboardMarkersUtils, ClipboardPipeline } from '@ckeditor/ckeditor5-clipboard/dist/index.js';
12
12
  import { DomEventObserver, isColorStyleValue, isLengthStyleValue, isPercentageStyleValue, addBorderStylesRules, addPaddingStylesRules, addBackgroundStylesRules, addMarginStylesRules, enableViewPlaceholder, ModelElement } from '@ckeditor/ckeditor5-engine/dist/index.js';
@@ -1053,8 +1053,8 @@ const downcastTableAlignmentConfig = {
1053
1053
  *
1054
1054
  * @internal
1055
1055
  */ function isTableCellTypeEnabled(editor) {
1056
- const { model } = editor;
1057
- return model.schema.checkAttribute('tableCell', 'tableCellType');
1056
+ const { model, config } = editor;
1057
+ return model.schema.checkAttribute('tableCell', 'tableCellType') && config.get('experimentalFlags.tableCellTypeSupport') === true;
1058
1058
  }
1059
1059
 
1060
1060
  /**
@@ -2175,7 +2175,10 @@ const downcastTableAlignmentConfig = {
2175
2175
  * Downcasts a plain table (also used in the clipboard pipeline).
2176
2176
  */ function convertPlainTable(editor) {
2177
2177
  return (table, conversionApi)=>{
2178
- if (!conversionApi.options.isClipboardPipeline && !editor.plugins.has('PlainTableOutput')) {
2178
+ const hasPlainTableOutput = editor.plugins.has('PlainTableOutput');
2179
+ const isClipboardPipeline = conversionApi.options.isClipboardPipeline;
2180
+ const useExtendedAlignment = editor.config.get('experimentalFlags.useExtendedTableBlockAlignment');
2181
+ if (!hasPlainTableOutput && !(useExtendedAlignment && isClipboardPipeline)) {
2179
2182
  return null;
2180
2183
  }
2181
2184
  return downcastPlainTable(table, conversionApi, editor);
@@ -2185,7 +2188,10 @@ const downcastTableAlignmentConfig = {
2185
2188
  * Downcasts a plain table caption (also used in the clipboard pipeline).
2186
2189
  */ function convertPlainTableCaption(editor) {
2187
2190
  return (modelElement, { writer, options })=>{
2188
- if (!options.isClipboardPipeline && !editor.plugins.has('PlainTableOutput')) {
2191
+ const hasPlainTableOutput = editor.plugins.has('PlainTableOutput');
2192
+ const isClipboardPipeline = options.isClipboardPipeline;
2193
+ const useExtendedAlignment = editor.config.get('experimentalFlags.useExtendedTableBlockAlignment');
2194
+ if (!hasPlainTableOutput && !(useExtendedAlignment && isClipboardPipeline)) {
2189
2195
  return null;
2190
2196
  }
2191
2197
  if (modelElement.parent.name === 'table') {
@@ -2273,7 +2279,10 @@ const downcastTableAlignmentConfig = {
2273
2279
  return dispatcher.on(`attribute:${modelAttribute}:table`, (evt, data, conversionApi)=>{
2274
2280
  const { item, attributeNewValue } = data;
2275
2281
  const { mapper, writer } = conversionApi;
2276
- if (!conversionApi.options.isClipboardPipeline && !editor.plugins.has('PlainTableOutput')) {
2282
+ const hasPlainTableOutput = editor.plugins.has('PlainTableOutput');
2283
+ const isClipboardPipeline = conversionApi.options.isClipboardPipeline;
2284
+ const useExtendedAlignment = editor.config.get('experimentalFlags.useExtendedTableBlockAlignment');
2285
+ if (!hasPlainTableOutput && !(useExtendedAlignment && isClipboardPipeline)) {
2277
2286
  return;
2278
2287
  }
2279
2288
  if (!conversionApi.consumable.consume(item, evt.name)) {
@@ -7898,7 +7907,7 @@ const isEmpty = (val)=>val === '';
7898
7907
  *
7899
7908
  * @internal
7900
7909
  * @param t The "t" function provided by the editor that is used to localize strings.
7901
- */ function getBorderStyleLabels(t) {
7910
+ */ function getBorderStyleLabels$1(t) {
7902
7911
  return {
7903
7912
  none: t('None'),
7904
7913
  solid: t('Solid'),
@@ -7968,9 +7977,9 @@ const isEmpty = (val)=>val === '';
7968
7977
  *
7969
7978
  * @internal
7970
7979
  * @param defaultStyle The default border.
7971
- */ function getBorderStyleDefinitions(view, defaultStyle) {
7980
+ */ function getBorderStyleDefinitions$1(view, defaultStyle) {
7972
7981
  const itemDefinitions = new Collection();
7973
- const styleLabels = getBorderStyleLabels(view.t);
7982
+ const styleLabels = getBorderStyleLabels$1(view.t);
7974
7983
  for(const style in styleLabels){
7975
7984
  const definition = {
7976
7985
  type: 'button',
@@ -8013,7 +8022,7 @@ const isEmpty = (val)=>val === '';
8013
8022
  * @param options.propertyName The name of the observable property in the view.
8014
8023
  * @param options.nameToValue A function that maps a button name to a value. By default names are the same as values.
8015
8024
  * @param options.defaultValue Default value for the property.
8016
- */ function fillToolbar(options) {
8025
+ */ function fillToolbar$1(options) {
8017
8026
  const { view, icons, toolbar, labels, propertyName, nameToValue, defaultValue } = options;
8018
8027
  for(const name in labels){
8019
8028
  const button = new ButtonView(view.locale);
@@ -8217,10 +8226,10 @@ const isEmpty = (val)=>val === '';
8217
8226
  * @param options.defaultColorValue If specified, the color input view will replace the "Remove color" button with
8218
8227
  * the "Restore default" button. Instead of clearing the input field, the default color value will be set.
8219
8228
  * @param options.colorPickerConfig The configuration of the color picker. You could disable it or define your output format.
8220
- */ function getLabeledColorInputCreator(options) {
8229
+ */ function getLabeledColorInputCreator$1(options) {
8221
8230
  return (labeledFieldView, viewUid, statusUid)=>{
8222
8231
  const colorInputView = new ColorInputView(labeledFieldView.locale, {
8223
- colorDefinitions: colorConfigToColorGridDefinitions(options.colorConfig),
8232
+ colorDefinitions: colorConfigToColorGridDefinitions$1(options.colorConfig),
8224
8233
  columns: options.columns,
8225
8234
  defaultColorValue: options.defaultColorValue,
8226
8235
  colorPickerConfig: options.colorPickerConfig
@@ -8247,7 +8256,7 @@ const isEmpty = (val)=>val === '';
8247
8256
  const parsedValue = parseFloat(value);
8248
8257
  return !Number.isNaN(parsedValue) && value === String(parsedValue);
8249
8258
  }
8250
- function colorConfigToColorGridDefinitions(colorConfig) {
8259
+ function colorConfigToColorGridDefinitions$1(colorConfig) {
8251
8260
  return colorConfig.map((item)=>({
8252
8261
  color: item.model,
8253
8262
  label: item.label,
@@ -8285,9 +8294,6 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8285
8294
  /**
8286
8295
  * An input that allows specifying the table cell background color.
8287
8296
  */ backgroundInput;
8288
- /**
8289
- * A dropdown that allows selecting the type of the table cell (data or header).
8290
- */ cellTypeDropdown;
8291
8297
  /**
8292
8298
  * An input that allows specifying the table cell padding.
8293
8299
  */ paddingInput;
@@ -8309,9 +8315,6 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8309
8315
  /**
8310
8316
  * The "Cancel" button view.
8311
8317
  */ cancelButtonView;
8312
- /**
8313
- * The "Back" button view.
8314
- */ backButtonView;
8315
8318
  /**
8316
8319
  * A collection of views that can be focused in the form.
8317
8320
  */ _focusables;
@@ -8337,13 +8340,11 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8337
8340
  width: '',
8338
8341
  height: '',
8339
8342
  horizontalAlignment: '',
8340
- verticalAlignment: '',
8341
- cellType: ''
8343
+ verticalAlignment: ''
8342
8344
  });
8343
8345
  this.options = options;
8344
8346
  const { borderStyleDropdown, borderWidthInput, borderColorInput, borderRowLabel } = this._createBorderFields();
8345
8347
  const { backgroundRowLabel, backgroundInput } = this._createBackgroundFields();
8346
- const { cellTypeRowLabel, cellTypeDropdown } = this._createCellTypeField();
8347
8348
  const { widthInput, operatorLabel, heightInput, dimensionsLabel } = this._createDimensionFields();
8348
8349
  const { horizontalAlignmentToolbar, verticalAlignmentToolbar, alignmentLabel } = this._createAlignmentFields();
8349
8350
  this.focusTracker = new FocusTracker();
@@ -8353,7 +8354,6 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8353
8354
  this.borderWidthInput = borderWidthInput;
8354
8355
  this.borderColorInput = borderColorInput;
8355
8356
  this.backgroundInput = backgroundInput;
8356
- this.cellTypeDropdown = cellTypeDropdown;
8357
8357
  this.paddingInput = this._createPaddingField();
8358
8358
  this.widthInput = widthInput;
8359
8359
  this.heightInput = heightInput;
@@ -8365,7 +8365,6 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8365
8365
  const { saveButtonView, cancelButtonView } = this._createActionButtons();
8366
8366
  this.saveButtonView = saveButtonView;
8367
8367
  this.cancelButtonView = cancelButtonView;
8368
- this.backButtonView = this._createBackButton();
8369
8368
  this._focusables = new ViewCollection();
8370
8369
  this._focusCycler = new FocusCycler({
8371
8370
  focusables: this._focusables,
@@ -8379,42 +8378,28 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8379
8378
  }
8380
8379
  });
8381
8380
  // Form header.
8382
- const header = new FormHeaderView(locale, {
8381
+ this.children.add(new FormHeaderView(locale, {
8383
8382
  label: this.t('Cell properties')
8384
- });
8385
- header.children.add(this.backButtonView, 0);
8386
- this.children.add(header);
8383
+ }));
8387
8384
  // Border row.
8388
8385
  this.children.add(new FormRowView(locale, {
8389
8386
  labelView: borderRowLabel,
8390
8387
  children: [
8391
8388
  borderRowLabel,
8392
8389
  borderStyleDropdown,
8393
- borderWidthInput,
8394
- borderColorInput
8390
+ borderColorInput,
8391
+ borderWidthInput
8395
8392
  ],
8396
8393
  class: 'ck-table-form__border-row'
8397
8394
  }));
8398
- // Background and cell type.
8395
+ // Background.
8399
8396
  this.children.add(new FormRowView(locale, {
8397
+ labelView: backgroundRowLabel,
8400
8398
  children: [
8401
- new FormRowView(locale, {
8402
- labelView: cellTypeRowLabel,
8403
- children: [
8404
- cellTypeRowLabel,
8405
- cellTypeDropdown
8406
- ],
8407
- class: 'ck-table-form__cell-type-row'
8408
- }),
8409
- new FormRowView(locale, {
8410
- labelView: backgroundRowLabel,
8411
- children: [
8412
- backgroundRowLabel,
8413
- backgroundInput
8414
- ],
8415
- class: 'ck-table-form__background-row'
8416
- })
8417
- ]
8399
+ backgroundRowLabel,
8400
+ backgroundInput
8401
+ ],
8402
+ class: 'ck-table-form__background-row'
8418
8403
  }));
8419
8404
  // Dimensions row and padding.
8420
8405
  this.children.add(new FormRowView(locale, {
@@ -8452,8 +8437,8 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8452
8437
  // Action row.
8453
8438
  this.children.add(new FormRowView(locale, {
8454
8439
  children: [
8455
- this.cancelButtonView,
8456
- this.saveButtonView
8440
+ this.saveButtonView,
8441
+ this.cancelButtonView
8457
8442
  ],
8458
8443
  class: 'ck-table-form__action-row'
8459
8444
  }));
@@ -8492,16 +8477,14 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8492
8477
  this.borderStyleDropdown,
8493
8478
  this.borderColorInput,
8494
8479
  this.borderWidthInput,
8495
- this.cellTypeDropdown,
8496
8480
  this.backgroundInput,
8497
8481
  this.widthInput,
8498
8482
  this.heightInput,
8499
8483
  this.paddingInput,
8500
8484
  this.horizontalAlignmentToolbar,
8501
8485
  this.verticalAlignmentToolbar,
8502
- this.cancelButtonView,
8503
8486
  this.saveButtonView,
8504
- this.backButtonView
8487
+ this.cancelButtonView
8505
8488
  ].forEach((view)=>{
8506
8489
  // Register the view as focusable.
8507
8490
  this._focusables.add(view);
@@ -8536,7 +8519,7 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8536
8519
  width: defaultTableCellProperties.borderWidth,
8537
8520
  color: defaultTableCellProperties.borderColor
8538
8521
  };
8539
- const colorInputCreator = getLabeledColorInputCreator({
8522
+ const colorInputCreator = getLabeledColorInputCreator$1({
8540
8523
  colorConfig: this.options.borderColors,
8541
8524
  columns: 5,
8542
8525
  defaultColorValue: defaultBorder.color,
@@ -8549,7 +8532,7 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8549
8532
  const borderRowLabel = new LabelView(locale);
8550
8533
  borderRowLabel.text = t('Border');
8551
8534
  // -- Style ---------------------------------------------------
8552
- const styleLabels = getBorderStyleLabels(t);
8535
+ const styleLabels = getBorderStyleLabels$1(t);
8553
8536
  const borderStyleDropdown = new LabeledFieldView(locale, createLabeledDropdown);
8554
8537
  borderStyleDropdown.set({
8555
8538
  label: accessibleLabel,
@@ -8569,7 +8552,7 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8569
8552
  this.borderStyle = evt.source._borderStyleValue;
8570
8553
  });
8571
8554
  borderStyleDropdown.bind('isEmpty').to(this, 'borderStyle', (value)=>!value);
8572
- addListToDropdown(borderStyleDropdown.fieldView, getBorderStyleDefinitions(this, defaultBorder.style), {
8555
+ addListToDropdown(borderStyleDropdown.fieldView, getBorderStyleDefinitions$1(this, defaultBorder.style), {
8573
8556
  role: 'menu',
8574
8557
  ariaLabel: accessibleLabel
8575
8558
  });
@@ -8580,7 +8563,7 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8580
8563
  class: 'ck-table-form__border-width'
8581
8564
  });
8582
8565
  borderWidthInput.fieldView.bind('value').to(this, 'borderWidth');
8583
- borderWidthInput.bind('isEnabled').to(this, 'borderStyle', isBorderStyleSet$1);
8566
+ borderWidthInput.bind('isEnabled').to(this, 'borderStyle', isBorderStyleSet$3);
8584
8567
  borderWidthInput.fieldView.on('input', ()=>{
8585
8568
  this.borderWidth = borderWidthInput.fieldView.element.value;
8586
8569
  });
@@ -8591,7 +8574,7 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8591
8574
  class: 'ck-table-form__border-color'
8592
8575
  });
8593
8576
  borderColorInput.fieldView.bind('value').to(this, 'borderColor');
8594
- borderColorInput.bind('isEnabled').to(this, 'borderStyle', isBorderStyleSet$1);
8577
+ borderColorInput.bind('isEnabled').to(this, 'borderStyle', isBorderStyleSet$3);
8595
8578
  borderColorInput.fieldView.on('input', ()=>{
8596
8579
  this.borderColor = borderColorInput.fieldView.value;
8597
8580
  });
@@ -8599,12 +8582,12 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8599
8582
  this.on('change:borderStyle', (evt, name, newValue, oldValue)=>{
8600
8583
  // When removing the border (`border-style:none`), clear the remaining `border-*` properties.
8601
8584
  // See: https://github.com/ckeditor/ckeditor5/issues/6227.
8602
- if (!isBorderStyleSet$1(newValue)) {
8585
+ if (!isBorderStyleSet$3(newValue)) {
8603
8586
  this.borderColor = '';
8604
8587
  this.borderWidth = '';
8605
8588
  }
8606
8589
  // When setting the `border-style` from `none`, set the default `border-color` and `border-width` properties.
8607
- if (!isBorderStyleSet$1(oldValue)) {
8590
+ if (!isBorderStyleSet$3(oldValue)) {
8608
8591
  this.borderColor = defaultBorder.color;
8609
8592
  this.borderWidth = defaultBorder.width;
8610
8593
  }
@@ -8627,7 +8610,7 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8627
8610
  const backgroundRowLabel = new LabelView(locale);
8628
8611
  backgroundRowLabel.text = t('Background');
8629
8612
  // -- Background color input -----------------------------------
8630
- const colorInputCreator = getLabeledColorInputCreator({
8613
+ const colorInputCreator = getLabeledColorInputCreator$1({
8631
8614
  colorConfig: this.options.backgroundColors,
8632
8615
  columns: 5,
8633
8616
  defaultColorValue: this.options.defaultTableCellProperties.backgroundColor,
@@ -8647,46 +8630,6 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8647
8630
  backgroundInput
8648
8631
  };
8649
8632
  }
8650
- /**
8651
- * Create cell type field.
8652
- *
8653
- * * {@link #cellTypeDropdown}.
8654
- *
8655
- * @internal
8656
- */ _createCellTypeField() {
8657
- const locale = this.locale;
8658
- const t = this.t;
8659
- const cellTypeRowLabel = new LabelView(locale);
8660
- cellTypeRowLabel.text = t('Cell type');
8661
- const cellTypeLabels = this._cellTypeLabels;
8662
- const cellTypeDropdown = new LabeledFieldView(locale, createLabeledDropdown);
8663
- cellTypeDropdown.set({
8664
- label: t('Cell type'),
8665
- class: 'ck-table-cell-properties-form__cell-type'
8666
- });
8667
- cellTypeDropdown.fieldView.buttonView.set({
8668
- ariaLabel: t('Cell type'),
8669
- ariaLabelledBy: undefined,
8670
- isOn: false,
8671
- withText: true,
8672
- tooltip: t('Cell type')
8673
- });
8674
- cellTypeDropdown.fieldView.buttonView.bind('label').to(this, 'cellType', (value)=>{
8675
- return cellTypeLabels[value || 'data'];
8676
- });
8677
- cellTypeDropdown.fieldView.on('execute', (evt)=>{
8678
- this.cellType = evt.source._cellTypeValue;
8679
- });
8680
- cellTypeDropdown.bind('isEmpty').to(this, 'cellType', (value)=>!value);
8681
- addListToDropdown(cellTypeDropdown.fieldView, this._getCellTypeDefinitions(), {
8682
- role: 'menu',
8683
- ariaLabel: t('Cell type')
8684
- });
8685
- return {
8686
- cellTypeRowLabel,
8687
- cellTypeDropdown
8688
- };
8689
- }
8690
8633
  /**
8691
8634
  * Creates the following form fields:
8692
8635
  *
@@ -8783,10 +8726,9 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8783
8726
  horizontalAlignmentToolbar.set({
8784
8727
  isCompact: true,
8785
8728
  role: 'radiogroup',
8786
- ariaLabel: t('Horizontal text alignment toolbar'),
8787
- class: 'ck-table-cell-properties-form__horizontal-alignment-toolbar'
8729
+ ariaLabel: t('Horizontal text alignment toolbar')
8788
8730
  });
8789
- fillToolbar({
8731
+ fillToolbar$1({
8790
8732
  view: this,
8791
8733
  icons: ALIGNMENT_ICONS,
8792
8734
  toolbar: horizontalAlignmentToolbar,
@@ -8810,10 +8752,9 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8810
8752
  verticalAlignmentToolbar.set({
8811
8753
  isCompact: true,
8812
8754
  role: 'radiogroup',
8813
- ariaLabel: t('Vertical text alignment toolbar'),
8814
- class: 'ck-table-cell-properties-form__vertical-alignment-toolbar'
8755
+ ariaLabel: t('Vertical text alignment toolbar')
8815
8756
  });
8816
- fillToolbar({
8757
+ fillToolbar$1({
8817
8758
  view: this,
8818
8759
  icons: ALIGNMENT_ICONS,
8819
8760
  toolbar: verticalAlignmentToolbar,
@@ -8845,7 +8786,8 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8845
8786
  ];
8846
8787
  saveButtonView.set({
8847
8788
  label: t('Save'),
8848
- class: 'ck-button-action',
8789
+ icon: IconCheck,
8790
+ class: 'ck-button-save',
8849
8791
  type: 'submit',
8850
8792
  withText: true
8851
8793
  });
@@ -8854,6 +8796,8 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8854
8796
  });
8855
8797
  cancelButtonView.set({
8856
8798
  label: t('Cancel'),
8799
+ icon: IconCancel,
8800
+ class: 'ck-button-cancel',
8857
8801
  withText: true
8858
8802
  });
8859
8803
  cancelButtonView.delegate('execute').to(this, 'cancel');
@@ -8862,43 +8806,6 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8862
8806
  cancelButtonView
8863
8807
  };
8864
8808
  }
8865
- /**
8866
- * Creates a back button view that cancels the form.
8867
- */ _createBackButton() {
8868
- const t = this.locale.t;
8869
- const backButton = new ButtonView(this.locale);
8870
- backButton.set({
8871
- class: 'ck-button-back',
8872
- label: t('Back'),
8873
- icon: IconPreviousArrow,
8874
- tooltip: true
8875
- });
8876
- backButton.delegate('execute').to(this, 'cancel');
8877
- return backButton;
8878
- }
8879
- /**
8880
- * Creates the cell type dropdown definitions.
8881
- */ _getCellTypeDefinitions() {
8882
- const itemDefinitions = new Collection();
8883
- const cellTypeLabels = this._cellTypeLabels;
8884
- for (const type of [
8885
- 'data',
8886
- 'header'
8887
- ]){
8888
- const definition = {
8889
- type: 'button',
8890
- model: new UIModel({
8891
- _cellTypeValue: type,
8892
- label: cellTypeLabels[type],
8893
- role: 'menuitemradio',
8894
- withText: true
8895
- })
8896
- };
8897
- definition.model.bind('isOn').to(this, 'cellType', (value)=>value === type);
8898
- itemDefinitions.add(definition);
8899
- }
8900
- return itemDefinitions;
8901
- }
8902
8809
  /**
8903
8810
  * Provides localized labels for {@link #horizontalAlignmentToolbar} buttons.
8904
8811
  */ get _horizontalAlignmentLabels() {
@@ -8935,17 +8842,8 @@ function colorConfigToColorGridDefinitions(colorConfig) {
8935
8842
  bottom: t('Align cell text to the bottom')
8936
8843
  };
8937
8844
  }
8938
- /**
8939
- * Provides localized labels for {@link #cellTypeDropdown}.
8940
- */ get _cellTypeLabels() {
8941
- const t = this.t;
8942
- return {
8943
- data: t('Data cell'),
8944
- header: t('Header cell')
8945
- };
8946
- }
8947
8845
  }
8948
- function isBorderStyleSet$1(value) {
8846
+ function isBorderStyleSet$3(value) {
8949
8847
  return value !== 'none';
8950
8848
  }
8951
8849
 
@@ -9044,9 +8942,9 @@ const BALLOON_POSITIONS = /* #__PURE__ */ (()=>[
9044
8942
  return Rect.getBoundingRect(rects);
9045
8943
  }
9046
8944
 
9047
- const ERROR_TEXT_TIMEOUT$1 = 500;
8945
+ const ERROR_TEXT_TIMEOUT$3 = 500;
9048
8946
  // Map of view properties and related commands.
9049
- const propertyToCommandMap$1 = {
8947
+ const propertyToCommandMap$3 = {
9050
8948
  borderStyle: 'tableCellBorderStyle',
9051
8949
  borderColor: 'tableCellBorderColor',
9052
8950
  borderWidth: 'tableCellBorderWidth',
@@ -9055,8 +8953,7 @@ const propertyToCommandMap$1 = {
9055
8953
  padding: 'tableCellPadding',
9056
8954
  backgroundColor: 'tableCellBackgroundColor',
9057
8955
  horizontalAlignment: 'tableCellHorizontalAlignment',
9058
- verticalAlignment: 'tableCellVerticalAlignment',
9059
- cellType: 'tableCellType'
8956
+ verticalAlignment: 'tableCellVerticalAlignment'
9060
8957
  };
9061
8958
  /**
9062
8959
  * The table cell properties UI plugin. It introduces the `'tableCellProperties'` button
@@ -9143,7 +9040,7 @@ const propertyToCommandMap$1 = {
9143
9040
  tooltip: true
9144
9041
  });
9145
9042
  this.listenTo(view, 'execute', ()=>this._showView());
9146
- const commands = Object.values(propertyToCommandMap$1).map((commandName)=>editor.commands.get(commandName)).filter((val)=>!!val);
9043
+ const commands = Object.values(propertyToCommandMap$3).map((commandName)=>editor.commands.get(commandName));
9147
9044
  view.bind('isEnabled').toMany(commands, 'isEnabled', (...areEnabled)=>areEnabled.some((isCommandEnabled)=>isCommandEnabled));
9148
9045
  return view;
9149
9046
  });
@@ -9249,11 +9146,6 @@ const propertyToCommandMap$1 = {
9249
9146
  }));
9250
9147
  view.on('change:horizontalAlignment', this._getPropertyChangeCallback('tableCellHorizontalAlignment'));
9251
9148
  view.on('change:verticalAlignment', this._getPropertyChangeCallback('tableCellVerticalAlignment'));
9252
- const cellTypeCommand = editor.commands.get('tableCellType');
9253
- if (cellTypeCommand) {
9254
- view.cellTypeDropdown.bind('isEnabled').to(cellTypeCommand, 'isEnabled');
9255
- view.on('change:cellType', this._getPropertyChangeCallback('tableCellType'));
9256
- }
9257
9149
  return view;
9258
9150
  }
9259
9151
  /**
@@ -9266,24 +9158,12 @@ const propertyToCommandMap$1 = {
9266
9158
  */ _fillViewFormFromCommandValues() {
9267
9159
  const commands = this.editor.commands;
9268
9160
  const borderStyleCommand = commands.get('tableCellBorderStyle');
9269
- Object.entries(propertyToCommandMap$1).flatMap(([property, commandName])=>{
9270
- const command = commands.get(commandName);
9271
- if (!command) {
9272
- return [];
9273
- }
9161
+ Object.entries(propertyToCommandMap$3).map(([property, commandName])=>{
9274
9162
  const propertyKey = property;
9275
- let defaultValue;
9276
- if (propertyKey === 'cellType') {
9277
- defaultValue = '';
9278
- } else {
9279
- defaultValue = this.view === this._viewWithContentTableDefaults ? this._defaultContentTableCellProperties[propertyKey] || '' : this._defaultLayoutTableCellProperties[propertyKey] || '';
9280
- }
9281
- const entry = [
9282
- property,
9283
- command.value || defaultValue
9284
- ];
9163
+ const defaultValue = this.view === this._viewWithContentTableDefaults ? this._defaultContentTableCellProperties[propertyKey] || '' : this._defaultLayoutTableCellProperties[propertyKey] || '';
9285
9164
  return [
9286
- entry
9165
+ property,
9166
+ commands.get(commandName).value || defaultValue
9287
9167
  ];
9288
9168
  }).forEach(([property, value])=>{
9289
9169
  // Do not set the `border-color` and `border-width` fields if `border-style:none`.
@@ -9384,7 +9264,7 @@ const propertyToCommandMap$1 = {
9384
9264
  const { commandName, viewField, validator, errorText } = options;
9385
9265
  const setErrorTextDebounced = debounce(()=>{
9386
9266
  viewField.errorText = errorText;
9387
- }, ERROR_TEXT_TIMEOUT$1);
9267
+ }, ERROR_TEXT_TIMEOUT$3);
9388
9268
  return (evt, propertyName, newValue)=>{
9389
9269
  setErrorTextDebounced.cancel();
9390
9270
  // Do not execute the command on initial call (opening the table properties view).
@@ -10170,8 +10050,10 @@ const ALIGN_VALUES_REG_EXP = /^(left|center|right|justify)$/;
10170
10050
  editor.commands.add('tableCellHorizontalAlignment', new TableCellHorizontalAlignmentCommand(editor, defaultTableCellProperties.horizontalAlignment));
10171
10051
  enableVerticalAlignmentProperty(schema, conversion, defaultTableCellProperties.verticalAlignment);
10172
10052
  editor.commands.add('tableCellVerticalAlignment', new TableCellVerticalAlignmentCommand(editor, defaultTableCellProperties.verticalAlignment));
10173
- enableCellTypeProperty(editor);
10174
- editor.commands.add('tableCellType', new TableCellTypeCommand(editor));
10053
+ if (editor.config.get('experimentalFlags.tableCellTypeSupport')) {
10054
+ enableCellTypeProperty(editor);
10055
+ editor.commands.add('tableCellType', new TableCellTypeCommand(editor));
10056
+ }
10175
10057
  }
10176
10058
  }
10177
10059
  /**
@@ -12356,7 +12238,7 @@ const TABLE_TYPES = [
12356
12238
  const defaultTableProperties = getNormalizedDefaultTableProperties(editor.config.get('table.tableProperties.defaultProperties'), {
12357
12239
  includeAlignmentProperty: true
12358
12240
  });
12359
- const useInlineStyles = editor.config.get('table.tableProperties.alignment.useInlineStyles') === true;
12241
+ const useInlineStyles = editor.config.get('table.tableProperties.alignment.useInlineStyles') !== false;
12360
12242
  editor.data.addStyleProcessorRules(addMarginStylesRules);
12361
12243
  editor.data.addStyleProcessorRules(addBorderStylesRules);
12362
12244
  enableBorderProperties(editor, {
@@ -12367,7 +12249,11 @@ const TABLE_TYPES = [
12367
12249
  editor.commands.add('tableBorderColor', new TableBorderColorCommand(editor, defaultTableProperties.borderColor));
12368
12250
  editor.commands.add('tableBorderStyle', new TableBorderStyleCommand(editor, defaultTableProperties.borderStyle));
12369
12251
  editor.commands.add('tableBorderWidth', new TableBorderWidthCommand(editor, defaultTableProperties.borderWidth));
12370
- enableAlignmentProperty(schema, conversion, defaultTableProperties.alignment, useInlineStyles);
12252
+ if (editor.config.get('experimentalFlags.useExtendedTableBlockAlignment')) {
12253
+ enableExtendedAlignmentProperty(schema, conversion, defaultTableProperties.alignment, useInlineStyles);
12254
+ } else {
12255
+ enableAlignmentProperty(schema, conversion, defaultTableProperties.alignment);
12256
+ }
12371
12257
  editor.commands.add('tableAlignment', new TableAlignmentCommand(editor, defaultTableProperties.alignment));
12372
12258
  enableTableToFigureProperty(schema, conversion, {
12373
12259
  modelAttribute: 'tableWidth',
@@ -12394,18 +12280,20 @@ const TABLE_TYPES = [
12394
12280
  defaultValue: defaultTableProperties.backgroundColor
12395
12281
  });
12396
12282
  editor.commands.add('tableBackgroundColor', new TableBackgroundColorCommand(editor, defaultTableProperties.backgroundColor));
12397
- const viewDoc = editor.editing.view.document;
12398
- // Adjust clipboard output to wrap tables in divs if needed (for alignment).
12399
- this.listenTo(viewDoc, 'clipboardOutput', (evt, data)=>{
12400
- editor.editing.view.change((writer)=>{
12401
- for (const { item } of writer.createRangeIn(data.content)){
12402
- wrapInDivIfNeeded(item, writer);
12403
- }
12404
- data.dataTransfer.setData('text/html', this.editor.data.htmlProcessor.toData(data.content));
12283
+ if (editor.config.get('experimentalFlags.useExtendedTableBlockAlignment')) {
12284
+ const viewDoc = editor.editing.view.document;
12285
+ // Adjust clipboard output to wrap tables in divs if needed (for alignment).
12286
+ this.listenTo(viewDoc, 'clipboardOutput', (evt, data)=>{
12287
+ editor.editing.view.change((writer)=>{
12288
+ for (const { item } of writer.createRangeIn(data.content)){
12289
+ wrapInDivIfNeeded(item, writer);
12290
+ }
12291
+ data.dataTransfer.setData('text/html', this.editor.data.htmlProcessor.toData(data.content));
12292
+ });
12293
+ }, {
12294
+ priority: 'lowest'
12405
12295
  });
12406
- }, {
12407
- priority: 'lowest'
12408
- });
12296
+ }
12409
12297
  }
12410
12298
  }
12411
12299
  /**
@@ -12475,10 +12363,10 @@ function insertWrapperWithAlignment(writer, align, table) {
12475
12363
  });
12476
12364
  }
12477
12365
  /**
12478
- * Enables the `'alignment'` attribute for table.
12366
+ * Enables the extended block`'alignment'` attribute for table.
12479
12367
  *
12480
12368
  * @param defaultValue The default alignment value.
12481
- */ function enableAlignmentProperty(schema, conversion, defaultValue, useInlineStyles) {
12369
+ */ function enableExtendedAlignmentProperty(schema, conversion, defaultValue, useInlineStyles) {
12482
12370
  schema.extend('table', {
12483
12371
  allowAttributes: [
12484
12372
  'tableAlignment'
@@ -12578,37 +12466,175 @@ function insertWrapperWithAlignment(writer, align, table) {
12578
12466
  conversion.for('upcast').add(upcastTableAlignedDiv(defaultValue));
12579
12467
  }
12580
12468
  /**
12581
- * Returns a function that converts the table view representation:
12582
- *
12583
- * ```html
12584
- * <div align="right"><table>...</table></div>
12585
- * <!-- or -->
12586
- * <div align="center"><table>...</table></div>
12587
- * <!-- or -->
12588
- * <div align="left"><table>...</table></div>
12589
- * ```
12590
- *
12591
- * to the model representation:
12592
- *
12593
- * ```xml
12594
- * <table tableAlignment="right|center|left"></table>
12595
- * ```
12469
+ * Enables the `'alignment'` attribute for table.
12596
12470
  *
12597
- * @internal
12598
- */ function upcastTableAlignedDiv(defaultValue) {
12599
- return (dispatcher)=>{
12600
- dispatcher.on('element:div', (evt, data, conversionApi)=>{
12601
- // Do not convert if this is not a "table wrapped in div with align attribute".
12602
- if (!conversionApi.consumable.test(data.viewItem, {
12603
- name: true,
12604
- attributes: 'align'
12605
- })) {
12606
- return;
12471
+ * @param defaultValue The default alignment value.
12472
+ */ function enableAlignmentProperty(schema, conversion, defaultValue) {
12473
+ const ALIGN_VALUES_REG_EXP = /^(left|center|right)$/;
12474
+ const FLOAT_VALUES_REG_EXP = /^(left|none|right)$/;
12475
+ schema.extend('table', {
12476
+ allowAttributes: [
12477
+ 'tableAlignment'
12478
+ ]
12479
+ });
12480
+ schema.setAttributeProperties('tableAlignment', {
12481
+ isFormatting: true
12482
+ });
12483
+ conversion.for('downcast').attributeToAttribute({
12484
+ model: {
12485
+ name: 'table',
12486
+ key: 'tableAlignment',
12487
+ values: [
12488
+ 'left',
12489
+ 'center',
12490
+ 'right'
12491
+ ]
12492
+ },
12493
+ view: {
12494
+ left: {
12495
+ key: 'style',
12496
+ value: {
12497
+ float: 'left'
12498
+ }
12499
+ },
12500
+ right: {
12501
+ key: 'style',
12502
+ value: {
12503
+ float: 'right'
12504
+ }
12505
+ },
12506
+ center: (alignment, conversionApi, data)=>{
12507
+ const value = data.item.getAttribute('tableType') !== 'layout' ? {
12508
+ // Model: `alignment:center` => CSS: `float:none`.
12509
+ float: 'none'
12510
+ } : {
12511
+ 'margin-left': 'auto',
12512
+ 'margin-right': 'auto'
12513
+ };
12514
+ return {
12515
+ key: 'style',
12516
+ value
12517
+ };
12607
12518
  }
12608
- // Find a table element inside the div element.
12609
- const viewTable = getViewTableFromWrapper(data.viewItem);
12610
- // Do not convert if table element is absent or was already converted.
12611
- if (!viewTable || !conversionApi.consumable.test(viewTable, {
12519
+ },
12520
+ converterPriority: 'high'
12521
+ });
12522
+ conversion.for('upcast')// Support for the `float:*;` CSS definition for the table alignment.
12523
+ .attributeToAttribute({
12524
+ view: {
12525
+ name: /^(table|figure)$/,
12526
+ styles: {
12527
+ float: FLOAT_VALUES_REG_EXP
12528
+ }
12529
+ },
12530
+ model: {
12531
+ key: 'tableAlignment',
12532
+ value: (viewElement, conversionApi, data)=>{
12533
+ // Ignore other figure elements.
12534
+ if (viewElement.name == 'figure' && !viewElement.hasClass('table')) {
12535
+ return;
12536
+ }
12537
+ const localDefaultValue = getDefaultValueAdjusted(defaultValue, '', data);
12538
+ let align = viewElement.getStyle('float');
12539
+ // CSS: `float:none` => Model: `alignment:center`.
12540
+ if (align === 'none') {
12541
+ align = 'center';
12542
+ }
12543
+ if (align !== localDefaultValue) {
12544
+ return align;
12545
+ }
12546
+ // Consume the style even if not applied to the element so it won't be processed by other converters.
12547
+ conversionApi.consumable.consume(viewElement, {
12548
+ styles: 'float'
12549
+ });
12550
+ }
12551
+ }
12552
+ })// Support for the `margin-left:auto; margin-right:auto;` CSS definition for the table alignment.
12553
+ .attributeToAttribute({
12554
+ view: {
12555
+ name: /^(table|figure)$/,
12556
+ styles: {
12557
+ 'margin-left': 'auto',
12558
+ 'margin-right': 'auto'
12559
+ }
12560
+ },
12561
+ model: {
12562
+ key: 'tableAlignment',
12563
+ value: (viewElement, conversionApi, data)=>{
12564
+ // Ignore other figure elements.
12565
+ if (viewElement.name == 'figure' && !viewElement.hasClass('table')) {
12566
+ return;
12567
+ }
12568
+ const localDefaultValue = getDefaultValueAdjusted(defaultValue, '', data);
12569
+ const align = 'center';
12570
+ if (align !== localDefaultValue) {
12571
+ return align;
12572
+ }
12573
+ // Consume the styles even if not applied to the element so it won't be processed by other converters.
12574
+ conversionApi.consumable.consume(viewElement, {
12575
+ styles: [
12576
+ 'margin-left',
12577
+ 'margin-right'
12578
+ ]
12579
+ });
12580
+ }
12581
+ }
12582
+ })// Support for the `align` attribute as the backward compatibility while pasting from other sources.
12583
+ .attributeToAttribute({
12584
+ view: {
12585
+ name: 'table',
12586
+ attributes: {
12587
+ align: ALIGN_VALUES_REG_EXP
12588
+ }
12589
+ },
12590
+ model: {
12591
+ key: 'tableAlignment',
12592
+ value: (viewElement, conversionApi, data)=>{
12593
+ const localDefaultValue = getDefaultValueAdjusted(defaultValue, '', data);
12594
+ const align = viewElement.getAttribute('align');
12595
+ if (align !== localDefaultValue) {
12596
+ return align;
12597
+ }
12598
+ // Consume the attribute even if not applied to the element so it won't be processed by other converters.
12599
+ conversionApi.consumable.consume(viewElement, {
12600
+ attributes: 'align'
12601
+ });
12602
+ }
12603
+ }
12604
+ });
12605
+ }
12606
+ /**
12607
+ * Returns a function that converts the table view representation:
12608
+ *
12609
+ * ```html
12610
+ * <div align="right"><table>...</table></div>
12611
+ * <!-- or -->
12612
+ * <div align="center"><table>...</table></div>
12613
+ * <!-- or -->
12614
+ * <div align="left"><table>...</table></div>
12615
+ * ```
12616
+ *
12617
+ * to the model representation:
12618
+ *
12619
+ * ```xml
12620
+ * <table tableAlignment="right|center|left"></table>
12621
+ * ```
12622
+ *
12623
+ * @internal
12624
+ */ function upcastTableAlignedDiv(defaultValue) {
12625
+ return (dispatcher)=>{
12626
+ dispatcher.on('element:div', (evt, data, conversionApi)=>{
12627
+ // Do not convert if this is not a "table wrapped in div with align attribute".
12628
+ if (!conversionApi.consumable.test(data.viewItem, {
12629
+ name: true,
12630
+ attributes: 'align'
12631
+ })) {
12632
+ return;
12633
+ }
12634
+ // Find a table element inside the div element.
12635
+ const viewTable = getViewTableFromWrapper(data.viewItem);
12636
+ // Do not convert if table element is absent or was already converted.
12637
+ if (!viewTable || !conversionApi.consumable.test(viewTable, {
12612
12638
  name: true
12613
12639
  })) {
12614
12640
  return;
@@ -12767,9 +12793,6 @@ function insertWrapperWithAlignment(writer, align, table) {
12767
12793
  /**
12768
12794
  * The "Cancel" button view.
12769
12795
  */ cancelButtonView;
12770
- /**
12771
- * The Back button view displayed in the header.
12772
- */ backButtonView;
12773
12796
  /**
12774
12797
  * A collection of views that can be focused in the form.
12775
12798
  */ _focusables;
@@ -12811,7 +12834,6 @@ function insertWrapperWithAlignment(writer, align, table) {
12811
12834
  const { saveButtonView, cancelButtonView } = this._createActionButtons();
12812
12835
  this.saveButtonView = saveButtonView;
12813
12836
  this.cancelButtonView = cancelButtonView;
12814
- this.backButtonView = this._createBackButton();
12815
12837
  this._focusables = new ViewCollection();
12816
12838
  this._focusCycler = new FocusCycler({
12817
12839
  focusables: this._focusables,
@@ -12825,22 +12847,29 @@ function insertWrapperWithAlignment(writer, align, table) {
12825
12847
  }
12826
12848
  });
12827
12849
  // Form header.
12828
- const headerView = new FormHeaderView(locale, {
12850
+ this.children.add(new FormHeaderView(locale, {
12829
12851
  label: this.t('Table properties')
12830
- });
12831
- headerView.children.add(this.backButtonView, 0);
12832
- this.children.add(headerView);
12852
+ }));
12833
12853
  // Border row.
12834
12854
  this.children.add(new FormRowView(locale, {
12835
12855
  labelView: borderRowLabel,
12836
12856
  children: [
12837
12857
  borderRowLabel,
12838
12858
  borderStyleDropdown,
12839
- borderWidthInput,
12840
- borderColorInput
12859
+ borderColorInput,
12860
+ borderWidthInput
12841
12861
  ],
12842
12862
  class: 'ck-table-form__border-row'
12843
12863
  }));
12864
+ // Background row.
12865
+ this.children.add(new FormRowView(locale, {
12866
+ labelView: backgroundRowLabel,
12867
+ children: [
12868
+ backgroundRowLabel,
12869
+ backgroundInput
12870
+ ],
12871
+ class: 'ck-table-form__background-row'
12872
+ }));
12844
12873
  this.children.add(new FormRowView(locale, {
12845
12874
  children: [
12846
12875
  // Dimensions row.
@@ -12854,31 +12883,22 @@ function insertWrapperWithAlignment(writer, align, table) {
12854
12883
  ],
12855
12884
  class: 'ck-table-form__dimensions-row'
12856
12885
  }),
12857
- // Background row.
12886
+ // Alignment row.
12858
12887
  new FormRowView(locale, {
12859
- labelView: backgroundRowLabel,
12888
+ labelView: alignmentLabel,
12860
12889
  children: [
12861
- backgroundRowLabel,
12862
- backgroundInput
12890
+ alignmentLabel,
12891
+ alignmentToolbar
12863
12892
  ],
12864
- class: 'ck-table-form__background-row'
12893
+ class: 'ck-table-properties-form__alignment-row'
12865
12894
  })
12866
12895
  ]
12867
12896
  }));
12868
- // Alignment row.
12869
- this.children.add(new FormRowView(locale, {
12870
- labelView: alignmentLabel,
12871
- children: [
12872
- alignmentLabel,
12873
- alignmentToolbar
12874
- ],
12875
- class: 'ck-table-properties-form__alignment-row'
12876
- }));
12877
12897
  // Action row.
12878
12898
  this.children.add(new FormRowView(locale, {
12879
12899
  children: [
12880
- this.cancelButtonView,
12881
- this.saveButtonView
12900
+ this.saveButtonView,
12901
+ this.cancelButtonView
12882
12902
  ],
12883
12903
  class: 'ck-table-form__action-row'
12884
12904
  }));
@@ -12915,15 +12935,14 @@ function insertWrapperWithAlignment(writer, align, table) {
12915
12935
  });
12916
12936
  [
12917
12937
  this.borderStyleDropdown,
12918
- this.borderWidthInput,
12919
12938
  this.borderColorInput,
12939
+ this.borderWidthInput,
12940
+ this.backgroundInput,
12920
12941
  this.widthInput,
12921
12942
  this.heightInput,
12922
- this.backgroundInput,
12923
12943
  this.alignmentToolbar,
12924
- this.cancelButtonView,
12925
12944
  this.saveButtonView,
12926
- this.backButtonView
12945
+ this.cancelButtonView
12927
12946
  ].forEach((view)=>{
12928
12947
  // Register the view as focusable.
12929
12948
  this._focusables.add(view);
@@ -12958,7 +12977,7 @@ function insertWrapperWithAlignment(writer, align, table) {
12958
12977
  width: defaultTableProperties.borderWidth,
12959
12978
  color: defaultTableProperties.borderColor
12960
12979
  };
12961
- const colorInputCreator = getLabeledColorInputCreator({
12980
+ const colorInputCreator = getLabeledColorInputCreator$1({
12962
12981
  colorConfig: this.options.borderColors,
12963
12982
  columns: 5,
12964
12983
  defaultColorValue: defaultBorder.color,
@@ -12971,7 +12990,7 @@ function insertWrapperWithAlignment(writer, align, table) {
12971
12990
  const borderRowLabel = new LabelView(locale);
12972
12991
  borderRowLabel.text = t('Border');
12973
12992
  // -- Style ---------------------------------------------------
12974
- const styleLabels = getBorderStyleLabels(t);
12993
+ const styleLabels = getBorderStyleLabels$1(t);
12975
12994
  const borderStyleDropdown = new LabeledFieldView(locale, createLabeledDropdown);
12976
12995
  borderStyleDropdown.set({
12977
12996
  label: accessibleLabel,
@@ -12991,7 +13010,7 @@ function insertWrapperWithAlignment(writer, align, table) {
12991
13010
  this.borderStyle = evt.source._borderStyleValue;
12992
13011
  });
12993
13012
  borderStyleDropdown.bind('isEmpty').to(this, 'borderStyle', (value)=>!value);
12994
- addListToDropdown(borderStyleDropdown.fieldView, getBorderStyleDefinitions(this, defaultBorder.style), {
13013
+ addListToDropdown(borderStyleDropdown.fieldView, getBorderStyleDefinitions$1(this, defaultBorder.style), {
12995
13014
  role: 'menu',
12996
13015
  ariaLabel: accessibleLabel
12997
13016
  });
@@ -13002,7 +13021,7 @@ function insertWrapperWithAlignment(writer, align, table) {
13002
13021
  class: 'ck-table-form__border-width'
13003
13022
  });
13004
13023
  borderWidthInput.fieldView.bind('value').to(this, 'borderWidth');
13005
- borderWidthInput.bind('isEnabled').to(this, 'borderStyle', isBorderStyleSet);
13024
+ borderWidthInput.bind('isEnabled').to(this, 'borderStyle', isBorderStyleSet$2);
13006
13025
  borderWidthInput.fieldView.on('input', ()=>{
13007
13026
  this.borderWidth = borderWidthInput.fieldView.element.value;
13008
13027
  });
@@ -13013,7 +13032,7 @@ function insertWrapperWithAlignment(writer, align, table) {
13013
13032
  class: 'ck-table-form__border-color'
13014
13033
  });
13015
13034
  borderColorInput.fieldView.bind('value').to(this, 'borderColor');
13016
- borderColorInput.bind('isEnabled').to(this, 'borderStyle', isBorderStyleSet);
13035
+ borderColorInput.bind('isEnabled').to(this, 'borderStyle', isBorderStyleSet$2);
13017
13036
  borderColorInput.fieldView.on('input', ()=>{
13018
13037
  this.borderColor = borderColorInput.fieldView.value;
13019
13038
  });
@@ -13021,12 +13040,12 @@ function insertWrapperWithAlignment(writer, align, table) {
13021
13040
  this.on('change:borderStyle', (evt, name, newValue, oldValue)=>{
13022
13041
  // When removing the border (`border-style:none`), clear the remaining `border-*` properties.
13023
13042
  // See: https://github.com/ckeditor/ckeditor5/issues/6227.
13024
- if (!isBorderStyleSet(newValue)) {
13043
+ if (!isBorderStyleSet$2(newValue)) {
13025
13044
  this.borderColor = '';
13026
13045
  this.borderWidth = '';
13027
13046
  }
13028
13047
  // When setting the `border-style` from `none`, set the default `border-color` and `border-width` properties.
13029
- if (!isBorderStyleSet(oldValue)) {
13048
+ if (!isBorderStyleSet$2(oldValue)) {
13030
13049
  this.borderColor = defaultBorder.color;
13031
13050
  this.borderWidth = defaultBorder.width;
13032
13051
  }
@@ -13049,7 +13068,7 @@ function insertWrapperWithAlignment(writer, align, table) {
13049
13068
  const backgroundRowLabel = new LabelView(locale);
13050
13069
  backgroundRowLabel.text = t('Background');
13051
13070
  // -- Background color input -----------------------------------
13052
- const backgroundInputCreator = getLabeledColorInputCreator({
13071
+ const backgroundInputCreator = getLabeledColorInputCreator$1({
13053
13072
  colorConfig: this.options.backgroundColors,
13054
13073
  columns: 5,
13055
13074
  defaultColorValue: this.options.defaultTableProperties.backgroundColor,
@@ -13131,7 +13150,7 @@ function insertWrapperWithAlignment(writer, align, table) {
13131
13150
  const t = this.t;
13132
13151
  // -- Label ---------------------------------------------------
13133
13152
  const alignmentLabel = new LabelView(locale);
13134
- alignmentLabel.text = t('Table Alignment');
13153
+ alignmentLabel.text = t('Alignment');
13135
13154
  // -- Toolbar ---------------------------------------------------
13136
13155
  const alignmentToolbar = new ToolbarView(locale);
13137
13156
  alignmentToolbar.set({
@@ -13139,14 +13158,12 @@ function insertWrapperWithAlignment(writer, align, table) {
13139
13158
  isCompact: true,
13140
13159
  ariaLabel: t('Table alignment toolbar')
13141
13160
  });
13142
- fillToolbar({
13161
+ fillToolbar$1({
13143
13162
  view: this,
13144
13163
  icons: {
13145
13164
  left: IconObjectInlineLeft,
13146
13165
  center: IconObjectCenter,
13147
- right: IconObjectInlineRight,
13148
- blockLeft: IconObjectLeft,
13149
- blockRight: IconObjectRight
13166
+ right: IconObjectInlineRight
13150
13167
  },
13151
13168
  toolbar: alignmentToolbar,
13152
13169
  labels: this._alignmentLabels,
@@ -13177,7 +13194,8 @@ function insertWrapperWithAlignment(writer, align, table) {
13177
13194
  ];
13178
13195
  saveButtonView.set({
13179
13196
  label: t('Save'),
13180
- class: 'ck-button-action',
13197
+ icon: IconCheck,
13198
+ class: 'ck-button-save',
13181
13199
  type: 'submit',
13182
13200
  withText: true
13183
13201
  });
@@ -13186,6 +13204,8 @@ function insertWrapperWithAlignment(writer, align, table) {
13186
13204
  });
13187
13205
  cancelButtonView.set({
13188
13206
  label: t('Cancel'),
13207
+ icon: IconCancel,
13208
+ class: 'ck-button-cancel',
13189
13209
  withText: true
13190
13210
  });
13191
13211
  cancelButtonView.delegate('execute').to(this, 'cancel');
@@ -13194,56 +13214,37 @@ function insertWrapperWithAlignment(writer, align, table) {
13194
13214
  cancelButtonView
13195
13215
  };
13196
13216
  }
13197
- /**
13198
- * Creates a back button view that cancels the form.
13199
- */ _createBackButton() {
13200
- const t = this.locale.t;
13201
- const backButton = new ButtonView(this.locale);
13202
- backButton.set({
13203
- class: 'ck-button-back',
13204
- label: t('Back'),
13205
- icon: IconPreviousArrow,
13206
- tooltip: true
13207
- });
13208
- backButton.delegate('execute').to(this, 'cancel');
13209
- return backButton;
13210
- }
13211
13217
  /**
13212
13218
  * Provides localized labels for {@link #alignmentToolbar} buttons.
13213
13219
  */ get _alignmentLabels() {
13214
13220
  const locale = this.locale;
13215
13221
  const t = this.t;
13216
- const blockLeft = t('Align table to the left with no text wrapping');
13217
- const blockRight = t('Align table to the right with no text wrapping');
13218
- const left = t('Align table to the left with text wrapping');
13219
- const center = t('Center table with no text wrapping');
13220
- const right = t('Align table to the right with text wrapping');
13222
+ const left = t('Align table to the left');
13223
+ const center = t('Center table');
13224
+ const right = t('Align table to the right');
13221
13225
  // Returns object with a proper order of labels.
13222
13226
  if (locale.uiLanguageDirection === 'rtl') {
13223
13227
  return {
13224
13228
  right,
13229
+ center,
13230
+ left
13231
+ };
13232
+ } else {
13233
+ return {
13225
13234
  left,
13226
- blockRight,
13227
13235
  center,
13228
- blockLeft
13236
+ right
13229
13237
  };
13230
13238
  }
13231
- return {
13232
- blockLeft,
13233
- center,
13234
- blockRight,
13235
- left,
13236
- right
13237
- };
13238
13239
  }
13239
13240
  }
13240
- function isBorderStyleSet(value) {
13241
+ function isBorderStyleSet$2(value) {
13241
13242
  return value !== 'none';
13242
13243
  }
13243
13244
 
13244
- const ERROR_TEXT_TIMEOUT = 500;
13245
+ const ERROR_TEXT_TIMEOUT$2 = 500;
13245
13246
  // Map of view properties and related commands.
13246
- const propertyToCommandMap = {
13247
+ const propertyToCommandMap$2 = {
13247
13248
  borderStyle: 'tableBorderStyle',
13248
13249
  borderColor: 'tableBorderColor',
13249
13250
  borderWidth: 'tableBorderWidth',
@@ -13335,7 +13336,7 @@ const propertyToCommandMap = {
13335
13336
  tooltip: true
13336
13337
  });
13337
13338
  this.listenTo(view, 'execute', ()=>this._showView());
13338
- const commands = Object.values(propertyToCommandMap).map((commandName)=>editor.commands.get(commandName));
13339
+ const commands = Object.values(propertyToCommandMap$2).map((commandName)=>editor.commands.get(commandName));
13339
13340
  view.bind('isEnabled').toMany(commands, 'isEnabled', (...areEnabled)=>areEnabled.some((isCommandEnabled)=>isCommandEnabled));
13340
13341
  return view;
13341
13342
  }
@@ -13445,7 +13446,7 @@ const propertyToCommandMap = {
13445
13446
  */ _fillViewFormFromCommandValues() {
13446
13447
  const commands = this.editor.commands;
13447
13448
  const borderStyleCommand = commands.get('tableBorderStyle');
13448
- Object.entries(propertyToCommandMap).map(([property, commandName])=>{
13449
+ Object.entries(propertyToCommandMap$2).map(([property, commandName])=>{
13449
13450
  const propertyKey = property;
13450
13451
  const defaultValue = this.view === this._viewWithContentTableDefaults ? this._defaultContentTableProperties[propertyKey] || '' : this._defaultLayoutTableProperties[propertyKey] || '';
13451
13452
  return [
@@ -13554,7 +13555,7 @@ const propertyToCommandMap = {
13554
13555
  const { commandName, viewField, validator, errorText } = options;
13555
13556
  const setErrorTextDebounced = debounce(()=>{
13556
13557
  viewField.errorText = errorText;
13557
- }, ERROR_TEXT_TIMEOUT);
13558
+ }, ERROR_TEXT_TIMEOUT$2);
13558
13559
  return (evt, propertyName, newValue)=>{
13559
13560
  setErrorTextDebounced.cancel();
13560
13561
  // Do not execute the command on initial call (opening the table properties view).
@@ -13995,5 +13996,2096 @@ const propertyToCommandMap = {
13995
13996
  }
13996
13997
  }
13997
13998
 
13998
- export { InsertColumnCommand, InsertRowCommand, InsertTableCommand, InsertTableLayoutCommand, MergeCellCommand, MergeCellsCommand, PlainTableOutput, RemoveColumnCommand, RemoveRowCommand, SelectColumnCommand, SelectRowCommand, SetHeaderColumnCommand, SetHeaderRowCommand, SplitCellCommand, Table, TableAlignmentCommand, TableBackgroundColorCommand, TableBorderColorCommand, TableBorderStyleCommand, TableBorderWidthCommand, TableCaption, TableCaptionEditing, TableCaptionUI, TableCellBackgroundColorCommand, TableCellBorderColorCommand, TableCellBorderStyleCommand, TableCellBorderWidthCommand, TableCellHeightCommand, TableCellHorizontalAlignmentCommand, TableCellPaddingCommand, TableCellProperties, TableCellPropertiesEditing, TableCellPropertiesUI, TableCellPropertiesView, TableCellPropertyCommand, TableCellTypeCommand, TableCellVerticalAlignmentCommand, TableCellWidthCommand, TableCellWidthEditing, TableClipboard, TableColumnResize, TableColumnResizeEditing, TableEditing, TableHeightCommand, TableKeyboard, TableLayout, TableLayoutEditing, TableLayoutUI, TableMouse, TableProperties, TablePropertiesEditing, TablePropertiesUI, TablePropertiesView, TablePropertyCommand, TableSelection, TableToolbar, TableTypeCommand, TableUI, TableUtils, TableWalker, TableWidthCommand, TableWidthsCommand, ToggleTableCaptionCommand, InsertTableView as _InsertTableView, COLUMN_MIN_WIDTH_AS_PERCENTAGE as _TABLE_COLUMN_MIN_WIDTH_AS_PERCENTAGE, COLUMN_MIN_WIDTH_IN_PIXELS as _TABLE_COLUMN_MIN_WIDTH_IN_PIXELS, COLUMN_RESIZE_DISTANCE_THRESHOLD as _TABLE_COLUMN_RESIZE_DISTANCE_THRESHOLD, COLUMN_WIDTH_PRECISION as _TABLE_COLUMN_WIDTH_PRECISION, defaultColors as _TABLE_DEFAULT_COLORS, ColorInputView as _TableColorInputView, MouseEventsObserver as _TableMouseEventsObserver, addDefaultUnitToNumericValue as _addDefaultUnitToNumericValue, adjustLastColumnIndex as _adjustLastTableColumnIndex, adjustLastRowIndex as _adjustLastTableRowIndex, clamp as _clamp, colorFieldValidator as _colorTableFieldValidator, convertParagraphInTableCell as _convertParagraphInTableCell, createEmptyTableCell as _createEmptyTableCell, createFilledArray as _createFilledArray, cropTableToDimensions as _cropTableToDimensions, downcastTable as _downcastTable, downcastTableAttribute as _downcastTableAttribute, downcastAttributeToStyle as _downcastTableAttributeToStyle, downcastCell as _downcastTableCell, downcastTableResizedClass as _downcastTableResizedClass, downcastRow as _downcastTableRow, enableProperty$1 as _enableTableCellProperty, ensureParagraphInTableCell as _ensureParagraphInTableCell, fillToolbar as _fillTableOrCellToolbar, getBalloonCellPositionData as _getBalloonTableCellPositionData, getBalloonTablePositionData as _getBalloonTablePositionData, getBorderStyleLabels as _getBorderTableStyleLabels, getChangedResizedTables as _getChangedResizedTables, getDefaultValueAdjusted as _getDefaultTableValueAdjusted, getDomCellOuterWidth as _getDomTableCellOuterWidth, getElementWidthInPixels as _getElementWidthInPixels, getHorizontallyOverlappingCells as _getHorizontallyOverlappingTableCells, getLabeledColorInputCreator as _getLabeledTableColorInputCreator, getLocalizedColorErrorText as _getLocalizedTableColorErrorText, getLocalizedLengthErrorText as _getLocalizedTableLengthErrorText, getNormalizedDefaultProperties as _getNormalizedDefaultTableBaseProperties, getNormalizedDefaultCellProperties as _getNormalizedDefaultTableCellProperties, getNormalizedDefaultTableProperties as _getNormalizedDefaultTableProperties, getSelectedTableWidget as _getSelectedTableWidget, getSelectionAffectedTable as _getSelectionAffectedTable, getSelectionAffectedTableWidget as _getSelectionAffectedTableWidget, getSingleValue as _getTableBorderBoxSingleValue, getCaptionFromTableModelElement as _getTableCaptionFromModelElement, getCaptionFromModelSelection as _getTableCaptionFromModelSelection, getColumnEdgesIndexes as _getTableColumnEdgesIndexes, getTableColumnElements as _getTableColumnElements, getColumnGroupElement as _getTableColumnGroupElement, getColumnMinWidthAsPercentage as _getTableColumnMinWidthAsPercentage, getTableColumnsWidths as _getTableColumnsWidths, getBorderStyleDefinitions as _getTableOrCellBorderStyleDefinitions, getTableWidgetAncestor as _getTableWidgetAncestor, getTableWidthInPixels as _getTableWidthInPixels, getVerticallyOverlappingCells as _getVerticallyOverlappingTableCells, injectTableCaptionPostFixer as _injectTableCaptionPostFixer, injectTableCellParagraphPostFixer as _injectTableCellParagraphPostFixer, injectTableLayoutPostFixer as _injectTableLayoutPostFixer, isSingleParagraphWithoutAttributes as _isSingleTableParagraphWithoutAttributes, isHeadingColumnCell as _isTableHeadingColumnCell, isTable as _isTableModelElement, lengthFieldValidator as _lengthTableFieldValidator, lineWidthFieldValidator as _lineWidthTableFieldValidator, matchTableCaptionViewElement as _matchTableCaptionViewElement, normalizeColumnWidths as _normalizeTableColumnWidths, removeEmptyColumns as _removeEmptyTableColumns, removeEmptyRows as _removeEmptyTableRows, removeEmptyRowsColumns as _removeEmptyTableRowsColumns, repositionContextualBalloon as _repositionTableContextualBalloon, skipEmptyTableRow as _skipEmptyTableRow, splitHorizontally as _splitTableCellHorizontally, splitVertically as _splitTableCellVertically, sumArray as _sumArray, tableCellRefreshHandler as _tableCellRefreshHandler, tableHeadingsRefreshHandler as _tableHeadingsRefreshHandler, toPrecision as _toPrecision, translateColSpanAttribute as _translateTableColspanAttribute, trimTableCellIfNeeded as _trimTableCellIfNeeded, upcastStyleToAttribute as _upcastNormalizedTableStyleToAttribute, upcastTable as _upcastTable, upcastBorderStyles as _upcastTableBorderStyles, upcastColgroupElement as _upcastTableColgroupElement, upcastTableFigure as _upcastTableFigure, updateColumnElements as _updateTableColumnElements, updateNumericAttribute as _updateTableNumericAttribute };
13999
+ /**
14000
+ * Returns an object containing pairs of CSS border style values and their localized UI
14001
+ * labels. Used by {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView}
14002
+ * and {@link module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView}.
14003
+ *
14004
+ * @internal
14005
+ * @param t The "t" function provided by the editor that is used to localize strings.
14006
+ */ function getBorderStyleLabels(t) {
14007
+ return {
14008
+ none: t('None'),
14009
+ solid: t('Solid'),
14010
+ dotted: t('Dotted'),
14011
+ dashed: t('Dashed'),
14012
+ double: t('Double'),
14013
+ groove: t('Groove'),
14014
+ ridge: t('Ridge'),
14015
+ inset: t('Inset'),
14016
+ outset: t('Outset')
14017
+ };
14018
+ }
14019
+ /**
14020
+ * Generates item definitions for a UI dropdown that allows changing the border style of a table or a table cell.
14021
+ *
14022
+ * @internal
14023
+ * @param defaultStyle The default border.
14024
+ */ function getBorderStyleDefinitions(view, defaultStyle) {
14025
+ const itemDefinitions = new Collection();
14026
+ const styleLabels = getBorderStyleLabels(view.t);
14027
+ for(const style in styleLabels){
14028
+ const definition = {
14029
+ type: 'button',
14030
+ model: new UIModel({
14031
+ _borderStyleValue: style,
14032
+ label: styleLabels[style],
14033
+ role: 'menuitemradio',
14034
+ withText: true
14035
+ })
14036
+ };
14037
+ if (style === 'none') {
14038
+ definition.model.bind('isOn').to(view, 'borderStyle', (value)=>{
14039
+ if (defaultStyle === 'none') {
14040
+ return !value;
14041
+ }
14042
+ return value === style;
14043
+ });
14044
+ } else {
14045
+ definition.model.bind('isOn').to(view, 'borderStyle', (value)=>{
14046
+ return value === style;
14047
+ });
14048
+ }
14049
+ itemDefinitions.add(definition);
14050
+ }
14051
+ return itemDefinitions;
14052
+ }
14053
+ /**
14054
+ * A helper that fills a toolbar with buttons that:
14055
+ *
14056
+ * * have some labels,
14057
+ * * have some icons,
14058
+ * * set a certain UI view property value upon execution.
14059
+ *
14060
+ * @internal
14061
+ * @param options Configuration options
14062
+ * @param options.view The view that has the observable property.
14063
+ * @param options.icons Object with button icons.
14064
+ * @param options.toolbar The toolbar to fill with buttons.
14065
+ * @param options.labels Object with button labels.
14066
+ * @param options.propertyName The name of the observable property in the view.
14067
+ * @param options.nameToValue A function that maps a button name to a value. By default names are the same as values.
14068
+ * @param options.defaultValue Default value for the property.
14069
+ */ function fillToolbar(options) {
14070
+ const { view, icons, toolbar, labels, propertyName, nameToValue, defaultValue } = options;
14071
+ for(const name in labels){
14072
+ const button = new ButtonView(view.locale);
14073
+ button.set({
14074
+ role: 'radio',
14075
+ isToggleable: true,
14076
+ label: labels[name],
14077
+ icon: icons[name],
14078
+ tooltip: labels[name]
14079
+ });
14080
+ // If specified the `nameToValue()` callback, map the value based on the option's name.
14081
+ const buttonValue = nameToValue ? nameToValue(name) : name;
14082
+ button.bind('isOn').to(view, propertyName, (value)=>{
14083
+ // `value` comes from `view[ propertyName ]`.
14084
+ let valueToCompare = value;
14085
+ // If it's empty, and the `defaultValue` is specified, use it instead.
14086
+ if (value === '' && defaultValue) {
14087
+ valueToCompare = defaultValue;
14088
+ }
14089
+ return buttonValue === valueToCompare;
14090
+ });
14091
+ button.on('execute', ()=>{
14092
+ // Allow toggling alignment if there is no default value specified (especially for layout tables).
14093
+ if (!defaultValue && buttonValue && view[propertyName] === buttonValue) {
14094
+ view[propertyName] = undefined;
14095
+ } else {
14096
+ view[propertyName] = buttonValue;
14097
+ }
14098
+ });
14099
+ toolbar.items.add(button);
14100
+ }
14101
+ }
14102
+ /**
14103
+ * Returns a creator for a color input with a label.
14104
+ *
14105
+ * For given options, it returns a function that creates an instance of a
14106
+ * {@link module:table/ui/colorinputview~ColorInputView color input} logically related to
14107
+ * a {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView labeled view} in the DOM.
14108
+ *
14109
+ * The helper does the following:
14110
+ *
14111
+ * * It sets the color input `id` and `ariaDescribedById` attributes.
14112
+ * * It binds the color input `isReadOnly` to the labeled view.
14113
+ * * It binds the color input `hasError` to the labeled view.
14114
+ * * It enables a logic that cleans up the error when the user starts typing in the color input.
14115
+ *
14116
+ * Usage:
14117
+ *
14118
+ * ```ts
14119
+ * const colorInputCreator = getLabeledColorInputCreator( {
14120
+ * colorConfig: [ ... ],
14121
+ * columns: 3,
14122
+ * } );
14123
+ *
14124
+ * const labeledInputView = new LabeledFieldView( locale, colorInputCreator );
14125
+ * console.log( labeledInputView.view ); // A color input instance.
14126
+ * ```
14127
+ *
14128
+ * @internal
14129
+ * @param options Color input options.
14130
+ * @param options.colorConfig The configuration of the color palette displayed in the input's dropdown.
14131
+ * @param options.columns The configuration of the number of columns the color palette consists of in the input's dropdown.
14132
+ * @param options.defaultColorValue If specified, the color input view will replace the "Remove color" button with
14133
+ * the "Restore default" button. Instead of clearing the input field, the default color value will be set.
14134
+ * @param options.colorPickerConfig The configuration of the color picker. You could disable it or define your output format.
14135
+ */ function getLabeledColorInputCreator(options) {
14136
+ return (labeledFieldView, viewUid, statusUid)=>{
14137
+ const colorInputView = new ColorInputView(labeledFieldView.locale, {
14138
+ colorDefinitions: colorConfigToColorGridDefinitions(options.colorConfig),
14139
+ columns: options.columns,
14140
+ defaultColorValue: options.defaultColorValue,
14141
+ colorPickerConfig: options.colorPickerConfig
14142
+ });
14143
+ colorInputView.inputView.set({
14144
+ id: viewUid,
14145
+ ariaDescribedById: statusUid
14146
+ });
14147
+ colorInputView.bind('isReadOnly').to(labeledFieldView, 'isEnabled', (value)=>!value);
14148
+ colorInputView.bind('hasError').to(labeledFieldView, 'errorText', (value)=>!!value);
14149
+ colorInputView.on('input', ()=>{
14150
+ // UX: Make the error text disappear and disable the error indicator as the user
14151
+ // starts fixing the errors.
14152
+ labeledFieldView.errorText = null;
14153
+ });
14154
+ labeledFieldView.bind('isEmpty', 'isFocused').to(colorInputView);
14155
+ return colorInputView;
14156
+ };
14157
+ }
14158
+ function colorConfigToColorGridDefinitions(colorConfig) {
14159
+ return colorConfig.map((item)=>({
14160
+ color: item.model,
14161
+ label: item.label,
14162
+ options: {
14163
+ hasBorder: item.hasBorder
14164
+ }
14165
+ }));
14166
+ }
14167
+
14168
+ /**
14169
+ * The class representing a table properties form, allowing users to customize
14170
+ * certain style aspects of a table, for instance, border, background color, alignment, etc..
14171
+ */ class TablePropertiesViewExperimental extends View {
14172
+ /**
14173
+ * Options passed to the view. See {@link #constructor} to learn more.
14174
+ */ options;
14175
+ /**
14176
+ * Tracks information about the DOM focus in the form.
14177
+ */ focusTracker;
14178
+ /**
14179
+ * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.
14180
+ */ keystrokes;
14181
+ /**
14182
+ * A collection of child views in the form.
14183
+ */ children;
14184
+ /**
14185
+ * A dropdown that allows selecting the style of the table border.
14186
+ */ borderStyleDropdown;
14187
+ /**
14188
+ * An input that allows specifying the width of the table border.
14189
+ */ borderWidthInput;
14190
+ /**
14191
+ * An input that allows specifying the color of the table border.
14192
+ */ borderColorInput;
14193
+ /**
14194
+ * An input that allows specifying the table background color.
14195
+ */ backgroundInput;
14196
+ /**
14197
+ * An input that allows specifying the table width.
14198
+ */ widthInput;
14199
+ /**
14200
+ * An input that allows specifying the table height.
14201
+ */ heightInput;
14202
+ /**
14203
+ * A toolbar with buttons that allow changing the alignment of an entire table.
14204
+ */ alignmentToolbar;
14205
+ /**
14206
+ * The "Save" button view.
14207
+ */ saveButtonView;
14208
+ /**
14209
+ * The "Cancel" button view.
14210
+ */ cancelButtonView;
14211
+ /**
14212
+ * The Back button view displayed in the header.
14213
+ */ backButtonView;
14214
+ /**
14215
+ * A collection of views that can be focused in the form.
14216
+ */ _focusables;
14217
+ /**
14218
+ * Helps cycling over {@link #_focusables} in the form.
14219
+ */ _focusCycler;
14220
+ /**
14221
+ * @param locale The {@link module:core/editor/editor~Editor#locale} instance.
14222
+ * @param options Additional configuration of the view.
14223
+ */ constructor(locale, options){
14224
+ super(locale);
14225
+ this.set({
14226
+ borderStyle: '',
14227
+ borderWidth: '',
14228
+ borderColor: '',
14229
+ backgroundColor: '',
14230
+ width: '',
14231
+ height: '',
14232
+ alignment: ''
14233
+ });
14234
+ this.options = options;
14235
+ const { borderStyleDropdown, borderWidthInput, borderColorInput, borderRowLabel } = this._createBorderFields();
14236
+ const { backgroundRowLabel, backgroundInput } = this._createBackgroundFields();
14237
+ const { widthInput, operatorLabel, heightInput, dimensionsLabel } = this._createDimensionFields();
14238
+ const { alignmentToolbar, alignmentLabel } = this._createAlignmentFields();
14239
+ this.focusTracker = new FocusTracker();
14240
+ this.keystrokes = new KeystrokeHandler();
14241
+ this.children = this.createCollection();
14242
+ this.borderStyleDropdown = borderStyleDropdown;
14243
+ this.borderWidthInput = borderWidthInput;
14244
+ this.borderColorInput = borderColorInput;
14245
+ this.backgroundInput = backgroundInput;
14246
+ this.widthInput = widthInput;
14247
+ this.heightInput = heightInput;
14248
+ this.alignmentToolbar = alignmentToolbar;
14249
+ // Defer creating to make sure other fields are present and the Save button can
14250
+ // bind its #isEnabled to their error messages so there's no way to save unless all
14251
+ // fields are valid.
14252
+ const { saveButtonView, cancelButtonView } = this._createActionButtons();
14253
+ this.saveButtonView = saveButtonView;
14254
+ this.cancelButtonView = cancelButtonView;
14255
+ this.backButtonView = this._createBackButton();
14256
+ this._focusables = new ViewCollection();
14257
+ this._focusCycler = new FocusCycler({
14258
+ focusables: this._focusables,
14259
+ focusTracker: this.focusTracker,
14260
+ keystrokeHandler: this.keystrokes,
14261
+ actions: {
14262
+ // Navigate form fields backwards using the Shift + Tab keystroke.
14263
+ focusPrevious: 'shift + tab',
14264
+ // Navigate form fields forwards using the Tab key.
14265
+ focusNext: 'tab'
14266
+ }
14267
+ });
14268
+ // Form header.
14269
+ const headerView = new FormHeaderView(locale, {
14270
+ label: this.t('Table properties')
14271
+ });
14272
+ headerView.children.add(this.backButtonView, 0);
14273
+ this.children.add(headerView);
14274
+ // Border row.
14275
+ this.children.add(new FormRowView(locale, {
14276
+ labelView: borderRowLabel,
14277
+ children: [
14278
+ borderRowLabel,
14279
+ borderStyleDropdown,
14280
+ borderWidthInput,
14281
+ borderColorInput
14282
+ ],
14283
+ class: 'ck-table-form__border-row'
14284
+ }));
14285
+ this.children.add(new FormRowView(locale, {
14286
+ children: [
14287
+ // Dimensions row.
14288
+ new FormRowView(locale, {
14289
+ labelView: dimensionsLabel,
14290
+ children: [
14291
+ dimensionsLabel,
14292
+ widthInput,
14293
+ operatorLabel,
14294
+ heightInput
14295
+ ],
14296
+ class: 'ck-table-form__dimensions-row'
14297
+ }),
14298
+ // Background row.
14299
+ new FormRowView(locale, {
14300
+ labelView: backgroundRowLabel,
14301
+ children: [
14302
+ backgroundRowLabel,
14303
+ backgroundInput
14304
+ ],
14305
+ class: 'ck-table-form__background-row'
14306
+ })
14307
+ ]
14308
+ }));
14309
+ // Alignment row.
14310
+ this.children.add(new FormRowView(locale, {
14311
+ labelView: alignmentLabel,
14312
+ children: [
14313
+ alignmentLabel,
14314
+ alignmentToolbar
14315
+ ],
14316
+ class: 'ck-table-properties-form__alignment-row'
14317
+ }));
14318
+ // Action row.
14319
+ this.children.add(new FormRowView(locale, {
14320
+ children: [
14321
+ this.cancelButtonView,
14322
+ this.saveButtonView
14323
+ ],
14324
+ class: 'ck-table-form__action-row'
14325
+ }));
14326
+ this.setTemplate({
14327
+ tag: 'form',
14328
+ attributes: {
14329
+ class: [
14330
+ 'ck',
14331
+ 'ck-form',
14332
+ 'ck-table-form',
14333
+ 'ck-table-properties-form',
14334
+ 'ck-table-properties-form_experimental'
14335
+ ],
14336
+ // https://github.com/ckeditor/ckeditor5-link/issues/90
14337
+ tabindex: '-1'
14338
+ },
14339
+ children: this.children
14340
+ });
14341
+ }
14342
+ /**
14343
+ * @inheritDoc
14344
+ */ render() {
14345
+ super.render();
14346
+ // Enable the "submit" event for this view. It can be triggered by the #saveButtonView
14347
+ // which is of the "submit" DOM "type".
14348
+ submitHandler({
14349
+ view: this
14350
+ });
14351
+ // Maintain continuous focus cycling over views that have focusable children and focus cyclers themselves.
14352
+ [
14353
+ this.borderColorInput,
14354
+ this.backgroundInput
14355
+ ].forEach((view)=>{
14356
+ this._focusCycler.chain(view.fieldView.focusCycler);
14357
+ });
14358
+ [
14359
+ this.borderStyleDropdown,
14360
+ this.borderWidthInput,
14361
+ this.borderColorInput,
14362
+ this.widthInput,
14363
+ this.heightInput,
14364
+ this.backgroundInput,
14365
+ this.alignmentToolbar,
14366
+ this.cancelButtonView,
14367
+ this.saveButtonView,
14368
+ this.backButtonView
14369
+ ].forEach((view)=>{
14370
+ // Register the view as focusable.
14371
+ this._focusables.add(view);
14372
+ // Register the view in the focus tracker.
14373
+ this.focusTracker.add(view.element);
14374
+ });
14375
+ // Mainly for closing using "Esc" and navigation using "Tab".
14376
+ this.keystrokes.listenTo(this.element);
14377
+ }
14378
+ /**
14379
+ * @inheritDoc
14380
+ */ destroy() {
14381
+ super.destroy();
14382
+ this.focusTracker.destroy();
14383
+ this.keystrokes.destroy();
14384
+ }
14385
+ /**
14386
+ * Focuses the fist focusable field in the form.
14387
+ */ focus() {
14388
+ this._focusCycler.focusFirst();
14389
+ }
14390
+ /**
14391
+ * Creates the following form fields:
14392
+ *
14393
+ * * {@link #borderStyleDropdown},
14394
+ * * {@link #borderWidthInput},
14395
+ * * {@link #borderColorInput}.
14396
+ */ _createBorderFields() {
14397
+ const defaultTableProperties = this.options.defaultTableProperties;
14398
+ const defaultBorder = {
14399
+ style: defaultTableProperties.borderStyle,
14400
+ width: defaultTableProperties.borderWidth,
14401
+ color: defaultTableProperties.borderColor
14402
+ };
14403
+ const colorInputCreator = getLabeledColorInputCreator({
14404
+ colorConfig: this.options.borderColors,
14405
+ columns: 5,
14406
+ defaultColorValue: defaultBorder.color,
14407
+ colorPickerConfig: this.options.colorPickerConfig
14408
+ });
14409
+ const locale = this.locale;
14410
+ const t = this.t;
14411
+ const accessibleLabel = t('Style');
14412
+ // -- Group label ---------------------------------------------
14413
+ const borderRowLabel = new LabelView(locale);
14414
+ borderRowLabel.text = t('Border');
14415
+ // -- Style ---------------------------------------------------
14416
+ const styleLabels = getBorderStyleLabels(t);
14417
+ const borderStyleDropdown = new LabeledFieldView(locale, createLabeledDropdown);
14418
+ borderStyleDropdown.set({
14419
+ label: accessibleLabel,
14420
+ class: 'ck-table-form__border-style'
14421
+ });
14422
+ borderStyleDropdown.fieldView.buttonView.set({
14423
+ ariaLabel: accessibleLabel,
14424
+ ariaLabelledBy: undefined,
14425
+ isOn: false,
14426
+ withText: true,
14427
+ tooltip: accessibleLabel
14428
+ });
14429
+ borderStyleDropdown.fieldView.buttonView.bind('label').to(this, 'borderStyle', (value)=>{
14430
+ return styleLabels[value ? value : 'none'];
14431
+ });
14432
+ borderStyleDropdown.fieldView.on('execute', (evt)=>{
14433
+ this.borderStyle = evt.source._borderStyleValue;
14434
+ });
14435
+ borderStyleDropdown.bind('isEmpty').to(this, 'borderStyle', (value)=>!value);
14436
+ addListToDropdown(borderStyleDropdown.fieldView, getBorderStyleDefinitions(this, defaultBorder.style), {
14437
+ role: 'menu',
14438
+ ariaLabel: accessibleLabel
14439
+ });
14440
+ // -- Width ---------------------------------------------------
14441
+ const borderWidthInput = new LabeledFieldView(locale, createLabeledInputText);
14442
+ borderWidthInput.set({
14443
+ label: t('Width'),
14444
+ class: 'ck-table-form__border-width'
14445
+ });
14446
+ borderWidthInput.fieldView.bind('value').to(this, 'borderWidth');
14447
+ borderWidthInput.bind('isEnabled').to(this, 'borderStyle', isBorderStyleSet$1);
14448
+ borderWidthInput.fieldView.on('input', ()=>{
14449
+ this.borderWidth = borderWidthInput.fieldView.element.value;
14450
+ });
14451
+ // -- Color ---------------------------------------------------
14452
+ const borderColorInput = new LabeledFieldView(locale, colorInputCreator);
14453
+ borderColorInput.set({
14454
+ label: t('Color'),
14455
+ class: 'ck-table-form__border-color'
14456
+ });
14457
+ borderColorInput.fieldView.bind('value').to(this, 'borderColor');
14458
+ borderColorInput.bind('isEnabled').to(this, 'borderStyle', isBorderStyleSet$1);
14459
+ borderColorInput.fieldView.on('input', ()=>{
14460
+ this.borderColor = borderColorInput.fieldView.value;
14461
+ });
14462
+ // Reset the border color and width fields depending on the `border-style` value.
14463
+ this.on('change:borderStyle', (evt, name, newValue, oldValue)=>{
14464
+ // When removing the border (`border-style:none`), clear the remaining `border-*` properties.
14465
+ // See: https://github.com/ckeditor/ckeditor5/issues/6227.
14466
+ if (!isBorderStyleSet$1(newValue)) {
14467
+ this.borderColor = '';
14468
+ this.borderWidth = '';
14469
+ }
14470
+ // When setting the `border-style` from `none`, set the default `border-color` and `border-width` properties.
14471
+ if (!isBorderStyleSet$1(oldValue)) {
14472
+ this.borderColor = defaultBorder.color;
14473
+ this.borderWidth = defaultBorder.width;
14474
+ }
14475
+ });
14476
+ return {
14477
+ borderRowLabel,
14478
+ borderStyleDropdown,
14479
+ borderColorInput,
14480
+ borderWidthInput
14481
+ };
14482
+ }
14483
+ /**
14484
+ * Creates the following form fields:
14485
+ *
14486
+ * * {@link #backgroundInput}.
14487
+ */ _createBackgroundFields() {
14488
+ const locale = this.locale;
14489
+ const t = this.t;
14490
+ // -- Group label ---------------------------------------------
14491
+ const backgroundRowLabel = new LabelView(locale);
14492
+ backgroundRowLabel.text = t('Background');
14493
+ // -- Background color input -----------------------------------
14494
+ const backgroundInputCreator = getLabeledColorInputCreator({
14495
+ colorConfig: this.options.backgroundColors,
14496
+ columns: 5,
14497
+ defaultColorValue: this.options.defaultTableProperties.backgroundColor,
14498
+ colorPickerConfig: this.options.colorPickerConfig
14499
+ });
14500
+ const backgroundInput = new LabeledFieldView(locale, backgroundInputCreator);
14501
+ backgroundInput.set({
14502
+ label: t('Color'),
14503
+ class: 'ck-table-properties-form__background'
14504
+ });
14505
+ backgroundInput.fieldView.bind('value').to(this, 'backgroundColor');
14506
+ backgroundInput.fieldView.on('input', ()=>{
14507
+ this.backgroundColor = backgroundInput.fieldView.value;
14508
+ });
14509
+ return {
14510
+ backgroundRowLabel,
14511
+ backgroundInput
14512
+ };
14513
+ }
14514
+ /**
14515
+ * Creates the following form fields:
14516
+ *
14517
+ * * {@link #widthInput},
14518
+ * * {@link #heightInput}.
14519
+ */ _createDimensionFields() {
14520
+ const locale = this.locale;
14521
+ const t = this.t;
14522
+ // -- Label ---------------------------------------------------
14523
+ const dimensionsLabel = new LabelView(locale);
14524
+ dimensionsLabel.text = t('Dimensions');
14525
+ // -- Width ---------------------------------------------------
14526
+ const widthInput = new LabeledFieldView(locale, createLabeledInputText);
14527
+ widthInput.set({
14528
+ label: t('Width'),
14529
+ class: 'ck-table-form__dimensions-row__width'
14530
+ });
14531
+ widthInput.fieldView.bind('value').to(this, 'width');
14532
+ widthInput.fieldView.on('input', ()=>{
14533
+ this.width = widthInput.fieldView.element.value;
14534
+ });
14535
+ // -- Operator ---------------------------------------------------
14536
+ const operatorLabel = new View(locale);
14537
+ operatorLabel.setTemplate({
14538
+ tag: 'span',
14539
+ attributes: {
14540
+ class: [
14541
+ 'ck-table-form__dimension-operator'
14542
+ ]
14543
+ },
14544
+ children: [
14545
+ {
14546
+ text: '×'
14547
+ }
14548
+ ]
14549
+ });
14550
+ // -- Height ---------------------------------------------------
14551
+ const heightInput = new LabeledFieldView(locale, createLabeledInputText);
14552
+ heightInput.set({
14553
+ label: t('Height'),
14554
+ class: 'ck-table-form__dimensions-row__height'
14555
+ });
14556
+ heightInput.fieldView.bind('value').to(this, 'height');
14557
+ heightInput.fieldView.on('input', ()=>{
14558
+ this.height = heightInput.fieldView.element.value;
14559
+ });
14560
+ return {
14561
+ dimensionsLabel,
14562
+ widthInput,
14563
+ operatorLabel,
14564
+ heightInput
14565
+ };
14566
+ }
14567
+ /**
14568
+ * Creates the following form fields:
14569
+ *
14570
+ * * {@link #alignmentToolbar}.
14571
+ */ _createAlignmentFields() {
14572
+ const locale = this.locale;
14573
+ const t = this.t;
14574
+ // -- Label ---------------------------------------------------
14575
+ const alignmentLabel = new LabelView(locale);
14576
+ alignmentLabel.text = t('Table Alignment');
14577
+ // -- Toolbar ---------------------------------------------------
14578
+ const alignmentToolbar = new ToolbarView(locale);
14579
+ alignmentToolbar.set({
14580
+ role: 'radiogroup',
14581
+ isCompact: true,
14582
+ ariaLabel: t('Table alignment toolbar')
14583
+ });
14584
+ fillToolbar({
14585
+ view: this,
14586
+ icons: {
14587
+ left: IconObjectInlineLeft,
14588
+ center: IconObjectCenter,
14589
+ right: IconObjectInlineRight,
14590
+ blockLeft: IconObjectLeft,
14591
+ blockRight: IconObjectRight
14592
+ },
14593
+ toolbar: alignmentToolbar,
14594
+ labels: this._alignmentLabels,
14595
+ propertyName: 'alignment',
14596
+ defaultValue: this.options.defaultTableProperties.alignment
14597
+ });
14598
+ return {
14599
+ alignmentLabel,
14600
+ alignmentToolbar
14601
+ };
14602
+ }
14603
+ /**
14604
+ * Creates the following form controls:
14605
+ *
14606
+ * * {@link #saveButtonView},
14607
+ * * {@link #cancelButtonView}.
14608
+ */ _createActionButtons() {
14609
+ const locale = this.locale;
14610
+ const t = this.t;
14611
+ const saveButtonView = new ButtonView(locale);
14612
+ const cancelButtonView = new ButtonView(locale);
14613
+ const fieldsThatShouldValidateToSave = [
14614
+ this.borderWidthInput,
14615
+ this.borderColorInput,
14616
+ this.backgroundInput,
14617
+ this.widthInput,
14618
+ this.heightInput
14619
+ ];
14620
+ saveButtonView.set({
14621
+ label: t('Save'),
14622
+ class: 'ck-button-action',
14623
+ type: 'submit',
14624
+ withText: true
14625
+ });
14626
+ saveButtonView.bind('isEnabled').toMany(fieldsThatShouldValidateToSave, 'errorText', (...errorTexts)=>{
14627
+ return errorTexts.every((errorText)=>!errorText);
14628
+ });
14629
+ cancelButtonView.set({
14630
+ label: t('Cancel'),
14631
+ withText: true
14632
+ });
14633
+ cancelButtonView.delegate('execute').to(this, 'cancel');
14634
+ return {
14635
+ saveButtonView,
14636
+ cancelButtonView
14637
+ };
14638
+ }
14639
+ /**
14640
+ * Creates a back button view that cancels the form.
14641
+ */ _createBackButton() {
14642
+ const t = this.locale.t;
14643
+ const backButton = new ButtonView(this.locale);
14644
+ backButton.set({
14645
+ class: 'ck-button-back',
14646
+ label: t('Back'),
14647
+ icon: IconPreviousArrow,
14648
+ tooltip: true
14649
+ });
14650
+ backButton.delegate('execute').to(this, 'cancel');
14651
+ return backButton;
14652
+ }
14653
+ /**
14654
+ * Provides localized labels for {@link #alignmentToolbar} buttons.
14655
+ */ get _alignmentLabels() {
14656
+ const locale = this.locale;
14657
+ const t = this.t;
14658
+ const blockLeft = t('Align table to the left with no text wrapping');
14659
+ const blockRight = t('Align table to the right with no text wrapping');
14660
+ const left = t('Align table to the left with text wrapping');
14661
+ const center = t('Center table with no text wrapping');
14662
+ const right = t('Align table to the right with text wrapping');
14663
+ // Returns object with a proper order of labels.
14664
+ if (locale.uiLanguageDirection === 'rtl') {
14665
+ return {
14666
+ right,
14667
+ left,
14668
+ blockRight,
14669
+ center,
14670
+ blockLeft
14671
+ };
14672
+ }
14673
+ return {
14674
+ blockLeft,
14675
+ center,
14676
+ blockRight,
14677
+ left,
14678
+ right
14679
+ };
14680
+ }
14681
+ }
14682
+ function isBorderStyleSet$1(value) {
14683
+ return value !== 'none';
14684
+ }
14685
+
14686
+ const ERROR_TEXT_TIMEOUT$1 = 500;
14687
+ // Map of view properties and related commands.
14688
+ const propertyToCommandMap$1 = {
14689
+ borderStyle: 'tableBorderStyle',
14690
+ borderColor: 'tableBorderColor',
14691
+ borderWidth: 'tableBorderWidth',
14692
+ backgroundColor: 'tableBackgroundColor',
14693
+ width: 'tableWidth',
14694
+ height: 'tableHeight',
14695
+ alignment: 'tableAlignment'
14696
+ };
14697
+ /**
14698
+ * The table properties UI plugin. It introduces the `'tableProperties'` button
14699
+ * that opens a form allowing to specify visual styling of an entire table.
14700
+ *
14701
+ * It uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.
14702
+ */ class TablePropertiesUIExperimental extends Plugin {
14703
+ /**
14704
+ * The default table properties.
14705
+ */ _defaultContentTableProperties;
14706
+ /**
14707
+ * The default layout table properties.
14708
+ */ _defaultLayoutTableProperties;
14709
+ /**
14710
+ * The contextual balloon plugin instance.
14711
+ */ _balloon;
14712
+ /**
14713
+ * The properties form view displayed inside the balloon.
14714
+ */ view = null;
14715
+ /**
14716
+ * The properties form view displayed inside the balloon (content table).
14717
+ */ _viewWithContentTableDefaults = null;
14718
+ /**
14719
+ * The properties form view displayed inside the balloon (layout table).
14720
+ */ _viewWithLayoutTableDefaults = null;
14721
+ /**
14722
+ * The batch used to undo all changes made by the form (which are live, as the user types)
14723
+ * when "Cancel" was pressed. Each time the view is shown, a new batch is created.
14724
+ */ _undoStepBatch;
14725
+ /**
14726
+ * Flag used to indicate whether view is ready to execute update commands
14727
+ * (it finished loading initial data).
14728
+ */ _isReady;
14729
+ /**
14730
+ * @inheritDoc
14731
+ */ static get requires() {
14732
+ return [
14733
+ ContextualBalloon
14734
+ ];
14735
+ }
14736
+ /**
14737
+ * @inheritDoc
14738
+ */ static get pluginName() {
14739
+ return 'TablePropertiesUIExperimental';
14740
+ }
14741
+ /**
14742
+ * @inheritDoc
14743
+ */ static get isOfficialPlugin() {
14744
+ return true;
14745
+ }
14746
+ /**
14747
+ * @inheritDoc
14748
+ */ constructor(editor){
14749
+ super(editor);
14750
+ editor.config.define('table.tableProperties', {
14751
+ borderColors: defaultColors,
14752
+ backgroundColors: defaultColors
14753
+ });
14754
+ }
14755
+ /**
14756
+ * @inheritDoc
14757
+ */ init() {
14758
+ const editor = this.editor;
14759
+ this._defaultContentTableProperties = getNormalizedDefaultTableProperties(editor.config.get('table.tableProperties.defaultProperties'), {
14760
+ includeAlignmentProperty: true
14761
+ });
14762
+ this._defaultLayoutTableProperties = getNormalizedDefaultProperties();
14763
+ this._balloon = editor.plugins.get(ContextualBalloon);
14764
+ editor.ui.componentFactory.add('tableProperties', ()=>this._createTablePropertiesButton());
14765
+ }
14766
+ /**
14767
+ * Creates the table properties button.
14768
+ *
14769
+ * @internal
14770
+ */ _createTablePropertiesButton() {
14771
+ const editor = this.editor;
14772
+ const t = editor.t;
14773
+ const view = new ButtonView(editor.locale);
14774
+ view.set({
14775
+ label: t('Table properties'),
14776
+ icon: IconTableProperties,
14777
+ tooltip: true
14778
+ });
14779
+ this.listenTo(view, 'execute', ()=>this._showView());
14780
+ const commands = Object.values(propertyToCommandMap$1).map((commandName)=>editor.commands.get(commandName));
14781
+ view.bind('isEnabled').toMany(commands, 'isEnabled', (...areEnabled)=>areEnabled.some((isCommandEnabled)=>isCommandEnabled));
14782
+ return view;
14783
+ }
14784
+ /**
14785
+ * @inheritDoc
14786
+ */ destroy() {
14787
+ super.destroy();
14788
+ // Destroy created UI components as they are not automatically destroyed.
14789
+ // See https://github.com/ckeditor/ckeditor5/issues/1341.
14790
+ if (this.view) {
14791
+ this.view.destroy();
14792
+ }
14793
+ }
14794
+ /**
14795
+ * Creates the {@link module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView} instance.
14796
+ *
14797
+ * @returns The table properties form view instance.
14798
+ */ _createPropertiesView(defaultTableProperties) {
14799
+ const editor = this.editor;
14800
+ const config = editor.config.get('table.tableProperties');
14801
+ const borderColorsConfig = normalizeColorOptions(config.borderColors);
14802
+ const localizedBorderColors = getLocalizedColorOptions(editor.locale, borderColorsConfig);
14803
+ const backgroundColorsConfig = normalizeColorOptions(config.backgroundColors);
14804
+ const localizedBackgroundColors = getLocalizedColorOptions(editor.locale, backgroundColorsConfig);
14805
+ const hasColorPicker = config.colorPicker !== false;
14806
+ const view = new TablePropertiesViewExperimental(editor.locale, {
14807
+ borderColors: localizedBorderColors,
14808
+ backgroundColors: localizedBackgroundColors,
14809
+ defaultTableProperties,
14810
+ colorPickerConfig: hasColorPicker ? config.colorPicker || {} : false
14811
+ });
14812
+ const t = editor.t;
14813
+ // Render the view so its #element is available for the clickOutsideHandler.
14814
+ view.render();
14815
+ this.listenTo(view, 'submit', ()=>{
14816
+ this._hideView();
14817
+ });
14818
+ this.listenTo(view, 'cancel', ()=>{
14819
+ // https://github.com/ckeditor/ckeditor5/issues/6180
14820
+ if (this._undoStepBatch.operations.length) {
14821
+ editor.execute('undo', this._undoStepBatch);
14822
+ }
14823
+ this._hideView();
14824
+ });
14825
+ // Close the balloon on Esc key press.
14826
+ view.keystrokes.set('Esc', (data, cancel)=>{
14827
+ this._hideView();
14828
+ cancel();
14829
+ });
14830
+ // Close on click outside of balloon panel element.
14831
+ clickOutsideHandler({
14832
+ emitter: view,
14833
+ activator: ()=>this._isViewInBalloon,
14834
+ contextElements: [
14835
+ this._balloon.view.element
14836
+ ],
14837
+ callback: ()=>this._hideView()
14838
+ });
14839
+ const colorErrorText = getLocalizedColorErrorText(t);
14840
+ const lengthErrorText = getLocalizedLengthErrorText(t);
14841
+ // Create the "UI -> editor data" binding.
14842
+ // These listeners update the editor data (via table commands) when any observable
14843
+ // property of the view has changed. They also validate the value and display errors in the UI
14844
+ // when necessary. This makes the view live, which means the changes are
14845
+ // visible in the editing as soon as the user types or changes fields' values.
14846
+ view.on('change:borderStyle', this._getPropertyChangeCallback('tableBorderStyle'));
14847
+ view.on('change:borderColor', this._getValidatedPropertyChangeCallback({
14848
+ viewField: view.borderColorInput,
14849
+ commandName: 'tableBorderColor',
14850
+ errorText: colorErrorText,
14851
+ validator: colorFieldValidator
14852
+ }));
14853
+ view.on('change:borderWidth', this._getValidatedPropertyChangeCallback({
14854
+ viewField: view.borderWidthInput,
14855
+ commandName: 'tableBorderWidth',
14856
+ errorText: lengthErrorText,
14857
+ validator: lineWidthFieldValidator
14858
+ }));
14859
+ view.on('change:backgroundColor', this._getValidatedPropertyChangeCallback({
14860
+ viewField: view.backgroundInput,
14861
+ commandName: 'tableBackgroundColor',
14862
+ errorText: colorErrorText,
14863
+ validator: colorFieldValidator
14864
+ }));
14865
+ view.on('change:width', this._getValidatedPropertyChangeCallback({
14866
+ viewField: view.widthInput,
14867
+ commandName: 'tableWidth',
14868
+ errorText: lengthErrorText,
14869
+ validator: lengthFieldValidator
14870
+ }));
14871
+ view.on('change:height', this._getValidatedPropertyChangeCallback({
14872
+ viewField: view.heightInput,
14873
+ commandName: 'tableHeight',
14874
+ errorText: lengthErrorText,
14875
+ validator: lengthFieldValidator
14876
+ }));
14877
+ view.on('change:alignment', this._getPropertyChangeCallback('tableAlignment'));
14878
+ return view;
14879
+ }
14880
+ /**
14881
+ * In this method the "editor data -> UI" binding is happening.
14882
+ *
14883
+ * When executed, this method obtains selected table property values from various table commands
14884
+ * and passes them to the {@link #view}.
14885
+ *
14886
+ * This way, the UI stays up–to–date with the editor data.
14887
+ */ _fillViewFormFromCommandValues() {
14888
+ const commands = this.editor.commands;
14889
+ const borderStyleCommand = commands.get('tableBorderStyle');
14890
+ Object.entries(propertyToCommandMap$1).map(([property, commandName])=>{
14891
+ const propertyKey = property;
14892
+ const defaultValue = this.view === this._viewWithContentTableDefaults ? this._defaultContentTableProperties[propertyKey] || '' : this._defaultLayoutTableProperties[propertyKey] || '';
14893
+ return [
14894
+ propertyKey,
14895
+ commands.get(commandName).value || defaultValue
14896
+ ];
14897
+ }).forEach(([property, value])=>{
14898
+ // Do not set the `border-color` and `border-width` fields if `border-style:none`.
14899
+ if ((property === 'borderColor' || property === 'borderWidth') && borderStyleCommand.value === 'none') {
14900
+ return;
14901
+ }
14902
+ this.view.set(property, value);
14903
+ });
14904
+ this._isReady = true;
14905
+ }
14906
+ /**
14907
+ * Shows the {@link #view} in the {@link #_balloon}.
14908
+ *
14909
+ * **Note**: Each time a view is shown, the new {@link #_undoStepBatch} is created that contains
14910
+ * all changes made to the document when the view is visible, allowing a single undo step
14911
+ * for all of them.
14912
+ */ _showView() {
14913
+ const editor = this.editor;
14914
+ const viewTable = getSelectionAffectedTableWidget(editor.editing.view.document.selection);
14915
+ const modelTable = viewTable && editor.editing.mapper.toModelElement(viewTable);
14916
+ const useDefaults = !modelTable || modelTable.getAttribute('tableType') !== 'layout';
14917
+ if (useDefaults && !this._viewWithContentTableDefaults) {
14918
+ this._viewWithContentTableDefaults = this._createPropertiesView(this._defaultContentTableProperties);
14919
+ } else if (!useDefaults && !this._viewWithLayoutTableDefaults) {
14920
+ this._viewWithLayoutTableDefaults = this._createPropertiesView(this._defaultLayoutTableProperties);
14921
+ }
14922
+ this.view = useDefaults ? this._viewWithContentTableDefaults : this._viewWithLayoutTableDefaults;
14923
+ this.listenTo(editor.ui, 'update', ()=>{
14924
+ this._updateView();
14925
+ });
14926
+ // Update the view with the model values.
14927
+ this._fillViewFormFromCommandValues();
14928
+ this._balloon.add({
14929
+ view: this.view,
14930
+ position: getBalloonTablePositionData(editor)
14931
+ });
14932
+ // Create a new batch. Clicking "Cancel" will undo this batch.
14933
+ this._undoStepBatch = editor.model.createBatch();
14934
+ // Basic a11y.
14935
+ this.view.focus();
14936
+ }
14937
+ /**
14938
+ * Removes the {@link #view} from the {@link #_balloon}.
14939
+ */ _hideView() {
14940
+ const editor = this.editor;
14941
+ this.stopListening(editor.ui, 'update');
14942
+ this._isReady = false;
14943
+ // Blur any input element before removing it from DOM to prevent issues in some browsers.
14944
+ // See https://github.com/ckeditor/ckeditor5/issues/1501.
14945
+ this.view.saveButtonView.focus();
14946
+ this._balloon.remove(this.view);
14947
+ // Make sure the focus is not lost in the process by putting it directly
14948
+ // into the editing view.
14949
+ this.editor.editing.view.focus();
14950
+ }
14951
+ /**
14952
+ * Repositions the {@link #_balloon} or hides the {@link #view} if a table is no longer selected.
14953
+ */ _updateView() {
14954
+ const editor = this.editor;
14955
+ const viewDocument = editor.editing.view.document;
14956
+ if (!getSelectionAffectedTableWidget(viewDocument.selection)) {
14957
+ this._hideView();
14958
+ } else if (this._isViewVisible) {
14959
+ repositionContextualBalloon(editor, 'table');
14960
+ }
14961
+ }
14962
+ /**
14963
+ * Returns `true` when the {@link #view} is the visible in the {@link #_balloon}.
14964
+ */ get _isViewVisible() {
14965
+ return !!this.view && this._balloon.visibleView === this.view;
14966
+ }
14967
+ /**
14968
+ * Returns `true` when the {@link #view} is in the {@link #_balloon}.
14969
+ */ get _isViewInBalloon() {
14970
+ return !!this.view && this._balloon.hasView(this.view);
14971
+ }
14972
+ /**
14973
+ * Creates a callback that when executed upon {@link #view view's} property change
14974
+ * executes a related editor command with the new property value.
14975
+ *
14976
+ * If new value will be set to the default value, the command will not be executed.
14977
+ *
14978
+ * @param commandName The command that will be executed.
14979
+ */ _getPropertyChangeCallback(commandName) {
14980
+ return (evt, propertyName, newValue)=>{
14981
+ // Do not execute the command on initial call (opening the table properties view).
14982
+ if (!this._isReady) {
14983
+ return;
14984
+ }
14985
+ this.editor.execute(commandName, {
14986
+ value: newValue,
14987
+ batch: this._undoStepBatch
14988
+ });
14989
+ };
14990
+ }
14991
+ /**
14992
+ * Creates a callback that when executed upon {@link #view view's} property change:
14993
+ * * executes a related editor command with the new property value if the value is valid,
14994
+ * * or sets the error text next to the invalid field, if the value did not pass the validation.
14995
+ */ _getValidatedPropertyChangeCallback(options) {
14996
+ const { commandName, viewField, validator, errorText } = options;
14997
+ const setErrorTextDebounced = debounce(()=>{
14998
+ viewField.errorText = errorText;
14999
+ }, ERROR_TEXT_TIMEOUT$1);
15000
+ return (evt, propertyName, newValue)=>{
15001
+ setErrorTextDebounced.cancel();
15002
+ // Do not execute the command on initial call (opening the table properties view).
15003
+ if (!this._isReady) {
15004
+ return;
15005
+ }
15006
+ if (validator(newValue)) {
15007
+ this.editor.execute(commandName, {
15008
+ value: newValue,
15009
+ batch: this._undoStepBatch
15010
+ });
15011
+ viewField.errorText = null;
15012
+ } else {
15013
+ setErrorTextDebounced();
15014
+ }
15015
+ };
15016
+ }
15017
+ }
15018
+
15019
+ /**
15020
+ * The class representing a table cell properties form, allowing users to customize
15021
+ * certain style aspects of a table cell, for instance, border, padding, text alignment, etc..
15022
+ */ class TableCellPropertiesViewExperimental extends View {
15023
+ /**
15024
+ * Options passed to the view. See {@link #constructor} to learn more.
15025
+ */ options;
15026
+ /**
15027
+ * Tracks information about the DOM focus in the form.
15028
+ */ focusTracker;
15029
+ /**
15030
+ * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.
15031
+ */ keystrokes;
15032
+ /**
15033
+ * A collection of child views in the form.
15034
+ */ children;
15035
+ /**
15036
+ * A dropdown that allows selecting the style of the table cell border.
15037
+ */ borderStyleDropdown;
15038
+ /**
15039
+ * An input that allows specifying the width of the table cell border.
15040
+ */ borderWidthInput;
15041
+ /**
15042
+ * An input that allows specifying the color of the table cell border.
15043
+ */ borderColorInput;
15044
+ /**
15045
+ * An input that allows specifying the table cell background color.
15046
+ */ backgroundInput;
15047
+ /**
15048
+ * A dropdown that allows selecting the type of the table cell (data or header).
15049
+ */ cellTypeDropdown;
15050
+ /**
15051
+ * An input that allows specifying the table cell padding.
15052
+ */ paddingInput;
15053
+ /**
15054
+ * An input that allows specifying the table cell width.
15055
+ */ widthInput;
15056
+ /**
15057
+ * An input that allows specifying the table cell height.
15058
+ */ heightInput;
15059
+ /**
15060
+ * A toolbar with buttons that allow changing the horizontal text alignment in a table cell.
15061
+ */ horizontalAlignmentToolbar;
15062
+ /**
15063
+ * A toolbar with buttons that allow changing the vertical text alignment in a table cell.
15064
+ */ verticalAlignmentToolbar;
15065
+ /**
15066
+ * The "Save" button view.
15067
+ */ saveButtonView;
15068
+ /**
15069
+ * The "Cancel" button view.
15070
+ */ cancelButtonView;
15071
+ /**
15072
+ * The "Back" button view.
15073
+ */ backButtonView;
15074
+ /**
15075
+ * A collection of views that can be focused in the form.
15076
+ */ _focusables;
15077
+ /**
15078
+ * Helps cycling over {@link #_focusables} in the form.
15079
+ */ _focusCycler;
15080
+ /**
15081
+ * @param locale The {@link module:core/editor/editor~Editor#locale} instance.
15082
+ * @param options Additional configuration of the view.
15083
+ * @param options.borderColors A configuration of the border color palette used by the
15084
+ * {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView#borderColorInput}.
15085
+ * @param options.backgroundColors A configuration of the background color palette used by the
15086
+ * {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView#backgroundInput}.
15087
+ * @param options.defaultTableCellProperties The default table cell properties.
15088
+ * @param options.isTableCellTypeSupported A flag indicating whether the table cell type is supported.
15089
+ */ constructor(locale, options){
15090
+ super(locale);
15091
+ this.set({
15092
+ borderStyle: '',
15093
+ borderWidth: '',
15094
+ borderColor: '',
15095
+ padding: '',
15096
+ backgroundColor: '',
15097
+ width: '',
15098
+ height: '',
15099
+ horizontalAlignment: '',
15100
+ verticalAlignment: '',
15101
+ cellType: ''
15102
+ });
15103
+ this.options = options;
15104
+ const { borderStyleDropdown, borderWidthInput, borderColorInput, borderRowLabel } = this._createBorderFields();
15105
+ const { backgroundRowLabel, backgroundInput } = this._createBackgroundFields();
15106
+ const { cellTypeRowLabel, cellTypeDropdown } = this._createCellTypeField();
15107
+ const { widthInput, operatorLabel, heightInput, dimensionsLabel } = this._createDimensionFields();
15108
+ const { horizontalAlignmentToolbar, verticalAlignmentToolbar, alignmentLabel } = this._createAlignmentFields();
15109
+ this.focusTracker = new FocusTracker();
15110
+ this.keystrokes = new KeystrokeHandler();
15111
+ this.children = this.createCollection();
15112
+ this.borderStyleDropdown = borderStyleDropdown;
15113
+ this.borderWidthInput = borderWidthInput;
15114
+ this.borderColorInput = borderColorInput;
15115
+ this.backgroundInput = backgroundInput;
15116
+ this.cellTypeDropdown = cellTypeDropdown;
15117
+ this.paddingInput = this._createPaddingField();
15118
+ this.widthInput = widthInput;
15119
+ this.heightInput = heightInput;
15120
+ this.horizontalAlignmentToolbar = horizontalAlignmentToolbar;
15121
+ this.verticalAlignmentToolbar = verticalAlignmentToolbar;
15122
+ // Defer creating to make sure other fields are present and the Save button can
15123
+ // bind its #isEnabled to their error messages so there's no way to save unless all
15124
+ // fields are valid.
15125
+ const { saveButtonView, cancelButtonView } = this._createActionButtons();
15126
+ this.saveButtonView = saveButtonView;
15127
+ this.cancelButtonView = cancelButtonView;
15128
+ this.backButtonView = this._createBackButton();
15129
+ this._focusables = new ViewCollection();
15130
+ this._focusCycler = new FocusCycler({
15131
+ focusables: this._focusables,
15132
+ focusTracker: this.focusTracker,
15133
+ keystrokeHandler: this.keystrokes,
15134
+ actions: {
15135
+ // Navigate form fields backwards using the Shift + Tab keystroke.
15136
+ focusPrevious: 'shift + tab',
15137
+ // Navigate form fields forwards using the Tab key.
15138
+ focusNext: 'tab'
15139
+ }
15140
+ });
15141
+ // Form header.
15142
+ const header = new FormHeaderView(locale, {
15143
+ label: this.t('Cell properties')
15144
+ });
15145
+ header.children.add(this.backButtonView, 0);
15146
+ this.children.add(header);
15147
+ // Border row.
15148
+ this.children.add(new FormRowView(locale, {
15149
+ labelView: borderRowLabel,
15150
+ children: this.options.isTableCellTypeSupported ? [
15151
+ borderRowLabel,
15152
+ borderStyleDropdown,
15153
+ borderWidthInput,
15154
+ borderColorInput
15155
+ ] : [
15156
+ borderRowLabel,
15157
+ borderStyleDropdown,
15158
+ borderColorInput,
15159
+ borderWidthInput
15160
+ ],
15161
+ class: `ck-table-form__border-row${this.options.isTableCellTypeSupported ? ' ck-table-form__border-row_experimental' : ''}`
15162
+ }));
15163
+ // Background and cell type.
15164
+ this.children.add(new FormRowView(locale, {
15165
+ children: this.options.isTableCellTypeSupported ? [
15166
+ new FormRowView(locale, {
15167
+ labelView: cellTypeRowLabel,
15168
+ children: [
15169
+ cellTypeRowLabel,
15170
+ cellTypeDropdown
15171
+ ],
15172
+ class: 'ck-table-form__cell-type-row'
15173
+ }),
15174
+ new FormRowView(locale, {
15175
+ labelView: backgroundRowLabel,
15176
+ children: [
15177
+ backgroundRowLabel,
15178
+ backgroundInput
15179
+ ],
15180
+ class: 'ck-table-form__background-row'
15181
+ })
15182
+ ] : [
15183
+ new FormRowView(locale, {
15184
+ labelView: backgroundRowLabel,
15185
+ children: [
15186
+ backgroundRowLabel,
15187
+ backgroundInput
15188
+ ],
15189
+ class: 'ck-table-form__background-row'
15190
+ })
15191
+ ]
15192
+ }));
15193
+ // Dimensions row and padding.
15194
+ this.children.add(new FormRowView(locale, {
15195
+ children: [
15196
+ // Dimensions row.
15197
+ new FormRowView(locale, {
15198
+ labelView: dimensionsLabel,
15199
+ children: [
15200
+ dimensionsLabel,
15201
+ widthInput,
15202
+ operatorLabel,
15203
+ heightInput
15204
+ ],
15205
+ class: 'ck-table-form__dimensions-row'
15206
+ }),
15207
+ // Padding row.
15208
+ new FormRowView(locale, {
15209
+ children: [
15210
+ this.paddingInput
15211
+ ],
15212
+ class: 'ck-table-cell-properties-form__padding-row'
15213
+ })
15214
+ ]
15215
+ }));
15216
+ // Text alignment row.
15217
+ this.children.add(new FormRowView(locale, {
15218
+ labelView: alignmentLabel,
15219
+ children: [
15220
+ alignmentLabel,
15221
+ horizontalAlignmentToolbar,
15222
+ verticalAlignmentToolbar
15223
+ ],
15224
+ class: 'ck-table-cell-properties-form__alignment-row'
15225
+ }));
15226
+ // Action row.
15227
+ this.children.add(new FormRowView(locale, {
15228
+ children: [
15229
+ this.cancelButtonView,
15230
+ this.saveButtonView
15231
+ ],
15232
+ class: 'ck-table-form__action-row'
15233
+ }));
15234
+ this.setTemplate({
15235
+ tag: 'form',
15236
+ attributes: {
15237
+ class: [
15238
+ 'ck',
15239
+ 'ck-form',
15240
+ 'ck-table-form',
15241
+ 'ck-table-cell-properties-form',
15242
+ 'ck-table-cell-properties-form_experimental',
15243
+ this.options.isTableCellTypeSupported ? 'ck-table-cell-properties-form_experimental-no-cell-type' : ''
15244
+ ],
15245
+ // https://github.com/ckeditor/ckeditor5-link/issues/90
15246
+ tabindex: '-1'
15247
+ },
15248
+ children: this.children
15249
+ });
15250
+ }
15251
+ /**
15252
+ * @inheritDoc
15253
+ */ render() {
15254
+ super.render();
15255
+ // Enable the "submit" event for this view. It can be triggered by the #saveButtonView
15256
+ // which is of the "submit" DOM "type".
15257
+ submitHandler({
15258
+ view: this
15259
+ });
15260
+ // Maintain continuous focus cycling over views that have focusable children and focus cyclers themselves.
15261
+ [
15262
+ this.borderColorInput,
15263
+ this.backgroundInput
15264
+ ].forEach((view)=>{
15265
+ this._focusCycler.chain(view.fieldView.focusCycler);
15266
+ });
15267
+ [
15268
+ this.borderStyleDropdown,
15269
+ this.borderColorInput,
15270
+ this.borderWidthInput,
15271
+ this.cellTypeDropdown,
15272
+ this.backgroundInput,
15273
+ this.widthInput,
15274
+ this.heightInput,
15275
+ this.paddingInput,
15276
+ this.horizontalAlignmentToolbar,
15277
+ this.verticalAlignmentToolbar,
15278
+ this.cancelButtonView,
15279
+ this.saveButtonView,
15280
+ this.backButtonView
15281
+ ].forEach((view)=>{
15282
+ // Register the view as focusable.
15283
+ this._focusables.add(view);
15284
+ // Register the view in the focus tracker.
15285
+ this.focusTracker.add(view.element);
15286
+ });
15287
+ // Mainly for closing using "Esc" and navigation using "Tab".
15288
+ this.keystrokes.listenTo(this.element);
15289
+ }
15290
+ /**
15291
+ * @inheritDoc
15292
+ */ destroy() {
15293
+ super.destroy();
15294
+ this.focusTracker.destroy();
15295
+ this.keystrokes.destroy();
15296
+ }
15297
+ /**
15298
+ * Focuses the fist focusable field in the form.
15299
+ */ focus() {
15300
+ this._focusCycler.focusFirst();
15301
+ }
15302
+ /**
15303
+ * Creates the following form fields:
15304
+ *
15305
+ * * {@link #borderStyleDropdown},
15306
+ * * {@link #borderWidthInput},
15307
+ * * {@link #borderColorInput}.
15308
+ */ _createBorderFields() {
15309
+ const defaultTableCellProperties = this.options.defaultTableCellProperties;
15310
+ const defaultBorder = {
15311
+ style: defaultTableCellProperties.borderStyle,
15312
+ width: defaultTableCellProperties.borderWidth,
15313
+ color: defaultTableCellProperties.borderColor
15314
+ };
15315
+ const colorInputCreator = getLabeledColorInputCreator({
15316
+ colorConfig: this.options.borderColors,
15317
+ columns: 5,
15318
+ defaultColorValue: defaultBorder.color,
15319
+ colorPickerConfig: this.options.colorPickerConfig
15320
+ });
15321
+ const locale = this.locale;
15322
+ const t = this.t;
15323
+ const accessibleLabel = t('Style');
15324
+ // -- Group label ---------------------------------------------
15325
+ const borderRowLabel = new LabelView(locale);
15326
+ borderRowLabel.text = t('Border');
15327
+ // -- Style ---------------------------------------------------
15328
+ const styleLabels = getBorderStyleLabels(t);
15329
+ const borderStyleDropdown = new LabeledFieldView(locale, createLabeledDropdown);
15330
+ borderStyleDropdown.set({
15331
+ label: accessibleLabel,
15332
+ class: 'ck-table-form__border-style'
15333
+ });
15334
+ borderStyleDropdown.fieldView.buttonView.set({
15335
+ ariaLabel: accessibleLabel,
15336
+ ariaLabelledBy: undefined,
15337
+ isOn: false,
15338
+ withText: true,
15339
+ tooltip: accessibleLabel
15340
+ });
15341
+ borderStyleDropdown.fieldView.buttonView.bind('label').to(this, 'borderStyle', (value)=>{
15342
+ return styleLabels[value ? value : 'none'];
15343
+ });
15344
+ borderStyleDropdown.fieldView.on('execute', (evt)=>{
15345
+ this.borderStyle = evt.source._borderStyleValue;
15346
+ });
15347
+ borderStyleDropdown.bind('isEmpty').to(this, 'borderStyle', (value)=>!value);
15348
+ addListToDropdown(borderStyleDropdown.fieldView, getBorderStyleDefinitions(this, defaultBorder.style), {
15349
+ role: 'menu',
15350
+ ariaLabel: accessibleLabel
15351
+ });
15352
+ // -- Width ---------------------------------------------------
15353
+ const borderWidthInput = new LabeledFieldView(locale, createLabeledInputText);
15354
+ borderWidthInput.set({
15355
+ label: t('Width'),
15356
+ class: 'ck-table-form__border-width'
15357
+ });
15358
+ borderWidthInput.fieldView.bind('value').to(this, 'borderWidth');
15359
+ borderWidthInput.bind('isEnabled').to(this, 'borderStyle', isBorderStyleSet);
15360
+ borderWidthInput.fieldView.on('input', ()=>{
15361
+ this.borderWidth = borderWidthInput.fieldView.element.value;
15362
+ });
15363
+ // -- Color ---------------------------------------------------
15364
+ const borderColorInput = new LabeledFieldView(locale, colorInputCreator);
15365
+ borderColorInput.set({
15366
+ label: t('Color'),
15367
+ class: 'ck-table-form__border-color'
15368
+ });
15369
+ borderColorInput.fieldView.bind('value').to(this, 'borderColor');
15370
+ borderColorInput.bind('isEnabled').to(this, 'borderStyle', isBorderStyleSet);
15371
+ borderColorInput.fieldView.on('input', ()=>{
15372
+ this.borderColor = borderColorInput.fieldView.value;
15373
+ });
15374
+ // Reset the border color and width fields depending on the `border-style` value.
15375
+ this.on('change:borderStyle', (evt, name, newValue, oldValue)=>{
15376
+ // When removing the border (`border-style:none`), clear the remaining `border-*` properties.
15377
+ // See: https://github.com/ckeditor/ckeditor5/issues/6227.
15378
+ if (!isBorderStyleSet(newValue)) {
15379
+ this.borderColor = '';
15380
+ this.borderWidth = '';
15381
+ }
15382
+ // When setting the `border-style` from `none`, set the default `border-color` and `border-width` properties.
15383
+ if (!isBorderStyleSet(oldValue)) {
15384
+ this.borderColor = defaultBorder.color;
15385
+ this.borderWidth = defaultBorder.width;
15386
+ }
15387
+ });
15388
+ return {
15389
+ borderRowLabel,
15390
+ borderStyleDropdown,
15391
+ borderColorInput,
15392
+ borderWidthInput
15393
+ };
15394
+ }
15395
+ /**
15396
+ * Creates the following form fields:
15397
+ *
15398
+ * * {@link #backgroundInput}.
15399
+ */ _createBackgroundFields() {
15400
+ const locale = this.locale;
15401
+ const t = this.t;
15402
+ // -- Group label ---------------------------------------------
15403
+ const backgroundRowLabel = new LabelView(locale);
15404
+ backgroundRowLabel.text = t('Background');
15405
+ // -- Background color input -----------------------------------
15406
+ const colorInputCreator = getLabeledColorInputCreator({
15407
+ colorConfig: this.options.backgroundColors,
15408
+ columns: 5,
15409
+ defaultColorValue: this.options.defaultTableCellProperties.backgroundColor,
15410
+ colorPickerConfig: this.options.colorPickerConfig
15411
+ });
15412
+ const backgroundInput = new LabeledFieldView(locale, colorInputCreator);
15413
+ backgroundInput.set({
15414
+ label: t('Color'),
15415
+ class: 'ck-table-cell-properties-form__background'
15416
+ });
15417
+ backgroundInput.fieldView.bind('value').to(this, 'backgroundColor');
15418
+ backgroundInput.fieldView.on('input', ()=>{
15419
+ this.backgroundColor = backgroundInput.fieldView.value;
15420
+ });
15421
+ return {
15422
+ backgroundRowLabel,
15423
+ backgroundInput
15424
+ };
15425
+ }
15426
+ /**
15427
+ * Create cell type field.
15428
+ *
15429
+ * * {@link #cellTypeDropdown}.
15430
+ *
15431
+ * @internal
15432
+ */ _createCellTypeField() {
15433
+ const locale = this.locale;
15434
+ const t = this.t;
15435
+ const cellTypeRowLabel = new LabelView(locale);
15436
+ cellTypeRowLabel.text = t('Cell type');
15437
+ const cellTypeLabels = this._cellTypeLabels;
15438
+ const cellTypeDropdown = new LabeledFieldView(locale, createLabeledDropdown);
15439
+ cellTypeDropdown.set({
15440
+ label: t('Cell type'),
15441
+ class: 'ck-table-cell-properties-form__cell-type'
15442
+ });
15443
+ cellTypeDropdown.fieldView.buttonView.set({
15444
+ ariaLabel: t('Cell type'),
15445
+ ariaLabelledBy: undefined,
15446
+ isOn: false,
15447
+ withText: true,
15448
+ tooltip: t('Cell type')
15449
+ });
15450
+ cellTypeDropdown.fieldView.buttonView.bind('label').to(this, 'cellType', (value)=>{
15451
+ return cellTypeLabels[value || 'data'];
15452
+ });
15453
+ cellTypeDropdown.fieldView.on('execute', (evt)=>{
15454
+ this.cellType = evt.source._cellTypeValue;
15455
+ });
15456
+ cellTypeDropdown.bind('isEmpty').to(this, 'cellType', (value)=>!value);
15457
+ addListToDropdown(cellTypeDropdown.fieldView, this._getCellTypeDefinitions(), {
15458
+ role: 'menu',
15459
+ ariaLabel: t('Cell type')
15460
+ });
15461
+ return {
15462
+ cellTypeRowLabel,
15463
+ cellTypeDropdown
15464
+ };
15465
+ }
15466
+ /**
15467
+ * Creates the following form fields:
15468
+ *
15469
+ * * {@link #widthInput}.
15470
+ * * {@link #heightInput}.
15471
+ */ _createDimensionFields() {
15472
+ const locale = this.locale;
15473
+ const t = this.t;
15474
+ // -- Label ---------------------------------------------------
15475
+ const dimensionsLabel = new LabelView(locale);
15476
+ dimensionsLabel.text = t('Dimensions');
15477
+ // -- Width ---------------------------------------------------
15478
+ const widthInput = new LabeledFieldView(locale, createLabeledInputText);
15479
+ widthInput.set({
15480
+ label: t('Width'),
15481
+ class: 'ck-table-form__dimensions-row__width'
15482
+ });
15483
+ widthInput.fieldView.bind('value').to(this, 'width');
15484
+ widthInput.fieldView.on('input', ()=>{
15485
+ this.width = widthInput.fieldView.element.value;
15486
+ });
15487
+ // -- Operator ---------------------------------------------------
15488
+ const operatorLabel = new View(locale);
15489
+ operatorLabel.setTemplate({
15490
+ tag: 'span',
15491
+ attributes: {
15492
+ class: [
15493
+ 'ck-table-form__dimension-operator'
15494
+ ]
15495
+ },
15496
+ children: [
15497
+ {
15498
+ text: '×'
15499
+ }
15500
+ ]
15501
+ });
15502
+ // -- Height ---------------------------------------------------
15503
+ const heightInput = new LabeledFieldView(locale, createLabeledInputText);
15504
+ heightInput.set({
15505
+ label: t('Height'),
15506
+ class: 'ck-table-form__dimensions-row__height'
15507
+ });
15508
+ heightInput.fieldView.bind('value').to(this, 'height');
15509
+ heightInput.fieldView.on('input', ()=>{
15510
+ this.height = heightInput.fieldView.element.value;
15511
+ });
15512
+ return {
15513
+ dimensionsLabel,
15514
+ widthInput,
15515
+ operatorLabel,
15516
+ heightInput
15517
+ };
15518
+ }
15519
+ /**
15520
+ * Creates the following form fields:
15521
+ *
15522
+ * * {@link #paddingInput}.
15523
+ */ _createPaddingField() {
15524
+ const locale = this.locale;
15525
+ const t = this.t;
15526
+ const paddingInput = new LabeledFieldView(locale, createLabeledInputText);
15527
+ paddingInput.set({
15528
+ label: t('Padding'),
15529
+ class: 'ck-table-cell-properties-form__padding'
15530
+ });
15531
+ paddingInput.fieldView.bind('value').to(this, 'padding');
15532
+ paddingInput.fieldView.on('input', ()=>{
15533
+ this.padding = paddingInput.fieldView.element.value;
15534
+ });
15535
+ return paddingInput;
15536
+ }
15537
+ /**
15538
+ * Creates the following form fields:
15539
+ *
15540
+ * * {@link #horizontalAlignmentToolbar},
15541
+ * * {@link #verticalAlignmentToolbar}.
15542
+ */ _createAlignmentFields() {
15543
+ const locale = this.locale;
15544
+ const t = this.t;
15545
+ const alignmentLabel = new LabelView(locale);
15546
+ const ALIGNMENT_ICONS = {
15547
+ left: IconAlignLeft,
15548
+ center: IconAlignCenter,
15549
+ right: IconAlignRight,
15550
+ justify: IconAlignJustify,
15551
+ top: IconAlignTop,
15552
+ middle: IconAlignMiddle,
15553
+ bottom: IconAlignBottom
15554
+ };
15555
+ alignmentLabel.text = t('Table cell text alignment');
15556
+ // -- Horizontal ---------------------------------------------------
15557
+ const horizontalAlignmentToolbar = new ToolbarView(locale);
15558
+ const isContentRTL = locale.contentLanguageDirection === 'rtl';
15559
+ horizontalAlignmentToolbar.set({
15560
+ isCompact: true,
15561
+ role: 'radiogroup',
15562
+ ariaLabel: t('Horizontal text alignment toolbar'),
15563
+ class: 'ck-table-cell-properties-form__horizontal-alignment-toolbar'
15564
+ });
15565
+ fillToolbar({
15566
+ view: this,
15567
+ icons: ALIGNMENT_ICONS,
15568
+ toolbar: horizontalAlignmentToolbar,
15569
+ labels: this._horizontalAlignmentLabels,
15570
+ propertyName: 'horizontalAlignment',
15571
+ nameToValue: (name)=>{
15572
+ // For the RTL content, we want to swap the buttons "align to the left" and "align to the right".
15573
+ if (isContentRTL) {
15574
+ if (name === 'left') {
15575
+ return 'right';
15576
+ } else if (name === 'right') {
15577
+ return 'left';
15578
+ }
15579
+ }
15580
+ return name;
15581
+ },
15582
+ defaultValue: this.options.defaultTableCellProperties.horizontalAlignment
15583
+ });
15584
+ // -- Vertical -----------------------------------------------------
15585
+ const verticalAlignmentToolbar = new ToolbarView(locale);
15586
+ verticalAlignmentToolbar.set({
15587
+ isCompact: true,
15588
+ role: 'radiogroup',
15589
+ ariaLabel: t('Vertical text alignment toolbar'),
15590
+ class: 'ck-table-cell-properties-form__vertical-alignment-toolbar'
15591
+ });
15592
+ fillToolbar({
15593
+ view: this,
15594
+ icons: ALIGNMENT_ICONS,
15595
+ toolbar: verticalAlignmentToolbar,
15596
+ labels: this._verticalAlignmentLabels,
15597
+ propertyName: 'verticalAlignment',
15598
+ defaultValue: this.options.defaultTableCellProperties.verticalAlignment
15599
+ });
15600
+ return {
15601
+ horizontalAlignmentToolbar,
15602
+ verticalAlignmentToolbar,
15603
+ alignmentLabel
15604
+ };
15605
+ }
15606
+ /**
15607
+ * Creates the following form controls:
15608
+ *
15609
+ * * {@link #saveButtonView},
15610
+ * * {@link #cancelButtonView}.
15611
+ */ _createActionButtons() {
15612
+ const locale = this.locale;
15613
+ const t = this.t;
15614
+ const saveButtonView = new ButtonView(locale);
15615
+ const cancelButtonView = new ButtonView(locale);
15616
+ const fieldsThatShouldValidateToSave = [
15617
+ this.borderWidthInput,
15618
+ this.borderColorInput,
15619
+ this.backgroundInput,
15620
+ this.paddingInput
15621
+ ];
15622
+ saveButtonView.set({
15623
+ label: t('Save'),
15624
+ class: 'ck-button-action',
15625
+ type: 'submit',
15626
+ withText: true
15627
+ });
15628
+ saveButtonView.bind('isEnabled').toMany(fieldsThatShouldValidateToSave, 'errorText', (...errorTexts)=>{
15629
+ return errorTexts.every((errorText)=>!errorText);
15630
+ });
15631
+ cancelButtonView.set({
15632
+ label: t('Cancel'),
15633
+ withText: true
15634
+ });
15635
+ cancelButtonView.delegate('execute').to(this, 'cancel');
15636
+ return {
15637
+ saveButtonView,
15638
+ cancelButtonView
15639
+ };
15640
+ }
15641
+ /**
15642
+ * Creates a back button view that cancels the form.
15643
+ */ _createBackButton() {
15644
+ const t = this.locale.t;
15645
+ const backButton = new ButtonView(this.locale);
15646
+ backButton.set({
15647
+ class: 'ck-button-back',
15648
+ label: t('Back'),
15649
+ icon: IconPreviousArrow,
15650
+ tooltip: true
15651
+ });
15652
+ backButton.delegate('execute').to(this, 'cancel');
15653
+ return backButton;
15654
+ }
15655
+ /**
15656
+ * Creates the cell type dropdown definitions.
15657
+ */ _getCellTypeDefinitions() {
15658
+ const itemDefinitions = new Collection();
15659
+ const cellTypeLabels = this._cellTypeLabels;
15660
+ for (const type of [
15661
+ 'data',
15662
+ 'header'
15663
+ ]){
15664
+ const definition = {
15665
+ type: 'button',
15666
+ model: new UIModel({
15667
+ _cellTypeValue: type,
15668
+ label: cellTypeLabels[type],
15669
+ role: 'menuitemradio',
15670
+ withText: true
15671
+ })
15672
+ };
15673
+ definition.model.bind('isOn').to(this, 'cellType', (value)=>value === type);
15674
+ itemDefinitions.add(definition);
15675
+ }
15676
+ return itemDefinitions;
15677
+ }
15678
+ /**
15679
+ * Provides localized labels for {@link #horizontalAlignmentToolbar} buttons.
15680
+ */ get _horizontalAlignmentLabels() {
15681
+ const locale = this.locale;
15682
+ const t = this.t;
15683
+ const left = t('Align cell text to the left');
15684
+ const center = t('Align cell text to the center');
15685
+ const right = t('Align cell text to the right');
15686
+ const justify = t('Justify cell text');
15687
+ // Returns object with a proper order of labels.
15688
+ if (locale.uiLanguageDirection === 'rtl') {
15689
+ return {
15690
+ right,
15691
+ center,
15692
+ left,
15693
+ justify
15694
+ };
15695
+ } else {
15696
+ return {
15697
+ left,
15698
+ center,
15699
+ right,
15700
+ justify
15701
+ };
15702
+ }
15703
+ }
15704
+ /**
15705
+ * Provides localized labels for {@link #verticalAlignmentToolbar} buttons.
15706
+ */ get _verticalAlignmentLabels() {
15707
+ const t = this.t;
15708
+ return {
15709
+ top: t('Align cell text to the top'),
15710
+ middle: t('Align cell text to the middle'),
15711
+ bottom: t('Align cell text to the bottom')
15712
+ };
15713
+ }
15714
+ /**
15715
+ * Provides localized labels for {@link #cellTypeDropdown}.
15716
+ */ get _cellTypeLabels() {
15717
+ const t = this.t;
15718
+ return {
15719
+ data: t('Data cell'),
15720
+ header: t('Header cell')
15721
+ };
15722
+ }
15723
+ }
15724
+ function isBorderStyleSet(value) {
15725
+ return value !== 'none';
15726
+ }
15727
+
15728
+ const ERROR_TEXT_TIMEOUT = 500;
15729
+ // Map of view properties and related commands.
15730
+ const propertyToCommandMap = {
15731
+ borderStyle: 'tableCellBorderStyle',
15732
+ borderColor: 'tableCellBorderColor',
15733
+ borderWidth: 'tableCellBorderWidth',
15734
+ height: 'tableCellHeight',
15735
+ width: 'tableCellWidth',
15736
+ padding: 'tableCellPadding',
15737
+ backgroundColor: 'tableCellBackgroundColor',
15738
+ horizontalAlignment: 'tableCellHorizontalAlignment',
15739
+ verticalAlignment: 'tableCellVerticalAlignment',
15740
+ cellType: 'tableCellType'
15741
+ };
15742
+ /**
15743
+ * The table cell properties UI plugin. It introduces the `'tableCellProperties'` button
15744
+ * that opens a form allowing to specify the visual styling of a table cell.
15745
+ *
15746
+ * It uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.
15747
+ */ class TableCellPropertiesUIExperimental extends Plugin {
15748
+ /**
15749
+ * The default table cell properties.
15750
+ */ _defaultContentTableCellProperties;
15751
+ /**
15752
+ * The default layout table cell properties.
15753
+ */ _defaultLayoutTableCellProperties;
15754
+ /**
15755
+ * The contextual balloon plugin instance.
15756
+ */ _balloon;
15757
+ /**
15758
+ * The cell properties form view displayed inside the balloon.
15759
+ */ view;
15760
+ /**
15761
+ * The cell properties form view displayed inside the balloon (content table).
15762
+ */ _viewWithContentTableDefaults;
15763
+ /**
15764
+ * The cell properties form view displayed inside the balloon (layout table).
15765
+ */ _viewWithLayoutTableDefaults;
15766
+ /**
15767
+ * The batch used to undo all changes made by the form (which are live, as the user types)
15768
+ * when "Cancel" was pressed. Each time the view is shown, a new batch is created.
15769
+ */ _undoStepBatch;
15770
+ /**
15771
+ * Flag used to indicate whether view is ready to execute update commands
15772
+ * (it finished loading initial data).
15773
+ */ _isReady;
15774
+ /**
15775
+ * @inheritDoc
15776
+ */ static get requires() {
15777
+ return [
15778
+ ContextualBalloon
15779
+ ];
15780
+ }
15781
+ /**
15782
+ * @inheritDoc
15783
+ */ static get pluginName() {
15784
+ return 'TableCellPropertiesUIExperimental';
15785
+ }
15786
+ /**
15787
+ * @inheritDoc
15788
+ */ static get isOfficialPlugin() {
15789
+ return true;
15790
+ }
15791
+ /**
15792
+ * @inheritDoc
15793
+ */ constructor(editor){
15794
+ super(editor);
15795
+ editor.config.define('table.tableCellProperties', {
15796
+ borderColors: defaultColors,
15797
+ backgroundColors: defaultColors
15798
+ });
15799
+ }
15800
+ /**
15801
+ * @inheritDoc
15802
+ */ init() {
15803
+ const editor = this.editor;
15804
+ const t = editor.t;
15805
+ this._defaultContentTableCellProperties = getNormalizedDefaultCellProperties(editor.config.get('table.tableCellProperties.defaultProperties'), {
15806
+ includeVerticalAlignmentProperty: true,
15807
+ includeHorizontalAlignmentProperty: true,
15808
+ includePaddingProperty: true,
15809
+ isRightToLeftContent: editor.locale.contentLanguageDirection === 'rtl'
15810
+ });
15811
+ this._defaultLayoutTableCellProperties = getNormalizedDefaultProperties(undefined, {
15812
+ includeVerticalAlignmentProperty: true,
15813
+ includeHorizontalAlignmentProperty: true,
15814
+ isRightToLeftContent: editor.locale.contentLanguageDirection === 'rtl'
15815
+ });
15816
+ this._balloon = editor.plugins.get(ContextualBalloon);
15817
+ this.view = null;
15818
+ this._isReady = false;
15819
+ editor.ui.componentFactory.add('tableCellProperties', (locale)=>{
15820
+ const view = new ButtonView(locale);
15821
+ view.set({
15822
+ label: t('Cell properties'),
15823
+ icon: IconTableCellProperties,
15824
+ tooltip: true
15825
+ });
15826
+ this.listenTo(view, 'execute', ()=>this._showView());
15827
+ const commands = Object.values(propertyToCommandMap).map((commandName)=>editor.commands.get(commandName)).filter((val)=>!!val);
15828
+ view.bind('isEnabled').toMany(commands, 'isEnabled', (...areEnabled)=>areEnabled.some((isCommandEnabled)=>isCommandEnabled));
15829
+ return view;
15830
+ });
15831
+ }
15832
+ /**
15833
+ * @inheritDoc
15834
+ */ destroy() {
15835
+ super.destroy();
15836
+ // Destroy created UI components as they are not automatically destroyed.
15837
+ // See https://github.com/ckeditor/ckeditor5/issues/1341.
15838
+ if (this.view) {
15839
+ this.view.destroy();
15840
+ }
15841
+ }
15842
+ /**
15843
+ * Creates the {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView} instance.
15844
+ *
15845
+ * @returns The cell properties form view instance.
15846
+ */ _createPropertiesView(defaultTableCellProperties) {
15847
+ const editor = this.editor;
15848
+ const config = editor.config.get('table.tableCellProperties');
15849
+ const borderColorsConfig = normalizeColorOptions(config.borderColors);
15850
+ const localizedBorderColors = getLocalizedColorOptions(editor.locale, borderColorsConfig);
15851
+ const backgroundColorsConfig = normalizeColorOptions(config.backgroundColors);
15852
+ const localizedBackgroundColors = getLocalizedColorOptions(editor.locale, backgroundColorsConfig);
15853
+ const hasColorPicker = config.colorPicker !== false;
15854
+ const isTableCellTypeSupported = !!editor.config.get('experimentalFlags.tableCellTypeSupport');
15855
+ const view = new TableCellPropertiesViewExperimental(editor.locale, {
15856
+ borderColors: localizedBorderColors,
15857
+ backgroundColors: localizedBackgroundColors,
15858
+ defaultTableCellProperties,
15859
+ colorPickerConfig: hasColorPicker ? config.colorPicker || {} : false,
15860
+ isTableCellTypeSupported
15861
+ });
15862
+ const t = editor.t;
15863
+ // Render the view so its #element is available for the clickOutsideHandler.
15864
+ view.render();
15865
+ this.listenTo(view, 'submit', ()=>{
15866
+ this._hideView();
15867
+ });
15868
+ this.listenTo(view, 'cancel', ()=>{
15869
+ // https://github.com/ckeditor/ckeditor5/issues/6180
15870
+ if (this._undoStepBatch.operations.length) {
15871
+ editor.execute('undo', this._undoStepBatch);
15872
+ }
15873
+ this._hideView();
15874
+ });
15875
+ // Close the balloon on Esc key press.
15876
+ view.keystrokes.set('Esc', (data, cancel)=>{
15877
+ this._hideView();
15878
+ cancel();
15879
+ });
15880
+ // Close on click outside of balloon panel element.
15881
+ clickOutsideHandler({
15882
+ emitter: view,
15883
+ activator: ()=>this._isViewInBalloon,
15884
+ contextElements: [
15885
+ this._balloon.view.element
15886
+ ],
15887
+ callback: ()=>this._hideView()
15888
+ });
15889
+ const colorErrorText = getLocalizedColorErrorText(t);
15890
+ const lengthErrorText = getLocalizedLengthErrorText(t);
15891
+ // Create the "UI -> editor data" binding.
15892
+ // These listeners update the editor data (via table commands) when any observable
15893
+ // property of the view has changed. They also validate the value and display errors in the UI
15894
+ // when necessary. This makes the view live, which means the changes are
15895
+ // visible in the editing as soon as the user types or changes fields' values.
15896
+ view.on('change:borderStyle', this._getPropertyChangeCallback('tableCellBorderStyle'));
15897
+ view.on('change:borderColor', this._getValidatedPropertyChangeCallback({
15898
+ viewField: view.borderColorInput,
15899
+ commandName: 'tableCellBorderColor',
15900
+ errorText: colorErrorText,
15901
+ validator: colorFieldValidator
15902
+ }));
15903
+ view.on('change:borderWidth', this._getValidatedPropertyChangeCallback({
15904
+ viewField: view.borderWidthInput,
15905
+ commandName: 'tableCellBorderWidth',
15906
+ errorText: lengthErrorText,
15907
+ validator: lineWidthFieldValidator
15908
+ }));
15909
+ view.on('change:padding', this._getValidatedPropertyChangeCallback({
15910
+ viewField: view.paddingInput,
15911
+ commandName: 'tableCellPadding',
15912
+ errorText: lengthErrorText,
15913
+ validator: lengthFieldValidator
15914
+ }));
15915
+ view.on('change:width', this._getValidatedPropertyChangeCallback({
15916
+ viewField: view.widthInput,
15917
+ commandName: 'tableCellWidth',
15918
+ errorText: lengthErrorText,
15919
+ validator: lengthFieldValidator
15920
+ }));
15921
+ view.on('change:height', this._getValidatedPropertyChangeCallback({
15922
+ viewField: view.heightInput,
15923
+ commandName: 'tableCellHeight',
15924
+ errorText: lengthErrorText,
15925
+ validator: lengthFieldValidator
15926
+ }));
15927
+ view.on('change:backgroundColor', this._getValidatedPropertyChangeCallback({
15928
+ viewField: view.backgroundInput,
15929
+ commandName: 'tableCellBackgroundColor',
15930
+ errorText: colorErrorText,
15931
+ validator: colorFieldValidator
15932
+ }));
15933
+ view.on('change:horizontalAlignment', this._getPropertyChangeCallback('tableCellHorizontalAlignment'));
15934
+ view.on('change:verticalAlignment', this._getPropertyChangeCallback('tableCellVerticalAlignment'));
15935
+ const cellTypeCommand = editor.commands.get('tableCellType');
15936
+ if (cellTypeCommand) {
15937
+ view.cellTypeDropdown.bind('isEnabled').to(cellTypeCommand, 'isEnabled');
15938
+ view.on('change:cellType', this._getPropertyChangeCallback('tableCellType'));
15939
+ }
15940
+ return view;
15941
+ }
15942
+ /**
15943
+ * In this method the "editor data -> UI" binding is happening.
15944
+ *
15945
+ * When executed, this method obtains selected cell property values from various table commands
15946
+ * and passes them to the {@link #view}.
15947
+ *
15948
+ * This way, the UI stays up–to–date with the editor data.
15949
+ */ _fillViewFormFromCommandValues() {
15950
+ const commands = this.editor.commands;
15951
+ const borderStyleCommand = commands.get('tableCellBorderStyle');
15952
+ Object.entries(propertyToCommandMap).flatMap(([property, commandName])=>{
15953
+ const command = commands.get(commandName);
15954
+ if (!command) {
15955
+ return [];
15956
+ }
15957
+ const propertyKey = property;
15958
+ let defaultValue;
15959
+ if (propertyKey === 'cellType') {
15960
+ defaultValue = '';
15961
+ } else {
15962
+ defaultValue = this.view === this._viewWithContentTableDefaults ? this._defaultContentTableCellProperties[propertyKey] || '' : this._defaultLayoutTableCellProperties[propertyKey] || '';
15963
+ }
15964
+ const entry = [
15965
+ property,
15966
+ command.value || defaultValue
15967
+ ];
15968
+ return [
15969
+ entry
15970
+ ];
15971
+ }).forEach(([property, value])=>{
15972
+ // Do not set the `border-color` and `border-width` fields if `border-style:none`.
15973
+ if ((property === 'borderColor' || property === 'borderWidth') && borderStyleCommand.value === 'none') {
15974
+ return;
15975
+ }
15976
+ this.view.set(property, value);
15977
+ });
15978
+ this._isReady = true;
15979
+ }
15980
+ /**
15981
+ * Shows the {@link #view} in the {@link #_balloon}.
15982
+ *
15983
+ * **Note**: Each time a view is shown, a new {@link #_undoStepBatch} is created. It contains
15984
+ * all changes made to the document when the view is visible, allowing a single undo step
15985
+ * for all of them.
15986
+ */ _showView() {
15987
+ const editor = this.editor;
15988
+ const viewTable = getSelectionAffectedTableWidget(editor.editing.view.document.selection);
15989
+ const modelTable = viewTable && editor.editing.mapper.toModelElement(viewTable);
15990
+ const useDefaults = !modelTable || modelTable.getAttribute('tableType') !== 'layout';
15991
+ if (useDefaults && !this._viewWithContentTableDefaults) {
15992
+ this._viewWithContentTableDefaults = this._createPropertiesView(this._defaultContentTableCellProperties);
15993
+ } else if (!useDefaults && !this._viewWithLayoutTableDefaults) {
15994
+ this._viewWithLayoutTableDefaults = this._createPropertiesView(this._defaultLayoutTableCellProperties);
15995
+ }
15996
+ this.view = useDefaults ? this._viewWithContentTableDefaults : this._viewWithLayoutTableDefaults;
15997
+ this.listenTo(editor.ui, 'update', ()=>{
15998
+ this._updateView();
15999
+ });
16000
+ // Update the view with the model values.
16001
+ this._fillViewFormFromCommandValues();
16002
+ this._balloon.add({
16003
+ view: this.view,
16004
+ position: getBalloonCellPositionData(editor)
16005
+ });
16006
+ // Create a new batch. Clicking "Cancel" will undo this batch.
16007
+ this._undoStepBatch = editor.model.createBatch();
16008
+ // Basic a11y.
16009
+ this.view.focus();
16010
+ }
16011
+ /**
16012
+ * Removes the {@link #view} from the {@link #_balloon}.
16013
+ */ _hideView() {
16014
+ const editor = this.editor;
16015
+ this.stopListening(editor.ui, 'update');
16016
+ this._isReady = false;
16017
+ // Blur any input element before removing it from DOM to prevent issues in some browsers.
16018
+ // See https://github.com/ckeditor/ckeditor5/issues/1501.
16019
+ this.view.saveButtonView.focus();
16020
+ this._balloon.remove(this.view);
16021
+ // Make sure the focus is not lost in the process by putting it directly
16022
+ // into the editing view.
16023
+ this.editor.editing.view.focus();
16024
+ }
16025
+ /**
16026
+ * Repositions the {@link #_balloon} or hides the {@link #view} if a table cell is no longer selected.
16027
+ */ _updateView() {
16028
+ const editor = this.editor;
16029
+ const viewDocument = editor.editing.view.document;
16030
+ if (!getTableWidgetAncestor(viewDocument.selection)) {
16031
+ this._hideView();
16032
+ } else if (this._isViewVisible) {
16033
+ repositionContextualBalloon(editor, 'cell');
16034
+ }
16035
+ }
16036
+ /**
16037
+ * Returns `true` when the {@link #view} is visible in the {@link #_balloon}.
16038
+ */ get _isViewVisible() {
16039
+ return !!this.view && this._balloon.visibleView === this.view;
16040
+ }
16041
+ /**
16042
+ * Returns `true` when the {@link #view} is in the {@link #_balloon}.
16043
+ */ get _isViewInBalloon() {
16044
+ return !!this.view && this._balloon.hasView(this.view);
16045
+ }
16046
+ /**
16047
+ * Creates a callback that when executed upon the {@link #view view's} property change
16048
+ * executes a related editor command with the new property value.
16049
+ *
16050
+ * @param commandName The default value of the command.
16051
+ */ _getPropertyChangeCallback(commandName) {
16052
+ return (evt, propertyName, newValue)=>{
16053
+ if (!this._isReady) {
16054
+ return;
16055
+ }
16056
+ this.editor.execute(commandName, {
16057
+ value: newValue,
16058
+ batch: this._undoStepBatch
16059
+ });
16060
+ };
16061
+ }
16062
+ /**
16063
+ * Creates a callback that when executed upon the {@link #view view's} property change:
16064
+ * * Executes a related editor command with the new property value if the value is valid,
16065
+ * * Or sets the error text next to the invalid field, if the value did not pass the validation.
16066
+ */ _getValidatedPropertyChangeCallback(options) {
16067
+ const { commandName, viewField, validator, errorText } = options;
16068
+ const setErrorTextDebounced = debounce(()=>{
16069
+ viewField.errorText = errorText;
16070
+ }, ERROR_TEXT_TIMEOUT);
16071
+ return (evt, propertyName, newValue)=>{
16072
+ setErrorTextDebounced.cancel();
16073
+ // Do not execute the command on initial call (opening the table properties view).
16074
+ if (!this._isReady) {
16075
+ return;
16076
+ }
16077
+ if (validator(newValue)) {
16078
+ this.editor.execute(commandName, {
16079
+ value: newValue,
16080
+ batch: this._undoStepBatch
16081
+ });
16082
+ viewField.errorText = null;
16083
+ } else {
16084
+ setErrorTextDebounced();
16085
+ }
16086
+ };
16087
+ }
16088
+ }
16089
+
16090
+ export { InsertColumnCommand, InsertRowCommand, InsertTableCommand, InsertTableLayoutCommand, MergeCellCommand, MergeCellsCommand, PlainTableOutput, RemoveColumnCommand, RemoveRowCommand, SelectColumnCommand, SelectRowCommand, SetHeaderColumnCommand, SetHeaderRowCommand, SplitCellCommand, Table, TableAlignmentCommand, TableBackgroundColorCommand, TableBorderColorCommand, TableBorderStyleCommand, TableBorderWidthCommand, TableCaption, TableCaptionEditing, TableCaptionUI, TableCellBackgroundColorCommand, TableCellBorderColorCommand, TableCellBorderStyleCommand, TableCellBorderWidthCommand, TableCellHeightCommand, TableCellHorizontalAlignmentCommand, TableCellPaddingCommand, TableCellProperties, TableCellPropertiesEditing, TableCellPropertiesUI, TableCellPropertiesUIExperimental, TableCellPropertiesView, TableCellPropertiesViewExperimental, TableCellPropertyCommand, TableCellTypeCommand, TableCellVerticalAlignmentCommand, TableCellWidthCommand, TableCellWidthEditing, TableClipboard, TableColumnResize, TableColumnResizeEditing, TableEditing, TableHeightCommand, TableKeyboard, TableLayout, TableLayoutEditing, TableLayoutUI, TableMouse, TableProperties, TablePropertiesEditing, TablePropertiesUI, TablePropertiesUIExperimental, TablePropertiesView, TablePropertiesViewExperimental, TablePropertyCommand, TableSelection, TableToolbar, TableTypeCommand, TableUI, TableUtils, TableWalker, TableWidthCommand, TableWidthsCommand, ToggleTableCaptionCommand, InsertTableView as _InsertTableView, COLUMN_MIN_WIDTH_AS_PERCENTAGE as _TABLE_COLUMN_MIN_WIDTH_AS_PERCENTAGE, COLUMN_MIN_WIDTH_IN_PIXELS as _TABLE_COLUMN_MIN_WIDTH_IN_PIXELS, COLUMN_RESIZE_DISTANCE_THRESHOLD as _TABLE_COLUMN_RESIZE_DISTANCE_THRESHOLD, COLUMN_WIDTH_PRECISION as _TABLE_COLUMN_WIDTH_PRECISION, defaultColors as _TABLE_DEFAULT_COLORS, ColorInputView as _TableColorInputView, MouseEventsObserver as _TableMouseEventsObserver, addDefaultUnitToNumericValue as _addDefaultUnitToNumericValue, adjustLastColumnIndex as _adjustLastTableColumnIndex, adjustLastRowIndex as _adjustLastTableRowIndex, clamp as _clamp, colorFieldValidator as _colorTableFieldValidator, convertParagraphInTableCell as _convertParagraphInTableCell, createEmptyTableCell as _createEmptyTableCell, createFilledArray as _createFilledArray, cropTableToDimensions as _cropTableToDimensions, downcastTable as _downcastTable, downcastTableAttribute as _downcastTableAttribute, downcastAttributeToStyle as _downcastTableAttributeToStyle, downcastCell as _downcastTableCell, downcastTableResizedClass as _downcastTableResizedClass, downcastRow as _downcastTableRow, enableProperty$1 as _enableTableCellProperty, ensureParagraphInTableCell as _ensureParagraphInTableCell, fillToolbar$1 as _fillTableOrCellToolbar, getBalloonCellPositionData as _getBalloonTableCellPositionData, getBalloonTablePositionData as _getBalloonTablePositionData, getBorderStyleLabels$1 as _getBorderTableStyleLabels, getChangedResizedTables as _getChangedResizedTables, getDefaultValueAdjusted as _getDefaultTableValueAdjusted, getDomCellOuterWidth as _getDomTableCellOuterWidth, getElementWidthInPixels as _getElementWidthInPixels, getHorizontallyOverlappingCells as _getHorizontallyOverlappingTableCells, getLabeledColorInputCreator$1 as _getLabeledTableColorInputCreator, getLocalizedColorErrorText as _getLocalizedTableColorErrorText, getLocalizedLengthErrorText as _getLocalizedTableLengthErrorText, getNormalizedDefaultProperties as _getNormalizedDefaultTableBaseProperties, getNormalizedDefaultCellProperties as _getNormalizedDefaultTableCellProperties, getNormalizedDefaultTableProperties as _getNormalizedDefaultTableProperties, getSelectedTableWidget as _getSelectedTableWidget, getSelectionAffectedTable as _getSelectionAffectedTable, getSelectionAffectedTableWidget as _getSelectionAffectedTableWidget, getSingleValue as _getTableBorderBoxSingleValue, getCaptionFromTableModelElement as _getTableCaptionFromModelElement, getCaptionFromModelSelection as _getTableCaptionFromModelSelection, getColumnEdgesIndexes as _getTableColumnEdgesIndexes, getTableColumnElements as _getTableColumnElements, getColumnGroupElement as _getTableColumnGroupElement, getColumnMinWidthAsPercentage as _getTableColumnMinWidthAsPercentage, getTableColumnsWidths as _getTableColumnsWidths, getBorderStyleDefinitions$1 as _getTableOrCellBorderStyleDefinitions, getTableWidgetAncestor as _getTableWidgetAncestor, getTableWidthInPixels as _getTableWidthInPixels, getVerticallyOverlappingCells as _getVerticallyOverlappingTableCells, injectTableCaptionPostFixer as _injectTableCaptionPostFixer, injectTableCellParagraphPostFixer as _injectTableCellParagraphPostFixer, injectTableLayoutPostFixer as _injectTableLayoutPostFixer, isSingleParagraphWithoutAttributes as _isSingleTableParagraphWithoutAttributes, isHeadingColumnCell as _isTableHeadingColumnCell, isTable as _isTableModelElement, lengthFieldValidator as _lengthTableFieldValidator, lineWidthFieldValidator as _lineWidthTableFieldValidator, matchTableCaptionViewElement as _matchTableCaptionViewElement, normalizeColumnWidths as _normalizeTableColumnWidths, removeEmptyColumns as _removeEmptyTableColumns, removeEmptyRows as _removeEmptyTableRows, removeEmptyRowsColumns as _removeEmptyTableRowsColumns, repositionContextualBalloon as _repositionTableContextualBalloon, skipEmptyTableRow as _skipEmptyTableRow, splitHorizontally as _splitTableCellHorizontally, splitVertically as _splitTableCellVertically, sumArray as _sumArray, tableCellRefreshHandler as _tableCellRefreshHandler, tableHeadingsRefreshHandler as _tableHeadingsRefreshHandler, toPrecision as _toPrecision, translateColSpanAttribute as _translateTableColspanAttribute, trimTableCellIfNeeded as _trimTableCellIfNeeded, upcastStyleToAttribute as _upcastNormalizedTableStyleToAttribute, upcastTable as _upcastTable, upcastBorderStyles as _upcastTableBorderStyles, upcastColgroupElement as _upcastTableColgroupElement, upcastTableFigure as _upcastTableFigure, updateColumnElements as _updateTableColumnElements, updateNumericAttribute as _updateTableNumericAttribute };
13999
16091
  //# sourceMappingURL=index.js.map