handsontable 0.0.0-next-0306a1a-20240826 → 0.0.0-next-eaf150e-20240903

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of handsontable might be problematic. Click here for more details.

Files changed (104) hide show
  1. package/3rdparty/walkontable/src/calculator/calculationType/fullyVisibleColumns.js +126 -0
  2. package/3rdparty/walkontable/src/calculator/calculationType/fullyVisibleColumns.mjs +122 -0
  3. package/3rdparty/walkontable/src/calculator/calculationType/fullyVisibleRows.js +119 -0
  4. package/3rdparty/walkontable/src/calculator/calculationType/fullyVisibleRows.mjs +115 -0
  5. package/3rdparty/walkontable/src/calculator/calculationType/partiallyVisibleColumns.js +125 -0
  6. package/3rdparty/walkontable/src/calculator/calculationType/partiallyVisibleColumns.mjs +121 -0
  7. package/3rdparty/walkontable/src/calculator/calculationType/partiallyVisibleRows.js +118 -0
  8. package/3rdparty/walkontable/src/calculator/calculationType/partiallyVisibleRows.mjs +114 -0
  9. package/3rdparty/walkontable/src/calculator/{renderAllColumns.js → calculationType/renderedAllColumns.js} +32 -9
  10. package/3rdparty/walkontable/src/calculator/{renderAllColumns.mjs → calculationType/renderedAllColumns.mjs} +31 -8
  11. package/3rdparty/walkontable/src/calculator/{renderAllRows.js → calculationType/renderedAllRows.js} +32 -9
  12. package/3rdparty/walkontable/src/calculator/{renderAllRows.mjs → calculationType/renderedAllRows.mjs} +31 -8
  13. package/3rdparty/walkontable/src/calculator/calculationType/renderedColumns.js +37 -0
  14. package/3rdparty/walkontable/src/calculator/calculationType/renderedColumns.mjs +33 -0
  15. package/3rdparty/walkontable/src/calculator/calculationType/renderedRows.js +37 -0
  16. package/3rdparty/walkontable/src/calculator/calculationType/renderedRows.mjs +33 -0
  17. package/3rdparty/walkontable/src/calculator/index.js +18 -17
  18. package/3rdparty/walkontable/src/calculator/index.mjs +11 -6
  19. package/3rdparty/walkontable/src/calculator/viewportBase.js +92 -0
  20. package/3rdparty/walkontable/src/calculator/viewportBase.mjs +88 -0
  21. package/3rdparty/walkontable/src/calculator/viewportColumns.js +51 -145
  22. package/3rdparty/walkontable/src/calculator/viewportColumns.mjs +51 -145
  23. package/3rdparty/walkontable/src/calculator/viewportRows.js +59 -141
  24. package/3rdparty/walkontable/src/calculator/viewportRows.mjs +59 -141
  25. package/3rdparty/walkontable/src/index.js +2 -0
  26. package/3rdparty/walkontable/src/index.mjs +2 -2
  27. package/3rdparty/walkontable/src/table.js +5 -11
  28. package/3rdparty/walkontable/src/table.mjs +5 -11
  29. package/3rdparty/walkontable/src/utils/column.js +2 -1
  30. package/3rdparty/walkontable/src/utils/column.mjs +2 -1
  31. package/3rdparty/walkontable/src/utils/columnStretching.js +10 -19
  32. package/3rdparty/walkontable/src/utils/columnStretching.mjs +10 -19
  33. package/3rdparty/walkontable/src/viewport.js +35 -46
  34. package/3rdparty/walkontable/src/viewport.mjs +36 -47
  35. package/CHANGELOG.md +27 -0
  36. package/base.js +2 -2
  37. package/base.mjs +2 -2
  38. package/core.d.ts +1 -2
  39. package/core.js +1 -1
  40. package/core.mjs +2 -2
  41. package/dataMap/metaManager/metaSchema.js +5 -6
  42. package/dataMap/metaManager/metaSchema.mjs +5 -6
  43. package/dist/handsontable.css +32 -20
  44. package/dist/handsontable.full.css +32 -20
  45. package/dist/handsontable.full.js +2741 -2091
  46. package/dist/handsontable.full.min.css +5 -5
  47. package/dist/handsontable.full.min.js +148 -148
  48. package/dist/handsontable.js +2742 -2092
  49. package/dist/handsontable.min.css +4 -4
  50. package/dist/handsontable.min.js +32 -32
  51. package/editors/autocompleteEditor/autocompleteEditor.d.ts +1 -1
  52. package/helpers/a11y.js +2 -0
  53. package/helpers/a11y.mjs +1 -0
  54. package/helpers/mixed.js +2 -2
  55. package/helpers/mixed.mjs +2 -2
  56. package/package.json +1 -1
  57. package/pluginHooks.d.ts +1 -1
  58. package/pluginHooks.js +1 -1
  59. package/pluginHooks.mjs +1 -1
  60. package/plugins/autoColumnSize/autoColumnSize.js +1 -1
  61. package/plugins/autoColumnSize/autoColumnSize.mjs +2 -2
  62. package/plugins/autoRowSize/autoRowSize.js +1 -2
  63. package/plugins/autoRowSize/autoRowSize.mjs +1 -2
  64. package/plugins/columnSorting/columnSorting.js +10 -1
  65. package/plugins/columnSorting/columnSorting.mjs +10 -1
  66. package/plugins/contextMenu/menu/menuItemRenderer.js +3 -4
  67. package/plugins/contextMenu/menu/menuItemRenderer.mjs +5 -6
  68. package/plugins/contextMenu/menu/positioner.js +4 -12
  69. package/plugins/contextMenu/menu/positioner.mjs +4 -12
  70. package/plugins/contextMenu/menu/utils.js +11 -0
  71. package/plugins/contextMenu/menu/utils.mjs +10 -0
  72. package/plugins/contextMenu/predefinedItems/alignment.js +67 -49
  73. package/plugins/contextMenu/predefinedItems/alignment.mjs +68 -50
  74. package/plugins/contextMenu/predefinedItems/readOnly.js +11 -0
  75. package/plugins/contextMenu/predefinedItems/readOnly.mjs +11 -0
  76. package/plugins/contextMenu/utils.js +26 -0
  77. package/plugins/contextMenu/utils.mjs +24 -0
  78. package/plugins/copyPaste/copyPaste.js +14 -14
  79. package/plugins/copyPaste/copyPaste.mjs +14 -14
  80. package/plugins/dropdownMenu/dropdownMenu.js +10 -4
  81. package/plugins/dropdownMenu/dropdownMenu.mjs +10 -4
  82. package/plugins/filters/component/condition.js +6 -1
  83. package/plugins/filters/component/condition.mjs +6 -1
  84. package/plugins/filters/component/value.js +6 -1
  85. package/plugins/filters/component/value.mjs +6 -1
  86. package/plugins/filters/conditionCollection.d.ts +4 -3
  87. package/plugins/filters/conditionCollection.js +26 -0
  88. package/plugins/filters/conditionCollection.mjs +26 -0
  89. package/plugins/filters/filters.js +2 -1
  90. package/plugins/filters/filters.mjs +2 -1
  91. package/plugins/filters/ui/multipleSelect.js +7 -9
  92. package/plugins/filters/ui/multipleSelect.mjs +7 -9
  93. package/plugins/manualRowResize/manualRowResize.js +1 -1
  94. package/plugins/manualRowResize/manualRowResize.mjs +2 -2
  95. package/plugins/mergeCells/cellsCollection.js +11 -9
  96. package/plugins/mergeCells/cellsCollection.mjs +12 -10
  97. package/plugins/undoRedo/undoRedo.js +9 -5
  98. package/plugins/undoRedo/undoRedo.mjs +9 -5
  99. package/shortcuts/utils.js +3 -1
  100. package/shortcuts/utils.mjs +3 -1
  101. package/utils/ghostTable.js +11 -9
  102. package/utils/ghostTable.mjs +12 -10
  103. package/3rdparty/walkontable/src/calculator/constants.js +0 -26
  104. package/3rdparty/walkontable/src/calculator/constants.mjs +0 -23
