handsontable 14.5.0 → 14.6.0-next-4d69faf-20240924

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. package/3rdparty/walkontable/src/renderer/rows.js +10 -0
  2. package/3rdparty/walkontable/src/renderer/rows.mjs +11 -1
  3. package/3rdparty/walkontable/src/selection/manager.js +7 -7
  4. package/3rdparty/walkontable/src/selection/manager.mjs +7 -7
  5. package/3rdparty/walkontable/src/selection/scanner.js +7 -7
  6. package/3rdparty/walkontable/src/selection/scanner.mjs +7 -7
  7. package/CHANGELOG.md +29 -0
  8. package/base.js +2 -2
  9. package/base.mjs +2 -2
  10. package/core.d.ts +13 -2
  11. package/core.js +160 -9
  12. package/core.mjs +160 -9
  13. package/dataMap/metaManager/lazyFactoryMap.js +7 -7
  14. package/dataMap/metaManager/lazyFactoryMap.mjs +7 -7
  15. package/dataMap/metaManager/metaSchema.js +5 -6
  16. package/dataMap/metaManager/metaSchema.mjs +7 -8
  17. package/dataMap/metaManager/mods/dynamicCellMeta.js +7 -7
  18. package/dataMap/metaManager/mods/dynamicCellMeta.mjs +7 -7
  19. package/dataMap/metaManager/mods/extendMetaProperties.js +7 -7
  20. package/dataMap/metaManager/mods/extendMetaProperties.mjs +7 -7
  21. package/dataMap/metaManager/utils.js +7 -7
  22. package/dataMap/metaManager/utils.mjs +7 -7
  23. package/dist/handsontable.css +3 -17
  24. package/dist/handsontable.full.css +3 -17
  25. package/dist/handsontable.full.js +3498 -3219
  26. package/dist/handsontable.full.min.css +3 -3
  27. package/dist/handsontable.full.min.js +109 -119
  28. package/dist/handsontable.js +3172 -2897
  29. package/dist/handsontable.min.css +3 -3
  30. package/dist/handsontable.min.js +19 -19
  31. package/editors/autocompleteEditor/autocompleteEditor.d.ts +1 -1
  32. package/helpers/a11y.js +2 -0
  33. package/helpers/a11y.mjs +1 -0
  34. package/helpers/array.js +7 -7
  35. package/helpers/array.mjs +7 -7
  36. package/helpers/mixed.js +2 -2
  37. package/helpers/mixed.mjs +2 -2
  38. package/helpers/number.js +7 -7
  39. package/helpers/number.mjs +7 -7
  40. package/package.json +1 -1
  41. package/pluginHooks.d.ts +1 -1
  42. package/pluginHooks.js +1 -0
  43. package/pluginHooks.mjs +1 -0
  44. package/plugins/autoRowSize/autoRowSize.js +1 -2
  45. package/plugins/autoRowSize/autoRowSize.mjs +1 -2
  46. package/plugins/columnSorting/columnSorting.js +10 -1
  47. package/plugins/columnSorting/columnSorting.mjs +10 -1
  48. package/plugins/columnSorting/utils.js +7 -7
  49. package/plugins/columnSorting/utils.mjs +7 -7
  50. package/plugins/contextMenu/contextMenu.js +7 -0
  51. package/plugins/contextMenu/contextMenu.mjs +7 -0
  52. package/plugins/contextMenu/menu/menu.js +47 -14
  53. package/plugins/contextMenu/menu/menu.mjs +48 -15
  54. package/plugins/contextMenu/menu/menuItemRenderer.js +3 -4
  55. package/plugins/contextMenu/menu/menuItemRenderer.mjs +5 -6
  56. package/plugins/contextMenu/menu/positioner.js +4 -12
  57. package/plugins/contextMenu/menu/positioner.mjs +4 -12
  58. package/plugins/contextMenu/menu/utils.js +11 -0
  59. package/plugins/contextMenu/menu/utils.mjs +10 -0
  60. package/plugins/contextMenu/predefinedItems/alignment.js +56 -49
  61. package/plugins/contextMenu/predefinedItems/alignment.mjs +57 -50
  62. package/plugins/contextMenu/predefinedItems/readOnly.js +8 -0
  63. package/plugins/contextMenu/predefinedItems/readOnly.mjs +8 -0
  64. package/plugins/contextMenu/utils.js +26 -0
  65. package/plugins/contextMenu/utils.mjs +24 -0
  66. package/plugins/copyPaste/copyPaste.js +14 -14
  67. package/plugins/copyPaste/copyPaste.mjs +14 -14
  68. package/plugins/dropdownMenu/dropdownMenu.js +10 -4
  69. package/plugins/dropdownMenu/dropdownMenu.mjs +10 -4
  70. package/plugins/filters/component/condition.js +6 -1
  71. package/plugins/filters/component/condition.mjs +6 -1
  72. package/plugins/filters/component/value.js +6 -1
  73. package/plugins/filters/component/value.mjs +6 -1
  74. package/plugins/filters/conditionCollection.d.ts +4 -3
  75. package/plugins/filters/conditionCollection.js +26 -0
  76. package/plugins/filters/conditionCollection.mjs +26 -0
  77. package/plugins/filters/filters.js +4 -1
  78. package/plugins/filters/filters.mjs +4 -1
  79. package/plugins/filters/ui/multipleSelect.js +7 -9
  80. package/plugins/filters/ui/multipleSelect.mjs +7 -9
  81. package/plugins/filters/utils.js +7 -7
  82. package/plugins/filters/utils.mjs +7 -7
  83. package/plugins/formulas/formulas.js +7 -7
  84. package/plugins/formulas/formulas.mjs +7 -7
  85. package/plugins/hiddenColumns/hiddenColumns.js +7 -7
  86. package/plugins/hiddenColumns/hiddenColumns.mjs +7 -7
  87. package/plugins/hiddenRows/hiddenRows.js +7 -7
  88. package/plugins/hiddenRows/hiddenRows.mjs +7 -7
  89. package/plugins/mergeCells/cellsCollection.js +18 -16
  90. package/plugins/mergeCells/cellsCollection.mjs +19 -17
  91. package/plugins/mergeCells/mergeCells.js +7 -7
  92. package/plugins/mergeCells/mergeCells.mjs +7 -7
  93. package/plugins/nestedHeaders/stateManager/nodeModifiers/collapse.js +7 -7
  94. package/plugins/nestedHeaders/stateManager/nodeModifiers/collapse.mjs +7 -7
  95. package/plugins/nestedHeaders/stateManager/nodeModifiers/expand.js +7 -7
  96. package/plugins/nestedHeaders/stateManager/nodeModifiers/expand.mjs +7 -7
  97. package/plugins/nestedRows/nestedRows.js +7 -7
  98. package/plugins/nestedRows/nestedRows.mjs +7 -7
  99. package/plugins/trimRows/trimRows.js +7 -7
  100. package/plugins/trimRows/trimRows.mjs +7 -7
  101. package/plugins/undoRedo/undoRedo.js +9 -5
  102. package/plugins/undoRedo/undoRedo.mjs +9 -5
  103. package/renderers/checkboxRenderer/checkboxRenderer.js +18 -6
  104. package/renderers/checkboxRenderer/checkboxRenderer.mjs +18 -6
  105. package/selection/selection.js +7 -7
  106. package/selection/selection.mjs +7 -7
  107. package/selection/utils.js +7 -7
  108. package/selection/utils.mjs +7 -7
  109. package/shortcutContexts/grid.js +10 -3
  110. package/shortcutContexts/grid.mjs +10 -3
  111. package/shortcuts/keyObserver.js +7 -7
  112. package/shortcuts/keyObserver.mjs +7 -7
  113. package/shortcuts/utils.js +3 -1
  114. package/shortcuts/utils.mjs +3 -1
  115. package/translations/changesObservable/observable.js +7 -7
  116. package/translations/changesObservable/observable.mjs +7 -7
  117. package/translations/indexMapper.js +7 -7
  118. package/translations/indexMapper.mjs +7 -7
  119. package/utils/dataStructures/uniqueSet.js +7 -7
  120. package/utils/dataStructures/uniqueSet.mjs +7 -7
  121. package/utils/ghostTable.js +11 -9
  122. package/utils/ghostTable.mjs +12 -10
  123. package/utils/paginator.js +7 -7
  124. package/utils/paginator.mjs +7 -7
@@ -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
  }
@@ -34,15 +34,16 @@ function alignmentItem() {
34
34
  submenu: {
35
35
  items: [{
36
36
  key: `${KEY}:left`,
37
+ checkable: true,
38
+ ariaLabel() {
39
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_LEFT);
40
+ },
41
+ ariaChecked() {
42
+ return (0, _utils.hasSelectionAClass)(this, 'htLeft');
43
+ },
37
44
  name() {
38
45
  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) {
46
+ if ((0, _utils.hasSelectionAClass)(this, 'htLeft')) {
46
47
  label = (0, _utils.markLabelAsSelected)(label);
47
48
  }
48
49
  return label;
@@ -59,15 +60,16 @@ function alignmentItem() {
59
60
  disabled: false
60
61
  }, {
61
62
  key: `${KEY}:center`,
63
+ checkable: true,
64
+ ariaLabel() {
65
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_CENTER);
66
+ },
67
+ ariaChecked() {
68
+ return (0, _utils.hasSelectionAClass)(this, 'htCenter');
69
+ },
62
70
  name() {
63
71
  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) {
72
+ if ((0, _utils.hasSelectionAClass)(this, 'htCenter')) {
71
73
  label = (0, _utils.markLabelAsSelected)(label);
72
74
  }
73
75
  return label;
@@ -84,15 +86,16 @@ function alignmentItem() {
84
86
  disabled: false
85
87
  }, {
86
88
  key: `${KEY}:right`,
89
+ checkable: true,
90
+ ariaLabel() {
91
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_RIGHT);
92
+ },
93
+ ariaChecked() {
94
+ return (0, _utils.hasSelectionAClass)(this, 'htRight');
95
+ },
87
96
  name() {
88
97
  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) {
98
+ if ((0, _utils.hasSelectionAClass)(this, 'htRight')) {
96
99
  label = (0, _utils.markLabelAsSelected)(label);
97
100
  }
98
101
  return label;
@@ -109,15 +112,16 @@ function alignmentItem() {
109
112
  disabled: false
110
113
  }, {
111
114
  key: `${KEY}:justify`,
115
+ checkable: true,
116
+ ariaLabel() {
117
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_JUSTIFY);
118
+ },
119
+ ariaChecked() {
120
+ return (0, _utils.hasSelectionAClass)(this, 'htJustify');
121
+ },
112
122
  name() {
113
123
  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) {
124
+ if ((0, _utils.hasSelectionAClass)(this, 'htJustify')) {
121
125
  label = (0, _utils.markLabelAsSelected)(label);
122
126
  }
123
127
  return label;
@@ -136,15 +140,16 @@ function alignmentItem() {
136
140
  name: _separator.KEY
137
141
  }, {
138
142
  key: `${KEY}:top`,
143
+ checkable: true,
144
+ ariaLabel() {
145
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_TOP);
146
+ },
147
+ ariaChecked() {
148
+ return (0, _utils.hasSelectionAClass)(this, 'htTop');
149
+ },
139
150
  name() {
140
151
  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) {
152
+ if ((0, _utils.hasSelectionAClass)(this, 'htTop')) {
148
153
  label = (0, _utils.markLabelAsSelected)(label);
149
154
  }
150
155
  return label;
@@ -161,15 +166,16 @@ function alignmentItem() {
161
166
  disabled: false
162
167
  }, {
163
168
  key: `${KEY}:middle`,
169
+ checkable: true,
170
+ ariaLabel() {
171
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_MIDDLE);
172
+ },
173
+ ariaChecked() {
174
+ return (0, _utils.hasSelectionAClass)(this, 'htMiddle');
175
+ },
164
176
  name() {
165
177
  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) {
178
+ if ((0, _utils.hasSelectionAClass)(this, 'htMiddle')) {
173
179
  label = (0, _utils.markLabelAsSelected)(label);
174
180
  }
175
181
  return label;
@@ -186,15 +192,16 @@ function alignmentItem() {
186
192
  disabled: false
187
193
  }, {
188
194
  key: `${KEY}:bottom`,
195
+ checkable: true,
196
+ ariaLabel() {
197
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_BOTTOM);
198
+ },
199
+ ariaChecked() {
200
+ return (0, _utils.hasSelectionAClass)(this, 'htBottom');
201
+ },
189
202
  name() {
190
203
  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) {
204
+ if ((0, _utils.hasSelectionAClass)(this, 'htBottom')) {
198
205
  label = (0, _utils.markLabelAsSelected)(label);
199
206
  }
200
207
  return label;
@@ -1,4 +1,4 @@
1
- import { align, getAlignmentClasses, checkSelectionConsistency, markLabelAsSelected } from "../utils.mjs";
1
+ import { align, getAlignmentClasses, markLabelAsSelected, hasSelectionAClass } from "../utils.mjs";
2
2
  import { KEY as SEPARATOR } from "./separator.mjs";
3
3
  import * as C from "../../../i18n/constants.mjs";
4
4
  export const KEY = 'alignment';
@@ -28,15 +28,16 @@ export default function alignmentItem() {
28
28
  submenu: {
29
29
  items: [{
30
30
  key: `${KEY}:left`,
31
+ checkable: true,
32
+ ariaLabel() {
33
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_LEFT);
34
+ },
35
+ ariaChecked() {
36
+ return hasSelectionAClass(this, 'htLeft');
37
+ },
31
38
  name() {
32
39
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_LEFT);
33
- const hasClass = checkSelectionConsistency(this.getSelectedRange(), (row, col) => {
34
- const className = this.getCellMeta(row, col).className;
35
- if (className && className.indexOf('htLeft') !== -1) {
36
- return true;
37
- }
38
- });
39
- if (hasClass) {
40
+ if (hasSelectionAClass(this, 'htLeft')) {
40
41
  label = markLabelAsSelected(label);
41
42
  }
42
43
  return label;
@@ -53,15 +54,16 @@ export default function alignmentItem() {
53
54
  disabled: false
54
55
  }, {
55
56
  key: `${KEY}:center`,
57
+ checkable: true,
58
+ ariaLabel() {
59
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_CENTER);
60
+ },
61
+ ariaChecked() {
62
+ return hasSelectionAClass(this, 'htCenter');
63
+ },
56
64
  name() {
57
65
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_CENTER);
58
- const hasClass = checkSelectionConsistency(this.getSelectedRange(), (row, col) => {
59
- const className = this.getCellMeta(row, col).className;
60
- if (className && className.indexOf('htCenter') !== -1) {
61
- return true;
62
- }
63
- });
64
- if (hasClass) {
66
+ if (hasSelectionAClass(this, 'htCenter')) {
65
67
  label = markLabelAsSelected(label);
66
68
  }
67
69
  return label;
@@ -78,15 +80,16 @@ export default function alignmentItem() {
78
80
  disabled: false
79
81
  }, {
80
82
  key: `${KEY}:right`,
83
+ checkable: true,
84
+ ariaLabel() {
85
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_RIGHT);
86
+ },
87
+ ariaChecked() {
88
+ return hasSelectionAClass(this, 'htRight');
89
+ },
81
90
  name() {
82
91
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_RIGHT);
83
- const hasClass = checkSelectionConsistency(this.getSelectedRange(), (row, col) => {
84
- const className = this.getCellMeta(row, col).className;
85
- if (className && className.indexOf('htRight') !== -1) {
86
- return true;
87
- }
88
- });
89
- if (hasClass) {
92
+ if (hasSelectionAClass(this, 'htRight')) {
90
93
  label = markLabelAsSelected(label);
91
94
  }
92
95
  return label;
@@ -103,15 +106,16 @@ export default function alignmentItem() {
103
106
  disabled: false
104
107
  }, {
105
108
  key: `${KEY}:justify`,
109
+ checkable: true,
110
+ ariaLabel() {
111
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_JUSTIFY);
112
+ },
113
+ ariaChecked() {
114
+ return hasSelectionAClass(this, 'htJustify');
115
+ },
106
116
  name() {
107
117
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_JUSTIFY);
108
- const hasClass = checkSelectionConsistency(this.getSelectedRange(), (row, col) => {
109
- const className = this.getCellMeta(row, col).className;
110
- if (className && className.indexOf('htJustify') !== -1) {
111
- return true;
112
- }
113
- });
114
- if (hasClass) {
118
+ if (hasSelectionAClass(this, 'htJustify')) {
115
119
  label = markLabelAsSelected(label);
116
120
  }
117
121
  return label;
@@ -130,15 +134,16 @@ export default function alignmentItem() {
130
134
  name: SEPARATOR
131
135
  }, {
132
136
  key: `${KEY}:top`,
137
+ checkable: true,
138
+ ariaLabel() {
139
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_TOP);
140
+ },
141
+ ariaChecked() {
142
+ return hasSelectionAClass(this, 'htTop');
143
+ },
133
144
  name() {
134
145
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_TOP);
135
- const hasClass = checkSelectionConsistency(this.getSelectedRange(), (row, col) => {
136
- const className = this.getCellMeta(row, col).className;
137
- if (className && className.indexOf('htTop') !== -1) {
138
- return true;
139
- }
140
- });
141
- if (hasClass) {
146
+ if (hasSelectionAClass(this, 'htTop')) {
142
147
  label = markLabelAsSelected(label);
143
148
  }
144
149
  return label;
@@ -155,15 +160,16 @@ export default function alignmentItem() {
155
160
  disabled: false
156
161
  }, {
157
162
  key: `${KEY}:middle`,
163
+ checkable: true,
164
+ ariaLabel() {
165
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_MIDDLE);
166
+ },
167
+ ariaChecked() {
168
+ return hasSelectionAClass(this, 'htMiddle');
169
+ },
158
170
  name() {
159
171
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_MIDDLE);
160
- const hasClass = checkSelectionConsistency(this.getSelectedRange(), (row, col) => {
161
- const className = this.getCellMeta(row, col).className;
162
- if (className && className.indexOf('htMiddle') !== -1) {
163
- return true;
164
- }
165
- });
166
- if (hasClass) {
172
+ if (hasSelectionAClass(this, 'htMiddle')) {
167
173
  label = markLabelAsSelected(label);
168
174
  }
169
175
  return label;
@@ -180,15 +186,16 @@ export default function alignmentItem() {
180
186
  disabled: false
181
187
  }, {
182
188
  key: `${KEY}:bottom`,
189
+ checkable: true,
190
+ ariaLabel() {
191
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_BOTTOM);
192
+ },
193
+ ariaChecked() {
194
+ return hasSelectionAClass(this, 'htBottom');
195
+ },
183
196
  name() {
184
197
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_BOTTOM);
185
- const hasClass = checkSelectionConsistency(this.getSelectedRange(), (row, col) => {
186
- const className = this.getCellMeta(row, col).className;
187
- if (className && className.indexOf('htBottom') !== -1) {
188
- return true;
189
- }
190
- });
191
- if (hasClass) {
198
+ if (hasSelectionAClass(this, 'htBottom')) {
192
199
  label = markLabelAsSelected(label);
193
200
  }
194
201
  return label;
@@ -15,6 +15,14 @@ const KEY = exports.KEY = 'make_read_only';
15
15
  function readOnlyItem() {
16
16
  return {
17
17
  key: KEY,
18
+ checkable: true,
19
+ ariaChecked() {
20
+ const atLeastOneReadOnly = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => this.getCellMeta(row, col).readOnly);
21
+ return atLeastOneReadOnly;
22
+ },
23
+ ariaLabel() {
24
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_READ_ONLY);
25
+ },
18
26
  name() {
19
27
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_READ_ONLY);
20
28
  const atLeastOneReadOnly = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => this.getCellMeta(row, col).readOnly);
@@ -9,6 +9,14 @@ export const KEY = 'make_read_only';
9
9
  export default function readOnlyItem() {
10
10
  return {
11
11
  key: KEY,
12
+ checkable: true,
13
+ ariaChecked() {
14
+ const atLeastOneReadOnly = checkSelectionConsistency(this.getSelectedRange(), (row, col) => this.getCellMeta(row, col).readOnly);
15
+ return atLeastOneReadOnly;
16
+ },
17
+ ariaLabel() {
18
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_READ_ONLY);
19
+ },
12
20
  name() {
13
21
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_READ_ONLY);
14
22
  const atLeastOneReadOnly = checkSelectionConsistency(this.getSelectedRange(), (row, col) => this.getCellMeta(row, col).readOnly);
@@ -4,7 +4,9 @@ exports.__esModule = true;
4
4
  exports.align = align;
5
5
  exports.checkSelectionConsistency = checkSelectionConsistency;
6
6
  exports.getAlignmentClasses = getAlignmentClasses;
7
+ exports.getAlignmentComparatorByClass = getAlignmentComparatorByClass;
7
8
  exports.getDocumentOffsetByElement = getDocumentOffsetByElement;
9
+ exports.hasSelectionAClass = hasSelectionAClass;
8
10
  exports.markLabelAsSelected = markLabelAsSelected;
9
11
  exports.prepareHorizontalAlignClass = prepareHorizontalAlignClass;
10
12
  exports.prepareVerticalAlignClass = prepareVerticalAlignClass;
@@ -151,4 +153,28 @@ function getDocumentOffsetByElement(elementToCheck, baseDocument) {
151
153
  offset.left = left;
152
154
  }
153
155
  return offset;
156
+ }
157
+
158
+ /**
159
+ * Prepares comparator function consumable by checkSelectionConsistency
160
+ * Comparator function checks if the cell has the provided class name.
161
+ *
162
+ * @param {string} htClassName The class name to check.
163
+ * @returns {Function} Returns the comparator function.
164
+ * Use with .bind, .call or .apply to pass the Handsontable instance.
165
+ */
166
+ function getAlignmentComparatorByClass(htClassName) {
167
+ return function (row, col) {
168
+ const className = this.getCellMeta(row, col).className;
169
+ return className && className.indexOf(htClassName) !== -1;
170
+ };
171
+ }
172
+
173
+ /**
174
+ * @param {object} hot Handsontable instance.
175
+ * @param {string} htClassName The class name to check.
176
+ * @returns {boolean} Returns true if at least one cell has the provided class name.
177
+ */
178
+ function hasSelectionAClass(hot, htClassName) {
179
+ return checkSelectionConsistency(hot.getSelectedRange(), getAlignmentComparatorByClass(htClassName).bind(hot));
154
180
  }
@@ -141,4 +141,28 @@ export function getDocumentOffsetByElement(elementToCheck, baseDocument) {
141
141
  offset.left = left;
142
142
  }
143
143
  return offset;
144
+ }
145
+
146
+ /**
147
+ * Prepares comparator function consumable by checkSelectionConsistency
148
+ * Comparator function checks if the cell has the provided class name.
149
+ *
150
+ * @param {string} htClassName The class name to check.
151
+ * @returns {Function} Returns the comparator function.
152
+ * Use with .bind, .call or .apply to pass the Handsontable instance.
153
+ */
154
+ export function getAlignmentComparatorByClass(htClassName) {
155
+ return function (row, col) {
156
+ const className = this.getCellMeta(row, col).className;
157
+ return className && className.indexOf(htClassName) !== -1;
158
+ };
159
+ }
160
+
161
+ /**
162
+ * @param {object} hot Handsontable instance.
163
+ * @param {string} htClassName The class name to check.
164
+ * @returns {boolean} Returns true if at least one cell has the provided class name.
165
+ */
166
+ export function hasSelectionAClass(hot, htClassName) {
167
+ return checkSelectionConsistency(hot.getSelectedRange(), getAlignmentComparatorByClass(htClassName).bind(hot));
144
168
  }
@@ -553,12 +553,13 @@ class CopyPaste extends _base.BasePlugin {
553
553
  * @private
554
554
  */
555
555
  onCopy(event) {
556
- if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened()) {
557
- return;
558
- }
559
- if (!this.hot.getSettings().outsideClickDeselects && event.target !== this.hot.rootDocument.body) {
556
+ var _event$target;
557
+ const focusedElement = this.hot.getFocusManager().getRefocusElement();
558
+ const isHotInput = (_event$target = event.target) === null || _event$target === void 0 ? void 0 : _event$target.hasAttribute('data-hot-input');
559
+ if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened() || event.target instanceof HTMLElement && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body)) {
560
560
  return;
561
561
  }
562
+ event.preventDefault();
562
563
  this.setCopyableText();
563
564
  _classPrivateFieldSet(_isTriggeredByCopy, this, false);
564
565
  const data = this.getRangedData(this.copyableRanges);
@@ -576,7 +577,6 @@ class CopyPaste extends _base.BasePlugin {
576
577
  this.hot.runHooks('afterCopy', data, this.copyableRanges, copiedHeadersCount);
577
578
  }
578
579
  _classPrivateFieldSet(_copyMode, this, 'cells-only');
579
- event.preventDefault();
580
580
  }
581
581
 
582
582
  /**
@@ -586,12 +586,13 @@ class CopyPaste extends _base.BasePlugin {
586
586
  * @private
587
587
  */
588
588
  onCut(event) {
589
- if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened()) {
590
- return;
591
- }
592
- if (!this.hot.getSettings().outsideClickDeselects && event.target !== this.hot.rootDocument.body) {
589
+ var _event$target2;
590
+ const focusedElement = this.hot.getFocusManager().getRefocusElement();
591
+ const isHotInput = (_event$target2 = event.target) === null || _event$target2 === void 0 ? void 0 : _event$target2.hasAttribute('data-hot-input');
592
+ if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened() || event.target instanceof HTMLElement && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body)) {
593
593
  return;
594
594
  }
595
+ event.preventDefault();
595
596
  this.setCopyableText();
596
597
  _classPrivateFieldSet(_isTriggeredByCut, this, false);
597
598
  const rangedData = this.getRangedData(this.copyableRanges);
@@ -608,7 +609,6 @@ class CopyPaste extends _base.BasePlugin {
608
609
  this.hot.emptySelectedCells('CopyPaste.cut');
609
610
  this.hot.runHooks('afterCut', rangedData, this.copyableRanges);
610
611
  }
611
- event.preventDefault();
612
612
  }
613
613
 
614
614
  /**
@@ -618,10 +618,10 @@ class CopyPaste extends _base.BasePlugin {
618
618
  * @private
619
619
  */
620
620
  onPaste(event) {
621
- if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected()) {
622
- return;
623
- }
624
- if (!this.hot.getSettings().outsideClickDeselects && event.target !== this.hot.rootDocument.body) {
621
+ var _event$target3;
622
+ const focusedElement = this.hot.getFocusManager().getRefocusElement();
623
+ const isHotInput = (_event$target3 = event.target) === null || _event$target3 === void 0 ? void 0 : _event$target3.hasAttribute('data-hot-input');
624
+ if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected() || event.target instanceof HTMLElement && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body)) {
625
625
  return;
626
626
  }
627
627
  event.preventDefault();
@@ -549,12 +549,13 @@ export class CopyPaste extends BasePlugin {
549
549
  * @private
550
550
  */
551
551
  onCopy(event) {
552
- if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened()) {
553
- return;
554
- }
555
- if (!this.hot.getSettings().outsideClickDeselects && event.target !== this.hot.rootDocument.body) {
552
+ var _event$target;
553
+ const focusedElement = this.hot.getFocusManager().getRefocusElement();
554
+ const isHotInput = (_event$target = event.target) === null || _event$target === void 0 ? void 0 : _event$target.hasAttribute('data-hot-input');
555
+ if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened() || event.target instanceof HTMLElement && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body)) {
556
556
  return;
557
557
  }
558
+ event.preventDefault();
558
559
  this.setCopyableText();
559
560
  _classPrivateFieldSet(_isTriggeredByCopy, this, false);
560
561
  const data = this.getRangedData(this.copyableRanges);
@@ -572,7 +573,6 @@ export class CopyPaste extends BasePlugin {
572
573
  this.hot.runHooks('afterCopy', data, this.copyableRanges, copiedHeadersCount);
573
574
  }
574
575
  _classPrivateFieldSet(_copyMode, this, 'cells-only');
575
- event.preventDefault();
576
576
  }
577
577
 
578
578
  /**
@@ -582,12 +582,13 @@ export class CopyPaste extends BasePlugin {
582
582
  * @private
583
583
  */
584
584
  onCut(event) {
585
- if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened()) {
586
- return;
587
- }
588
- if (!this.hot.getSettings().outsideClickDeselects && event.target !== this.hot.rootDocument.body) {
585
+ var _event$target2;
586
+ const focusedElement = this.hot.getFocusManager().getRefocusElement();
587
+ const isHotInput = (_event$target2 = event.target) === null || _event$target2 === void 0 ? void 0 : _event$target2.hasAttribute('data-hot-input');
588
+ if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened() || event.target instanceof HTMLElement && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body)) {
589
589
  return;
590
590
  }
591
+ event.preventDefault();
591
592
  this.setCopyableText();
592
593
  _classPrivateFieldSet(_isTriggeredByCut, this, false);
593
594
  const rangedData = this.getRangedData(this.copyableRanges);
@@ -604,7 +605,6 @@ export class CopyPaste extends BasePlugin {
604
605
  this.hot.emptySelectedCells('CopyPaste.cut');
605
606
  this.hot.runHooks('afterCut', rangedData, this.copyableRanges);
606
607
  }
607
- event.preventDefault();
608
608
  }
609
609
 
610
610
  /**
@@ -614,10 +614,10 @@ export class CopyPaste extends BasePlugin {
614
614
  * @private
615
615
  */
616
616
  onPaste(event) {
617
- if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected()) {
618
- return;
619
- }
620
- if (!this.hot.getSettings().outsideClickDeselects && event.target !== this.hot.rootDocument.body) {
617
+ var _event$target3;
618
+ const focusedElement = this.hot.getFocusManager().getRefocusElement();
619
+ const isHotInput = (_event$target3 = event.target) === null || _event$target3 === void 0 ? void 0 : _event$target3.hasAttribute('data-hot-input');
620
+ if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected() || event.target instanceof HTMLElement && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body)) {
621
621
  return;
622
622
  }
623
623
  event.preventDefault();
@@ -260,13 +260,16 @@ class DropdownMenu extends _base.BasePlugin {
260
260
  from
261
261
  } = this.hot.getSelectedRangeLast();
262
262
  const offset = (0, _utils.getDocumentOffsetByElement)(this.menu.container, this.hot.rootDocument);
263
- const target = this.hot.getCell(-1, from.col, true);
263
+ const target = this.hot.getCell(-1, from.col, true).querySelector(`.${BUTTON_CLASS_NAME}`);
264
264
  const rect = target.getBoundingClientRect();
265
265
  this.open({
266
266
  left: rect.left + offset.left,
267
267
  top: rect.top + target.offsetHeight + offset.top
268
268
  }, {
269
- left: rect.width
269
+ left: rect.width,
270
+ right: 0,
271
+ above: 0,
272
+ below: 3
270
273
  });
271
274
  // Make sure the first item is selected (role=menuitem). Otherwise, screen readers
272
275
  // will block the Esc key for the whole menu.
@@ -433,9 +436,12 @@ function _onTableClick(event) {
433
436
  _classPrivateFieldSet(_isButtonClicked, this, false);
434
437
  this.open({
435
438
  left: rect.left + offset.left,
436
- top: rect.top + event.target.offsetHeight + 3 + offset.top
439
+ top: rect.top + event.target.offsetHeight + offset.top
437
440
  }, {
438
- left: rect.width
441
+ left: rect.width,
442
+ right: 0,
443
+ above: 0,
444
+ below: 3
439
445
  });
440
446
  }
441
447
  }