@@ -17,7 +17,7 @@ export class AutocompleteEditor extends HandsontableEditor {
17
17
  limitDropdownIfNeeded(spaceAvailable: number, dropdownHeight: number): void;
18
18
  flipDropdown(dropdownHeight: number): void;
19
19
  unflipDropdown(): void;
20
- updateDropdownHeight(): void;
20
+ updateDropdownDimensions(): void;
21
21
  setDropdownHeight(height: number): void;
22
22
  highlightBestMatchingChoice(index?: number): void;
23
23
  getDropdownHeight(): number;
package/helpers/a11y.js CHANGED
@@ -21,6 +21,8 @@ const A11Y_MENU = () => ['role', 'menu'];
21
21
  exports.A11Y_MENU = A11Y_MENU;
22
22
  const A11Y_MENU_ITEM = () => ['role', 'menuitem'];
23
23
  exports.A11Y_MENU_ITEM = A11Y_MENU_ITEM;
24
+ const A11Y_MENU_ITEM_CHECKBOX = () => ['role', 'menuitemcheckbox'];
25
+ exports.A11Y_MENU_ITEM_CHECKBOX = A11Y_MENU_ITEM_CHECKBOX;
24
26
  const A11Y_COMBOBOX = () => ['role', 'combobox'];
25
27
  exports.A11Y_COMBOBOX = A11Y_COMBOBOX;
26
28
  const A11Y_LISTBOX = () => ['role', 'listbox'];
package/helpers/a11y.mjs CHANGED
@@ -8,6 +8,7 @@ export const A11Y_COLUMNHEADER = () => ['role', 'columnheader'];
8
8
  export const A11Y_ROW = () => ['role', 'row'];
9
9
  export const A11Y_MENU = () => ['role', 'menu'];
10
10
  export const A11Y_MENU_ITEM = () => ['role', 'menuitem'];
11
+ export const A11Y_MENU_ITEM_CHECKBOX = () => ['role', 'menuitemcheckbox'];
11
12
  export const A11Y_COMBOBOX = () => ['role', 'combobox'];
12
13
  export const A11Y_LISTBOX = () => ['role', 'listbox'];
13
14
  export const A11Y_OPTION = () => ['role', 'option'];
package/helpers/mixed.js CHANGED
@@ -134,7 +134,7 @@ const domMessages = {
134
134
  function _injectProductInfo(key, element) {
135
135
  const hasValidType = !isEmpty(key);
136
136
  const isNonCommercial = typeof key === 'string' && key.toLowerCase() === 'non-commercial-and-evaluation';
137
- const hotVersion = "0.0.0-next-0306a1a-20240826";
137
+ const hotVersion = "0.0.0-next-eaf150e-20240903";
138
138
  let keyValidityDate;
139
139
  let consoleMessageState = 'invalid';
140
140
  let domMessageState = 'invalid';
@@ -142,7 +142,7 @@ function _injectProductInfo(key, element) {
142
142
  const schemaValidity = _checkKeySchema(key);
143
143
  if (hasValidType || isNonCommercial || schemaValidity) {
144
144
  if (schemaValidity) {
145
- const releaseDate = (0, _moment.default)("11/06/2024", 'DD/MM/YYYY');
145
+ const releaseDate = (0, _moment.default)("30/07/2024", 'DD/MM/YYYY');
146
146
  const releaseDays = Math.floor(releaseDate.toDate().getTime() / 8.64e7);
147
147
  const keyValidityDays = _extractTime(key);
148
148
  keyValidityDate = (0, _moment.default)((keyValidityDays + 1) * 8.64e7, 'x').format('MMMM DD, YYYY');
package/helpers/mixed.mjs CHANGED
@@ -124,7 +124,7 @@ const domMessages = {
124
124
  export function _injectProductInfo(key, element) {
125
125
  const hasValidType = !isEmpty(key);
126
126
  const isNonCommercial = typeof key === 'string' && key.toLowerCase() === 'non-commercial-and-evaluation';
127
- const hotVersion = "0.0.0-next-0306a1a-20240826";
127
+ const hotVersion = "0.0.0-next-eaf150e-20240903";
128
128
  let keyValidityDate;
129
129
  let consoleMessageState = 'invalid';
130
130
  let domMessageState = 'invalid';
@@ -132,7 +132,7 @@ export function _injectProductInfo(key, element) {
132
132
  const schemaValidity = _checkKeySchema(key);
133
133
  if (hasValidType || isNonCommercial || schemaValidity) {
134
134
  if (schemaValidity) {
135
- const releaseDate = moment("11/06/2024", 'DD/MM/YYYY');
135
+ const releaseDate = moment("30/07/2024", 'DD/MM/YYYY');
136
136
  const releaseDays = Math.floor(releaseDate.toDate().getTime() / 8.64e7);
137
137
  const keyValidityDays = _extractTime(key);
138
138
  keyValidityDate = moment((keyValidityDays + 1) * 8.64e7, 'x').format('MMMM DD, YYYY');
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "url": "https://github.com/handsontable/handsontable/issues"
11
11
  },
12
12
  "author": "Handsoncode <hello@handsontable.com>",
13
- "version": "0.0.0-next-0306a1a-20240826",
13
+ "version": "0.0.0-next-eaf150e-20240903",
14
14
  "main": "index",
15
15
  "module": "index.mjs",
16
16
  "jsnext:main": "index.mjs",
package/pluginHooks.d.ts CHANGED
@@ -180,7 +180,7 @@ export interface Events {
180
180
  beforeDrawBorders?: (corners: number[], borderClassName: 'current' | 'area' | 'highlight' | undefined) => void;
181
181
  beforeDropdownMenuSetItems?: (menuItems: ContextMenuMenuItemConfig[]) => void;
182
182
  beforeDropdownMenuShow?: (instance: DropdownMenu) => void;
183
- beforeFilter?: (conditionsStack: FiltersColumnConditions[]) => void | boolean;
183
+ beforeFilter?: (conditionsStack: FiltersColumnConditions[], previousConditionsStack: FiltersColumnConditions[]) => void | boolean;
184
184
  beforeGetCellMeta?: (row: number, column: number, cellProperties: CellProperties) => void;
185
185
  beforeHideColumns?: (currentHideConfig: number[], destinationHideConfig: number[], actionPossible: boolean) => void | boolean;
186
186
  beforeHideRows?: (currentHideConfig: number[], destinationHideConfig: number[], actionPossible: boolean) => void | boolean;
package/pluginHooks.js CHANGED
@@ -609,7 +609,6 @@ const REGISTERED_HOOKS = [/* eslint-disable jsdoc/require-description-complete-s
609
609
  * @param {object} preventScrolling A reference to the observable object with the `value` property.
610
610
  * Property `preventScrolling.value` expects a boolean value that
611
611
  * Handsontable uses to control scroll behavior after selection.
612
- * @param {object} preventScrolling Object with `value` property where its value change will be observed.
613
612
  * @param {number} selectionLayerLevel The number which indicates what selection layer is currently modified.
614
613
  * @example
615
614
  * ::: only-for javascript
@@ -2005,6 +2004,7 @@ const REGISTERED_HOOKS = [/* eslint-disable jsdoc/require-description-complete-s
2005
2004
  *
2006
2005
  * @event Hooks#beforeFilter
2007
2006
  * @param {object[]} conditionsStack An array of objects with your [column filters](@/api/filters.md#addcondition).
2007
+ * @param {object[]|null} previousConditionsStack An array of objects with your previous [column filters](@/api/filters.md#addcondition). It can also be `null` if there was no previous filters applied or the conditions did not change between performing the `filter` action.
2008
2008
  * @returns {boolean} To perform server-side filtering (i.e., to not apply filtering to Handsontable's UI), return `false`.
2009
2009
  */
2010
2010
  'beforeFilter',
package/pluginHooks.mjs CHANGED
@@ -605,7 +605,6 @@ const REGISTERED_HOOKS = [/* eslint-disable jsdoc/require-description-complete-s
605
605
  * @param {object} preventScrolling A reference to the observable object with the `value` property.
606
606
  * Property `preventScrolling.value` expects a boolean value that
607
607
  * Handsontable uses to control scroll behavior after selection.
608
- * @param {object} preventScrolling Object with `value` property where its value change will be observed.
609
608
  * @param {number} selectionLayerLevel The number which indicates what selection layer is currently modified.
610
609
  * @example
611
610
  * ::: only-for javascript
@@ -2001,6 +2000,7 @@ const REGISTERED_HOOKS = [/* eslint-disable jsdoc/require-description-complete-s
2001
2000
  *
2002
2001
  * @event Hooks#beforeFilter
2003
2002
  * @param {object[]} conditionsStack An array of objects with your [column filters](@/api/filters.md#addcondition).
2003
+ * @param {object[]|null} previousConditionsStack An array of objects with your previous [column filters](@/api/filters.md#addcondition). It can also be `null` if there was no previous filters applied or the conditions did not change between performing the `filter` action.
2004
2004
  * @returns {boolean} To perform server-side filtering (i.e., to not apply filtering to Handsontable's UI), return `false`.
2005
2005
  */
2006
2006
  'beforeFilter',
@@ -482,7 +482,7 @@ class AutoColumnSize extends _base.BasePlugin {
482
482
  if (width === undefined) {
483
483
  width = this.columnWidthsMap.getValueAtIndex(this.hot.toPhysicalColumn(column));
484
484
  if (keepMinimum && typeof width === 'number') {
485
- width = Math.max(width, _src.ViewportColumnsCalculator.DEFAULT_WIDTH);
485
+ width = Math.max(width, _src.DEFAULT_COLUMN_WIDTH);
486
486
  }
487
487
  }
488
488
  return width;
@@ -17,7 +17,7 @@ import { isObject, hasOwnProperty } from "../../helpers/object.mjs";
17
17
  import { valueAccordingPercent, rangeEach } from "../../helpers/number.mjs";
18
18
  import SamplesGenerator from "../../utils/samplesGenerator.mjs";
19
19
  import { isPercentValue } from "../../helpers/string.mjs";
20
- import { ViewportColumnsCalculator } from "../../3rdparty/walkontable/src/index.mjs";
20
+ import { DEFAULT_COLUMN_WIDTH } from "../../3rdparty/walkontable/src/index.mjs";
21
21
  import { PhysicalIndexToValueMap as IndexToValueMap } from "../../translations/index.mjs";
22
22
  Hooks.getSingleton().register('modifyAutoColumnSizeSeed');
23
23
  export const PLUGIN_KEY = 'autoColumnSize';
@@ -478,7 +478,7 @@ export class AutoColumnSize extends BasePlugin {
478
478
  if (width === undefined) {
479
479
  width = this.columnWidthsMap.getValueAtIndex(this.hot.toPhysicalColumn(column));
480
480
  if (keepMinimum && typeof width === 'number') {
481
- width = Math.max(width, ViewportColumnsCalculator.DEFAULT_WIDTH);
481
+ width = Math.max(width, DEFAULT_COLUMN_WIDTH);
482
482
  }
483
483
  }
484
484
  return width;
@@ -37,8 +37,7 @@ const ROW_WIDTHS_MAP_NAME = 'autoRowSize';
37
37
  * resize the rows accordingly.
38
38
  * If you experience problems with the performance, try turning this feature off and declaring the row heights manually.
39
39
  *
40
- * But, to display Handsontable's [scrollbar](https://handsontable.com/docs/8.0.0/demo-scrolling.html)
41
- * in a proper size, you need to enable the `AutoRowSize` plugin,
40
+ * But, to display Handsontable's scrollbar in a proper size, you need to enable the `AutoRowSize` plugin,
42
41
  * by setting the [`autoRowSize`](@/api/options.md#autoRowSize) option to `true`.
43
42
  *
44
43
  * Row height calculations are divided into sync and async part. Each of this parts has their own advantages and
@@ -33,8 +33,7 @@ const ROW_WIDTHS_MAP_NAME = 'autoRowSize';
33
33
  * resize the rows accordingly.
34
34
  * If you experience problems with the performance, try turning this feature off and declaring the row heights manually.
35
35
  *
36
- * But, to display Handsontable's [scrollbar](https://handsontable.com/docs/8.0.0/demo-scrolling.html)
37
- * in a proper size, you need to enable the `AutoRowSize` plugin,
36
+ * But, to display Handsontable's scrollbar in a proper size, you need to enable the `AutoRowSize` plugin,
38
37
  * by setting the [`autoRowSize`](@/api/options.md#autoRowSize) option to `true`.
39
38
  *
40
39
  * Row height calculations are divided into sync and async part. Each of this parts has their own advantages and
@@ -722,7 +722,16 @@ class ColumnSorting extends _base.BasePlugin {
722
722
  this.hot.deselectCell();
723
723
  this.hot.selectColumns(coords.col);
724
724
  }
725
- this.sort(this.getColumnNextConfig(coords.col));
725
+ const activeEditor = this.hot.getActiveEditor();
726
+ const nextConfig = this.getColumnNextConfig(coords.col);
727
+ if (activeEditor !== null && activeEditor !== void 0 && activeEditor.isOpened() && this.hot.getCellValidator(activeEditor.row, activeEditor.col)) {
728
+ // Postpone sorting until the cell's value is validated and saved.
729
+ this.hot.addHookOnce('postAfterValidate', () => {
730
+ this.sort(nextConfig);
731
+ });
732
+ } else {
733
+ this.sort(nextConfig);
734
+ }
726
735
  }
727
736
  }
728
737
 
@@ -718,7 +718,16 @@ export class ColumnSorting extends BasePlugin {
718
718
  this.hot.deselectCell();
719
719
  this.hot.selectColumns(coords.col);
720
720
  }
721
- this.sort(this.getColumnNextConfig(coords.col));
721
+ const activeEditor = this.hot.getActiveEditor();
722
+ const nextConfig = this.getColumnNextConfig(coords.col);
723
+ if (activeEditor !== null && activeEditor !== void 0 && activeEditor.isOpened() && this.hot.getCellValidator(activeEditor.row, activeEditor.col)) {
724
+ // Postpone sorting until the cell's value is validated and saved.
725
+ this.hot.addHookOnce('postAfterValidate', () => {
726
+ this.sort(nextConfig);
727
+ });
728
+ } else {
729
+ this.sort(nextConfig);
730
+ }
722
731
  }
723
732
  }
724
733
 
@@ -25,17 +25,16 @@ function createMenuItemRenderer(mainTableHot) {
25
25
  * @param {string} value The cell value.
26
26
  */
27
27
  return (menuHot, TD, row, col, prop, value) => {
28
- if (TD.hasAttribute('ghost-table')) {
29
- return;
30
- }
31
28
  const item = menuHot.getSourceDataAtRow(row);
32
29
  const wrapper = mainTableHot.rootDocument.createElement('div');
33
30
  const itemValue = typeof value === 'function' ? value.call(mainTableHot) : value;
31
+ const ariaLabel = typeof item.ariaLabel === 'function' ? item.ariaLabel.call(mainTableHot) : item.ariaLabel;
32
+ const ariaChecked = typeof item.ariaChecked === 'function' ? item.ariaChecked.call(mainTableHot) : item.ariaChecked;
34
33
  (0, _element.empty)(TD);
35
34
  (0, _element.addClass)(wrapper, 'htItemWrapper');
36
35
  if (mainTableHot.getSettings().ariaTags) {
37
36
  const isFocusable = !(0, _utils.isItemDisabled)(item, mainTableHot) && !(0, _utils.isItemSelectionDisabled)(item) && !(0, _utils.isItemSeparator)(item);
38
- (0, _element.setAttribute)(TD, [(0, _a11y.A11Y_MENU_ITEM)(), (0, _a11y.A11Y_LABEL)(itemValue), ...(isFocusable ? [(0, _a11y.A11Y_TABINDEX)(-1)] : []), ...((0, _utils.isItemDisabled)(item, mainTableHot) ? [(0, _a11y.A11Y_DISABLED)()] : []), ...((0, _utils.isItemSubMenu)(item) ? [(0, _a11y.A11Y_EXPANDED)(false)] : [])]);
37
+ (0, _element.setAttribute)(TD, [...((0, _utils.isItemCheckable)(item) ? [(0, _a11y.A11Y_MENU_ITEM_CHECKBOX)(), (0, _a11y.A11Y_LABEL)(ariaLabel), (0, _a11y.A11Y_CHECKED)(ariaChecked)] : [(0, _a11y.A11Y_MENU_ITEM)(), (0, _a11y.A11Y_LABEL)(itemValue)]), ...(isFocusable ? [(0, _a11y.A11Y_TABINDEX)(-1)] : []), ...((0, _utils.isItemDisabled)(item, mainTableHot) ? [(0, _a11y.A11Y_DISABLED)()] : []), ...((0, _utils.isItemSubMenu)(item) ? [(0, _a11y.A11Y_EXPANDED)(false)] : [])]);
39
38
  }
40
39
  TD.className = '';
41
40
  TD.appendChild(wrapper);
@@ -1,6 +1,6 @@
1
- import { isItemSubMenu, isItemDisabled, isItemSelectionDisabled, isItemSeparator } from "./utils.mjs";
1
+ import { isItemSubMenu, isItemDisabled, isItemSelectionDisabled, isItemSeparator, isItemCheckable } from "./utils.mjs";
2
2
  import { addClass, empty, fastInnerHTML, setAttribute } from "../../../helpers/dom/element.mjs";
3
- import { A11Y_DISABLED, A11Y_EXPANDED, A11Y_LABEL, A11Y_MENU_ITEM, A11Y_TABINDEX } from "../../../helpers/a11y.mjs";
3
+ import { A11Y_MENU_ITEM_CHECKBOX, A11Y_DISABLED, A11Y_EXPANDED, A11Y_LABEL, A11Y_MENU_ITEM, A11Y_TABINDEX, A11Y_CHECKED } from "../../../helpers/a11y.mjs";
4
4
  /**
5
5
  * Creates the menu renderer function.
6
6
  *
@@ -21,17 +21,16 @@ export function createMenuItemRenderer(mainTableHot) {
21
21
  * @param {string} value The cell value.
22
22
  */
23
23
  return (menuHot, TD, row, col, prop, value) => {
24
- if (TD.hasAttribute('ghost-table')) {
25
- return;
26
- }
27
24
  const item = menuHot.getSourceDataAtRow(row);
28
25
  const wrapper = mainTableHot.rootDocument.createElement('div');
29
26
  const itemValue = typeof value === 'function' ? value.call(mainTableHot) : value;
27
+ const ariaLabel = typeof item.ariaLabel === 'function' ? item.ariaLabel.call(mainTableHot) : item.ariaLabel;
28
+ const ariaChecked = typeof item.ariaChecked === 'function' ? item.ariaChecked.call(mainTableHot) : item.ariaChecked;
30
29
  empty(TD);
31
30
  addClass(wrapper, 'htItemWrapper');
32
31
  if (mainTableHot.getSettings().ariaTags) {
33
32
  const isFocusable = !isItemDisabled(item, mainTableHot) && !isItemSelectionDisabled(item) && !isItemSeparator(item);
34
- setAttribute(TD, [A11Y_MENU_ITEM(), A11Y_LABEL(itemValue), ...(isFocusable ? [A11Y_TABINDEX(-1)] : []), ...(isItemDisabled(item, mainTableHot) ? [A11Y_DISABLED()] : []), ...(isItemSubMenu(item) ? [A11Y_EXPANDED(false)] : [])]);
33
+ setAttribute(TD, [...(isItemCheckable(item) ? [A11Y_MENU_ITEM_CHECKBOX(), A11Y_LABEL(ariaLabel), A11Y_CHECKED(ariaChecked)] : [A11Y_MENU_ITEM(), A11Y_LABEL(itemValue)]), ...(isFocusable ? [A11Y_TABINDEX(-1)] : []), ...(isItemDisabled(item, mainTableHot) ? [A11Y_DISABLED()] : []), ...(isItemSubMenu(item) ? [A11Y_EXPANDED(false)] : [])]);
35
34
  }
36
35
  TD.className = '';
37
36
  TD.appendChild(wrapper);
@@ -165,12 +165,8 @@ class Positioner {
165
165
  setPositionOnRightOfCursor() {
166
166
  let left = _classPrivateFieldGet(_cursor, this).left;
167
167
  if (_classPrivateFieldGet(_parentContainer, this)) {
168
- const {
169
- right: parentMenuRight
170
- } = _classPrivateFieldGet(_parentContainer, this).getBoundingClientRect();
171
-
172
- // move the sub menu by the width of the parent's border (usually by 1-2 pixels)
173
- left += _classPrivateFieldGet(_cursor, this).cellWidth + parentMenuRight - (_classPrivateFieldGet(_cursor, this).left + _classPrivateFieldGet(_cursor, this).cellWidth);
168
+ const borderRightWidth = Number.parseInt(getComputedStyle(_classPrivateFieldGet(_parentContainer, this).querySelector('.htCore')).borderRightWidth, 10);
169
+ left += _classPrivateFieldGet(_cursor, this).cellWidth + borderRightWidth;
174
170
  } else {
175
171
  left += _classPrivateFieldGet(_offset, this).right;
176
172
  }
@@ -183,12 +179,8 @@ class Positioner {
183
179
  setPositionOnLeftOfCursor() {
184
180
  let left = _classPrivateFieldGet(_offset, this).left + _classPrivateFieldGet(_cursor, this).left - _classPrivateFieldGet(_container, this).offsetWidth;
185
181
  if (_classPrivateFieldGet(_parentContainer, this)) {
186
- const {
187
- left: parentMenuLeft
188
- } = _classPrivateFieldGet(_parentContainer, this).getBoundingClientRect();
189
-
190
- // move the sub menu by the width of the parent's border (usually by 1-2 pixels)
191
- left -= _classPrivateFieldGet(_cursor, this).left - parentMenuLeft;
182
+ const borderLeftWidth = Number.parseInt(getComputedStyle(_classPrivateFieldGet(_parentContainer, this).querySelector('.htCore')).borderLeftWidth, 10);
183
+ left -= borderLeftWidth;
192
184
  }
193
185
  _classPrivateFieldGet(_container, this).style.left = `${left}px`;
194
186
  }
@@ -162,12 +162,8 @@ export class Positioner {
162
162
  setPositionOnRightOfCursor() {
163
163
  let left = _classPrivateFieldGet(_cursor, this).left;
164
164
  if (_classPrivateFieldGet(_parentContainer, this)) {
165
- const {
166
- right: parentMenuRight
167
- } = _classPrivateFieldGet(_parentContainer, this).getBoundingClientRect();
168
-
169
- // move the sub menu by the width of the parent's border (usually by 1-2 pixels)
170
- left += _classPrivateFieldGet(_cursor, this).cellWidth + parentMenuRight - (_classPrivateFieldGet(_cursor, this).left + _classPrivateFieldGet(_cursor, this).cellWidth);
165
+ const borderRightWidth = Number.parseInt(getComputedStyle(_classPrivateFieldGet(_parentContainer, this).querySelector('.htCore')).borderRightWidth, 10);
166
+ left += _classPrivateFieldGet(_cursor, this).cellWidth + borderRightWidth;
171
167
  } else {
172
168
  left += _classPrivateFieldGet(_offset, this).right;
173
169
  }
@@ -180,12 +176,8 @@ export class Positioner {
180
176
  setPositionOnLeftOfCursor() {
181
177
  let left = _classPrivateFieldGet(_offset, this).left + _classPrivateFieldGet(_cursor, this).left - _classPrivateFieldGet(_container, this).offsetWidth;
182
178
  if (_classPrivateFieldGet(_parentContainer, this)) {
183
- const {
184
- left: parentMenuLeft
185
- } = _classPrivateFieldGet(_parentContainer, this).getBoundingClientRect();
186
-
187
- // move the sub menu by the width of the parent's border (usually by 1-2 pixels)
188
- left -= _classPrivateFieldGet(_cursor, this).left - parentMenuLeft;
179
+ const borderLeftWidth = Number.parseInt(getComputedStyle(_classPrivateFieldGet(_parentContainer, this).querySelector('.htCore')).borderLeftWidth, 10);
180
+ left -= borderLeftWidth;
189
181
  }
190
182
  _classPrivateFieldGet(_container, this).style.left = `${left}px`;
191
183
  }
@@ -4,6 +4,7 @@ exports.__esModule = true;
4
4
  exports.filterSeparators = filterSeparators;
5
5
  exports.hasSubMenu = hasSubMenu;
6
6
  exports.isDisabled = isDisabled;
7
+ exports.isItemCheckable = isItemCheckable;
7
8
  exports.isItemDisabled = isItemDisabled;
8
9
  exports.isItemHidden = isItemHidden;
9
10
  exports.isItemSelectionDisabled = isItemSelectionDisabled;
@@ -174,4 +175,14 @@ function filterSeparators(items) {
174
175
  result = popSeparators(result, separator);
175
176
  result = removeDuplicatedSeparators(result);
176
177
  return result;
178
+ }
179
+
180
+ /**
181
+ * Check if the provided element presents the checkboxable menu item.
182
+ *
183
+ * @param {object} itemToTest Item element.
184
+ * @returns {boolean}
185
+ */
186
+ function isItemCheckable(itemToTest) {
187
+ return itemToTest.checkable === true;
177
188
  }
@@ -160,4 +160,14 @@ export function filterSeparators(items) {
160
160
  result = popSeparators(result, separator);
161
161
  result = removeDuplicatedSeparators(result);
162
162
  return result;
163
+ }
164
+
165
+ /**
166
+ * Check if the provided element presents the checkboxable menu item.
167
+ *
168
+ * @param {object} itemToTest Item element.
169
+ * @returns {boolean}
170
+ */
171
+ export function isItemCheckable(itemToTest) {
172
+ return itemToTest.checkable === true;
163
173
  }
@@ -9,6 +9,17 @@ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return
9
9
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
10
10
  const KEY = exports.KEY = 'alignment';
11
11
 
12
+ /**
13
+ * @param {object} hot The current Handsontable instance.
14
+ * @param {string} rawName The raw name of the menu item.
15
+ * @param {string} htClassName The class name to check.
16
+ * @returns {string} The value of aria-label parameter.
17
+ */
18
+ function ariaLabel(hot, rawName, htClassName) {
19
+ const checkboxState = (0, _utils.hasSelectionAClass)(hot, htClassName) ? hot.getTranslatedPhrase(C.CHECKBOX_CHECKED) : hot.getTranslatedPhrase(C.CHECKBOX_UNCHECKED);
20
+ return `${rawName} ${checkboxState.toLowerCase()}`;
21
+ }
22
+
12
23
  /**
13
24
  * @returns {object}
14
25
  */
@@ -34,15 +45,16 @@ function alignmentItem() {
34
45
  submenu: {
35
46
  items: [{
36
47
  key: `${KEY}:left`,
48
+ checkable: true,
49
+ ariaLabel() {
50
+ return ariaLabel(this, this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_LEFT), 'htLeft');
51
+ },
52
+ ariaChecked() {
53
+ return (0, _utils.hasSelectionAClass)(this, 'htLeft');
54
+ },
37
55
  name() {
38
56
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_LEFT);
39
- const hasClass = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => {
40
- const className = this.getCellMeta(row, col).className;
41
- if (className && className.indexOf('htLeft') !== -1) {
42
- return true;
43
- }
44
- });
45
- if (hasClass) {
57
+ if ((0, _utils.hasSelectionAClass)(this, 'htLeft')) {
46
58
  label = (0, _utils.markLabelAsSelected)(label);
47
59
  }
48
60
  return label;
@@ -59,15 +71,16 @@ function alignmentItem() {
59
71
  disabled: false
60
72
  }, {
61
73
  key: `${KEY}:center`,
74
+ checkable: true,
75
+ ariaLabel() {
76
+ return ariaLabel(this, this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_CENTER), 'htCenter');
77
+ },
78
+ ariaChecked() {
79
+ return (0, _utils.hasSelectionAClass)(this, 'htCenter');
80
+ },
62
81
  name() {
63
82
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_CENTER);
64
- const hasClass = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => {
65
- const className = this.getCellMeta(row, col).className;
66
- if (className && className.indexOf('htCenter') !== -1) {
67
- return true;
68
- }
69
- });
70
- if (hasClass) {
83
+ if ((0, _utils.hasSelectionAClass)(this, 'htCenter')) {
71
84
  label = (0, _utils.markLabelAsSelected)(label);
72
85
  }
73
86
  return label;
@@ -84,15 +97,16 @@ function alignmentItem() {
84
97
  disabled: false
85
98
  }, {
86
99
  key: `${KEY}:right`,
100
+ checkable: true,
101
+ ariaLabel() {
102
+ return ariaLabel(this, this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_RIGHT), 'htRight');
103
+ },
104
+ ariaChecked() {
105
+ return (0, _utils.hasSelectionAClass)(this, 'htRight');
106
+ },
87
107
  name() {
88
108
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_RIGHT);
89
- const hasClass = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => {
90
- const className = this.getCellMeta(row, col).className;
91
- if (className && className.indexOf('htRight') !== -1) {
92
- return true;
93
- }
94
- });
95
- if (hasClass) {
109
+ if ((0, _utils.hasSelectionAClass)(this, 'htRight')) {
96
110
  label = (0, _utils.markLabelAsSelected)(label);
97
111
  }
98
112
  return label;
@@ -109,15 +123,16 @@ function alignmentItem() {
109
123
  disabled: false
110
124
  }, {
111
125
  key: `${KEY}:justify`,
126
+ checkable: true,
127
+ ariaLabel() {
128
+ return ariaLabel(this, this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_JUSTIFY), 'htJustify');
129
+ },
130
+ ariaChecked() {
131
+ return (0, _utils.hasSelectionAClass)(this, 'htJustify');
132
+ },
112
133
  name() {
113
134
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_JUSTIFY);
114
- const hasClass = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => {
115
- const className = this.getCellMeta(row, col).className;
116
- if (className && className.indexOf('htJustify') !== -1) {
117
- return true;
118
- }
119
- });
120
- if (hasClass) {
135
+ if ((0, _utils.hasSelectionAClass)(this, 'htJustify')) {
121
136
  label = (0, _utils.markLabelAsSelected)(label);
122
137
  }
123
138
  return label;
@@ -136,15 +151,16 @@ function alignmentItem() {
136
151
  name: _separator.KEY
137
152
  }, {
138
153
  key: `${KEY}:top`,
154
+ checkable: true,
155
+ ariaLabel() {
156
+ return ariaLabel(this, this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_TOP), 'htTop');
157
+ },
158
+ ariaChecked() {
159
+ return (0, _utils.hasSelectionAClass)(this, 'htTop');
160
+ },
139
161
  name() {
140
162
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_TOP);
141
- const hasClass = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => {
142
- const className = this.getCellMeta(row, col).className;
143
- if (className && className.indexOf('htTop') !== -1) {
144
- return true;
145
- }
146
- });
147
- if (hasClass) {
163
+ if ((0, _utils.hasSelectionAClass)(this, 'htTop')) {
148
164
  label = (0, _utils.markLabelAsSelected)(label);
149
165
  }
150
166
  return label;
@@ -161,15 +177,16 @@ function alignmentItem() {
161
177
  disabled: false
162
178
  }, {
163
179
  key: `${KEY}:middle`,
180
+ checkable: true,
181
+ ariaLabel() {
182
+ return ariaLabel(this, this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_MIDDLE), 'htMiddle');
183
+ },
184
+ ariaChecked() {
185
+ return (0, _utils.hasSelectionAClass)(this, 'htMiddle');
186
+ },
164
187
  name() {
165
188
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_MIDDLE);
166
- const hasClass = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => {
167
- const className = this.getCellMeta(row, col).className;
168
- if (className && className.indexOf('htMiddle') !== -1) {
169
- return true;
170
- }
171
- });
172
- if (hasClass) {
189
+ if ((0, _utils.hasSelectionAClass)(this, 'htMiddle')) {
173
190
  label = (0, _utils.markLabelAsSelected)(label);
174
191
  }
175
192
  return label;
@@ -186,15 +203,16 @@ function alignmentItem() {
186
203
  disabled: false
187
204
  }, {
188
205
  key: `${KEY}:bottom`,
206
+ checkable: true,
207
+ ariaLabel() {
208
+ return ariaLabel(this, this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_BOTTOM), 'htBottom');
209
+ },
210
+ ariaChecked() {
211
+ return (0, _utils.hasSelectionAClass)(this, 'htBottom');
212
+ },
189
213
  name() {
190
214
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_BOTTOM);
191
- const hasClass = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => {
192
- const className = this.getCellMeta(row, col).className;
193
- if (className && className.indexOf('htBottom') !== -1) {
194
- return true;
195
- }
196
- });
197
- if (hasClass) {
215
+ if ((0, _utils.hasSelectionAClass)(this, 'htBottom')) {
198
216
  label = (0, _utils.markLabelAsSelected)(label);
199
217
  }
200
218
  return label;